Skip to content

Commit 6949e9b

Browse files
authored
Merge pull request #174 from yoshuawuyts/docs
Update docs for docs.rs
2 parents 398a2f1 + 220cb6e commit 6949e9b

File tree

4 files changed

+233
-45
lines changed

4 files changed

+233
-45
lines changed

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,68 @@
4141
</h3>
4242
</div>
4343

44+
Performant, portable, structured concurrency operations for async Rust. It
45+
works with any runtime, does not erase lifetimes, always handles
46+
cancellation, and always returns output to the caller.
47+
48+
`futures-concurrency` provides concurrency operations for both groups of futures
49+
and streams. Both for bounded and unbounded sets of futures and streams. In both
50+
cases performance should be on par with, if not exceed conventional executor
51+
implementations.
52+
53+
## Examples
54+
55+
**Await multiple futures of different types**
56+
```rust
57+
use futures_concurrency::prelude::*;
58+
use std::future;
59+
60+
let a = future::ready(1u8);
61+
let b = future::ready("hello");
62+
let c = future::ready(3u16);
63+
assert_eq!((a, b, c).join().await, (1, "hello", 3));
64+
```
65+
66+
**Concurrently process items in a stream**
67+
68+
```rust
69+
use futures_concurrency::prelude::*;
70+
71+
let v: Vec<_> = vec!["chashu", "nori"]
72+
.into_co_stream()
73+
.map(|msg| async move { format!("hello {msg}") })
74+
.collect()
75+
.await;
76+
77+
assert_eq!(v, &["hello chashu", "hello nori"]);
78+
```
79+
80+
**Access stack data outside the futures' scope**
81+
82+
_Adapted from [`std::thread::scope`](https://doc.rust-lang.org/std/thread/fn.scope.html)._
83+
84+
```rust
85+
use futures_concurrency::prelude::*;
86+
87+
let mut container = vec![1, 2, 3];
88+
let mut num = 0;
89+
90+
let a = async {
91+
println!("hello from the first future");
92+
dbg!(&container);
93+
};
94+
95+
let b = async {
96+
println!("hello from the second future");
97+
num += container[0] + container[2];
98+
};
99+
100+
println!("hello from the main future");
101+
let _ = (a, b).join().await;
102+
container.push(4);
103+
assert_eq!(num, container.len());
104+
```
105+
44106
## Installation
45107
```sh
46108
$ cargo add futures-concurrency

src/collections/vec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! You will rarely need to interact with this module directly unless you need
44
//! to name one of the iterator types.
55
//!
6-
//! [std::vec]: https://doc.rust-lang.org/stable/std/vec/use core::future::Ready;
6+
//! [std::vec]: https://doc.rust-lang.org/std/vec/index.html
77
88
use crate::concurrent_stream::{self, FromStream};
99
use crate::prelude::*;

src/concurrent_stream/mod.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
11
//! Concurrent execution of streams
2+
//!
3+
//! # Examples
4+
//!
5+
//! **Concurrently process items in a collection**
6+
//!
7+
//! ```rust
8+
//! use futures_concurrency::prelude::*;
9+
//!
10+
//! # futures::executor::block_on(async {
11+
//! let v: Vec<_> = vec!["chashu", "nori"]
12+
//! .into_co_stream()
13+
//! .map(|msg| async move { format!("hello {msg}") })
14+
//! .collect()
15+
//! .await;
16+
//!
17+
//! assert_eq!(v, &["hello chashu", "hello nori"]);
18+
//! # });
19+
//! ```
20+
//!
21+
//! **Concurrently process items in a stream**
22+
//!
23+
//! ```rust
24+
//! use futures_concurrency::prelude::*;
25+
//! use futures_lite::stream;
26+
//!
27+
//! # futures::executor::block_on(async {
28+
//! let v: Vec<_> = stream::repeat("chashu")
29+
//! .co()
30+
//! .take(2)
31+
//! .map(|msg| async move { format!("hello {msg}") })
32+
//! .collect()
33+
//! .await;
34+
//!
35+
//! assert_eq!(v, &["hello chashu", "hello chashu"]);
36+
//! # });
37+
//! ```
238
339
mod enumerate;
440
mod for_each;

src/lib.rs

Lines changed: 134 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,152 @@
1-
//! Concurrency extensions for [`Future`][core::future::Future] and `Stream`
2-
//! (also known as [`AsyncIterator`][core::async_iter::AsyncIterator]).
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.
34
//!
4-
//! Companion library for the "Futures Concurrency" blog post
5-
//! series:
6-
//! - [Futures Concurrency I: Introduction](https://blog.yoshuawuyts.com/futures-concurrency/)
7-
//! - [Futures Concurrency II: A Trait Approach](https://blog.yoshuawuyts.com/futures-concurrency-2/)
8-
//! - [Futures Concurrency III: `select!`](https://blog.yoshuawuyts.com/futures-concurrency-3/)
9-
//! - [Futures Concurrency IV: Join Semantics](https://blog.yoshuawuyts.com/futures-concurrency-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.
109
//!
11-
//! The purpose of this library is to serve as a staging ground for what
12-
//! eventually may become the futures concurrency methods provided by the
13-
//! stdlib. See the [`future`] and [`stream`] submodules for more.
10+
//! # Examples
1411
//!
15-
//! # Operations
12+
//! **Await multiple futures of different types**
13+
//! ```rust
14+
//! use futures_concurrency::prelude::*;
15+
//! use std::future;
1616
//!
17-
//! This library provides the following operations on arrays, vecs, and tuples:
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+
//! ```
1824
//!
19-
//! - [`future::Join`]: Wait for all futures to complete.
20-
//! - [`future::TryJoin`]: Wait for all futures to complete successfully, or abort early on error.
21-
//! - [`future::Race`]: Wait for the first future to complete.
22-
//! - [`future::RaceOk`]: Wait for the first successful future to complete.
23-
//! - [`stream::Chain`]: Takes multiple streams and creates a new stream over all in sequence.
24-
//! - [`stream::Merge`]: Combines multiple streams into a single stream of all their outputs.
25-
//! - [`stream::Zip`]: ‘Zips up’ multiple streams into a single stream of pairs.
25+
//! **Concurrently process items in a collection**
2626
//!
27-
//! # Examples
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)._
2844
//!
29-
//! Concurrently await multiple heterogenous futures:
3045
//! ```rust
3146
//! use futures_concurrency::prelude::*;
32-
//! use futures_lite::future::block_on;
33-
//! use std::future;
3447
//!
35-
//! block_on(async {
36-
//! let a = future::ready(1u8);
37-
//! let b = future::ready("hello");
38-
//! let c = future::ready(3u16);
39-
//! assert_eq!((a, b, c).join().await, (1, "hello", 3));
40-
//! })
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+
//! # });
4167
//! ```
4268
//!
43-
//! # Limitations
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>]
44117
//!
45-
//! Because of orphan rules this library can't implement everything the stdlib
46-
//! can. The missing implementations are:
118+
//! # Runtime Support
47119
//!
48-
//! - `impl<T> IntoFuture for Vec<T>`
49-
//! - `impl<T, const N: usize> IntoFuture for [T; N]`
50-
//! - `impl<T..> IntoFuture for (T..)`
51-
//! - `impl<T> IntoAsyncIterator for Vec<T>`
52-
//! - `impl<T, const N: usize> IntoAsyncIterator for [T; N]`
53-
//! - `impl<T..> IntoAsyncIterator for (T..)`
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`.
54125
//!
55-
//! This would enable containers of futures to directly be `.await`ed to get
56-
//! `merge` semantics. Or containers of async iterators to be passed directly to
57-
//! `for..await in` loops to be iterated over using `merge` semantics. This would
58-
//! remove the need to think of "merge" as a verb, and would enable treating
59-
//! sets of futures concurrently.
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/)
60150
61151
#![deny(missing_debug_implementations, nonstandard_style)]
62152
#![warn(missing_docs)]

0 commit comments

Comments
 (0)