1 //! Task abstraction for building executors. 2 //! 3 //! To spawn a future onto an executor, we first need to allocate it on the heap and keep some 4 //! state attached to it. The state indicates whether the future is ready for polling, waiting to 5 //! be woken up, or completed. Such a stateful future is called a *task*. 6 //! 7 //! All executors have a queue that holds scheduled tasks: 8 //! 9 //! ``` 10 //! let (sender, receiver) = flume::unbounded(); 11 //! # 12 //! # // A future that will get spawned. 13 //! # let future = async { 1 + 2 }; 14 //! # 15 //! # // A function that schedules the task when it gets woken up. 16 //! # let schedule = move |runnable| sender.send(runnable).unwrap(); 17 //! # 18 //! # // Create a task. 19 //! # let (runnable, task) = async_task::spawn(future, schedule); 20 //! ``` 21 //! 22 //! A task is created using either [`spawn()`], [`spawn_local()`], or [`spawn_unchecked()`] which 23 //! return a [`Runnable`] and a [`Task`]: 24 //! 25 //! ``` 26 //! # let (sender, receiver) = flume::unbounded(); 27 //! # 28 //! // A future that will be spawned. 29 //! let future = async { 1 + 2 }; 30 //! 31 //! // A function that schedules the task when it gets woken up. 32 //! let schedule = move |runnable| sender.send(runnable).unwrap(); 33 //! 34 //! // Construct a task. 35 //! let (runnable, task) = async_task::spawn(future, schedule); 36 //! 37 //! // Push the task into the queue by invoking its schedule function. 38 //! runnable.schedule(); 39 //! ``` 40 //! 41 //! The [`Runnable`] is used to poll the task's future, and the [`Task`] is used to await its 42 //! output. 43 //! 44 //! Finally, we need a loop that takes scheduled tasks from the queue and runs them: 45 //! 46 //! ```no_run 47 //! # let (sender, receiver) = flume::unbounded(); 48 //! # 49 //! # // A future that will get spawned. 50 //! # let future = async { 1 + 2 }; 51 //! # 52 //! # // A function that schedules the task when it gets woken up. 53 //! # let schedule = move |runnable| sender.send(runnable).unwrap(); 54 //! # 55 //! # // Create a task. 56 //! # let (runnable, task) = async_task::spawn(future, schedule); 57 //! # 58 //! # // Push the task into the queue by invoking its schedule function. 59 //! # runnable.schedule(); 60 //! # 61 //! for runnable in receiver { 62 //! runnable.run(); 63 //! } 64 //! ``` 65 //! 66 //! Method [`run()`][`Runnable::run()`] polls the task's future once. Then, the [`Runnable`] 67 //! vanishes and only reappears when its [`Waker`][`core::task::Waker`] wakes the task, thus 68 //! scheduling it to be run again. 69 70 #![no_std] 71 #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] 72 #![doc(test(attr(deny(rust_2018_idioms, warnings))))] 73 #![doc(test(attr(allow(unused_extern_crates, unused_variables))))] 74 #![doc( 75 html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" 76 )] 77 #![doc( 78 html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" 79 )] 80 81 extern crate alloc; 82 #[cfg(feature = "std")] 83 extern crate std; 84 85 /// We can't use `?` in const contexts yet, so this macro acts 86 /// as a workaround. 87 macro_rules! leap { 88 ($x: expr) => {{ 89 match ($x) { 90 Some(val) => val, 91 None => return None, 92 } 93 }}; 94 } 95 96 macro_rules! leap_unwrap { 97 ($x: expr) => {{ 98 match ($x) { 99 Some(val) => val, 100 None => panic!("called `Option::unwrap()` on a `None` value"), 101 } 102 }}; 103 } 104 105 mod header; 106 mod raw; 107 mod runnable; 108 mod state; 109 mod task; 110 mod utils; 111 112 pub use crate::runnable::{ 113 spawn, spawn_unchecked, Builder, Runnable, Schedule, ScheduleInfo, WithInfo, 114 }; 115 pub use crate::task::{FallibleTask, Task}; 116 117 #[cfg(feature = "std")] 118 pub use crate::runnable::spawn_local; 119