├── .editorconfig
├── .git-blame-ignore-revs
├── .github
├── dependabot.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .rustfmt.toml
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── examples
├── functional
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
└── imperative
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── futures-channel
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── benches
│ └── sync_mpsc.rs
├── src
│ ├── lib.rs
│ ├── lock.rs
│ ├── mpsc
│ │ ├── mod.rs
│ │ ├── queue.rs
│ │ └── sink_impl.rs
│ └── oneshot.rs
└── tests
│ ├── channel.rs
│ ├── mpsc-close.rs
│ ├── mpsc-size_hint.rs
│ ├── mpsc.rs
│ └── oneshot.rs
├── futures-core
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ ├── future.rs
│ ├── lib.rs
│ ├── stream.rs
│ └── task
│ ├── __internal
│ ├── atomic_waker.rs
│ └── mod.rs
│ ├── mod.rs
│ └── poll.rs
├── futures-executor
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── benches
│ └── thread_notify.rs
├── src
│ ├── enter.rs
│ ├── lib.rs
│ ├── local_pool.rs
│ ├── thread_pool.rs
│ └── unpark_mutex.rs
└── tests
│ └── local_pool.rs
├── futures-io
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ └── lib.rs
├── futures-macro
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
└── src
│ ├── executor.rs
│ ├── join.rs
│ ├── lib.rs
│ ├── select.rs
│ └── stream_select.rs
├── futures-sink
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ └── lib.rs
├── futures-task
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ ├── arc_wake.rs
│ ├── future_obj.rs
│ ├── lib.rs
│ ├── noop_waker.rs
│ ├── spawn.rs
│ ├── waker.rs
│ └── waker_ref.rs
├── futures-test
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src
│ ├── assert.rs
│ ├── assert_unmoved.rs
│ ├── future
│ ├── mod.rs
│ └── pending_once.rs
│ ├── interleave_pending.rs
│ ├── io
│ ├── limited.rs
│ ├── mod.rs
│ ├── read
│ │ └── mod.rs
│ └── write
│ │ └── mod.rs
│ ├── lib.rs
│ ├── sink
│ └── mod.rs
│ ├── stream
│ └── mod.rs
│ ├── task
│ ├── context.rs
│ ├── mod.rs
│ ├── noop_spawner.rs
│ ├── panic_spawner.rs
│ ├── panic_waker.rs
│ ├── record_spawner.rs
│ └── wake_counter.rs
│ └── track_closed.rs
├── futures-util
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── benches
│ ├── bilock.rs
│ ├── flatten_unordered.rs
│ ├── futures_unordered.rs
│ └── select.rs
└── src
│ ├── abortable.rs
│ ├── async_await
│ ├── join_mod.rs
│ ├── mod.rs
│ ├── pending.rs
│ ├── poll.rs
│ ├── random.rs
│ ├── select_mod.rs
│ └── stream_select_mod.rs
│ ├── compat
│ ├── compat01as03.rs
│ ├── compat03as01.rs
│ ├── executor.rs
│ └── mod.rs
│ ├── fns.rs
│ ├── future
│ ├── abortable.rs
│ ├── always_ready.rs
│ ├── either.rs
│ ├── future
│ │ ├── catch_unwind.rs
│ │ ├── flatten.rs
│ │ ├── fuse.rs
│ │ ├── map.rs
│ │ ├── mod.rs
│ │ ├── remote_handle.rs
│ │ └── shared.rs
│ ├── join.rs
│ ├── join_all.rs
│ ├── lazy.rs
│ ├── maybe_done.rs
│ ├── mod.rs
│ ├── option.rs
│ ├── pending.rs
│ ├── poll_fn.rs
│ ├── poll_immediate.rs
│ ├── ready.rs
│ ├── select.rs
│ ├── select_all.rs
│ ├── select_ok.rs
│ ├── try_future
│ │ ├── into_future.rs
│ │ ├── mod.rs
│ │ ├── try_flatten.rs
│ │ └── try_flatten_err.rs
│ ├── try_join.rs
│ ├── try_join_all.rs
│ ├── try_maybe_done.rs
│ └── try_select.rs
│ ├── io
│ ├── allow_std.rs
│ ├── buf_reader.rs
│ ├── buf_writer.rs
│ ├── chain.rs
│ ├── close.rs
│ ├── copy.rs
│ ├── copy_buf.rs
│ ├── copy_buf_abortable.rs
│ ├── cursor.rs
│ ├── empty.rs
│ ├── fill_buf.rs
│ ├── flush.rs
│ ├── into_sink.rs
│ ├── line_writer.rs
│ ├── lines.rs
│ ├── mod.rs
│ ├── read.rs
│ ├── read_exact.rs
│ ├── read_line.rs
│ ├── read_to_end.rs
│ ├── read_to_string.rs
│ ├── read_until.rs
│ ├── read_vectored.rs
│ ├── repeat.rs
│ ├── seek.rs
│ ├── sink.rs
│ ├── split.rs
│ ├── take.rs
│ ├── window.rs
│ ├── write.rs
│ ├── write_all.rs
│ ├── write_all_vectored.rs
│ └── write_vectored.rs
│ ├── lib.rs
│ ├── lock
│ ├── bilock.rs
│ ├── mod.rs
│ └── mutex.rs
│ ├── sink
│ ├── buffer.rs
│ ├── close.rs
│ ├── drain.rs
│ ├── err_into.rs
│ ├── fanout.rs
│ ├── feed.rs
│ ├── flush.rs
│ ├── map_err.rs
│ ├── mod.rs
│ ├── send.rs
│ ├── send_all.rs
│ ├── unfold.rs
│ ├── with.rs
│ └── with_flat_map.rs
│ ├── stream
│ ├── abortable.rs
│ ├── empty.rs
│ ├── futures_ordered.rs
│ ├── futures_unordered
│ │ ├── abort.rs
│ │ ├── iter.rs
│ │ ├── mod.rs
│ │ ├── ready_to_run_queue.rs
│ │ └── task.rs
│ ├── iter.rs
│ ├── mod.rs
│ ├── once.rs
│ ├── pending.rs
│ ├── poll_fn.rs
│ ├── poll_immediate.rs
│ ├── repeat.rs
│ ├── repeat_with.rs
│ ├── select.rs
│ ├── select_all.rs
│ ├── select_with_strategy.rs
│ ├── stream
│ │ ├── all.rs
│ │ ├── any.rs
│ │ ├── buffer_unordered.rs
│ │ ├── buffered.rs
│ │ ├── catch_unwind.rs
│ │ ├── chain.rs
│ │ ├── chunks.rs
│ │ ├── collect.rs
│ │ ├── concat.rs
│ │ ├── count.rs
│ │ ├── cycle.rs
│ │ ├── enumerate.rs
│ │ ├── filter.rs
│ │ ├── filter_map.rs
│ │ ├── flatten.rs
│ │ ├── flatten_unordered.rs
│ │ ├── fold.rs
│ │ ├── for_each.rs
│ │ ├── for_each_concurrent.rs
│ │ ├── forward.rs
│ │ ├── fuse.rs
│ │ ├── into_future.rs
│ │ ├── map.rs
│ │ ├── mod.rs
│ │ ├── next.rs
│ │ ├── peek.rs
│ │ ├── ready_chunks.rs
│ │ ├── scan.rs
│ │ ├── select_next_some.rs
│ │ ├── skip.rs
│ │ ├── skip_while.rs
│ │ ├── split.rs
│ │ ├── take.rs
│ │ ├── take_until.rs
│ │ ├── take_while.rs
│ │ ├── then.rs
│ │ ├── try_fold.rs
│ │ ├── try_for_each.rs
│ │ ├── try_for_each_concurrent.rs
│ │ ├── unzip.rs
│ │ └── zip.rs
│ ├── try_stream
│ │ ├── and_then.rs
│ │ ├── into_async_read.rs
│ │ ├── into_stream.rs
│ │ ├── mod.rs
│ │ ├── or_else.rs
│ │ ├── try_all.rs
│ │ ├── try_any.rs
│ │ ├── try_buffer_unordered.rs
│ │ ├── try_buffered.rs
│ │ ├── try_chunks.rs
│ │ ├── try_collect.rs
│ │ ├── try_concat.rs
│ │ ├── try_filter.rs
│ │ ├── try_filter_map.rs
│ │ ├── try_flatten.rs
│ │ ├── try_flatten_unordered.rs
│ │ ├── try_forward.rs
│ │ ├── try_next.rs
│ │ ├── try_ready_chunks.rs
│ │ ├── try_skip_while.rs
│ │ ├── try_take_while.rs
│ │ └── try_unfold.rs
│ └── unfold.rs
│ ├── task
│ ├── mod.rs
│ └── spawn.rs
│ └── unfold_state.rs
├── futures
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── src
│ └── lib.rs
├── tests
│ ├── _require_features.rs
│ ├── async_await_macros.rs
│ ├── auto_traits.rs
│ ├── bilock.rs
│ ├── compat.rs
│ ├── eager_drop.rs
│ ├── eventual.rs
│ ├── future_abortable.rs
│ ├── future_basic_combinators.rs
│ ├── future_fuse.rs
│ ├── future_inspect.rs
│ ├── future_join.rs
│ ├── future_join_all.rs
│ ├── future_obj.rs
│ ├── future_select_all.rs
│ ├── future_select_ok.rs
│ ├── future_shared.rs
│ ├── future_try_flatten_stream.rs
│ ├── future_try_join_all.rs
│ ├── io_buf_reader.rs
│ ├── io_buf_writer.rs
│ ├── io_cursor.rs
│ ├── io_line_writer.rs
│ ├── io_lines.rs
│ ├── io_read.rs
│ ├── io_read_exact.rs
│ ├── io_read_line.rs
│ ├── io_read_to_end.rs
│ ├── io_read_to_string.rs
│ ├── io_read_until.rs
│ ├── io_window.rs
│ ├── io_write.rs
│ ├── lock_mutex.rs
│ ├── macro-reexport
│ │ ├── Cargo.toml
│ │ └── src
│ │ │ └── lib.rs
│ ├── macro-tests
│ │ ├── Cargo.toml
│ │ └── src
│ │ │ └── main.rs
│ ├── macro_comma_support.rs
│ ├── no-std
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src
│ │ │ └── lib.rs
│ ├── object_safety.rs
│ ├── oneshot.rs
│ ├── ready_queue.rs
│ ├── recurse.rs
│ ├── sink.rs
│ ├── sink_fanout.rs
│ ├── stream.rs
│ ├── stream_abortable.rs
│ ├── stream_buffer_unordered.rs
│ ├── stream_catch_unwind.rs
│ ├── stream_futures_ordered.rs
│ ├── stream_futures_unordered.rs
│ ├── stream_into_async_read.rs
│ ├── stream_peekable.rs
│ ├── stream_select_all.rs
│ ├── stream_select_next_some.rs
│ ├── stream_split.rs
│ ├── stream_try_stream.rs
│ ├── stream_unfold.rs
│ ├── task_arc_wake.rs
│ ├── task_atomic_waker.rs
│ ├── test_macro.rs
│ └── try_join.rs
└── tests_disabled
│ ├── all.rs
│ └── stream.rs
└── triagebot.toml
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.rs]
2 | end_of_line = lf
3 | insert_final_newline = true
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Cargo fmt all code
2 | dd019055ef5bf4309f15db934407e202caf52e14
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: cargo
4 | directory: /
5 | schedule:
6 | interval: weekly
7 | commit-message:
8 | prefix: ''
9 | labels: []
10 | - package-ecosystem: github-actions
11 | directory: /
12 | schedule:
13 | interval: weekly
14 | commit-message:
15 | prefix: ''
16 | labels: []
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | **/*.rs.bk
3 | Cargo.lock
4 | _site
5 | .sass-cache
6 | .idea
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/.rustfmt.toml:
--------------------------------------------------------------------------------
1 | use_small_heuristics = "Max"
2 | edition = "2018"
3 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "futures",
4 | "futures-core",
5 | "futures-channel",
6 | "futures-executor",
7 | "futures-io",
8 | "futures-macro",
9 | "futures-sink",
10 | "futures-task",
11 | "futures-util",
12 | "futures-test",
13 |
14 | "futures/tests/macro-tests",
15 | "futures/tests/macro-reexport",
16 | "futures/tests/no-std",
17 |
18 | "examples/functional",
19 | "examples/imperative",
20 | ]
21 |
22 | [workspace.lints.rust]
23 | missing_debug_implementations = "warn"
24 | rust_2018_idioms = "warn"
25 | single_use_lifetimes = "warn"
26 | unexpected_cfgs = { level = "warn", check-cfg = [
27 | 'cfg(futures_sanitizer)',
28 | ] }
29 | unreachable_pub = "warn"
30 | # unsafe_op_in_unsafe_fn = "warn" # Set at crate-level instead since https://github.com/rust-lang/rust/pull/100081 is not available on MSRV
31 | [workspace.lints.clippy]
32 | incompatible_msrv = { level = "allow", priority = 1 } # https://github.com/rust-lang/rust-clippy/issues/12273, https://github.com/rust-lang/rust-clippy/issues/12257
33 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Alex Crichton
2 | Copyright (c) 2017 The Tokio Authors
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Zero-cost asynchronous programming in Rust
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Documentation
22 | |
23 | Website
24 |
25 |
26 |
27 | `futures-rs` is a library providing the foundations for asynchronous programming in Rust.
28 | It includes key trait definitions like `Stream`, as well as utilities like `join!`,
29 | `select!`, and various futures combinator methods which enable expressive asynchronous
30 | control flow.
31 |
32 | ## Usage
33 |
34 | Add this to your `Cargo.toml`:
35 |
36 | ```toml
37 | [dependencies]
38 | futures = "0.3"
39 | ```
40 |
41 | The current `futures` requires Rust 1.68 or later.
42 |
43 | ### Feature `std`
44 |
45 | Futures-rs works without the standard library, such as in bare metal environments.
46 | However, it has a significantly reduced API surface. To use futures-rs in
47 | a `#[no_std]` environment, use:
48 |
49 | ```toml
50 | [dependencies]
51 | futures = { version = "0.3", default-features = false }
52 | ```
53 |
54 | ## License
55 |
56 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
57 | [MIT license](LICENSE-MIT) at your option.
58 |
59 | Unless you explicitly state otherwise, any contribution intentionally submitted
60 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
61 | be dual licensed as above, without any additional terms or conditions.
62 |
--------------------------------------------------------------------------------
/examples/functional/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-example-functional"
3 | version = "0.0.0"
4 | edition = "2018"
5 | publish = false
6 |
7 | [dependencies]
8 | futures = { path = "../../futures", features = ["thread-pool"] }
9 |
10 | [lints]
11 | workspace = true
12 |
--------------------------------------------------------------------------------
/examples/functional/src/main.rs:
--------------------------------------------------------------------------------
1 | use futures::channel::mpsc;
2 | use futures::executor; //standard executors to provide a context for futures and streams
3 | use futures::executor::ThreadPool;
4 | use futures::StreamExt;
5 |
6 | fn main() {
7 | let pool = ThreadPool::new().expect("Failed to build pool");
8 | let (tx, rx) = mpsc::unbounded::();
9 |
10 | // Create a future by an async block, where async is responsible for an
11 | // implementation of Future. At this point no executor has been provided
12 | // to this future, so it will not be running.
13 | let fut_values = async {
14 | // Create another async block, again where the Future implementation
15 | // is generated by async. Since this is inside of a parent async block,
16 | // it will be provided with the executor of the parent block when the parent
17 | // block is executed.
18 | //
19 | // This executor chaining is done by Future::poll whose second argument
20 | // is a std::task::Context. This represents our executor, and the Future
21 | // implemented by this async block can be polled using the parent async
22 | // block's executor.
23 | let fut_tx_result = async move {
24 | (0..100).for_each(|v| {
25 | tx.unbounded_send(v).expect("Failed to send");
26 | })
27 | };
28 |
29 | // Use the provided thread pool to spawn the generated future
30 | // responsible for transmission
31 | pool.spawn_ok(fut_tx_result);
32 |
33 | let fut_values = rx.map(|v| v * 2).collect();
34 |
35 | // Use the executor provided to this async block to wait for the
36 | // future to complete.
37 | fut_values.await
38 | };
39 |
40 | // Actually execute the above future, which will invoke Future::poll and
41 | // subsequently chain appropriate Future::poll and methods needing executors
42 | // to drive all futures. Eventually fut_values will be driven to completion.
43 | let values: Vec = executor::block_on(fut_values);
44 |
45 | println!("Values={values:?}");
46 | }
47 |
--------------------------------------------------------------------------------
/examples/imperative/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-example-imperative"
3 | version = "0.0.0"
4 | edition = "2018"
5 | publish = false
6 |
7 | [dependencies]
8 | futures = { path = "../../futures", features = ["thread-pool"] }
9 |
10 | [lints]
11 | workspace = true
12 |
--------------------------------------------------------------------------------
/examples/imperative/src/main.rs:
--------------------------------------------------------------------------------
1 | use futures::channel::mpsc;
2 | use futures::executor; //standard executors to provide a context for futures and streams
3 | use futures::executor::ThreadPool;
4 | use futures::StreamExt;
5 |
6 | fn main() {
7 | let pool = ThreadPool::new().expect("Failed to build pool");
8 | let (tx, mut rx) = mpsc::unbounded::();
9 |
10 | // Create a future by an async block, where async is responsible for generating
11 | // an implementation of Future. At this point no executor has been provided
12 | // to this future, so it will not be running.
13 | let fut_values = async {
14 | // Create another async block, again where Future is implemented by
15 | // async. Since this is inside of a parent async block, it will be
16 | // provided with the executor of the parent block when the parent
17 | // block is executed.
18 | //
19 | // This executor chaining is done by Future::poll whose second argument
20 | // is a std::task::Context. This represents our executor, and the Future
21 | // implemented by this async block can be polled using the parent async
22 | // block's executor.
23 | let fut_tx_result = async move {
24 | (0..100).for_each(|v| {
25 | tx.unbounded_send(v).expect("Failed to send");
26 | })
27 | };
28 |
29 | // Use the provided thread pool to spawn the transmission
30 | pool.spawn_ok(fut_tx_result);
31 |
32 | let mut pending = vec![];
33 | // Use the provided executor to wait for the next value
34 | // of the stream to be available.
35 | while let Some(v) = rx.next().await {
36 | pending.push(v * 2);
37 | }
38 |
39 | pending
40 | };
41 |
42 | // Actually execute the above future, which will invoke Future::poll and
43 | // subsequently chain appropriate Future::poll and methods needing executors
44 | // to drive all futures. Eventually fut_values will be driven to completion.
45 | let values: Vec = executor::block_on(fut_values);
46 |
47 | println!("Values={values:?}");
48 | }
49 |
--------------------------------------------------------------------------------
/futures-channel/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-channel"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.68"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | Channels for asynchronous communication using futures-rs.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = ["alloc", "futures-core/std"]
16 | alloc = ["futures-core/alloc"]
17 | sink = ["futures-sink"]
18 |
19 | [dependencies]
20 | futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false }
21 | futures-sink = { path = "../futures-sink", version = "=0.4.0-alpha.0", default-features = false, optional = true }
22 |
23 | [dev-dependencies]
24 | futures = { path = "../futures", default-features = true }
25 | futures-test = { path = "../futures-test", default-features = true }
26 |
27 | [package.metadata.docs.rs]
28 | all-features = true
29 | rustdoc-args = ["--cfg", "docsrs"]
30 |
31 | [lints]
32 | workspace = true
33 |
--------------------------------------------------------------------------------
/futures-channel/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-channel/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-channel/README.md:
--------------------------------------------------------------------------------
1 | # futures-channel
2 |
3 | Channels for asynchronous communication using futures-rs.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-channel = "0.3"
12 | ```
13 |
14 | The current `futures-channel` requires Rust 1.68 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-channel/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Asynchronous channels.
2 | //!
3 | //! Like threads, concurrent tasks sometimes need to communicate with each
4 | //! other. This module contains two basic abstractions for doing so:
5 | //!
6 | //! - [oneshot], a way of sending a single value from one task to another.
7 | //! - [mpsc], a multi-producer, single-consumer channel for sending values
8 | //! between tasks, analogous to the similarly-named structure in the standard
9 | //! library.
10 | //!
11 | //! All items are only available when the `std` or `alloc` feature of this
12 | //! library is activated, and it is activated by default.
13 |
14 | #![no_std]
15 | #![doc(test(
16 | no_crate_inject,
17 | attr(
18 | deny(warnings, rust_2018_idioms, single_use_lifetimes),
19 | allow(dead_code, unused_assignments, unused_variables)
20 | )
21 | ))]
22 | #![warn(missing_docs, unsafe_op_in_unsafe_fn)]
23 |
24 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
25 | #[cfg(feature = "alloc")]
26 | extern crate alloc;
27 | #[cfg(feature = "std")]
28 | extern crate std;
29 |
30 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
31 | #[cfg(feature = "alloc")]
32 | mod lock;
33 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
34 | #[cfg(feature = "std")]
35 | pub mod mpsc;
36 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
37 | #[cfg(feature = "alloc")]
38 | pub mod oneshot;
39 |
--------------------------------------------------------------------------------
/futures-channel/tests/channel.rs:
--------------------------------------------------------------------------------
1 | use futures::channel::mpsc;
2 | use futures::executor::block_on;
3 | use futures::future::poll_fn;
4 | use futures::sink::SinkExt;
5 | use futures::stream::StreamExt;
6 | use std::sync::atomic::{AtomicUsize, Ordering};
7 | use std::thread;
8 |
9 | #[test]
10 | fn sequence() {
11 | let (tx, rx) = mpsc::channel(1);
12 |
13 | let amt = 20;
14 | let t = thread::spawn(move || block_on(send_sequence(amt, tx)));
15 | let list: Vec<_> = block_on(rx.collect());
16 | let mut list = list.into_iter();
17 | for i in (1..=amt).rev() {
18 | assert_eq!(list.next(), Some(i));
19 | }
20 | assert_eq!(list.next(), None);
21 |
22 | t.join().unwrap();
23 | }
24 |
25 | async fn send_sequence(n: u32, mut sender: mpsc::Sender) {
26 | for x in 0..n {
27 | sender.send(n - x).await.unwrap();
28 | }
29 | }
30 |
31 | #[test]
32 | fn drop_sender() {
33 | let (tx, mut rx) = mpsc::channel::(1);
34 | drop(tx);
35 | let f = poll_fn(|cx| rx.poll_next_unpin(cx));
36 | assert_eq!(block_on(f), None)
37 | }
38 |
39 | #[test]
40 | fn drop_rx() {
41 | let (mut tx, rx) = mpsc::channel::(1);
42 | block_on(tx.send(1)).unwrap();
43 | drop(rx);
44 | assert!(block_on(tx.send(1)).is_err());
45 | }
46 |
47 | #[test]
48 | fn drop_order() {
49 | static DROPS: AtomicUsize = AtomicUsize::new(0);
50 | let (mut tx, rx) = mpsc::channel(1);
51 |
52 | struct A;
53 |
54 | impl Drop for A {
55 | fn drop(&mut self) {
56 | DROPS.fetch_add(1, Ordering::SeqCst);
57 | }
58 | }
59 |
60 | block_on(tx.send(A)).unwrap();
61 | assert_eq!(DROPS.load(Ordering::SeqCst), 0);
62 | drop(rx);
63 | assert_eq!(DROPS.load(Ordering::SeqCst), 1);
64 | assert!(block_on(tx.send(A)).is_err());
65 | assert_eq!(DROPS.load(Ordering::SeqCst), 2);
66 | }
67 |
--------------------------------------------------------------------------------
/futures-channel/tests/mpsc-size_hint.rs:
--------------------------------------------------------------------------------
1 | use futures::channel::mpsc;
2 | use futures::stream::Stream;
3 |
4 | #[test]
5 | fn unbounded_size_hint() {
6 | let (tx, mut rx) = mpsc::unbounded::();
7 | assert_eq!((0, None), rx.size_hint());
8 | tx.unbounded_send(1).unwrap();
9 | assert_eq!((1, None), rx.size_hint());
10 | rx.try_recv().unwrap();
11 | assert_eq!((0, None), rx.size_hint());
12 | tx.unbounded_send(2).unwrap();
13 | tx.unbounded_send(3).unwrap();
14 | assert_eq!((2, None), rx.size_hint());
15 | drop(tx);
16 | assert_eq!((2, Some(2)), rx.size_hint());
17 | rx.try_recv().unwrap();
18 | assert_eq!((1, Some(1)), rx.size_hint());
19 | rx.try_recv().unwrap();
20 | assert_eq!((0, Some(0)), rx.size_hint());
21 | }
22 |
23 | #[test]
24 | fn channel_size_hint() {
25 | let (mut tx, mut rx) = mpsc::channel::(10);
26 | assert_eq!((0, None), rx.size_hint());
27 | tx.try_send(1).unwrap();
28 | assert_eq!((1, None), rx.size_hint());
29 | rx.try_recv().unwrap();
30 | assert_eq!((0, None), rx.size_hint());
31 | tx.try_send(2).unwrap();
32 | tx.try_send(3).unwrap();
33 | assert_eq!((2, None), rx.size_hint());
34 | drop(tx);
35 | assert_eq!((2, Some(2)), rx.size_hint());
36 | rx.try_recv().unwrap();
37 | assert_eq!((1, Some(1)), rx.size_hint());
38 | rx.try_recv().unwrap();
39 | assert_eq!((0, Some(0)), rx.size_hint());
40 | }
41 |
--------------------------------------------------------------------------------
/futures-core/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-core"
3 | version = "1.0.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.36"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | The core traits and types in for the `futures` library.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = ["alloc"]
16 | alloc = []
17 |
18 | [dependencies]
19 | portable-atomic = { version = "1.3", optional = true, default-features = false, features = ["require-cas"] }
20 |
21 | [dev-dependencies]
22 | futures = { path = "../futures" }
23 |
24 | [package.metadata.docs.rs]
25 | all-features = true
26 | rustdoc-args = ["--cfg", "docsrs"]
27 |
28 | [lints]
29 | workspace = true
30 |
--------------------------------------------------------------------------------
/futures-core/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-core/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-core/README.md:
--------------------------------------------------------------------------------
1 | # futures-core
2 |
3 | The core traits and types in for the `futures` library.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-core = "0.3"
12 | ```
13 |
14 | The current `futures-core` requires Rust 1.36 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-core/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Core traits and types for asynchronous operations in Rust.
2 |
3 | #![no_std]
4 | #![doc(test(
5 | no_crate_inject,
6 | attr(
7 | deny(warnings, rust_2018_idioms, single_use_lifetimes),
8 | allow(dead_code, unused_assignments, unused_variables)
9 | )
10 | ))]
11 | #![warn(missing_docs, /* unsafe_op_in_unsafe_fn */)] // unsafe_op_in_unsafe_fn requires Rust 1.52
12 |
13 | #[cfg(feature = "alloc")]
14 | extern crate alloc;
15 | #[cfg(feature = "std")]
16 | extern crate std;
17 |
18 | pub mod future;
19 | #[doc(no_inline)]
20 | pub use self::future::{FusedFuture, Future, TryFuture};
21 |
22 | pub mod stream;
23 | #[doc(no_inline)]
24 | pub use self::stream::{FusedStream, Stream, TryStream};
25 |
26 | #[macro_use]
27 | pub mod task;
28 |
--------------------------------------------------------------------------------
/futures-core/src/task/__internal/mod.rs:
--------------------------------------------------------------------------------
1 | #[cfg_attr(target_os = "none", cfg(any(target_has_atomic = "ptr", feature = "portable-atomic")))]
2 | mod atomic_waker;
3 | #[cfg_attr(
4 | target_os = "none",
5 | cfg(any(target_has_atomic = "ptr", feature = "portable-atomic"))
6 | )]
7 | pub use self::atomic_waker::AtomicWaker;
8 |
--------------------------------------------------------------------------------
/futures-core/src/task/mod.rs:
--------------------------------------------------------------------------------
1 | //! Task notification.
2 |
3 | #[macro_use]
4 | mod poll;
5 |
6 | #[doc(hidden)]
7 | pub mod __internal;
8 |
9 | #[doc(no_inline)]
10 | pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
11 |
--------------------------------------------------------------------------------
/futures-core/src/task/poll.rs:
--------------------------------------------------------------------------------
1 | /// Extracts the successful type of `Poll`.
2 | ///
3 | /// This macro bakes in propagation of `Pending` signals by returning early.
4 | ///
5 | /// **Note:** Since Rust 1.64, this macro is soft-deprecated in favor of
6 | /// [`ready!`](core::task::ready) macro in the standard library.
7 | #[macro_export]
8 | macro_rules! ready {
9 | ($e:expr $(,)?) => {
10 | match $e {
11 | $crate::task::Poll::Ready(t) => t,
12 | $crate::task::Poll::Pending => return $crate::task::Poll::Pending,
13 | }
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/futures-executor/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-executor"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.68"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | Executors for asynchronous tasks based on the futures-rs library.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = ["futures-core/std", "futures-task/std", "futures-util/std"]
16 | thread-pool = ["std"]
17 |
18 | [dependencies]
19 | futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false }
20 | futures-task = { path = "../futures-task", version = "=0.4.0-alpha.0", default-features = false }
21 | futures-util = { path = "../futures-util", version = "=0.4.0-alpha.0", default-features = false }
22 |
23 | [dev-dependencies]
24 | futures = { path = "../futures", features = ["thread-pool"] }
25 |
26 | [package.metadata.docs.rs]
27 | all-features = true
28 | rustdoc-args = ["--cfg", "docsrs"]
29 |
30 | [lints]
31 | workspace = true
32 |
--------------------------------------------------------------------------------
/futures-executor/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-executor/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-executor/README.md:
--------------------------------------------------------------------------------
1 | # futures-executor
2 |
3 | Executors for asynchronous tasks based on the futures-rs library.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-executor = "0.3"
12 | ```
13 |
14 | The current `futures-executor` requires Rust 1.68 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-io/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-io"
3 | version = "0.3.31"
4 | edition = "2018"
5 | rust-version = "1.36"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | The `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and `AsyncBufRead` traits for the futures-rs library.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = []
16 |
17 | # Unstable features
18 | # These features are outside of the normal semver guarantees and require the
19 | # `unstable` feature as an explicit opt-in to unstable API.
20 | unstable = []
21 |
22 | [dependencies]
23 |
24 | [package.metadata.docs.rs]
25 | all-features = true
26 | rustdoc-args = ["--cfg", "docsrs"]
27 |
28 | [lints]
29 | workspace = true
30 |
--------------------------------------------------------------------------------
/futures-io/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-io/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-io/README.md:
--------------------------------------------------------------------------------
1 | # futures-io
2 |
3 | The `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and `AsyncBufRead` traits for the futures-rs library.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-io = "0.3"
12 | ```
13 |
14 | The current `futures-io` requires Rust 1.36 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-macro/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-macro"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.68"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | The futures-rs procedural macro implementations.
11 | """
12 |
13 | [lib]
14 | proc-macro = true
15 |
16 | [features]
17 |
18 | [dependencies]
19 | proc-macro2 = "1.0.60"
20 | quote = "1.0"
21 | syn = { version = "2.0.52", features = ["full"] }
22 |
23 | [lints]
24 | workspace = true
25 |
--------------------------------------------------------------------------------
/futures-macro/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-macro/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-macro/src/executor.rs:
--------------------------------------------------------------------------------
1 | use proc_macro::TokenStream;
2 | use proc_macro2::Span;
3 | use quote::{quote, quote_spanned, ToTokens};
4 |
5 | pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
6 | if !args.is_empty() {
7 | return syn::Error::new_spanned(proc_macro2::TokenStream::from(args), "invalid argument")
8 | .to_compile_error()
9 | .into();
10 | }
11 |
12 | let mut input = syn::parse_macro_input!(item as syn::ItemFn);
13 |
14 | if input.sig.asyncness.take().is_none() {
15 | return syn::Error::new_spanned(input.sig.fn_token, "Only async functions are supported")
16 | .to_compile_error()
17 | .into();
18 | }
19 |
20 | // If type mismatch occurs, the current rustc points to the last statement.
21 | let (last_stmt_start_span, last_stmt_end_span) = {
22 | let mut last_stmt = input
23 | .block
24 | .stmts
25 | .last()
26 | .map(ToTokens::into_token_stream)
27 | .unwrap_or_default()
28 | .into_iter();
29 | // `Span` on stable Rust has a limitation that only points to the first
30 | // token, not the whole tokens. We can work around this limitation by
31 | // using the first/last span of the tokens like
32 | // `syn::Error::new_spanned` does.
33 | let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
34 | let end = last_stmt.last().map_or(start, |t| t.span());
35 | (start, end)
36 | };
37 |
38 | let path = quote_spanned! {last_stmt_start_span=>
39 | ::futures_test::__private
40 | };
41 | let body = &input.block;
42 | input.block.stmts = vec![syn::Stmt::Expr(
43 | syn::parse2(quote_spanned! {last_stmt_end_span=>
44 | #path::block_on(async #body)
45 | })
46 | .unwrap(),
47 | None,
48 | )];
49 |
50 | let gen = quote! {
51 | #[::core::prelude::v1::test]
52 | #input
53 | };
54 |
55 | gen.into()
56 | }
57 |
--------------------------------------------------------------------------------
/futures-macro/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! The futures-rs procedural macro implementations.
2 |
3 | #![doc(test(
4 | no_crate_inject,
5 | attr(
6 | deny(warnings, rust_2018_idioms, single_use_lifetimes),
7 | allow(dead_code, unused_assignments, unused_variables)
8 | )
9 | ))]
10 |
11 | use proc_macro::TokenStream;
12 |
13 | mod executor;
14 | mod join;
15 | mod select;
16 | mod stream_select;
17 |
18 | /// The `join!` macro.
19 | #[proc_macro]
20 | pub fn join_internal(input: TokenStream) -> TokenStream {
21 | crate::join::join(input)
22 | }
23 |
24 | /// The `try_join!` macro.
25 | #[proc_macro]
26 | pub fn try_join_internal(input: TokenStream) -> TokenStream {
27 | crate::join::try_join(input)
28 | }
29 |
30 | /// The `select!` macro.
31 | #[proc_macro]
32 | pub fn select_internal(input: TokenStream) -> TokenStream {
33 | crate::select::select(input)
34 | }
35 |
36 | /// The `select_biased!` macro.
37 | #[proc_macro]
38 | pub fn select_biased_internal(input: TokenStream) -> TokenStream {
39 | crate::select::select_biased(input)
40 | }
41 |
42 | // TODO: Change this to doc comment once rustdoc bug fixed: https://github.com/rust-lang/futures-rs/pull/2435
43 | // The `test` attribute.
44 | #[proc_macro_attribute]
45 | pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream {
46 | crate::executor::test(input, item)
47 | }
48 |
49 | /// The `stream_select!` macro.
50 | #[proc_macro]
51 | pub fn stream_select_internal(input: TokenStream) -> TokenStream {
52 | crate::stream_select::stream_select(input.into())
53 | .unwrap_or_else(syn::Error::into_compile_error)
54 | .into()
55 | }
56 |
--------------------------------------------------------------------------------
/futures-sink/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-sink"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.36"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | The asynchronous `Sink` trait for the futures-rs library.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = ["alloc"]
16 | alloc = []
17 |
18 | [dependencies]
19 |
20 | [package.metadata.docs.rs]
21 | all-features = true
22 |
23 | [lints]
24 | workspace = true
25 |
--------------------------------------------------------------------------------
/futures-sink/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-sink/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-sink/README.md:
--------------------------------------------------------------------------------
1 | # futures-sink
2 |
3 | The asynchronous `Sink` trait for the futures-rs library.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-sink = "0.3"
12 | ```
13 |
14 | The current `futures-sink` requires Rust 1.36 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-task/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-task"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.68"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | Tools for working with tasks.
11 | """
12 |
13 | [features]
14 | default = ["std"]
15 | std = ["alloc"]
16 | alloc = []
17 |
18 | [dependencies]
19 |
20 | [dev-dependencies]
21 | futures = { path = "../futures" }
22 |
23 | [package.metadata.docs.rs]
24 | all-features = true
25 |
26 | [lints]
27 | workspace = true
28 |
--------------------------------------------------------------------------------
/futures-task/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-task/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-task/README.md:
--------------------------------------------------------------------------------
1 | # futures-task
2 |
3 | Tools for working with tasks.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-task = "0.3"
12 | ```
13 |
14 | The current `futures-task` requires Rust 1.68 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-task/src/arc_wake.rs:
--------------------------------------------------------------------------------
1 | use alloc::sync::Arc;
2 |
3 | /// A way of waking up a specific task.
4 | ///
5 | /// By implementing this trait, types that are expected to be wrapped in an `Arc`
6 | /// can be converted into [`Waker`] objects.
7 | /// Those Wakers can be used to signal executors that a task it owns
8 | /// is ready to be `poll`ed again.
9 | ///
10 | /// Currently, there are two ways to convert `ArcWake` into [`Waker`]:
11 | ///
12 | /// * [`waker`](super::waker()) converts `Arc` into [`Waker`].
13 | /// * [`waker_ref`](super::waker_ref()) converts `&Arc` into [`WakerRef`] that
14 | /// provides access to a [`&Waker`][`Waker`].
15 | ///
16 | /// [`Waker`]: std::task::Waker
17 | /// [`WakerRef`]: super::WakerRef
18 | // Note: Send + Sync required because `Arc` doesn't automatically imply
19 | // those bounds, but `Waker` implements them.
20 | pub trait ArcWake: Send + Sync {
21 | /// Indicates that the associated task is ready to make progress and should
22 | /// be `poll`ed.
23 | ///
24 | /// This function can be called from an arbitrary thread, including threads which
25 | /// did not create the `ArcWake` based [`Waker`].
26 | ///
27 | /// Executors generally maintain a queue of "ready" tasks; `wake` should place
28 | /// the associated task onto this queue.
29 | ///
30 | /// [`Waker`]: std::task::Waker
31 | fn wake(self: Arc) {
32 | Self::wake_by_ref(&self)
33 | }
34 |
35 | /// Indicates that the associated task is ready to make progress and should
36 | /// be `poll`ed.
37 | ///
38 | /// This function can be called from an arbitrary thread, including threads which
39 | /// did not create the `ArcWake` based [`Waker`].
40 | ///
41 | /// Executors generally maintain a queue of "ready" tasks; `wake_by_ref` should place
42 | /// the associated task onto this queue.
43 | ///
44 | /// This function is similar to [`wake`](ArcWake::wake), but must not consume the provided data
45 | /// pointer.
46 | ///
47 | /// [`Waker`]: std::task::Waker
48 | fn wake_by_ref(arc_self: &Arc);
49 | }
50 |
--------------------------------------------------------------------------------
/futures-task/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Tools for working with tasks.
2 |
3 | #![no_std]
4 | #![doc(test(
5 | no_crate_inject,
6 | attr(
7 | deny(warnings, rust_2018_idioms, single_use_lifetimes),
8 | allow(dead_code, unused_assignments, unused_variables)
9 | )
10 | ))]
11 | #![warn(missing_docs, unsafe_op_in_unsafe_fn)]
12 |
13 | #[cfg(feature = "alloc")]
14 | extern crate alloc;
15 | #[cfg(feature = "std")]
16 | extern crate std;
17 |
18 | mod spawn;
19 | pub use crate::spawn::{LocalSpawn, Spawn, SpawnError};
20 |
21 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
22 | #[cfg(feature = "alloc")]
23 | mod arc_wake;
24 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
25 | #[cfg(feature = "alloc")]
26 | pub use crate::arc_wake::ArcWake;
27 |
28 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
29 | #[cfg(feature = "alloc")]
30 | mod waker;
31 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
32 | #[cfg(feature = "alloc")]
33 | pub use crate::waker::waker;
34 |
35 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
36 | #[cfg(feature = "alloc")]
37 | mod waker_ref;
38 | #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
39 | #[cfg(feature = "alloc")]
40 | pub use crate::waker_ref::{waker_ref, WakerRef};
41 |
42 | mod future_obj;
43 | pub use crate::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj};
44 |
45 | mod noop_waker;
46 | pub use crate::noop_waker::noop_waker;
47 | pub use crate::noop_waker::noop_waker_ref;
48 |
49 | #[doc(no_inline)]
50 | pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
51 |
--------------------------------------------------------------------------------
/futures-task/src/noop_waker.rs:
--------------------------------------------------------------------------------
1 | //! Utilities for creating zero-cost wakers that don't do anything.
2 |
3 | use core::ptr::null;
4 | use core::task::{RawWaker, RawWakerVTable, Waker};
5 |
6 | unsafe fn noop_clone(_data: *const ()) -> RawWaker {
7 | noop_raw_waker()
8 | }
9 |
10 | unsafe fn noop(_data: *const ()) {}
11 |
12 | const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
13 |
14 | const fn noop_raw_waker() -> RawWaker {
15 | RawWaker::new(null(), &NOOP_WAKER_VTABLE)
16 | }
17 |
18 | /// Create a new [`Waker`] which does
19 | /// nothing when `wake()` is called on it.
20 | ///
21 | /// # Examples
22 | ///
23 | /// ```
24 | /// use futures::task::noop_waker;
25 | /// let waker = noop_waker();
26 | /// waker.wake();
27 | /// ```
28 | #[inline]
29 | pub fn noop_waker() -> Waker {
30 | // FIXME: Since 1.46.0 we can use transmute in consts, allowing this function to be const.
31 | unsafe { Waker::from_raw(noop_raw_waker()) }
32 | }
33 |
34 | /// Get a static reference to a [`Waker`] which
35 | /// does nothing when `wake()` is called on it.
36 | ///
37 | /// # Examples
38 | ///
39 | /// ```
40 | /// use futures::task::noop_waker_ref;
41 | /// let waker = noop_waker_ref();
42 | /// waker.wake_by_ref();
43 | /// ```
44 | #[inline]
45 | pub fn noop_waker_ref() -> &'static Waker {
46 | struct SyncRawWaker(RawWaker);
47 | unsafe impl Sync for SyncRawWaker {}
48 |
49 | static NOOP_WAKER_INSTANCE: SyncRawWaker = SyncRawWaker(noop_raw_waker());
50 |
51 | // SAFETY: `Waker` is #[repr(transparent)] over its `RawWaker`.
52 | unsafe { &*(&NOOP_WAKER_INSTANCE.0 as *const RawWaker as *const Waker) }
53 | }
54 |
55 | #[cfg(test)]
56 | mod tests {
57 | #[test]
58 | #[cfg(feature = "std")]
59 | fn issue_2091_cross_thread_segfault() {
60 | let waker = std::thread::spawn(super::noop_waker_ref).join().unwrap();
61 | waker.wake_by_ref();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/futures-task/src/waker.rs:
--------------------------------------------------------------------------------
1 | use super::arc_wake::ArcWake;
2 | use alloc::sync::Arc;
3 | use core::mem;
4 | use core::task::{RawWaker, RawWakerVTable, Waker};
5 |
6 | pub(super) fn waker_vtable() -> &'static RawWakerVTable {
7 | &RawWakerVTable::new(
8 | clone_arc_raw::,
9 | wake_arc_raw::,
10 | wake_by_ref_arc_raw::,
11 | drop_arc_raw::,
12 | )
13 | }
14 |
15 | /// Creates a [`Waker`] from an `Arc`.
16 | ///
17 | /// The returned [`Waker`] will call
18 | /// [`ArcWake.wake()`](ArcWake::wake) if awoken.
19 | pub fn waker(wake: Arc) -> Waker
20 | where
21 | W: ArcWake + 'static,
22 | {
23 | let ptr = Arc::into_raw(wake).cast::<()>();
24 |
25 | unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::())) }
26 | }
27 |
28 | // FIXME: panics on Arc::clone / refcount changes could wreak havoc on the
29 | // code here. We should guard against this by aborting.
30 |
31 | unsafe fn increase_refcount(data: *const ()) {
32 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
33 | let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) });
34 | // Now increase refcount, but don't drop new refcount either
35 | let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
36 | }
37 |
38 | // used by `waker_ref`
39 | #[inline(always)]
40 | unsafe fn clone_arc_raw(data: *const ()) -> RawWaker {
41 | unsafe { increase_refcount::(data) }
42 | RawWaker::new(data, waker_vtable::())
43 | }
44 |
45 | unsafe fn wake_arc_raw(data: *const ()) {
46 | let arc: Arc = unsafe { Arc::from_raw(data.cast::()) };
47 | ArcWake::wake(arc);
48 | }
49 |
50 | // used by `waker_ref`
51 | unsafe fn wake_by_ref_arc_raw(data: *const ()) {
52 | // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
53 | let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) });
54 | ArcWake::wake_by_ref(&arc);
55 | }
56 |
57 | unsafe fn drop_arc_raw(data: *const ()) {
58 | drop(unsafe { Arc::::from_raw(data.cast::()) })
59 | }
60 |
--------------------------------------------------------------------------------
/futures-test/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "futures-test"
3 | version = "0.4.0-alpha.0"
4 | edition = "2018"
5 | rust-version = "1.68"
6 | license = "MIT OR Apache-2.0"
7 | repository = "https://github.com/rust-lang/futures-rs"
8 | homepage = "https://rust-lang.github.io/futures-rs"
9 | description = """
10 | Common utilities for testing components built off futures-rs.
11 | """
12 |
13 | [dependencies]
14 | futures-core = { version = "=1.0.0-alpha.0", path = "../futures-core", default-features = false }
15 | futures-task = { version = "=0.4.0-alpha.0", path = "../futures-task", default-features = false }
16 | futures-io = { version = "0.3.31", path = "../futures-io", default-features = false }
17 | futures-util = { version = "=0.4.0-alpha.0", path = "../futures-util", default-features = false }
18 | futures-executor = { version = "=0.4.0-alpha.0", path = "../futures-executor", default-features = false }
19 | futures-sink = { version = "=0.4.0-alpha.0", path = "../futures-sink", default-features = false }
20 | futures-macro = { version = "=0.4.0-alpha.0", path = "../futures-macro", default-features = false }
21 | pin-project = "1.0.11"
22 |
23 | [dev-dependencies]
24 | futures = { path = "../futures", default-features = false, features = ["std", "executor"] }
25 |
26 | [features]
27 | default = ["std"]
28 | std = ["futures-core/std", "futures-task/std", "futures-io/std", "futures-util/std", "futures-util/io", "futures-executor/std"]
29 |
30 | [package.metadata.docs.rs]
31 | all-features = true
32 |
33 | [lints]
34 | workspace = true
35 |
--------------------------------------------------------------------------------
/futures-test/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-test/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-test/README.md:
--------------------------------------------------------------------------------
1 | # futures-test
2 |
3 | Common utilities for testing components built off futures-rs.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-test = "0.3"
12 | ```
13 |
14 | The current `futures-test` requires Rust 1.68 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-test/src/future/pending_once.rs:
--------------------------------------------------------------------------------
1 | use futures_core::future::{FusedFuture, Future};
2 | use futures_core::task::{Context, Poll};
3 | use pin_project::pin_project;
4 | use std::pin::Pin;
5 |
6 | /// Combinator that guarantees one [`Poll::Pending`] before polling its inner
7 | /// future.
8 | ///
9 | /// This is created by the
10 | /// [`FutureTestExt::pending_once`](super::FutureTestExt::pending_once)
11 | /// method.
12 | #[pin_project]
13 | #[derive(Debug, Clone)]
14 | #[must_use = "futures do nothing unless you `.await` or poll them"]
15 | pub struct PendingOnce {
16 | #[pin]
17 | future: Fut,
18 | polled_before: bool,
19 | }
20 |
21 | impl PendingOnce {
22 | pub(super) fn new(future: Fut) -> Self {
23 | Self { future, polled_before: false }
24 | }
25 | }
26 |
27 | impl Future for PendingOnce {
28 | type Output = Fut::Output;
29 |
30 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
31 | let this = self.project();
32 | if *this.polled_before {
33 | this.future.poll(cx)
34 | } else {
35 | *this.polled_before = true;
36 | cx.waker().wake_by_ref();
37 | Poll::Pending
38 | }
39 | }
40 | }
41 |
42 | impl FusedFuture for PendingOnce {
43 | fn is_terminated(&self) -> bool {
44 | self.polled_before && self.future.is_terminated()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/futures-test/src/io/mod.rs:
--------------------------------------------------------------------------------
1 | //! Additional combinators for testing async IO.
2 |
3 | mod limited;
4 |
5 | pub mod read;
6 | pub use read::AsyncReadTestExt;
7 |
8 | pub mod write;
9 | pub use write::AsyncWriteTestExt;
10 |
--------------------------------------------------------------------------------
/futures-test/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Utilities to make testing [`Future`s](futures_core::future::Future) easier
2 |
3 | #![doc(test(
4 | no_crate_inject,
5 | attr(
6 | deny(warnings, rust_2018_idioms, single_use_lifetimes),
7 | allow(dead_code, unused_assignments, unused_variables)
8 | )
9 | ))]
10 | #![warn(missing_docs, unsafe_op_in_unsafe_fn)]
11 | #![allow(clippy::test_attr_in_doctest)]
12 |
13 | #[cfg(not(feature = "std"))]
14 | compile_error!(
15 | "`futures-test` must have the `std` feature activated, this is a default-active feature"
16 | );
17 |
18 | // Not public API.
19 | #[doc(hidden)]
20 | #[cfg(feature = "std")]
21 | pub mod __private {
22 | pub use futures_core::{future, stream, task};
23 | pub use futures_executor::block_on;
24 | pub use std::{
25 | option::Option::{None, Some},
26 | pin::Pin,
27 | result::Result::{Err, Ok},
28 | };
29 |
30 | pub mod assert {
31 | pub use crate::assert::*;
32 | }
33 | }
34 |
35 | #[macro_use]
36 | #[cfg(feature = "std")]
37 | mod assert;
38 |
39 | #[cfg(feature = "std")]
40 | pub mod task;
41 |
42 | #[cfg(feature = "std")]
43 | pub mod future;
44 |
45 | #[cfg(feature = "std")]
46 | pub mod stream;
47 |
48 | #[cfg(feature = "std")]
49 | pub mod sink;
50 |
51 | #[cfg(feature = "std")]
52 | pub mod io;
53 |
54 | mod assert_unmoved;
55 | mod interleave_pending;
56 | mod track_closed;
57 |
58 | /// Enables an `async` test function. The generated future will be run to completion with
59 | /// [`futures_executor::block_on`].
60 | ///
61 | /// ```
62 | /// #[futures_test::test]
63 | /// async fn my_test() {
64 | /// let fut = async { true };
65 | /// assert!(fut.await);
66 | /// }
67 | /// ```
68 | ///
69 | /// This is equivalent to the following code:
70 | ///
71 | /// ```
72 | /// #[test]
73 | /// fn my_test() {
74 | /// futures::executor::block_on(async move {
75 | /// let fut = async { true };
76 | /// assert!(fut.await);
77 | /// })
78 | /// }
79 | /// ```
80 | #[cfg(feature = "std")]
81 | pub use futures_macro::test_internal as test;
82 |
--------------------------------------------------------------------------------
/futures-test/src/stream/mod.rs:
--------------------------------------------------------------------------------
1 | //! Additional combinators for testing streams.
2 |
3 | use futures_core::stream::Stream;
4 |
5 | pub use crate::assert_unmoved::AssertUnmoved;
6 | pub use crate::interleave_pending::InterleavePending;
7 |
8 | /// Additional combinators for testing streams.
9 | pub trait StreamTestExt: Stream {
10 | /// Asserts that the given is not moved after being polled.
11 | ///
12 | /// A check for movement is performed each time the stream is polled
13 | /// and when `Drop` is called.
14 | ///
15 | /// Aside from keeping track of the location at which the stream was first
16 | /// polled and providing assertions, this stream adds no runtime behavior
17 | /// and simply delegates to the child stream.
18 | fn assert_unmoved(self) -> AssertUnmoved
19 | where
20 | Self: Sized,
21 | {
22 | AssertUnmoved::new(self)
23 | }
24 |
25 | /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending)
26 | /// in between each item of the stream.
27 | ///
28 | /// # Examples
29 | ///
30 | /// ```
31 | /// use core::pin::pin;
32 | ///
33 | /// use futures::task::Poll;
34 | /// use futures::stream::{self, Stream};
35 | /// use futures_test::task::noop_context;
36 | /// use futures_test::stream::StreamTestExt;
37 | ///
38 | /// let stream = stream::iter(vec![1, 2]).interleave_pending();
39 | /// let mut stream = pin!(stream);
40 | ///
41 | /// let mut cx = noop_context();
42 | ///
43 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending);
44 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(1)));
45 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending);
46 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(2)));
47 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending);
48 | /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(None));
49 | /// ```
50 | fn interleave_pending(self) -> InterleavePending
51 | where
52 | Self: Sized,
53 | {
54 | InterleavePending::new(self)
55 | }
56 | }
57 |
58 | impl StreamTestExt for St where St: Stream {}
59 |
--------------------------------------------------------------------------------
/futures-test/src/task/context.rs:
--------------------------------------------------------------------------------
1 | use crate::task::{noop_waker_ref, panic_waker_ref};
2 | use futures_core::task::Context;
3 |
4 | /// Create a new [`Context`](core::task::Context) where the
5 | /// [waker](core::task::Context::waker) will panic if used.
6 | ///
7 | /// # Examples
8 | ///
9 | /// ```should_panic
10 | /// use futures_test::task::panic_context;
11 | ///
12 | /// let cx = panic_context();
13 | /// cx.waker().wake_by_ref(); // Will panic
14 | /// ```
15 | pub fn panic_context() -> Context<'static> {
16 | Context::from_waker(panic_waker_ref())
17 | }
18 |
19 | /// Create a new [`Context`](core::task::Context) where the
20 | /// [waker](core::task::Context::waker) will ignore any uses.
21 | ///
22 | /// # Examples
23 | ///
24 | /// ```
25 | /// use core::pin::pin;
26 | ///
27 | /// use futures::future::Future;
28 | /// use futures::task::Poll;
29 | /// use futures_test::task::noop_context;
30 | ///
31 | /// let future = async { 5 };
32 | /// let future = pin!(future);
33 | ///
34 | /// assert_eq!(future.poll(&mut noop_context()), Poll::Ready(5));
35 | /// ```
36 | pub fn noop_context() -> Context<'static> {
37 | Context::from_waker(noop_waker_ref())
38 | }
39 |
--------------------------------------------------------------------------------
/futures-test/src/task/noop_spawner.rs:
--------------------------------------------------------------------------------
1 | use futures_task::{FutureObj, Spawn, SpawnError};
2 |
3 | /// An implementation of [`Spawn`](futures_task::Spawn) that
4 | /// discards spawned futures when used.
5 | ///
6 | /// # Examples
7 | ///
8 | /// ```
9 | /// use futures::task::SpawnExt;
10 | /// use futures_test::task::NoopSpawner;
11 | ///
12 | /// let spawner = NoopSpawner::new();
13 | /// spawner.spawn(async { }).unwrap();
14 | /// ```
15 | #[derive(Debug)]
16 | pub struct NoopSpawner {
17 | _reserved: (),
18 | }
19 |
20 | impl NoopSpawner {
21 | /// Create a new instance
22 | pub fn new() -> Self {
23 | Self { _reserved: () }
24 | }
25 | }
26 |
27 | impl Spawn for NoopSpawner {
28 | fn spawn_obj(&self, _future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
29 | Ok(())
30 | }
31 | }
32 |
33 | impl Default for NoopSpawner {
34 | fn default() -> Self {
35 | Self::new()
36 | }
37 | }
38 |
39 | /// Get a reference to a singleton instance of [`NoopSpawner`].
40 | ///
41 | /// # Examples
42 | ///
43 | /// ```
44 | /// use futures::task::SpawnExt;
45 | /// use futures_test::task::noop_spawner_mut;
46 | ///
47 | /// let spawner = noop_spawner_mut();
48 | /// spawner.spawn(async { }).unwrap();
49 | /// ```
50 | pub fn noop_spawner_mut() -> &'static mut NoopSpawner {
51 | Box::leak(Box::new(NoopSpawner::new()))
52 | }
53 |
--------------------------------------------------------------------------------
/futures-test/src/task/panic_spawner.rs:
--------------------------------------------------------------------------------
1 | use futures_task::{FutureObj, Spawn, SpawnError};
2 |
3 | /// An implementation of [`Spawn`](futures_task::Spawn) that panics
4 | /// when used.
5 | ///
6 | /// # Examples
7 | ///
8 | /// ```should_panic
9 | /// use futures::task::SpawnExt;
10 | /// use futures_test::task::PanicSpawner;
11 | ///
12 | /// let spawn = PanicSpawner::new();
13 | /// spawn.spawn(async { })?; // Will panic
14 | /// # Ok::<(), Box>(())
15 | /// ```
16 | #[derive(Debug)]
17 | pub struct PanicSpawner {
18 | _reserved: (),
19 | }
20 |
21 | impl PanicSpawner {
22 | /// Create a new instance
23 | pub fn new() -> Self {
24 | Self { _reserved: () }
25 | }
26 | }
27 |
28 | impl Spawn for PanicSpawner {
29 | fn spawn_obj(&self, _future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
30 | panic!("should not spawn")
31 | }
32 | }
33 |
34 | impl Default for PanicSpawner {
35 | fn default() -> Self {
36 | Self::new()
37 | }
38 | }
39 |
40 | /// Get a reference to a singleton instance of [`PanicSpawner`].
41 | ///
42 | /// # Examples
43 | ///
44 | /// ```should_panic
45 | /// use futures::task::SpawnExt;
46 | /// use futures_test::task::panic_spawner_mut;
47 | ///
48 | /// let spawner = panic_spawner_mut();
49 | /// spawner.spawn(async { })?; // Will panic
50 | /// # Ok::<(), Box>(())
51 | /// ```
52 | pub fn panic_spawner_mut() -> &'static mut PanicSpawner {
53 | Box::leak(Box::new(PanicSpawner::new()))
54 | }
55 |
--------------------------------------------------------------------------------
/futures-test/src/task/record_spawner.rs:
--------------------------------------------------------------------------------
1 | use futures_task::{FutureObj, Spawn, SpawnError};
2 | use std::cell::{Ref, RefCell};
3 |
4 | /// An implementation of [`Spawn`](futures_task::Spawn) that records
5 | /// any [`Future`](futures_core::future::Future)s spawned on it.
6 | ///
7 | /// # Examples
8 | ///
9 | /// ```
10 | /// use futures::task::SpawnExt;
11 | /// use futures_test::task::RecordSpawner;
12 | ///
13 | /// let recorder = RecordSpawner::new();
14 | /// recorder.spawn(async { }).unwrap();
15 | /// assert_eq!(recorder.spawned().len(), 1);
16 | /// ```
17 | #[derive(Debug, Default)]
18 | pub struct RecordSpawner {
19 | spawned: RefCell>>,
20 | }
21 |
22 | impl RecordSpawner {
23 | /// Create a new instance
24 | pub fn new() -> Self {
25 | Default::default()
26 | }
27 |
28 | /// Inspect any futures that were spawned onto this [`Spawn`].
29 | pub fn spawned(&self) -> Ref<'_, Vec>> {
30 | self.spawned.borrow()
31 | }
32 | }
33 |
34 | impl Spawn for RecordSpawner {
35 | fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
36 | self.spawned.borrow_mut().push(future);
37 | Ok(())
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/futures-test/src/task/wake_counter.rs:
--------------------------------------------------------------------------------
1 | use futures_core::task::Waker;
2 | use futures_util::task::{self, ArcWake};
3 | use std::sync::atomic::{AtomicUsize, Ordering};
4 | use std::sync::Arc;
5 |
6 | /// Number of times the waker was awoken.
7 | ///
8 | /// See [`new_count_waker`] for usage.
9 | #[derive(Debug)]
10 | pub struct AwokenCount {
11 | inner: Arc,
12 | }
13 |
14 | impl AwokenCount {
15 | /// Get the current count.
16 | pub fn get(&self) -> usize {
17 | self.inner.count.load(Ordering::SeqCst)
18 | }
19 | }
20 |
21 | impl PartialEq for AwokenCount {
22 | fn eq(&self, other: &usize) -> bool {
23 | self.get() == *other
24 | }
25 | }
26 |
27 | #[derive(Debug)]
28 | struct WakerInner {
29 | count: AtomicUsize,
30 | }
31 |
32 | impl ArcWake for WakerInner {
33 | fn wake_by_ref(arc_self: &Arc) {
34 | let _ = arc_self.count.fetch_add(1, Ordering::SeqCst);
35 | }
36 | }
37 |
38 | /// Create a new [`Waker`] that counts the number of times it's awoken.
39 | ///
40 | /// [`Waker`]: futures_core::task::Waker
41 | ///
42 | /// # Examples
43 | ///
44 | /// ```
45 | /// use futures_test::task::new_count_waker;
46 | ///
47 | /// let (waker, count) = new_count_waker();
48 | ///
49 | /// assert_eq!(count, 0);
50 | ///
51 | /// waker.wake_by_ref();
52 | /// waker.wake();
53 | ///
54 | /// assert_eq!(count, 2);
55 | /// ```
56 | pub fn new_count_waker() -> (Waker, AwokenCount) {
57 | let inner = Arc::new(WakerInner { count: AtomicUsize::new(0) });
58 | (task::waker(inner.clone()), AwokenCount { inner })
59 | }
60 |
--------------------------------------------------------------------------------
/futures-util/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | ../LICENSE-APACHE
--------------------------------------------------------------------------------
/futures-util/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | ../LICENSE-MIT
--------------------------------------------------------------------------------
/futures-util/README.md:
--------------------------------------------------------------------------------
1 | # futures-util
2 |
3 | Common utilities and extension traits for the futures-rs library.
4 |
5 | ## Usage
6 |
7 | Add this to your `Cargo.toml`:
8 |
9 | ```toml
10 | [dependencies]
11 | futures-util = "0.3"
12 | ```
13 |
14 | The current `futures-util` requires Rust 1.68 or later.
15 |
16 | ## License
17 |
18 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
19 | [MIT license](LICENSE-MIT) at your option.
20 |
21 | Unless you explicitly state otherwise, any contribution intentionally submitted
22 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall
23 | be dual licensed as above, without any additional terms or conditions.
24 |
--------------------------------------------------------------------------------
/futures-util/benches/bilock.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 | #![cfg(feature = "bilock")]
3 |
4 | extern crate test;
5 |
6 | use futures::task::Poll;
7 | use futures_test::task::noop_context;
8 | use futures_util::lock::BiLock;
9 |
10 | use crate::test::Bencher;
11 |
12 | #[bench]
13 | fn contended(b: &mut Bencher) {
14 | let mut context = noop_context();
15 |
16 | b.iter(|| {
17 | let (x, y) = BiLock::new(1);
18 |
19 | for _ in 0..1000 {
20 | let x_guard = match x.poll_lock(&mut context) {
21 | Poll::Ready(guard) => guard,
22 | _ => panic!(),
23 | };
24 |
25 | // Try poll second lock while first lock still holds the lock
26 | match y.poll_lock(&mut context) {
27 | Poll::Pending => (),
28 | _ => panic!(),
29 | };
30 |
31 | drop(x_guard);
32 |
33 | let y_guard = match y.poll_lock(&mut context) {
34 | Poll::Ready(guard) => guard,
35 | _ => panic!(),
36 | };
37 |
38 | drop(y_guard);
39 | }
40 | (x, y)
41 | });
42 | }
43 |
44 | #[bench]
45 | fn lock_unlock(b: &mut Bencher) {
46 | let mut context = noop_context();
47 |
48 | b.iter(|| {
49 | let (x, y) = BiLock::new(1);
50 |
51 | for _ in 0..1000 {
52 | let x_guard = match x.poll_lock(&mut context) {
53 | Poll::Ready(guard) => guard,
54 | _ => panic!(),
55 | };
56 |
57 | drop(x_guard);
58 |
59 | let y_guard = match y.poll_lock(&mut context) {
60 | Poll::Ready(guard) => guard,
61 | _ => panic!(),
62 | };
63 |
64 | drop(y_guard);
65 | }
66 | (x, y)
67 | })
68 | }
69 |
--------------------------------------------------------------------------------
/futures-util/benches/flatten_unordered.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate test;
4 | use crate::test::Bencher;
5 |
6 | use futures::channel::oneshot;
7 | use futures::executor::block_on;
8 | use futures::future;
9 | use futures::stream::{self, StreamExt};
10 | use futures::task::Poll;
11 | use futures_util::FutureExt;
12 | use std::collections::VecDeque;
13 | use std::thread;
14 |
15 | #[bench]
16 | fn oneshot_streams(b: &mut Bencher) {
17 | const STREAM_COUNT: usize = 10_000;
18 | const STREAM_ITEM_COUNT: usize = 1;
19 |
20 | b.iter(|| {
21 | let mut txs = VecDeque::with_capacity(STREAM_COUNT);
22 | let mut rxs = Vec::new();
23 |
24 | for _ in 0..STREAM_COUNT {
25 | let (tx, rx) = oneshot::channel();
26 | txs.push_back(tx);
27 | rxs.push(rx);
28 | }
29 |
30 | thread::spawn(move || {
31 | let mut last = 1;
32 | while let Some(tx) = txs.pop_front() {
33 | let _ = tx.send(stream::iter(last..last + STREAM_ITEM_COUNT));
34 | last += STREAM_ITEM_COUNT;
35 | }
36 | });
37 |
38 | let mut flatten = stream::iter(rxs)
39 | .map(|recv| recv.into_stream().map(|val| val.unwrap()).flatten())
40 | .flatten_unordered(None);
41 |
42 | block_on(future::poll_fn(move |cx| {
43 | let mut count = 0;
44 | loop {
45 | match flatten.poll_next_unpin(cx) {
46 | Poll::Ready(None) => break,
47 | Poll::Ready(Some(_)) => {
48 | count += 1;
49 | }
50 | _ => {}
51 | }
52 | }
53 | assert_eq!(count, STREAM_COUNT * STREAM_ITEM_COUNT);
54 |
55 | Poll::Ready(())
56 | }))
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/futures-util/benches/futures_unordered.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate test;
4 | use crate::test::Bencher;
5 |
6 | use futures::channel::oneshot;
7 | use futures::executor::block_on;
8 | use futures::future;
9 | use futures::stream::{FuturesUnordered, StreamExt};
10 | use futures::task::Poll;
11 | use std::collections::VecDeque;
12 | use std::thread;
13 |
14 | #[bench]
15 | fn oneshots(b: &mut Bencher) {
16 | const NUM: usize = 10_000;
17 |
18 | b.iter(|| {
19 | let mut txs = VecDeque::with_capacity(NUM);
20 | let mut rxs = FuturesUnordered::new();
21 |
22 | for _ in 0..NUM {
23 | let (tx, rx) = oneshot::channel();
24 | txs.push_back(tx);
25 | rxs.push(rx);
26 | }
27 |
28 | thread::spawn(move || {
29 | while let Some(tx) = txs.pop_front() {
30 | let _ = tx.send("hello");
31 | }
32 | });
33 |
34 | block_on(future::poll_fn(move |cx| {
35 | loop {
36 | if let Poll::Ready(None) = rxs.poll_next_unpin(cx) {
37 | break;
38 | }
39 | }
40 | Poll::Ready(())
41 | }))
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/futures-util/benches/select.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate test;
4 | use crate::test::Bencher;
5 |
6 | use futures::executor::block_on;
7 | use futures::stream::{repeat, select, StreamExt};
8 |
9 | #[bench]
10 | fn select_streams(b: &mut Bencher) {
11 | const STREAM_COUNT: usize = 10_000;
12 |
13 | b.iter(|| {
14 | let stream1 = repeat(1).take(STREAM_COUNT);
15 | let stream2 = repeat(2).take(STREAM_COUNT);
16 | let stream3 = repeat(3).take(STREAM_COUNT);
17 | let stream4 = repeat(4).take(STREAM_COUNT);
18 | let stream5 = repeat(5).take(STREAM_COUNT);
19 | let stream6 = repeat(6).take(STREAM_COUNT);
20 | let stream7 = repeat(7).take(STREAM_COUNT);
21 | let count = block_on(
22 | select(
23 | stream1,
24 | select(
25 | stream2,
26 | select(stream3, select(stream4, select(stream5, select(stream6, stream7)))),
27 | ),
28 | )
29 | .count(),
30 | );
31 | assert_eq!(count, STREAM_COUNT * 7);
32 | });
33 | }
34 |
--------------------------------------------------------------------------------
/futures-util/src/async_await/mod.rs:
--------------------------------------------------------------------------------
1 | //! Await
2 | //!
3 | //! This module contains a number of functions and combinators for working
4 | //! with `async`/`await` code.
5 |
6 | use futures_core::future::{FusedFuture, Future};
7 | use futures_core::stream::{FusedStream, Stream};
8 |
9 | #[macro_use]
10 | mod poll;
11 | pub use self::poll::*;
12 |
13 | #[macro_use]
14 | mod pending;
15 | pub use self::pending::*;
16 |
17 | // Primary export is a macro
18 | #[cfg(feature = "async-await-macro")]
19 | mod join_mod;
20 | #[cfg(feature = "async-await-macro")]
21 | pub use self::join_mod::*;
22 |
23 | // Primary export is a macro
24 | #[cfg(feature = "async-await-macro")]
25 | mod select_mod;
26 | #[cfg(feature = "async-await-macro")]
27 | pub use self::select_mod::*;
28 |
29 | // Primary export is a macro
30 | #[cfg(feature = "std")]
31 | #[cfg(feature = "async-await-macro")]
32 | mod stream_select_mod;
33 | #[cfg(feature = "std")]
34 | #[cfg(feature = "async-await-macro")]
35 | pub use self::stream_select_mod::*;
36 |
37 | #[cfg(feature = "std")]
38 | #[cfg(feature = "async-await-macro")]
39 | mod random;
40 | #[cfg(feature = "std")]
41 | #[cfg(feature = "async-await-macro")]
42 | pub use self::random::*;
43 |
44 | #[doc(hidden)]
45 | #[inline(always)]
46 | pub fn assert_unpin(_: &T) {}
47 |
48 | #[doc(hidden)]
49 | #[inline(always)]
50 | pub fn assert_fused_future(_: &T) {}
51 |
52 | #[doc(hidden)]
53 | #[inline(always)]
54 | pub fn assert_fused_stream(_: &T) {}
55 |
--------------------------------------------------------------------------------
/futures-util/src/async_await/pending.rs:
--------------------------------------------------------------------------------
1 | use core::pin::Pin;
2 | use futures_core::future::Future;
3 | use futures_core::task::{Context, Poll};
4 |
5 | /// A macro which yields to the event loop once.
6 | ///
7 | /// This is equivalent to returning [`Poll::Pending`](futures_core::task::Poll)
8 | /// from a [`Future::poll`](futures_core::future::Future::poll) implementation.
9 | /// Similarly, when using this macro, it must be ensured that [`wake`](std::task::Waker::wake)
10 | /// is called somewhere when further progress can be made.
11 | ///
12 | /// This macro is only usable inside of async functions, closures, and blocks.
13 | /// It is also gated behind the `async-await` feature of this library, which is
14 | /// activated by default.
15 | #[macro_export]
16 | macro_rules! pending {
17 | () => {
18 | $crate::__private::async_await::pending_once().await
19 | };
20 | }
21 |
22 | #[doc(hidden)]
23 | pub fn pending_once() -> PendingOnce {
24 | PendingOnce { is_ready: false }
25 | }
26 |
27 | #[allow(missing_debug_implementations)]
28 | #[doc(hidden)]
29 | pub struct PendingOnce {
30 | is_ready: bool,
31 | }
32 |
33 | impl Future for PendingOnce {
34 | type Output = ();
35 | fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll {
36 | if self.is_ready {
37 | Poll::Ready(())
38 | } else {
39 | self.is_ready = true;
40 | Poll::Pending
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/futures-util/src/async_await/poll.rs:
--------------------------------------------------------------------------------
1 | use crate::future::FutureExt;
2 | use core::pin::Pin;
3 | use futures_core::future::Future;
4 | use futures_core::task::{Context, Poll};
5 |
6 | /// A macro which returns the result of polling a future once within the
7 | /// current `async` context.
8 | ///
9 | /// This macro is only usable inside of `async` functions, closures, and blocks.
10 | /// It is also gated behind the `async-await` feature of this library, which is
11 | /// activated by default.
12 | ///
13 | /// If you need the result of polling a [`Stream`](crate::stream::Stream),
14 | /// you can use this macro with the [`next`](crate::stream::StreamExt::next) method:
15 | /// `poll!(stream.next())`.
16 | #[macro_export]
17 | macro_rules! poll {
18 | ($x:expr $(,)?) => {
19 | $crate::__private::async_await::poll($x).await
20 | };
21 | }
22 |
23 | #[doc(hidden)]
24 | pub fn poll(future: F) -> PollOnce {
25 | PollOnce { future }
26 | }
27 |
28 | #[allow(missing_debug_implementations)]
29 | #[doc(hidden)]
30 | pub struct PollOnce {
31 | future: F,
32 | }
33 |
34 | impl Future for PollOnce {
35 | type Output = Poll;
36 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
37 | Poll::Ready(self.future.poll_unpin(cx))
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/futures-util/src/async_await/random.rs:
--------------------------------------------------------------------------------
1 | use std::{
2 | cell::Cell,
3 | collections::hash_map::DefaultHasher,
4 | hash::Hasher,
5 | num::Wrapping,
6 | sync::atomic::{AtomicUsize, Ordering},
7 | };
8 |
9 | // Based on [Fisher–Yates shuffle].
10 | //
11 | // [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
12 | #[doc(hidden)]
13 | pub fn shuffle(slice: &mut [T]) {
14 | for i in (1..slice.len()).rev() {
15 | slice.swap(i, gen_index(i + 1));
16 | }
17 | }
18 |
19 | /// Return a value from `0..n`.
20 | fn gen_index(n: usize) -> usize {
21 | (random() % n as u64) as usize
22 | }
23 |
24 | /// Pseudorandom number generator based on [xorshift*].
25 | ///
26 | /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
27 | fn random() -> u64 {
28 | std::thread_local! {
29 | static RNG: Cell> = Cell::new(Wrapping(prng_seed()));
30 | }
31 |
32 | fn prng_seed() -> u64 {
33 | static COUNTER: AtomicUsize = AtomicUsize::new(0);
34 |
35 | // Any non-zero seed will do
36 | let mut seed = 0;
37 | while seed == 0 {
38 | let mut hasher = DefaultHasher::new();
39 | hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed));
40 | seed = hasher.finish();
41 | }
42 | seed
43 | }
44 |
45 | RNG.with(|rng| {
46 | let mut x = rng.get();
47 | debug_assert_ne!(x.0, 0);
48 | x ^= x >> 12;
49 | x ^= x << 25;
50 | x ^= x >> 27;
51 | rng.set(x);
52 | x.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/futures-util/src/async_await/stream_select_mod.rs:
--------------------------------------------------------------------------------
1 | //! The `stream_select` macro.
2 |
3 | #[doc(hidden)]
4 | pub use futures_macro::stream_select_internal;
5 |
6 | #[allow(clippy::too_long_first_doc_paragraph)]
7 | /// Combines several streams, all producing the same `Item` type, into one stream.
8 | /// This is similar to `select_all` but does not require the streams to all be the same type.
9 | /// It also keeps the streams inline, and does not require `Box`s to be allocated.
10 | /// Streams passed to this macro must be `Unpin`.
11 | ///
12 | /// If multiple streams are ready, one will be pseudo randomly selected at runtime.
13 | ///
14 | /// # Examples
15 | ///
16 | /// ```
17 | /// # futures::executor::block_on(async {
18 | /// use futures::{stream, StreamExt, stream_select};
19 | /// let endless_ints = |i| stream::iter(vec![i].into_iter().cycle()).fuse();
20 | ///
21 | /// let mut endless_numbers = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3));
22 | /// match endless_numbers.next().await {
23 | /// Some(1) => println!("Got a 1"),
24 | /// Some(2) => println!("Got a 2"),
25 | /// Some(3) => println!("Got a 3"),
26 | /// _ => unreachable!(),
27 | /// }
28 | /// # });
29 | /// ```
30 | #[macro_export]
31 | macro_rules! stream_select {
32 | ($($tokens:tt)*) => {{
33 | use $crate::__private as __futures_crate;
34 | $crate::stream_select_internal! {
35 | $( $tokens )*
36 | }
37 | }}
38 | }
39 |
--------------------------------------------------------------------------------
/futures-util/src/compat/mod.rs:
--------------------------------------------------------------------------------
1 | //! Interop between `futures` 0.1 and 0.3.
2 | //!
3 | //! This module is only available when the `compat` feature of this
4 | //! library is activated.
5 |
6 | mod executor;
7 | pub use self::executor::{Executor01As03, Executor01CompatExt, Executor01Future};
8 |
9 | mod compat01as03;
10 | #[cfg(feature = "io-compat")]
11 | #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))]
12 | pub use self::compat01as03::{AsyncRead01CompatExt, AsyncWrite01CompatExt};
13 | pub use self::compat01as03::{Compat01As03, Future01CompatExt, Stream01CompatExt};
14 | #[cfg(feature = "sink")]
15 | #[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
16 | pub use self::compat01as03::{Compat01As03Sink, Sink01CompatExt};
17 |
18 | mod compat03as01;
19 | pub use self::compat03as01::Compat;
20 | #[cfg(feature = "sink")]
21 | #[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
22 | pub use self::compat03as01::CompatSink;
23 |
--------------------------------------------------------------------------------
/futures-util/src/future/abortable.rs:
--------------------------------------------------------------------------------
1 | use super::assert_future;
2 | use crate::future::{AbortHandle, Abortable, Aborted};
3 | use futures_core::future::Future;
4 |
5 | /// Creates a new `Abortable` future and an `AbortHandle` which can be used to stop it.
6 | ///
7 | /// This function is a convenient (but less flexible) alternative to calling
8 | /// `AbortHandle::new` and `Abortable::new` manually.
9 | ///
10 | /// This function is only available when the `std` or `alloc` feature of this
11 | /// library is activated, and it is activated by default.
12 | pub fn abortable(future: Fut) -> (Abortable, AbortHandle)
13 | where
14 | Fut: Future,
15 | {
16 | let (handle, reg) = AbortHandle::new_pair();
17 | let abortable = assert_future::, _>(Abortable::new(future, reg));
18 | (abortable, handle)
19 | }
20 |
--------------------------------------------------------------------------------
/futures-util/src/future/always_ready.rs:
--------------------------------------------------------------------------------
1 | use super::assert_future;
2 | use core::pin::Pin;
3 | use futures_core::future::{FusedFuture, Future};
4 | use futures_core::task::{Context, Poll};
5 |
6 | /// Future for the [`always_ready`](always_ready()) function.
7 | #[must_use = "futures do nothing unless you `.await` or poll them"]
8 | pub struct AlwaysReady T>(F);
9 |
10 | impl T> core::fmt::Debug for AlwaysReady {
11 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12 | f.debug_tuple("AlwaysReady").finish()
13 | }
14 | }
15 |
16 | impl T + Clone> Clone for AlwaysReady {
17 | fn clone(&self) -> Self {
18 | Self(self.0.clone())
19 | }
20 | }
21 |
22 | impl T + Copy> Copy for AlwaysReady {}
23 |
24 | impl T> Unpin for AlwaysReady {}
25 |
26 | impl T> FusedFuture for AlwaysReady {
27 | fn is_terminated(&self) -> bool {
28 | false
29 | }
30 | }
31 |
32 | impl T> Future for AlwaysReady {
33 | type Output = T;
34 |
35 | #[inline]
36 | fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll {
37 | Poll::Ready(self.0())
38 | }
39 | }
40 |
41 | /// Creates a future that is always immediately ready with a value.
42 | ///
43 | /// This is particularly useful in avoiding a heap allocation when an API needs [`Box>`],
44 | /// as [`AlwaysReady`] does not have to store a boolean for `is_finished`.
45 | ///
46 | /// # Examples
47 | ///
48 | /// ```
49 | /// # futures::executor::block_on(async {
50 | /// use std::mem::size_of_val;
51 | ///
52 | /// use futures::future;
53 | ///
54 | /// let a = future::always_ready(|| 1);
55 | /// assert_eq!(size_of_val(&a), 0);
56 | /// assert_eq!(a.await, 1);
57 | /// assert_eq!(a.await, 1);
58 | /// # });
59 | /// ```
60 | pub fn always_ready T>(prod: F) -> AlwaysReady {
61 | assert_future::(AlwaysReady(prod))
62 | }
63 |
--------------------------------------------------------------------------------
/futures-util/src/future/future/catch_unwind.rs:
--------------------------------------------------------------------------------
1 | use core::any::Any;
2 | use core::pin::Pin;
3 | use std::boxed::Box;
4 | use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe};
5 |
6 | use futures_core::future::Future;
7 | use futures_core::task::{Context, Poll};
8 | use pin_project_lite::pin_project;
9 |
10 | pin_project! {
11 | /// Future for the [`catch_unwind`](super::FutureExt::catch_unwind) method.
12 | #[derive(Debug)]
13 | #[must_use = "futures do nothing unless you `.await` or poll them"]
14 | pub struct CatchUnwind {
15 | #[pin]
16 | future: Fut,
17 | }
18 | }
19 |
20 | impl CatchUnwind
21 | where
22 | Fut: Future + UnwindSafe,
23 | {
24 | pub(super) fn new(future: Fut) -> Self {
25 | Self { future }
26 | }
27 | }
28 |
29 | impl Future for CatchUnwind
30 | where
31 | Fut: Future + UnwindSafe,
32 | {
33 | type Output = Result>;
34 |
35 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
36 | let f = self.project().future;
37 | catch_unwind(AssertUnwindSafe(|| f.poll(cx)))?.map(Ok)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/futures-util/src/future/future/map.rs:
--------------------------------------------------------------------------------
1 | use core::pin::Pin;
2 | use futures_core::future::{FusedFuture, Future};
3 | use futures_core::ready;
4 | use futures_core::task::{Context, Poll};
5 | use pin_project_lite::pin_project;
6 |
7 | use crate::fns::FnOnce1;
8 |
9 | pin_project! {
10 | /// Internal Map future
11 | #[project = MapProj]
12 | #[project_replace = MapProjReplace]
13 | #[derive(Debug)]
14 | #[must_use = "futures do nothing unless you `.await` or poll them"]
15 | pub enum Map {
16 | Incomplete {
17 | #[pin]
18 | future: Fut,
19 | f: F,
20 | },
21 | Complete,
22 | }
23 | }
24 |
25 | impl Map {
26 | /// Creates a new Map.
27 | pub(crate) fn new(future: Fut, f: F) -> Self {
28 | Self::Incomplete { future, f }
29 | }
30 | }
31 |
32 | impl FusedFuture for Map
33 | where
34 | Fut: Future,
35 | F: FnOnce1,
36 | {
37 | fn is_terminated(&self) -> bool {
38 | match self {
39 | Self::Incomplete { .. } => false,
40 | Self::Complete => true,
41 | }
42 | }
43 | }
44 |
45 | impl Future for Map
46 | where
47 | Fut: Future,
48 | F: FnOnce1,
49 | {
50 | type Output = T;
51 |
52 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
53 | match self.as_mut().project() {
54 | MapProj::Incomplete { future, .. } => {
55 | let output = ready!(future.poll(cx));
56 | match self.project_replace(Self::Complete) {
57 | MapProjReplace::Incomplete { f, .. } => Poll::Ready(f.call_once(output)),
58 | MapProjReplace::Complete => unreachable!(),
59 | }
60 | }
61 | MapProj::Complete => {
62 | panic!("Map must not be polled after it returned `Poll::Ready`")
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/futures-util/src/future/lazy.rs:
--------------------------------------------------------------------------------
1 | use super::assert_future;
2 | use core::pin::Pin;
3 | use futures_core::future::{FusedFuture, Future};
4 | use futures_core::task::{Context, Poll};
5 |
6 | /// Future for the [`lazy`] function.
7 | #[derive(Debug)]
8 | #[must_use = "futures do nothing unless you `.await` or poll them"]
9 | pub struct Lazy {
10 | f: Option,
11 | }
12 |
13 | // safe because we never generate `Pin<&mut F>`
14 | impl Unpin for Lazy {}
15 |
16 | /// Creates a new future that allows delayed execution of a closure.
17 | ///
18 | /// The provided closure is only run once the future is polled.
19 | ///
20 | /// # Examples
21 | ///
22 | /// ```
23 | /// # futures::executor::block_on(async {
24 | /// use futures::future;
25 | ///
26 | /// let a = future::lazy(|_| 1);
27 | /// assert_eq!(a.await, 1);
28 | ///
29 | /// let b = future::lazy(|_| -> i32 {
30 | /// panic!("oh no!")
31 | /// });
32 | /// drop(b); // closure is never run
33 | /// # });
34 | /// ```
35 | pub fn lazy(f: F) -> Lazy
36 | where
37 | F: FnOnce(&mut Context<'_>) -> R,
38 | {
39 | assert_future::(Lazy { f: Some(f) })
40 | }
41 |
42 | impl FusedFuture for Lazy
43 | where
44 | F: FnOnce(&mut Context<'_>) -> R,
45 | {
46 | fn is_terminated(&self) -> bool {
47 | self.f.is_none()
48 | }
49 | }
50 |
51 | impl Future for Lazy
52 | where
53 | F: FnOnce(&mut Context<'_>) -> R,
54 | {
55 | type Output = R;
56 |
57 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
58 | Poll::Ready((self.f.take().expect("Lazy polled after completion"))(cx))
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/futures-util/src/future/option.rs:
--------------------------------------------------------------------------------
1 | //! Definition of the `Option` (optional step) combinator
2 |
3 | use core::pin::Pin;
4 | use futures_core::future::{FusedFuture, Future};
5 | use futures_core::task::{Context, Poll};
6 | use pin_project_lite::pin_project;
7 |
8 | pin_project! {
9 | /// A future representing a value which may or may not be present.
10 | ///
11 | /// Created by the [`From`] implementation for [`Option`](std::option::Option).
12 | ///
13 | /// # Examples
14 | ///
15 | /// ```
16 | /// # futures::executor::block_on(async {
17 | /// use futures::future::OptionFuture;
18 | ///
19 | /// let mut a: OptionFuture<_> = Some(async { 123 }).into();
20 | /// assert_eq!(a.await, Some(123));
21 | ///
22 | /// a = None.into();
23 | /// assert_eq!(a.await, None);
24 | /// # });
25 | /// ```
26 | #[derive(Debug, Clone)]
27 | #[must_use = "futures do nothing unless you `.await` or poll them"]
28 | pub struct OptionFuture {
29 | #[pin]
30 | inner: Option,
31 | }
32 | }
33 |
34 | impl Default for OptionFuture {
35 | fn default() -> Self {
36 | Self { inner: None }
37 | }
38 | }
39 |
40 | impl Future for OptionFuture {
41 | type Output = Option;
42 |
43 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
44 | match self.project().inner.as_pin_mut() {
45 | Some(x) => x.poll(cx).map(Some),
46 | None => Poll::Ready(None),
47 | }
48 | }
49 | }
50 |
51 | impl FusedFuture for OptionFuture {
52 | fn is_terminated(&self) -> bool {
53 | match &self.inner {
54 | Some(x) => x.is_terminated(),
55 | None => true,
56 | }
57 | }
58 | }
59 |
60 | impl From