async_task/lib.rs
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//! returns 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//! # let handle = std::thread::spawn(move || { for runnable in receiver { runnable.run(); }});
40//! # smol::future::block_on(task);
41//! # handle.join().unwrap();
42//! ```
43//!
44//! The [`Runnable`] is used to poll the task's future, and the [`Task`] is used to await its
45//! output.
46//!
47//! Finally, we need a loop that takes scheduled tasks from the queue and runs them:
48//!
49//! ```no_run
50//! # let (sender, receiver) = flume::unbounded();
51//! #
52//! # // A future that will get spawned.
53//! # let future = async { 1 + 2 };
54//! #
55//! # // A function that schedules the task when it gets woken up.
56//! # let schedule = move |runnable| sender.send(runnable).unwrap();
57//! #
58//! # // Create a task.
59//! # let (runnable, task) = async_task::spawn(future, schedule);
60//! #
61//! # // Push the task into the queue by invoking its schedule function.
62//! # runnable.schedule();
63//! #
64//! for runnable in receiver {
65//! runnable.run();
66//! }
67//! ```
68//!
69//! Method [`run()`][`Runnable::run()`] polls the task's future once. Then, the [`Runnable`]
70//! vanishes and only reappears when its [`Waker`][`core::task::Waker`] wakes the task, thus
71//! scheduling it to be run again.
72
73#![no_std]
74#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
75#![doc(test(attr(deny(rust_2018_idioms, warnings))))]
76#![doc(test(attr(allow(unused_variables))))]
77#![doc(
78 html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
79)]
80#![doc(
81 html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
82)]
83
84extern crate alloc;
85#[cfg(feature = "std")]
86extern crate std;
87
88/// We can't use `?` in const contexts yet, so this macro acts
89/// as a workaround.
90macro_rules! leap {
91 ($x: expr) => {{
92 match ($x) {
93 Some(val) => val,
94 None => return None,
95 }
96 }};
97}
98
99macro_rules! leap_unwrap {
100 ($x: expr) => {{
101 match ($x) {
102 Some(val) => val,
103 None => panic!("called `Option::unwrap()` on a `None` value"),
104 }
105 }};
106}
107
108mod header;
109mod raw;
110mod runnable;
111mod state;
112mod task;
113mod utils;
114
115pub use crate::runnable::{
116 spawn, spawn_unchecked, Builder, Runnable, Schedule, ScheduleInfo, ScheduleParts, WithInfo,
117};
118pub use crate::task::{FallibleTask, Task};
119
120#[cfg(feature = "std")]
121pub use crate::runnable::spawn_local;