futures_concurrency/lib.rs
1//! Performant, portable, structured concurrency operations for async Rust. It
2//! works with any runtime, does not erase lifetimes, always handles
3//! cancellation, and always returns output to the caller.
4//!
5//! `futures-concurrency` provides concurrency operations for both groups of futures
6//! and streams. Both for bounded and unbounded sets of futures and streams. In both
7//! cases performance should be on par with, if not exceed conventional executor
8//! implementations.
9//!
10//! # Examples
11//!
12//! **Await multiple futures of different types**
13//! ```rust
14//! use futures_concurrency::prelude::*;
15//! use std::future;
16//!
17//! # futures::executor::block_on(async {
18//! let a = future::ready(1u8);
19//! let b = future::ready("hello");
20//! let c = future::ready(3u16);
21//! assert_eq!((a, b, c).join().await, (1, "hello", 3));
22//! # });
23//! ```
24//!
25//! **Concurrently process items in a collection**
26//!
27//! ```rust
28//! use futures_concurrency::prelude::*;
29//!
30//! # futures::executor::block_on(async {
31//! let v: Vec<_> = vec!["chashu", "nori"]
32//! .into_co_stream()
33//! .map(|msg| async move { format!("hello {msg}") })
34//! .collect()
35//! .await;
36//!
37//! assert_eq!(v, &["hello chashu", "hello nori"]);
38//! # });
39//! ```
40//!
41//! **Access stack data outside the futures' scope**
42//!
43//! _Adapted from [`std::thread::scope`](https://doc.rust-lang.org/std/thread/fn.scope.html)._
44//!
45//! ```rust
46//! use futures_concurrency::prelude::*;
47//!
48//! # futures::executor::block_on(async {
49//! let mut container = vec![1, 2, 3];
50//! let mut num = 0;
51//!
52//! let a = async {
53//! println!("hello from the first future");
54//! dbg!(&container);
55//! };
56//!
57//! let b = async {
58//! println!("hello from the second future");
59//! num += container[0] + container[2];
60//! };
61//!
62//! println!("hello from the main future");
63//! let _ = (a, b).join().await;
64//! container.push(4);
65//! assert_eq!(num, container.len());
66//! # });
67//! ```
68//!
69//! # Operations
70//!
71//! ## Futures
72//!
73//! For futures which return a regular type `T` only the `join` and `race`
74//! operations are available. `join` waits for all futures to complete, while `race`
75//! will wait for the first future to complete. However for futures which return a
76//! `Try<Output = T>` two additional operations are available. The following table
77//! describes the behavior of concurrency operations for fallible futures:
78//!
79//! | | **Wait for all outputs** | **Wait for first output** |
80//! | -------------------------- | :----------------------- | :------------------------ |
81//! | **Continue on error** | `Future::join` | `Future::race_ok` |
82//! | **Short-circuit on error** | `Future::try_join` | `Future::race` |
83//!
84//! The following futures implementations are provided by `futures-concurrency`:
85//! - [`FutureGroup`][future::FutureGroup]: A growable group of futures which operate as a single unit.
86//! - `tuple`: [`join`][future::Join#impl-Join-for-(A,+B)], [`try_join`][future::TryJoin#impl-TryJoin-for-(A,+B)], [`race`][future::Race#impl-Race-for-(A,+B)], [`race_ok`][future::RaceOk#impl-RaceOk-for-(A,+B)]
87//! - `array`: [`join`][future::Join#impl-Join-for-\[Fut;+N\]], [`try_join`][future::TryJoin#impl-TryJoin-for-\[Fut;+N\]], [`race`][future::Race#impl-Race-for-\[Fut;+N\]], [`race_ok`][future::RaceOk#impl-RaceOk-for-\[Fut;+N\]]
88//! - `Vec`: [`join`][future::Join#impl-Join-for-Vec<Fut>], [`try_join`][future::TryJoin#impl-TryJoin-for-Vec<Fut>], [`race`][future::Race#impl-Race-for-Vec<Fut>], [`race_ok`][future::RaceOk#impl-RaceOk-for-Vec<Fut>]
89//!
90//! ## Streams
91//!
92//! Streams yield outputs one-by-one, which means that deciding to stop iterating is
93//! the same for fallible and infallible streams. The operations provided for
94//! streams can be categorized based on whether their inputs can be concurrently
95//! evaluated, and whether their outputs can be concurrently processed.
96//!
97//! Specifically in the case of `merge`, it takes `N` streams in, and yields items
98//! one-by-one as soon as any are available. This enables the output of individual
99//! streams to be concurrently processed by further operations later on.
100//!
101//! | | __Sequential output processing__ | __Concurrent output processing__ |
102//! | ------------------------------- | -------------------------------- | -------------------------------- |
103//! | __Sequential input evaluation__ | `Stream::chain` | *not yet available* ‡ |
104//! | __Concurrent input evaluation__ | `Stream::zip` | `Stream::merge` |
105//!
106//! ‡: _This could be addressed by a hypothetical `Stream::unzip` operation,
107//! however because we aspire for semantic compatibility with `std::iter::Iterator`
108//! in our operations, the path to adding it is currently unclear_.
109//!
110//! The following streams implementations are provided by `futures-concurrency`:
111//!
112//! - [`StreamGroup`][stream::StreamGroup]: A growable group of streams which operate as a single unit.
113//! - [`ConcurrentStream`][concurrent_stream::ConcurrentStream]: A trait for asynchronous streams which can concurrently process items.
114//! - `tuple`: [`chain`][stream::Chain#impl-Chain-for-(A,+B)], [`merge`][stream::Merge#impl-Merge-for-(A,+B)], [`zip`][stream::Zip#impl-Zip-for-(A,+B)]
115//! - `array`: [`chain`][stream::Chain#impl-Chain-for-\[Fut;+N\]], [`merge`][stream::Merge#impl-Merge-for-\[Fut;+N\]], [`zip`][stream::Zip#impl-Zip-for-\[Fut;+N\]]
116//! - `Vec`: [`chain`][stream::Chain#impl-Chain-for-Vec<Fut>], [`merge`][stream::Merge#impl-Merge-for-Vec<Fut>], [`zip`][stream::Zip#impl-Zip-for-Vec<Fut>]
117//!
118//! # Runtime Support
119//!
120//! `futures-concurrency` does not depend on any runtime executor being present.
121//! This enables it to work out of the box with any async runtime, including:
122//! `tokio`, `async-std`, `smol`, `glommio`, and `monoio`. It also supports
123//! `#[no_std]` environments, allowing it to be used with embedded async
124//! runtimes such as `embassy`.
125//!
126//! # Feature Flags
127//!
128//! The `std` feature flag is enabled by default. To target `alloc` or `no_std`
129//! environments, you can enable the following configuration:
130//!
131//! ```toml
132//! [dependencies]
133//! # no_std
134//! futures-concurrency = { version = "7.5.0", default-features = false }
135//!
136//! # alloc
137//! futures-concurrency = { version = "7.5.0", default-features = false, features = ["alloc"] }
138//! ```
139//!
140//! # Further Reading
141//!
142//! `futures-concurrency` has been developed over the span of several years. It is
143//! primarily maintained by Yosh Wuyts, a member of the Rust Async WG. You can read
144//! more about the development and ideas behind `futures-concurrency` here:
145//!
146//! - [Futures Concurrency I: Introduction](https://blog.yoshuawuyts.com/futures-concurrency/)
147//! - [Futures Concurrency II: A Trait Approach](https://blog.yoshuawuyts.com/futures-concurrency-2/)
148//! - [Futures Concurrency III: `select!`](https://blog.yoshuawuyts.com/futures-concurrency-3/)
149//! - [Futures Concurrency IV: Join Semantics](https://blog.yoshuawuyts.com/futures-concurrency-4/)
150
151#![deny(missing_debug_implementations, nonstandard_style)]
152#![warn(missing_docs)]
153#![allow(non_snake_case)]
154#![cfg_attr(not(feature = "std"), no_std)]
155
156#[cfg(feature = "alloc")]
157extern crate alloc;
158
159mod collections;
160mod utils;
161
162#[doc(hidden)]
163pub use utils::private;
164
165/// The futures concurrency prelude.
166pub mod prelude {
167 pub use super::future::FutureExt as _;
168 pub use super::stream::StreamExt as _;
169
170 pub use super::future::Join as _;
171 pub use super::future::Race as _;
172 pub use super::future::RaceOk as _;
173 pub use super::future::TryJoin as _;
174 pub use super::stream::Chain as _;
175 pub use super::stream::IntoStream as _;
176 pub use super::stream::Merge as _;
177 pub use super::stream::Zip as _;
178
179 #[cfg(feature = "alloc")]
180 pub use super::concurrent_stream::{
181 ConcurrentStream, FromConcurrentStream, IntoConcurrentStream,
182 };
183}
184
185#[cfg(feature = "alloc")]
186pub mod concurrent_stream;
187
188#[cfg(feature = "alloc")]
189pub use collections::vec;
190
191pub mod future;
192pub mod stream;
193
194/// Helper functions and types for fixed-length arrays.
195pub mod array {
196 pub use crate::future::join::array::Join;
197 pub use crate::future::race::array::Race;
198 pub use crate::future::race_ok::array::{AggregateError, RaceOk};
199 pub use crate::future::try_join::array::TryJoin;
200 pub use crate::stream::chain::array::Chain;
201 pub use crate::stream::merge::array::Merge;
202 pub use crate::stream::zip::array::Zip;
203}