1 //! A simple single-threaded executor.
2 
3 use std::future::Future;
4 use std::panic::catch_unwind;
5 use std::thread;
6 
7 use async_task::{Runnable, Task};
8 use once_cell::sync::Lazy;
9 use smol::future;
10 
11 /// Spawns a future on the executor.
spawn<F, T>(future: F) -> Task<T> where F: Future<Output = T> + Send + 'static, T: Send + 'static,12 fn spawn<F, T>(future: F) -> Task<T>
13 where
14     F: Future<Output = T> + Send + 'static,
15     T: Send + 'static,
16 {
17     // A queue that holds scheduled tasks.
18     static QUEUE: Lazy<flume::Sender<Runnable>> = Lazy::new(|| {
19         let (sender, receiver) = flume::unbounded::<Runnable>();
20 
21         // Start the executor thread.
22         thread::spawn(|| {
23             for runnable in receiver {
24                 // Ignore panics inside futures.
25                 let _ignore_panic = catch_unwind(|| runnable.run());
26             }
27         });
28 
29         sender
30     });
31 
32     // Create a task that is scheduled by pushing it into the queue.
33     let schedule = |runnable| QUEUE.send(runnable).unwrap();
34     let (runnable, task) = async_task::spawn(future, schedule);
35 
36     // Schedule the task by pushing it into the queue.
37     runnable.schedule();
38 
39     task
40 }
41 
main()42 fn main() {
43     // Spawn a future and await its result.
44     let task = spawn(async {
45         println!("Hello, world!");
46     });
47     future::block_on(task);
48 }
49