async_fuse/lib.rs
1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/async--fuse-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/async-fuse)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/async-fuse.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/async-fuse)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--fuse-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/async-fuse)
4//!
5//! Helpers for "fusing" asynchronous computations.
6//!
7//! A fused operation has a well-defined behavior once the operation has
8//! completed. For [`Fuse`] it means that an operation that has completed will
9//! *block forever* by returning [`Poll::Pending`].
10//!
11//! This is similar to the [`Fuse`][futures-fs-fuse] type provided in
12//! futures-rs, but provides more utility allowing it to interact with types
13//! which does not implement [`FusedFuture`] or [`FusedStream`] as is now the
14//! case with all Tokio types since 1.0.
15//!
16//! We also use [`Fuse`] to represent optional values, just like `Option`. But
17//! [`Fuse`] provides implementations and functions which allow us to safely
18//! perform operations over the value when it's pinned. Exactly what's needed to
19//! drive a [`Stream`][stream03] (see [`next`]) or poll a [`Future`] that might
20//! or might not be set.
21//!
22//! <br>
23//!
24//! ## Features
25//!
26//! * `stream03` - Makes the [`Fuse`] implement the [`Stream`][stream03] trait
27//! if it contains a stream from the futures-core (`0.3.x`) crate.
28//!
29//! <br>
30//!
31//! ## Simplifying [`tokio::select!`]
32//!
33//! One of the main uses for [`Fuse`] is to simplify how we use
34//! [`tokio::select!`]. In this section we'll look at how we can improve an
35//! optional branch, where the future being polled might or might not be set.
36//!
37//! ```rust
38//! use std::pin::pin;
39//!
40//! # #[tokio::main] async fn main() {
41//! let mut maybe_future = pin!(Some(async { 42u32 }));
42//!
43//! tokio::select! {
44//! value = async { maybe_future.as_mut().as_pin_mut().unwrap().await }, if maybe_future.is_some() => {
45//! maybe_future.set(None);
46//! assert_eq!(value, 42);
47//! }
48//! /* other branches */
49//! }
50//!
51//! assert!(maybe_future.is_none());
52//! # }
53//! ```
54//!
55//! The `async` block above is necessary because the future is polled *eagerly*
56//! regardless of the [branch precondition]. This would cause the `unwrap` to
57//! panic in case the future isn't set. We also need to explicitly set the pin
58//! to `None` after completion. Otherwise we might poll it later [which might
59//! panic].
60//!
61//! With [`Fuse`] we can rewrite the branch and remove the `async` block. It also
62//! unsets the future for us after completion.
63//!
64//! ```rust
65//! use std::pin::pin;
66//! use async_fuse::Fuse;
67//!
68//! # #[tokio::main]
69//! # async fn main() {
70//! let mut maybe_future = pin!(Fuse::new(async { 42u32 }));
71//!
72//! tokio::select! {
73//! value = &mut maybe_future, if !maybe_future.is_empty() => {
74//! assert_eq!(value, 42);
75//! }
76//! /* other branches */
77//! }
78//!
79//! assert!(maybe_future.is_empty());
80//! # }
81//! ```
82//!
83//! Finally if we don't need the [else branch] to evalute we can skip the
84//! [branch precondition] entirely. Allowing us to further reduce the code.
85//!
86//! ```rust
87//! use std::pin::pin;
88//! use async_fuse::Fuse;
89//!
90//! # #[tokio::main]
91//! # async fn main() {
92//! let mut maybe_future = pin!(Fuse::new(async { 42u32 }));
93//!
94//! tokio::select! {
95//! value = &mut maybe_future => {
96//! assert_eq!(value, 42);
97//! }
98//! /* other branches */
99//! }
100//!
101//! assert!(maybe_future.is_empty());
102//! # }
103//! ```
104//!
105//! <br>
106//!
107//! ## Fusing on the stack
108//!
109//! For the first example we'll be fusing the value *on the stack* using
110//! [`pin!`]. We'll also be updating the fuse as it completes with another sleep
111//! with a configurable delay. Mimicking the behavior of [`Interval`].
112//!
113//! > This is available as the `stack_ticker` example:
114//! > ```sh
115//! > cargo run --example stack_ticker
116//! > ```
117//!
118//! ```rust
119//! use std::pin::pin;
120//! use async_fuse::Fuse;
121//! use std::time::Duration;
122//! use tokio::time;
123//!
124//! # #[tokio::main]
125//! # async fn main() {
126//! let mut duration = Duration::from_millis(500);
127//!
128//! let mut sleep = pin!(Fuse::new(time::sleep(duration)));
129//! let mut update_duration = pin!(Fuse::new(time::sleep(Duration::from_secs(2))));
130//!
131//! for _ in 0..10usize {
132//! tokio::select! {
133//! _ = &mut sleep => {
134//! println!("Tick");
135//! sleep.set(Fuse::new(time::sleep(duration)));
136//! }
137//! _ = &mut update_duration => {
138//! println!("Tick faster!");
139//! duration = Duration::from_millis(250);
140//! }
141//! }
142//! }
143//! # }
144//! ```
145//!
146//! <br>
147//!
148//! ## Fusing on the heap
149//!
150//! For some types it might be easier to fuse the value on the heap. To make
151//! this easier, we provide the [`Fuse::pin`] constructor which provides a fused
152//! value which is pinned on the heap.
153//!
154//! As a result, it looks pretty similar to the above example.
155//!
156//! > This is available as the `heap_ticker` example:
157//! > ```sh
158//! > cargo run --example heap_ticker
159//! > ```
160//!
161//! ```rust
162//! use async_fuse::Fuse;
163//! use std::time::Duration;
164//! use tokio::time;
165//!
166//! # #[tokio::main]
167//! # async fn main() {
168//! let mut duration = Duration::from_millis(500);
169//!
170//! let mut sleep = Fuse::pin(time::sleep(duration));
171//! let mut update_duration = Fuse::pin(time::sleep(Duration::from_secs(2)));
172//!
173//! for _ in 0..10usize {
174//! tokio::select! {
175//! _ = &mut sleep => {
176//! println!("Tick");
177//! sleep.set(Box::pin(time::sleep(duration)));
178//! }
179//! _ = &mut update_duration => {
180//! println!("Tick faster!");
181//! duration = Duration::from_millis(250);
182//! }
183//! }
184//! }
185//! # }
186//! ```
187//!
188//! <br>
189//!
190//! ## Fusing trait objects
191//!
192//! The following showcases how we can fuse a trait object. Trait objects are
193//! useful since they allow the fused value to change between distinct
194//! implementations. The price is that we perform dynamic dispatch which has a
195//! small cost.
196//!
197//! Also note that because [`CoerceUnsized`] is not yet stable, we cannot use
198//! [`Fuse::pin`] for convenience and have to pass a pinned box through
199//! [`Fuse::new`].
200//!
201//! > This is available as the `trait_object_ticker` example:
202//! > ```sh
203//! > cargo run --example trait_object_ticker
204//! > ```
205//!
206//! ```rust
207//! use std::future::Future;
208//! use std::time::Duration;
209//! use std::pin::Pin;
210//! use async_fuse::Fuse;
211//! use tokio::time;
212//!
213//! # #[tokio::main]
214//! # async fn main() {
215//! let mut duration = Duration::from_millis(500);
216//!
217//! let mut sleep: Fuse<Pin<Box<dyn Future<Output = ()>>>> =
218//! Fuse::new(Box::pin(time::sleep(duration)));
219//!
220//! let mut update_duration: Fuse<Pin<Box<dyn Future<Output = ()>>>> =
221//! Fuse::new(Box::pin(time::sleep(Duration::from_secs(2))));
222//!
223//! for _ in 0..10usize {
224//! tokio::select! {
225//! _ = &mut sleep => {
226//! println!("Tick");
227//! sleep.set(Box::pin(time::sleep(duration)));
228//! }
229//! _ = &mut update_duration => {
230//! println!("Tick faster!");
231//! duration = Duration::from_millis(250);
232//! }
233//! }
234//! }
235//! # }
236//! ```
237//!
238//! [`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html
239//! [`Fuse::new`]: https://docs.rs/async-fuse/0/async_fuse/struct.Fuse.html#method.new
240//! [`Fuse::pin`]: https://docs.rs/async-fuse/0/async_fuse/struct.Fuse.html#method.pin
241//! [`Fuse`]: https://docs.rs/async-fuse/0/async_fuse/struct.Fuse.html
242//! [`FusedFuture`]: https://docs.rs/futures/0/futures/future/trait.FusedFuture.html
243//! [`FusedStream`]: https://docs.rs/futures/0/futures/stream/trait.FusedStream.html
244//! [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
245//! [`Interval`]: https://docs.rs/tokio/1/tokio/time/struct.Interval.html
246//! [`next`]: https://docs.rs/async-fuse/0/async_fuse/struct.Fuse.html#method.next
247//! [`pin!`]: https://doc.rust-lang.org/std/pin/macro.pin.html
248//! [`Poll::Pending`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending
249//! [`tokio::select!`]: https://docs.rs/tokio/1/tokio/macro.select.html
250//! [branch precondition]: https://docs.rs/tokio/1.0.1/tokio/macro.select.html#avoid-racy-if-preconditions
251//! [else branch]: https://docs.rs/tokio/1.0.1/tokio/macro.select.html
252//! [futures-fs-fuse]: https://docs.rs/futures/0/futures/future/struct.Fuse.html
253//! [stream03]: https://docs.rs/futures-core/0/futures_core/stream/trait.Stream.html
254//! [which might panic]: https://doc.rust-lang.org/std/future/trait.Future.html#panics
255
256#![deny(missing_docs)]
257#![cfg_attr(docsrs, feature(doc_cfg))]
258#![no_std]
259
260#[cfg(feature = "alloc")]
261extern crate alloc;
262
263#[cfg(feature = "std")]
264extern crate std;
265
266mod fuse;
267mod poll;
268
269pub use self::fuse::Fuse;