use async_trait::async_trait; use futures::{executor::block_on, Future}; use std::{convert::Infallible, path::Path}; /// Basic logging effect #[async_trait(?Send)] trait Log { async fn log(&self, message: &str); } // TODO // async fn handle_log<'a, T: 'a, Fut: Future + 'a>( // log: impl Fn(&str) + 'a, // f: impl FnOnce(Box) -> Fut + 'a, // ) -> T { // reset(|reset_handler| async move { // struct LogHandler<'a, T> { // log: Rc, // reset_handler: ResetHandlerImpl<'a, T>, // } // #[async_trait(?Send)] // impl<'a, T> Log for LogHandler<'a, T> { // async fn log(&self, message: &str) { // let log = self.log.clone(); // let _: () = { // self.reset_handler.shift(move |resume| async move { // log(message); // resume(()).await // }) // } // .await; // unreachable!() // } // } // let cancel = LogHandler { // log: Rc::new(log), // reset_handler, // }; // f(Box::new(cancel)).await // }) // .await // } // #[effect::handler] #[async_trait(?Send)] trait Cancel { async fn cancel(&self, value: T) -> Infallible; } async fn handle_cancel<'a, T: 'a, Fut: Future + 'a>( f: impl FnOnce(Box + 'a>) -> Fut + 'a, ) -> T { switch_resume::run(|task| async move { struct CancelHandler<'a, T> { reset_handler: switch_resume::Task<'a, T>, } #[async_trait(?Send)] impl<'a, T> Cancel for CancelHandler<'a, T> { async fn cancel(&self, value: T) -> Infallible { let _: () = { self.reset_handler.switch(|_cc| async { value }) }.await; unreachable!() } } let cancel = CancelHandler { reset_handler: task, }; f(Box::new(cancel)).await }) .await } #[async_trait(?Send)] trait FileSystem { async fn read_file(&self, path: impl AsRef) -> Result; } async fn simple(log: &(impl Log + ?Sized), cancel: &(impl Cancel + ?Sized)) -> i32 { log.log("hello").await; log.log("world").await; cancel.cancel(4).await; log.log("this will never be logged").await; 10 } async fn combined(log: &(impl Log + ?Sized), fs: &(impl FileSystem + ?Sized)) { let passwords = fs.read_file("passwords.txt").await.unwrap(); log.log(&format!("passwords are: {passwords:?}")).await; let x = handle_cancel(|cancel| async move { let cancel = &*cancel; simple(log, cancel).await }) .await; println!("x = {x}"); } async fn run() { struct LogHandler; #[async_trait(?Send)] impl Log for LogHandler { async fn log(&self, message: &str) { println!("{message}"); } } struct FileSystemHandler; #[async_trait(?Send)] impl FileSystem for FileSystemHandler { async fn read_file(&self, _path: impl AsRef) -> Result { Ok("hello, there!".to_owned()) } } combined(&LogHandler, &FileSystemHandler).await; } fn main() { // ask chatgpt to write you comment // This is my code - It's your probem now - I'm out block_on(run()); }