diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:22:09 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:22:09 +0000 |
commit | e750b72841396ce8e6151050eb9895e3cac0f344 (patch) | |
tree | 7b826874213015b98b9e0383a89c88be66b64b11 | |
parent | fad8fcacb606ceb9b990e6c93cc43547a9ecbbbf (diff) | |
parent | e177aca7d9e335e8989e592627752459e00df418 (diff) | |
download | futures-util-e750b72841396ce8e6151050eb9895e3cac0f344.tar.gz |
Snap for 8564071 from e177aca7d9e335e8989e592627752459e00df418 to mainline-art-releaseaml_art_331813100aml_art_331813010aml_art_331711080aml_art_331612010aml_art_331413030aml_art_331314010aml_art_331113000aml_art_331012050android13-mainline-art-release
Change-Id: Ied59b16f1ed45c3ae5c7151edc751d18f03b1ed3
165 files changed, 4632 insertions, 2488 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index f3ad3ab..b52386f 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "c91f8691672c7401b1923ab00bf138975c99391a" - } -} + "sha1": "fc1e3250219170e31cddb8857a276cba7dd08d44" + }, + "path_in_vcs": "futures-util" +}
\ No newline at end of file @@ -37,12 +37,18 @@ license { ], } -rust_defaults { - name: "futures-util_defaults", +rust_test { + name: "futures-util_test_src_lib", + host_supported: true, crate_name: "futures_util", + cargo_env_compat: true, + cargo_pkg_version: "0.3.21", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, + test_options: { + unit_test: true, + }, edition: "2018", features: [ "alloc", @@ -56,8 +62,6 @@ rust_defaults { "futures-sink", "io", "memchr", - "proc-macro-hack", - "proc-macro-nested", "sink", "slab", "std", @@ -71,33 +75,18 @@ rust_defaults { "libmemchr", "libpin_project_lite", "libpin_utils", - "libproc_macro_nested", "libslab", "libtokio", ], - proc_macros: [ - "libfutures_macro", - "libproc_macro_hack", - ], -} - -rust_test_host { - name: "futures-util_host_test_src_lib", - defaults: ["futures-util_defaults"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "futures-util_device_test_src_lib", - defaults: ["futures-util_defaults"], + proc_macros: ["libfutures_macro"], } rust_library { name: "libfutures_util", host_supported: true, crate_name: "futures_util", + cargo_env_compat: true, + cargo_pkg_version: "0.3.21", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -112,8 +101,6 @@ rust_library { "futures-sink", "io", "memchr", - "proc-macro-hack", - "proc-macro-nested", "sink", "slab", "std", @@ -127,77 +114,14 @@ rust_library { "libmemchr", "libpin_project_lite", "libpin_utils", - "libproc_macro_nested", "libslab", ], - proc_macros: [ - "libfutures_macro", - "libproc_macro_hack", - ], + proc_macros: ["libfutures_macro"], apex_available: [ "//apex_available:platform", + "com.android.bluetooth", "com.android.resolv", "com.android.virt", ], min_sdk_version: "29", } - -// dependent_library ["feature_list"] -// autocfg-1.0.1 -// byteorder-1.4.3 "default,std" -// bytes-0.4.12 -// cfg-if-0.1.10 -// cfg-if-1.0.0 -// crossbeam-deque-0.7.3 -// crossbeam-epoch-0.8.2 "default,lazy_static,std" -// crossbeam-queue-0.2.3 "default,std" -// crossbeam-utils-0.7.2 "default,lazy_static,std" -// fnv-1.0.7 "default,std" -// futures-0.1.31 "default,use_std,with-deprecated" -// futures-channel-0.3.14 "alloc,std" -// futures-core-0.3.14 "alloc,std" -// futures-io-0.3.14 "std" -// futures-macro-0.3.13 -// futures-sink-0.3.14 -// futures-task-0.3.14 "alloc,std" -// iovec-0.1.4 -// lazy_static-1.4.0 -// libc-0.2.94 "default,std" -// lock_api-0.3.4 -// log-0.4.14 -// maybe-uninit-2.0.0 -// memchr-2.3.4 "default,std" -// memoffset-0.5.6 "default" -// mio-0.6.23 "default,with-deprecated" -// mio-uds-0.6.8 -// net2-0.2.37 "default,duration" -// num_cpus-1.13.0 -// parking_lot-0.9.0 "default" -// parking_lot_core-0.6.2 -// pin-project-lite-0.2.6 -// pin-utils-0.1.0 -// proc-macro-hack-0.5.19 -// proc-macro-nested-0.1.7 -// proc-macro2-1.0.26 "default,proc-macro" -// quote-1.0.9 "default,proc-macro" -// rustc_version-0.2.3 -// scopeguard-1.1.0 -// semver-0.9.0 "default" -// semver-parser-0.7.0 -// slab-0.4.3 "default,std" -// smallvec-0.6.14 "default,std" -// syn-1.0.70 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote" -// tokio-0.1.22 "bytes,codec,default,fs,io,mio,num_cpus,reactor,rt-full,sync,tcp,timer,tokio-codec,tokio-current-thread,tokio-executor,tokio-fs,tokio-io,tokio-reactor,tokio-sync,tokio-tcp,tokio-threadpool,tokio-timer,tokio-udp,tokio-uds,udp,uds" -// tokio-codec-0.1.2 -// tokio-current-thread-0.1.7 -// tokio-executor-0.1.10 -// tokio-fs-0.1.7 -// tokio-io-0.1.13 -// tokio-reactor-0.1.12 -// tokio-sync-0.1.8 -// tokio-tcp-0.1.4 -// tokio-threadpool-0.1.18 -// tokio-timer-0.2.13 -// tokio-udp-0.1.6 -// tokio-uds-0.2.7 -// unicode-xid-0.2.1 "default" @@ -3,54 +3,59 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" +rust-version = "1.45" name = "futures-util" -version = "0.3.13" -authors = ["Alex Crichton <alex@alexcrichton.com>"] -description = "Common utilities and extension traits for the futures-rs library.\n" +version = "0.3.21" +description = """ +Common utilities and extension traits for the futures-rs library. +""" homepage = "https://rust-lang.github.io/futures-rs" -documentation = "https://docs.rs/futures-util/0.3" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" + [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] +rustdoc-args = [ + "--cfg", + "docsrs", +] + [dependencies.futures-channel] -version = "0.3.13" +version = "0.3.21" features = ["std"] optional = true default-features = false [dependencies.futures-core] -version = "0.3.13" +version = "0.3.21" default-features = false [dependencies.futures-io] -version = "0.3.13" +version = "0.3.21" features = ["std"] optional = true default-features = false [dependencies.futures-macro] -version = "=0.3.13" +version = "=0.3.21" optional = true default-features = false [dependencies.futures-sink] -version = "0.3.13" +version = "0.3.21" optional = true default-features = false [dependencies.futures-task] -version = "0.3.13" +version = "0.3.21" default-features = false [dependencies.futures_01] @@ -68,14 +73,6 @@ version = "0.2.4" [dependencies.pin-utils] version = "0.1.0" -[dependencies.proc-macro-hack] -version = "0.5.19" -optional = true - -[dependencies.proc-macro-nested] -version = "0.1.2" -optional = true - [dependencies.slab] version = "0.4.2" optional = true @@ -83,22 +80,54 @@ optional = true [dependencies.tokio-io] version = "0.1.9" optional = true + [dev-dependencies.tokio] version = "0.1.11" [features] -alloc = ["futures-core/alloc", "futures-task/alloc"] +alloc = [ + "futures-core/alloc", + "futures-task/alloc", +] async-await = [] -async-await-macro = ["async-await", "futures-macro", "proc-macro-hack", "proc-macro-nested"] +async-await-macro = [ + "async-await", + "futures-macro", +] bilock = [] -cfg-target-has-atomic = ["futures-core/cfg-target-has-atomic", "futures-task/cfg-target-has-atomic"] -channel = ["std", "futures-channel"] -compat = ["std", "futures_01"] -default = ["std", "async-await", "async-await-macro"] -io = ["std", "futures-io", "memchr"] -io-compat = ["io", "compat", "tokio-io"] -read-initializer = ["io", "futures-io/read-initializer", "futures-io/unstable"] +cfg-target-has-atomic = [] +channel = [ + "std", + "futures-channel", +] +compat = [ + "std", + "futures_01", +] +default = [ + "std", + "async-await", + "async-await-macro", +] +io = [ + "std", + "futures-io", + "memchr", +] +io-compat = [ + "io", + "compat", + "tokio-io", +] sink = ["futures-sink"] -std = ["alloc", "futures-core/std", "futures-task/std", "slab"] -unstable = ["futures-core/unstable", "futures-task/unstable"] +std = [ + "alloc", + "futures-core/std", + "futures-task/std", + "slab", +] +unstable = [ + "futures-core/unstable", + "futures-task/unstable", +] write-all-vectored = ["io"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index b7cc193..46ec854 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,12 +1,11 @@ [package] name = "futures-util" +version = "0.3.21" edition = "2018" -version = "0.3.13" -authors = ["Alex Crichton <alex@alexcrichton.com>"] +rust-version = "1.45" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" -documentation = "https://docs.rs/futures-util/0.3" description = """ Common utilities and extension traits for the futures-rs library. """ @@ -16,7 +15,7 @@ default = ["std", "async-await", "async-await-macro"] std = ["alloc", "futures-core/std", "futures-task/std", "slab"] alloc = ["futures-core/alloc", "futures-task/alloc"] async-await = [] -async-await-macro = ["async-await", "futures-macro", "proc-macro-hack", "proc-macro-nested"] +async-await-macro = ["async-await", "futures-macro"] compat = ["std", "futures_01"] io-compat = ["io", "compat", "tokio-io"] sink = ["futures-sink"] @@ -27,20 +26,20 @@ channel = ["std", "futures-channel"] # These features are outside of the normal semver guarantees and require the # `unstable` feature as an explicit opt-in to unstable API. unstable = ["futures-core/unstable", "futures-task/unstable"] -cfg-target-has-atomic = ["futures-core/cfg-target-has-atomic", "futures-task/cfg-target-has-atomic"] bilock = [] -read-initializer = ["io", "futures-io/read-initializer", "futures-io/unstable"] write-all-vectored = ["io"] +# These features are no longer used. +# TODO: remove in the next major version. +cfg-target-has-atomic = [] + [dependencies] -futures-core = { path = "../futures-core", version = "0.3.13", default-features = false } -futures-task = { path = "../futures-task", version = "0.3.13", default-features = false } -futures-channel = { path = "../futures-channel", version = "0.3.13", default-features = false, features = ["std"], optional = true } -futures-io = { path = "../futures-io", version = "0.3.13", default-features = false, features = ["std"], optional = true } -futures-sink = { path = "../futures-sink", version = "0.3.13", default-features = false, optional = true } -futures-macro = { path = "../futures-macro", version = "=0.3.13", default-features = false, optional = true } -proc-macro-hack = { version = "0.5.19", optional = true } -proc-macro-nested = { version = "0.1.2", optional = true } +futures-core = { path = "../futures-core", version = "0.3.21", default-features = false } +futures-task = { path = "../futures-task", version = "0.3.21", default-features = false } +futures-channel = { path = "../futures-channel", version = "0.3.21", default-features = false, features = ["std"], optional = true } +futures-io = { path = "../futures-io", version = "0.3.21", default-features = false, features = ["std"], optional = true } +futures-sink = { path = "../futures-sink", version = "0.3.21", default-features = false, optional = true } +futures-macro = { path = "../futures-macro", version = "=0.3.21", default-features = false, optional = true } slab = { version = "0.4.2", optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/futures-util/futures-util-0.3.13.crate" + value: "https://static.crates.io/crates/futures-util/futures-util-0.3.21.crate" } - version: "0.3.13" + version: "0.3.21" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 4 + year: 2022 + month: 3 day: 1 } } diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e0aaed --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# futures-util + +Common utilities and extension traits for the futures-rs library. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +futures-util = "0.3" +``` + +The current `futures-util` requires Rust 1.45 or later. + +## License + +Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or +[MIT license](LICENSE-MIT) at your option. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/TEST_MAPPING b/TEST_MAPPING index 203632d..1c27227 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,56 +1,48 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { - "presubmit": [ - { - "name": "anyhow_device_test_tests_test_boxed" - }, - { - "name": "anyhow_device_test_tests_test_ffi" - }, - { - "name": "futures-util_device_test_src_lib" - }, + "imports": [ { - "name": "anyhow_device_test_tests_test_chain" + "path": "external/rust/crates/anyhow" }, { - "name": "anyhow_device_test_tests_test_convert" + "path": "external/rust/crates/tokio" }, { - "name": "anyhow_device_test_tests_test_source" - }, - { - "name": "tokio-test_device_test_tests_io" - }, + "path": "external/rust/crates/tokio-test" + } + ], + "presubmit": [ { - "name": "tokio-test_device_test_tests_macros" + "name": "ZipFuseTest" }, { - "name": "anyhow_device_test_tests_test_context" + "name": "authfs_device_test_src_lib" }, { - "name": "anyhow_device_test_tests_test_autotrait" + "name": "doh_unit_test" }, { - "name": "tokio-test_device_test_src_lib" + "name": "futures-util_test_src_lib" }, { - "name": "anyhow_device_test_tests_test_macros" - }, + "name": "virtualizationservice_device_test" + } + ], + "presubmit-rust": [ { - "name": "anyhow_device_test_src_lib" + "name": "ZipFuseTest" }, { - "name": "tokio-test_device_test_tests_block_on" + "name": "authfs_device_test_src_lib" }, { - "name": "anyhow_device_test_tests_test_fmt" + "name": "doh_unit_test" }, { - "name": "anyhow_device_test_tests_test_downcast" + "name": "futures-util_test_src_lib" }, { - "name": "anyhow_device_test_tests_test_repr" + "name": "virtualizationservice_device_test" } ] } diff --git a/benches/flatten_unordered.rs b/benches/flatten_unordered.rs new file mode 100644 index 0000000..64d5f9a --- /dev/null +++ b/benches/flatten_unordered.rs @@ -0,0 +1,66 @@ +#![feature(test)] + +extern crate test; +use crate::test::Bencher; + +use futures::channel::oneshot; +use futures::executor::block_on; +use futures::future::{self, FutureExt}; +use futures::stream::{self, StreamExt}; +use futures::task::Poll; +use std::collections::VecDeque; +use std::thread; + +#[bench] +fn oneshot_streams(b: &mut Bencher) { + const STREAM_COUNT: usize = 10_000; + const STREAM_ITEM_COUNT: usize = 1; + + b.iter(|| { + let mut txs = VecDeque::with_capacity(STREAM_COUNT); + let mut rxs = Vec::new(); + + for _ in 0..STREAM_COUNT { + let (tx, rx) = oneshot::channel(); + txs.push_back(tx); + rxs.push(rx); + } + + thread::spawn(move || { + let mut last = 1; + while let Some(tx) = txs.pop_front() { + let _ = tx.send(stream::iter(last..last + STREAM_ITEM_COUNT)); + last += STREAM_ITEM_COUNT; + } + }); + + let mut flatten = stream::unfold(rxs.into_iter(), |mut vals| { + async { + if let Some(next) = vals.next() { + let val = next.await.unwrap(); + Some((val, vals)) + } else { + None + } + } + .boxed() + }) + .flatten_unordered(None); + + block_on(future::poll_fn(move |cx| { + let mut count = 0; + loop { + match flatten.poll_next_unpin(cx) { + Poll::Ready(None) => break, + Poll::Ready(Some(_)) => { + count += 1; + } + _ => {} + } + } + assert_eq!(count, STREAM_COUNT * STREAM_ITEM_COUNT); + + Poll::Ready(()) + })) + }); +} diff --git a/benches/futures_unordered.rs b/benches/futures_unordered.rs index 05e9ead..d5fe7a5 100644 --- a/benches/futures_unordered.rs +++ b/benches/futures_unordered.rs @@ -6,7 +6,7 @@ use crate::test::Bencher; use futures::channel::oneshot; use futures::executor::block_on; use futures::future; -use futures::stream::{StreamExt, FuturesUnordered}; +use futures::stream::{FuturesUnordered, StreamExt}; use futures::task::Poll; use std::collections::VecDeque; use std::thread; @@ -34,7 +34,7 @@ fn oneshots(b: &mut Bencher) { block_on(future::poll_fn(move |cx| { loop { if let Poll::Ready(None) = rxs.poll_next_unpin(cx) { - break + break; } } Poll::Ready(()) diff --git a/benches_disabled/bilock.rs b/benches_disabled/bilock.rs index 48afe3c..417f75d 100644 --- a/benches_disabled/bilock.rs +++ b/benches_disabled/bilock.rs @@ -2,125 +2,121 @@ #[cfg(feature = "bilock")] mod bench { -use futures::task::{Context, Waker}; -use futures::executor::LocalPool; -use futures_util::lock::BiLock; -use futures_util::lock::BiLockAcquire; -use futures_util::lock::BiLockAcquired; -use futures_util::task::ArcWake; + use futures::executor::LocalPool; + use futures::task::{Context, Waker}; + use futures_util::lock::BiLock; + use futures_util::lock::BiLockAcquire; + use futures_util::lock::BiLockAcquired; + use futures_util::task::ArcWake; -use std::sync::Arc; -use test::Bencher; + use std::sync::Arc; + use test::Bencher; -fn notify_noop() -> Waker { - struct Noop; + fn notify_noop() -> Waker { + struct Noop; - impl ArcWake for Noop { - fn wake(_: &Arc<Self>) {} - } - - ArcWake::into_waker(Arc::new(Noop)) -} - - -/// Pseudo-stream which simply calls `lock.poll()` on `poll` -struct LockStream { - lock: BiLockAcquire<u32>, -} - -impl LockStream { - fn new(lock: BiLock<u32>) -> Self { - Self { - lock: lock.lock() + impl ArcWake for Noop { + fn wake(_: &Arc<Self>) {} } - } - /// Release a lock after it was acquired in `poll`, - /// so `poll` could be called again. - fn release_lock(&mut self, guard: BiLockAcquired<u32>) { - self.lock = guard.unlock().lock() + ArcWake::into_waker(Arc::new(Noop)) } -} - -impl Stream for LockStream { - type Item = BiLockAcquired<u32>; - type Error = (); - fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>, Self::Error> { - self.lock.poll(cx).map(|a| a.map(Some)) + /// Pseudo-stream which simply calls `lock.poll()` on `poll` + struct LockStream { + lock: BiLockAcquire<u32>, } -} - - -#[bench] -fn contended(b: &mut Bencher) { - let pool = LocalPool::new(); - let mut exec = pool.executor(); - let waker = notify_noop(); - let mut map = task::LocalMap::new(); - let mut waker = task::Context::new(&mut map, &waker, &mut exec); - - b.iter(|| { - let (x, y) = BiLock::new(1); - - let mut x = LockStream::new(x); - let mut y = LockStream::new(y); - for _ in 0..1000 { - let x_guard = match x.poll_next(&mut waker) { - Ok(Poll::Ready(Some(guard))) => guard, - _ => panic!(), - }; - - // Try poll second lock while first lock still holds the lock - match y.poll_next(&mut waker) { - Ok(Poll::Pending) => (), - _ => panic!(), - }; - - x.release_lock(x_guard); - - let y_guard = match y.poll_next(&mut waker) { - Ok(Poll::Ready(Some(guard))) => guard, - _ => panic!(), - }; - - y.release_lock(y_guard); + impl LockStream { + fn new(lock: BiLock<u32>) -> Self { + Self { lock: lock.lock() } } - (x, y) - }); -} - -#[bench] -fn lock_unlock(b: &mut Bencher) { - let pool = LocalPool::new(); - let mut exec = pool.executor(); - let waker = notify_noop(); - let mut map = task::LocalMap::new(); - let mut waker = task::Context::new(&mut map, &waker, &mut exec); - b.iter(|| { - let (x, y) = BiLock::new(1); - - let mut x = LockStream::new(x); - let mut y = LockStream::new(y); + /// Release a lock after it was acquired in `poll`, + /// so `poll` could be called again. + fn release_lock(&mut self, guard: BiLockAcquired<u32>) { + self.lock = guard.unlock().lock() + } + } - for _ in 0..1000 { - let x_guard = match x.poll_next(&mut waker) { - Ok(Poll::Ready(Some(guard))) => guard, - _ => panic!(), - }; + impl Stream for LockStream { + type Item = BiLockAcquired<u32>; + type Error = (); - x.release_lock(x_guard); + fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>, Self::Error> { + self.lock.poll(cx).map(|a| a.map(Some)) + } + } - let y_guard = match y.poll_next(&mut waker) { - Ok(Poll::Ready(Some(guard))) => guard, - _ => panic!(), - }; + #[bench] + fn contended(b: &mut Bencher) { + let pool = LocalPool::new(); + let mut exec = pool.executor(); + let waker = notify_noop(); + let mut map = task::LocalMap::new(); + let mut waker = task::Context::new(&mut map, &waker, &mut exec); + + b.iter(|| { + let (x, y) = BiLock::new(1); + + let mut x = LockStream::new(x); + let mut y = LockStream::new(y); + + for _ in 0..1000 { + let x_guard = match x.poll_next(&mut waker) { + Ok(Poll::Ready(Some(guard))) => guard, + _ => panic!(), + }; + + // Try poll second lock while first lock still holds the lock + match y.poll_next(&mut waker) { + Ok(Poll::Pending) => (), + _ => panic!(), + }; + + x.release_lock(x_guard); + + let y_guard = match y.poll_next(&mut waker) { + Ok(Poll::Ready(Some(guard))) => guard, + _ => panic!(), + }; + + y.release_lock(y_guard); + } + (x, y) + }); + } - y.release_lock(y_guard); - } - (x, y) - }) -} + #[bench] + fn lock_unlock(b: &mut Bencher) { + let pool = LocalPool::new(); + let mut exec = pool.executor(); + let waker = notify_noop(); + let mut map = task::LocalMap::new(); + let mut waker = task::Context::new(&mut map, &waker, &mut exec); + + b.iter(|| { + let (x, y) = BiLock::new(1); + + let mut x = LockStream::new(x); + let mut y = LockStream::new(y); + + for _ in 0..1000 { + let x_guard = match x.poll_next(&mut waker) { + Ok(Poll::Ready(Some(guard))) => guard, + _ => panic!(), + }; + + x.release_lock(x_guard); + + let y_guard = match y.poll_next(&mut waker) { + Ok(Poll::Ready(Some(guard))) => guard, + _ => panic!(), + }; + + y.release_lock(y_guard); + } + (x, y) + }) + } } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..05e0496 --- /dev/null +++ b/build.rs @@ -0,0 +1,41 @@ +// The rustc-cfg listed below are considered public API, but it is *unstable* +// and outside of the normal semver guarantees: +// +// - `futures_no_atomic_cas` +// Assume the target does *not* support atomic CAS operations. +// This is usually detected automatically by the build script, but you may +// need to enable it manually when building for custom targets or using +// non-cargo build systems that don't run the build script. +// +// With the exceptions mentioned above, the rustc-cfg emitted by the build +// script are *not* public API. + +#![warn(rust_2018_idioms, single_use_lifetimes)] + +use std::env; + +include!("no_atomic_cas.rs"); + +fn main() { + let target = match env::var("TARGET") { + Ok(target) => target, + Err(e) => { + println!( + "cargo:warning={}: unable to get TARGET environment variable: {}", + env!("CARGO_PKG_NAME"), + e + ); + return; + } + }; + + // Note that this is `no_*`, not `has_*`. This allows treating + // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't + // run. This is needed for compatibility with non-cargo build systems that + // don't run the build script. + if NO_ATOMIC_CAS.contains(&&*target) { + println!("cargo:rustc-cfg=futures_no_atomic_cas"); + } + + println!("cargo:rerun-if-changed=no_atomic_cas.rs"); +} diff --git a/cargo2android.json b/cargo2android.json index 8bef0a5..4e11868 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,13 +1,14 @@ { "apex-available": [ "//apex_available:platform", + "com.android.bluetooth", "com.android.resolv", "com.android.virt" ], - "min_sdk_version": "29", "dependencies": true, "device": true, "features": "channel,default,io,memchr,sink", + "min-sdk-version": "29", "run": true, "tests": true -}
\ No newline at end of file +} diff --git a/no_atomic_cas.rs b/no_atomic_cas.rs new file mode 100644 index 0000000..9b05d4b --- /dev/null +++ b/no_atomic_cas.rs @@ -0,0 +1,13 @@ +// This file is @generated by no_atomic_cas.sh. +// It is not intended for manual editing. + +const NO_ATOMIC_CAS: &[&str] = &[ + "avr-unknown-gnu-atmega328", + "bpfeb-unknown-none", + "bpfel-unknown-none", + "msp430-none-elf", + "riscv32i-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "thumbv4t-none-eabi", + "thumbv6m-none-eabi", +]; diff --git a/src/abortable.rs b/src/abortable.rs new file mode 100644 index 0000000..bb82dd0 --- /dev/null +++ b/src/abortable.rs @@ -0,0 +1,185 @@ +use crate::task::AtomicWaker; +use alloc::sync::Arc; +use core::fmt; +use core::pin::Pin; +use core::sync::atomic::{AtomicBool, Ordering}; +use futures_core::future::Future; +use futures_core::task::{Context, Poll}; +use futures_core::Stream; +use pin_project_lite::pin_project; + +pin_project! { + /// A future/stream which can be remotely short-circuited using an `AbortHandle`. + #[derive(Debug, Clone)] + #[must_use = "futures/streams do nothing unless you poll them"] + pub struct Abortable<T> { + #[pin] + task: T, + inner: Arc<AbortInner>, + } +} + +impl<T> Abortable<T> { + /// Creates a new `Abortable` future/stream using an existing `AbortRegistration`. + /// `AbortRegistration`s can be acquired through `AbortHandle::new`. + /// + /// When `abort` is called on the handle tied to `reg` or if `abort` has + /// already been called, the future/stream will complete immediately without making + /// any further progress. + /// + /// # Examples: + /// + /// Usage with futures: + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::future::{Abortable, AbortHandle, Aborted}; + /// + /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); + /// let future = Abortable::new(async { 2 }, abort_registration); + /// abort_handle.abort(); + /// assert_eq!(future.await, Err(Aborted)); + /// # }); + /// ``` + /// + /// Usage with streams: + /// + /// ``` + /// # futures::executor::block_on(async { + /// # use futures::future::{Abortable, AbortHandle}; + /// # use futures::stream::{self, StreamExt}; + /// + /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); + /// let mut stream = Abortable::new(stream::iter(vec![1, 2, 3]), abort_registration); + /// abort_handle.abort(); + /// assert_eq!(stream.next().await, None); + /// # }); + /// ``` + pub fn new(task: T, reg: AbortRegistration) -> Self { + Self { task, inner: reg.inner } + } + + /// Checks whether the task has been aborted. Note that all this + /// method indicates is whether [`AbortHandle::abort`] was *called*. + /// This means that it will return `true` even if: + /// * `abort` was called after the task had completed. + /// * `abort` was called while the task was being polled - the task may still be running and + /// will not be stopped until `poll` returns. + pub fn is_aborted(&self) -> bool { + self.inner.aborted.load(Ordering::Relaxed) + } +} + +/// A registration handle for an `Abortable` task. +/// Values of this type can be acquired from `AbortHandle::new` and are used +/// in calls to `Abortable::new`. +#[derive(Debug)] +pub struct AbortRegistration { + inner: Arc<AbortInner>, +} + +/// A handle to an `Abortable` task. +#[derive(Debug, Clone)] +pub struct AbortHandle { + inner: Arc<AbortInner>, +} + +impl AbortHandle { + /// Creates an (`AbortHandle`, `AbortRegistration`) pair which can be used + /// to abort a running future or stream. + /// + /// This function is usually paired with a call to [`Abortable::new`]. + pub fn new_pair() -> (Self, AbortRegistration) { + let inner = + Arc::new(AbortInner { waker: AtomicWaker::new(), aborted: AtomicBool::new(false) }); + + (Self { inner: inner.clone() }, AbortRegistration { inner }) + } +} + +// Inner type storing the waker to awaken and a bool indicating that it +// should be aborted. +#[derive(Debug)] +struct AbortInner { + waker: AtomicWaker, + aborted: AtomicBool, +} + +/// Indicator that the `Abortable` task was aborted. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Aborted; + +impl fmt::Display for Aborted { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "`Abortable` future has been aborted") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Aborted {} + +impl<T> Abortable<T> { + fn try_poll<I>( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + poll: impl Fn(Pin<&mut T>, &mut Context<'_>) -> Poll<I>, + ) -> Poll<Result<I, Aborted>> { + // Check if the task has been aborted + if self.is_aborted() { + return Poll::Ready(Err(Aborted)); + } + + // attempt to complete the task + if let Poll::Ready(x) = poll(self.as_mut().project().task, cx) { + return Poll::Ready(Ok(x)); + } + + // Register to receive a wakeup if the task is aborted in the future + self.inner.waker.register(cx.waker()); + + // Check to see if the task was aborted between the first check and + // registration. + // Checking with `is_aborted` which uses `Relaxed` is sufficient because + // `register` introduces an `AcqRel` barrier. + if self.is_aborted() { + return Poll::Ready(Err(Aborted)); + } + + Poll::Pending + } +} + +impl<Fut> Future for Abortable<Fut> +where + Fut: Future, +{ + type Output = Result<Fut::Output, Aborted>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.try_poll(cx, |fut, cx| fut.poll(cx)) + } +} + +impl<St> Stream for Abortable<St> +where + St: Stream, +{ + type Item = St::Item; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + self.try_poll(cx, |stream, cx| stream.poll_next(cx)).map(Result::ok).map(Option::flatten) + } +} + +impl AbortHandle { + /// Abort the `Abortable` stream/future associated with this handle. + /// + /// Notifies the Abortable task associated with this handle that it + /// should abort. Note that if the task is currently being polled on + /// another thread, it will not immediately stop running. Instead, it will + /// continue to run until its poll method returns. + pub fn abort(&self) { + self.inner.aborted.store(true, Ordering::Relaxed); + self.inner.waker.wake(); + } +} diff --git a/src/async_await/join_mod.rs b/src/async_await/join_mod.rs index 965d9fb..28f3b23 100644 --- a/src/async_await/join_mod.rs +++ b/src/async_await/join_mod.rs @@ -1,7 +1,5 @@ //! The `join` macro. -use proc_macro_hack::proc_macro_hack; - macro_rules! document_join_macro { ($join:item $try_join:item) => { /// Polls multiple futures simultaneously, returning a tuple @@ -81,12 +79,12 @@ macro_rules! document_join_macro { } } +#[allow(unreachable_pub)] #[doc(hidden)] -#[proc_macro_hack(support_nested, only_hack_old_rustc)] pub use futures_macro::join_internal; +#[allow(unreachable_pub)] #[doc(hidden)] -#[proc_macro_hack(support_nested, only_hack_old_rustc)] pub use futures_macro::try_join_internal; document_join_macro! { diff --git a/src/async_await/mod.rs b/src/async_await/mod.rs index bdaed95..7276da2 100644 --- a/src/async_await/mod.rs +++ b/src/async_await/mod.rs @@ -3,8 +3,8 @@ //! This module contains a number of functions and combinators for working //! with `async`/`await` code. -use futures_core::future::{Future, FusedFuture}; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::future::{FusedFuture, Future}; +use futures_core::stream::{FusedStream, Stream}; #[macro_use] mod poll; @@ -30,6 +30,13 @@ mod select_mod; #[cfg(feature = "async-await-macro")] pub use self::select_mod::*; +// Primary export is a macro +#[cfg(feature = "async-await-macro")] +mod stream_select_mod; +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/64762 +#[cfg(feature = "async-await-macro")] +pub use self::stream_select_mod::*; + #[cfg(feature = "std")] #[cfg(feature = "async-await-macro")] mod random; diff --git a/src/async_await/pending.rs b/src/async_await/pending.rs index e0cf341..5d7a431 100644 --- a/src/async_await/pending.rs +++ b/src/async_await/pending.rs @@ -16,7 +16,7 @@ use futures_core::task::{Context, Poll}; macro_rules! pending { () => { $crate::__private::async_await::pending_once().await - } + }; } #[doc(hidden)] diff --git a/src/async_await/poll.rs b/src/async_await/poll.rs index b5782df..b62f45a 100644 --- a/src/async_await/poll.rs +++ b/src/async_await/poll.rs @@ -17,7 +17,7 @@ use futures_core::task::{Context, Poll}; macro_rules! poll { ($x:expr $(,)?) => { $crate::__private::async_await::poll($x).await - } + }; } #[doc(hidden)] diff --git a/src/async_await/select_mod.rs b/src/async_await/select_mod.rs index 59bca08..1d13067 100644 --- a/src/async_await/select_mod.rs +++ b/src/async_await/select_mod.rs @@ -1,7 +1,5 @@ //! The `select` macro. -use proc_macro_hack::proc_macro_hack; - macro_rules! document_select_macro { // This branch is required for `futures 0.3.1`, from before select_biased was introduced ($select:item) => { @@ -31,9 +29,6 @@ macro_rules! document_select_macro { /// It is also gated behind the `async-await` feature of this library, which is /// activated by default. /// - /// Note that `select!` relies on `proc-macro-hack`, and may require to set the - /// compiler's recursion limit very high, e.g. `#![recursion_limit="1024"]`. - /// /// # Examples /// /// ``` @@ -309,12 +304,12 @@ macro_rules! document_select_macro { } #[cfg(feature = "std")] +#[allow(unreachable_pub)] #[doc(hidden)] -#[proc_macro_hack(support_nested, only_hack_old_rustc)] pub use futures_macro::select_internal; +#[allow(unreachable_pub)] #[doc(hidden)] -#[proc_macro_hack(support_nested, only_hack_old_rustc)] pub use futures_macro::select_biased_internal; document_select_macro! { diff --git a/src/async_await/stream_select_mod.rs b/src/async_await/stream_select_mod.rs new file mode 100644 index 0000000..1c8002f --- /dev/null +++ b/src/async_await/stream_select_mod.rs @@ -0,0 +1,40 @@ +//! The `stream_select` macro. + +#[cfg(feature = "std")] +#[allow(unreachable_pub)] +#[doc(hidden)] +pub use futures_macro::stream_select_internal; + +/// Combines several streams, all producing the same `Item` type, into one stream. +/// This is similar to `select_all` but does not require the streams to all be the same type. +/// It also keeps the streams inline, and does not require `Box<dyn Stream>`s to be allocated. +/// Streams passed to this macro must be `Unpin`. +/// +/// If multiple streams are ready, one will be pseudo randomly selected at runtime. +/// +/// # Examples +/// +/// ``` +/// # futures::executor::block_on(async { +/// use futures::{stream, StreamExt, stream_select}; +/// let endless_ints = |i| stream::iter(vec![i].into_iter().cycle()).fuse(); +/// +/// let mut endless_numbers = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3)); +/// match endless_numbers.next().await { +/// Some(1) => println!("Got a 1"), +/// Some(2) => println!("Got a 2"), +/// Some(3) => println!("Got a 3"), +/// _ => unreachable!(), +/// } +/// # }); +/// ``` +#[cfg(feature = "std")] +#[macro_export] +macro_rules! stream_select { + ($($tokens:tt)*) => {{ + use $crate::__private as __futures_crate; + $crate::stream_select_internal! { + $( $tokens )* + } + }} +} diff --git a/src/compat/compat01as03.rs b/src/compat/compat01as03.rs index bc3aee3..36de1da 100644 --- a/src/compat/compat01as03.rs +++ b/src/compat/compat01as03.rs @@ -1,18 +1,15 @@ use futures_01::executor::{ - spawn as spawn01, Notify as Notify01, NotifyHandle as NotifyHandle01, - Spawn as Spawn01, UnsafeNotify as UnsafeNotify01, -}; -use futures_01::{ - Async as Async01, Future as Future01, - Stream as Stream01, + spawn as spawn01, Notify as Notify01, NotifyHandle as NotifyHandle01, Spawn as Spawn01, + UnsafeNotify as UnsafeNotify01, }; +use futures_01::{Async as Async01, Future as Future01, Stream as Stream01}; #[cfg(feature = "sink")] use futures_01::{AsyncSink as AsyncSink01, Sink as Sink01}; -use futures_core::{task as task03, future::Future as Future03, stream::Stream as Stream03}; -use std::pin::Pin; -use std::task::Context; +use futures_core::{future::Future as Future03, stream::Stream as Stream03, task as task03}; #[cfg(feature = "sink")] use futures_sink::Sink as Sink03; +use std::pin::Pin; +use std::task::Context; #[cfg(feature = "io-compat")] #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] @@ -33,9 +30,7 @@ impl<T> Compat01As03<T> { /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite /// object in a futures 0.3-compatible wrapper. pub fn new(object: T) -> Self { - Self { - inner: spawn01(object), - } + Self { inner: spawn01(object) } } fn in_notify<R>(&mut self, cx: &mut Context<'_>, f: impl FnOnce(&mut T) -> R) -> R { @@ -69,6 +64,7 @@ pub trait Future01CompatExt: Future01 { /// [`Future<Output = Result<T, E>>`](futures_core::future::Future). /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 /// # futures::executor::block_on(async { /// # // TODO: These should be all using `futures::compat`, but that runs up against Cargo /// # // feature issues @@ -95,6 +91,7 @@ pub trait Stream01CompatExt: Stream01 { /// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream). /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 /// # futures::executor::block_on(async { /// use futures::stream::StreamExt; /// use futures_util::compat::Stream01CompatExt; @@ -124,6 +121,7 @@ pub trait Sink01CompatExt: Sink01 { /// [`Sink<T, Error = E>`](futures_sink::Sink). /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 /// # futures::executor::block_on(async { /// use futures::{sink::SinkExt, stream::StreamExt}; /// use futures_util::compat::{Stream01CompatExt, Sink01CompatExt}; @@ -157,10 +155,7 @@ fn poll_01_to_03<T, E>(x: Result<Async01<T>, E>) -> task03::Poll<Result<T, E>> { impl<Fut: Future01> Future03 for Compat01As03<Fut> { type Output = Result<Fut::Item, Fut::Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> task03::Poll<Self::Output> { poll_01_to_03(self.in_notify(cx, Future01::poll)) } } @@ -198,18 +193,10 @@ impl<S, SinkItem> Unpin for Compat01As03Sink<S, SinkItem> {} impl<S, SinkItem> Compat01As03Sink<S, SinkItem> { /// Wraps a futures 0.1 Sink object in a futures 0.3-compatible wrapper. pub fn new(inner: S) -> Self { - Self { - inner: spawn01(inner), - buffer: None, - close_started: false - } + Self { inner: spawn01(inner), buffer: None, close_started: false } } - fn in_notify<R>( - &mut self, - cx: &mut Context<'_>, - f: impl FnOnce(&mut S) -> R, - ) -> R { + fn in_notify<R>(&mut self, cx: &mut Context<'_>, f: impl FnOnce(&mut S) -> R) -> R { let notify = &WakerToHandle(cx.waker()); self.inner.poll_fn_notify(notify, 0, f) } @@ -256,10 +243,7 @@ where { type Error = S::SinkError; - fn start_send( - mut self: Pin<&mut Self>, - item: SinkItem, - ) -> Result<(), Self::Error> { + fn start_send(mut self: Pin<&mut Self>, item: SinkItem) -> Result<(), Self::Error> { debug_assert!(self.buffer.is_none()); self.buffer = Some(item); Ok(()) @@ -289,9 +273,7 @@ where match self.in_notify(cx, |f| match item { Some(i) => match f.start_send(i)? { AsyncSink01::Ready => f.poll_complete().map(|i| (i, None)), - AsyncSink01::NotReady(t) => { - Ok((Async01::NotReady, Some(t))) - } + AsyncSink01::NotReady(t) => Ok((Async01::NotReady, Some(t))), }, None => f.poll_complete().map(|i| (i, None)), })? { @@ -372,8 +354,6 @@ unsafe impl UnsafeNotify01 for NotifyWaker { #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] mod io { use super::*; - #[cfg(feature = "read-initializer")] - use futures_io::Initializer; use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03}; use std::io::Error; use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01}; @@ -385,6 +365,7 @@ mod io { /// [`AsyncRead`](futures_io::AsyncRead). /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 /// # futures::executor::block_on(async { /// use futures::io::AsyncReadExt; /// use futures_util::compat::AsyncRead01CompatExt; @@ -414,6 +395,7 @@ mod io { /// [`AsyncWrite`](futures_io::AsyncWrite). /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 /// # futures::executor::block_on(async { /// use futures::io::AsyncWriteExt; /// use futures_util::compat::AsyncWrite01CompatExt; @@ -437,39 +419,35 @@ mod io { impl<W: AsyncWrite01> AsyncWrite01CompatExt for W {} impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> { - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - // check if `prepare_uninitialized_buffer` needs zeroing - if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) { - Initializer::zeroing() - } else { - Initializer::nop() - } - } - - fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) - -> task03::Poll<Result<usize, Error>> - { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut [u8], + ) -> task03::Poll<Result<usize, Error>> { poll_01_to_03(self.in_notify(cx, |x| x.poll_read(buf))) } } impl<W: AsyncWrite01> AsyncWrite03 for Compat01As03<W> { - fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) - -> task03::Poll<Result<usize, Error>> - { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> task03::Poll<Result<usize, Error>> { poll_01_to_03(self.in_notify(cx, |x| x.poll_write(buf))) } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) - -> task03::Poll<Result<(), Error>> - { + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> task03::Poll<Result<(), Error>> { poll_01_to_03(self.in_notify(cx, AsyncWrite01::poll_flush)) } - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) - -> task03::Poll<Result<(), Error>> - { + fn poll_close( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> task03::Poll<Result<(), Error>> { poll_01_to_03(self.in_notify(cx, AsyncWrite01::shutdown)) } } diff --git a/src/compat/compat03as01.rs b/src/compat/compat03as01.rs index 3f1eebb..5d3a6e9 100644 --- a/src/compat/compat03as01.rs +++ b/src/compat/compat03as01.rs @@ -1,31 +1,19 @@ +use crate::task::{self as task03, ArcWake as ArcWake03, WakerRef}; use futures_01::{ - task as task01, Async as Async01, Future as Future01, Poll as Poll01, - Stream as Stream01, + task as task01, Async as Async01, Future as Future01, Poll as Poll01, Stream as Stream01, }; #[cfg(feature = "sink")] -use futures_01::{ - AsyncSink as AsyncSink01, Sink as Sink01, StartSend as StartSend01, -}; +use futures_01::{AsyncSink as AsyncSink01, Sink as Sink01, StartSend as StartSend01}; use futures_core::{ - task::{RawWaker, RawWakerVTable}, future::TryFuture as TryFuture03, stream::TryStream as TryStream03, + task::{RawWaker, RawWakerVTable}, }; #[cfg(feature = "sink")] use futures_sink::Sink as Sink03; -use crate::task::{ - self as task03, - ArcWake as ArcWake03, - WakerRef, -}; #[cfg(feature = "sink")] use std::marker::PhantomData; -use std::{ - mem, - pin::Pin, - sync::Arc, - task::Context, -}; +use std::{mem, pin::Pin, sync::Arc, task::Context}; /// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture) or /// [`TryStream`](futures_core::stream::TryStream) into a futures 0.1 @@ -80,10 +68,7 @@ impl<T> Compat<T> { impl<T, Item> CompatSink<T, Item> { /// Creates a new [`CompatSink`]. pub fn new(inner: T) -> Self { - Self { - inner, - _phantom: PhantomData, - } + Self { inner, _phantom: PhantomData } } /// Get a reference to 0.3 Sink contained within. @@ -102,9 +87,7 @@ impl<T, Item> CompatSink<T, Item> { } } -fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>) - -> Result<Async01<T>, E> -{ +fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>) -> Result<Async01<T>, E> { match x? { task03::Poll::Ready(t) => Ok(Async01::Ready(t)), task03::Poll::Pending => Ok(Async01::NotReady), @@ -147,17 +130,10 @@ where type SinkItem = Item; type SinkError = T::Error; - fn start_send( - &mut self, - item: Self::SinkItem, - ) -> StartSend01<Self::SinkItem, Self::SinkError> { - with_sink_context(self, |mut inner, cx| { - match inner.as_mut().poll_ready(cx)? { - task03::Poll::Ready(()) => { - inner.start_send(item).map(|()| AsyncSink01::Ready) - } - task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)), - } + fn start_send(&mut self, item: Self::SinkItem) -> StartSend01<Self::SinkItem, Self::SinkError> { + with_sink_context(self, |mut inner, cx| match inner.as_mut().poll_ready(cx)? { + task03::Poll::Ready(()) => inner.start_send(item).map(|()| AsyncSink01::Ready), + task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)), }) } @@ -190,9 +166,9 @@ impl Current { // Lazily create the `Arc` only when the waker is actually cloned. // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion // function is landed in `core`. - mem::transmute::<task03::Waker, RawWaker>( - task03::waker(Arc::new(ptr_to_current(ptr).clone())) - ) + mem::transmute::<task03::Waker, RawWaker>(task03::waker(Arc::new( + ptr_to_current(ptr).clone(), + ))) } unsafe fn drop(_: *const ()) {} unsafe fn wake(ptr: *const ()) { @@ -243,9 +219,7 @@ mod io { use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03}; use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01}; - fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>) - -> Result<T, std::io::Error> - { + fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>) -> Result<T, std::io::Error> { match x { task03::Poll::Ready(Ok(t)) => Ok(t), task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), @@ -262,17 +236,7 @@ mod io { } } - impl<R: AsyncRead03 + Unpin> AsyncRead01 for Compat<R> { - #[cfg(feature = "read-initializer")] - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - let initializer = self.inner.initializer(); - let does_init = initializer.should_initialize(); - if does_init { - initializer.initialize(buf); - } - does_init - } - } + impl<R: AsyncRead03 + Unpin> AsyncRead01 for Compat<R> {} impl<W: AsyncWrite03 + Unpin> std::io::Write for Compat<W> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { diff --git a/src/compat/executor.rs b/src/compat/executor.rs index 82cb496..ea0c67a 100644 --- a/src/compat/executor.rs +++ b/src/compat/executor.rs @@ -17,6 +17,7 @@ pub trait Executor01CompatExt: Executor01<Executor01Future> + Clone + Send + 'st /// futures 0.3 [`Spawn`](futures_task::Spawn). /// /// ``` + /// # if cfg!(miri) { return; } // Miri does not support epoll /// use futures::task::SpawnExt; /// use futures::future::{FutureExt, TryFutureExt}; /// use futures_util::compat::Executor01CompatExt; @@ -66,9 +67,7 @@ where fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError03> { let future = future.unit_error().compat(); - self.executor01 - .execute(future) - .map_err(|_| SpawnError03::shutdown()) + self.executor01.execute(future).map_err(|_| SpawnError03::shutdown()) } } diff --git a/src/compat/mod.rs b/src/compat/mod.rs index c5edcc5..4812803 100644 --- a/src/compat/mod.rs +++ b/src/compat/mod.rs @@ -4,16 +4,16 @@ //! library is activated. mod executor; -pub use self::executor::{Executor01CompatExt, Executor01Future, Executor01As03}; +pub use self::executor::{Executor01As03, Executor01CompatExt, Executor01Future}; mod compat01as03; +#[cfg(feature = "io-compat")] +#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] +pub use self::compat01as03::{AsyncRead01CompatExt, AsyncWrite01CompatExt}; pub use self::compat01as03::{Compat01As03, Future01CompatExt, Stream01CompatExt}; #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] pub use self::compat01as03::{Compat01As03Sink, Sink01CompatExt}; -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -pub use self::compat01as03::{AsyncRead01CompatExt, AsyncWrite01CompatExt}; mod compat03as01; pub use self::compat03as01::Compat; @@ -1,5 +1,5 @@ -use core::marker::PhantomData; use core::fmt::{self, Debug}; +use core::marker::PhantomData; pub trait FnOnce1<A> { type Output; @@ -8,7 +8,7 @@ pub trait FnOnce1<A> { impl<T, A, R> FnOnce1<A> for T where - T: FnOnce(A) -> R + T: FnOnce(A) -> R, { type Output = R; fn call_once(self, arg: A) -> R { @@ -22,7 +22,7 @@ pub trait FnMut1<A>: FnOnce1<A> { impl<T, A, R> FnMut1<A> for T where - T: FnMut(A) -> R + T: FnMut(A) -> R, { fn call_mut(&mut self, arg: A) -> R { self(arg) @@ -37,7 +37,7 @@ pub trait Fn1<A>: FnMut1<A> { impl<T, A, R> Fn1<A> for T where - T: Fn(A) -> R + T: Fn(A) -> R, { fn call(&self, arg: A) -> R { self(arg) @@ -143,7 +143,7 @@ pub struct InspectFn<F>(F); #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 impl<F, A> FnOnce1<A> for InspectFn<F> where - F: for<'a> FnOnce1<&'a A, Output=()>, + F: for<'a> FnOnce1<&'a A, Output = ()>, { type Output = A; fn call_once(self, arg: A) -> Self::Output { @@ -154,7 +154,7 @@ where #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 impl<F, A> FnMut1<A> for InspectFn<F> where - F: for<'a> FnMut1<&'a A, Output=()>, + F: for<'a> FnMut1<&'a A, Output = ()>, { fn call_mut(&mut self, arg: A) -> Self::Output { self.0.call_mut(&arg); @@ -164,7 +164,7 @@ where #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 impl<F, A> Fn1<A> for InspectFn<F> where - F: for<'a> Fn1<&'a A, Output=()>, + F: for<'a> Fn1<&'a A, Output = ()>, { fn call(&self, arg: A) -> Self::Output { self.0.call(&arg); @@ -244,27 +244,33 @@ pub struct InspectOkFn<F>(F); impl<'a, F, T, E> FnOnce1<&'a Result<T, E>> for InspectOkFn<F> where - F: FnOnce1<&'a T, Output=()> + F: FnOnce1<&'a T, Output = ()>, { type Output = (); fn call_once(self, arg: &'a Result<T, E>) -> Self::Output { - if let Ok(x) = arg { self.0.call_once(x) } + if let Ok(x) = arg { + self.0.call_once(x) + } } } impl<'a, F, T, E> FnMut1<&'a Result<T, E>> for InspectOkFn<F> where - F: FnMut1<&'a T, Output=()>, + F: FnMut1<&'a T, Output = ()>, { fn call_mut(&mut self, arg: &'a Result<T, E>) -> Self::Output { - if let Ok(x) = arg { self.0.call_mut(x) } + if let Ok(x) = arg { + self.0.call_mut(x) + } } } impl<'a, F, T, E> Fn1<&'a Result<T, E>> for InspectOkFn<F> where - F: Fn1<&'a T, Output=()>, + F: Fn1<&'a T, Output = ()>, { fn call(&self, arg: &'a Result<T, E>) -> Self::Output { - if let Ok(x) = arg { self.0.call(x) } + if let Ok(x) = arg { + self.0.call(x) + } } } pub(crate) fn inspect_ok_fn<F>(f: F) -> InspectOkFn<F> { @@ -276,27 +282,33 @@ pub struct InspectErrFn<F>(F); impl<'a, F, T, E> FnOnce1<&'a Result<T, E>> for InspectErrFn<F> where - F: FnOnce1<&'a E, Output=()> + F: FnOnce1<&'a E, Output = ()>, { type Output = (); fn call_once(self, arg: &'a Result<T, E>) -> Self::Output { - if let Err(x) = arg { self.0.call_once(x) } + if let Err(x) = arg { + self.0.call_once(x) + } } } impl<'a, F, T, E> FnMut1<&'a Result<T, E>> for InspectErrFn<F> where - F: FnMut1<&'a E, Output=()>, + F: FnMut1<&'a E, Output = ()>, { fn call_mut(&mut self, arg: &'a Result<T, E>) -> Self::Output { - if let Err(x) = arg { self.0.call_mut(x) } + if let Err(x) = arg { + self.0.call_mut(x) + } } } impl<'a, F, T, E> Fn1<&'a Result<T, E>> for InspectErrFn<F> where - F: Fn1<&'a E, Output=()>, + F: Fn1<&'a E, Output = ()>, { fn call(&self, arg: &'a Result<T, E>) -> Self::Output { - if let Err(x) = arg { self.0.call(x) } + if let Err(x) = arg { + self.0.call(x) + } } } pub(crate) fn inspect_err_fn<F>(f: F) -> InspectErrFn<F> { @@ -313,7 +325,7 @@ pub struct UnwrapOrElseFn<F>(F); impl<F, T, E> FnOnce1<Result<T, E>> for UnwrapOrElseFn<F> where - F: FnOnce1<E, Output=T>, + F: FnOnce1<E, Output = T>, { type Output = T; fn call_once(self, arg: Result<T, E>) -> Self::Output { @@ -322,7 +334,7 @@ where } impl<F, T, E> FnMut1<Result<T, E>> for UnwrapOrElseFn<F> where - F: FnMut1<E, Output=T>, + F: FnMut1<E, Output = T>, { fn call_mut(&mut self, arg: Result<T, E>) -> Self::Output { arg.unwrap_or_else(|x| self.0.call_mut(x)) @@ -330,7 +342,7 @@ where } impl<F, T, E> Fn1<Result<T, E>> for UnwrapOrElseFn<F> where - F: Fn1<E, Output=T>, + F: Fn1<E, Output = T>, { fn call(&self, arg: Result<T, E>) -> Self::Output { arg.unwrap_or_else(|x| self.0.call(x)) @@ -347,7 +359,10 @@ impl<T> Default for IntoFn<T> { Self(PhantomData) } } -impl<A, T> FnOnce1<A> for IntoFn<T> where A: Into<T> { +impl<A, T> FnOnce1<A> for IntoFn<T> +where + A: Into<T>, +{ type Output = T; fn call_once(self, arg: A) -> Self::Output { arg.into() diff --git a/src/future/abortable.rs b/src/future/abortable.rs index 3f2e5a0..d017ab7 100644 --- a/src/future/abortable.rs +++ b/src/future/abortable.rs @@ -1,110 +1,8 @@ use super::assert_future; -use crate::task::AtomicWaker; +use crate::future::{AbortHandle, Abortable, Aborted}; use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use core::fmt; -use core::pin::Pin; -use core::sync::atomic::{AtomicBool, Ordering}; -use alloc::sync::Arc; -use pin_project_lite::pin_project; -pin_project! { - /// A future which can be remotely short-circuited using an `AbortHandle`. - #[derive(Debug, Clone)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Abortable<Fut> { - #[pin] - future: Fut, - inner: Arc<AbortInner>, - } -} - -impl<Fut> Abortable<Fut> where Fut: Future { - /// Creates a new `Abortable` future using an existing `AbortRegistration`. - /// `AbortRegistration`s can be acquired through `AbortHandle::new`. - /// - /// When `abort` is called on the handle tied to `reg` or if `abort` has - /// already been called, the future will complete immediately without making - /// any further progress. - /// - /// Example: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::{Abortable, AbortHandle, Aborted}; - /// - /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); - /// let future = Abortable::new(async { 2 }, abort_registration); - /// abort_handle.abort(); - /// assert_eq!(future.await, Err(Aborted)); - /// # }); - /// ``` - pub fn new(future: Fut, reg: AbortRegistration) -> Self { - assert_future::<Result<Fut::Output, Aborted>, _>(Self { - future, - inner: reg.inner, - }) - } -} - -/// A registration handle for a `Abortable` future. -/// Values of this type can be acquired from `AbortHandle::new` and are used -/// in calls to `Abortable::new`. -#[derive(Debug)] -pub struct AbortRegistration { - inner: Arc<AbortInner>, -} - -/// A handle to a `Abortable` future. -#[derive(Debug, Clone)] -pub struct AbortHandle { - inner: Arc<AbortInner>, -} - -impl AbortHandle { - /// Creates an (`AbortHandle`, `AbortRegistration`) pair which can be used - /// to abort a running future. - /// - /// This function is usually paired with a call to `Abortable::new`. - /// - /// Example: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::{Abortable, AbortHandle, Aborted}; - /// - /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); - /// let future = Abortable::new(async { 2 }, abort_registration); - /// abort_handle.abort(); - /// assert_eq!(future.await, Err(Aborted)); - /// # }); - /// ``` - pub fn new_pair() -> (Self, AbortRegistration) { - let inner = Arc::new(AbortInner { - waker: AtomicWaker::new(), - cancel: AtomicBool::new(false), - }); - - ( - Self { - inner: inner.clone(), - }, - AbortRegistration { - inner, - }, - ) - } -} - -// Inner type storing the waker to awaken and a bool indicating that it -// should be cancelled. -#[derive(Debug)] -struct AbortInner { - waker: AtomicWaker, - cancel: AtomicBool, -} - -/// Creates a new `Abortable` future and a `AbortHandle` which can be used to stop it. +/// Creates a new `Abortable` future and an `AbortHandle` which can be used to stop it. /// /// This function is a convenient (but less flexible) alternative to calling /// `AbortHandle::new` and `Abortable::new` manually. @@ -112,66 +10,10 @@ struct AbortInner { /// This function is only available when the `std` or `alloc` feature of this /// library is activated, and it is activated by default. pub fn abortable<Fut>(future: Fut) -> (Abortable<Fut>, AbortHandle) - where Fut: Future +where + Fut: Future, { let (handle, reg) = AbortHandle::new_pair(); - ( - Abortable::new(future, reg), - handle, - ) -} - -/// Indicator that the `Abortable` future was aborted. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Aborted; - -impl fmt::Display for Aborted { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "`Abortable` future has been aborted") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Aborted {} - -impl<Fut> Future for Abortable<Fut> where Fut: Future { - type Output = Result<Fut::Output, Aborted>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - // Check if the future has been aborted - if self.inner.cancel.load(Ordering::Relaxed) { - return Poll::Ready(Err(Aborted)) - } - - // attempt to complete the future - if let Poll::Ready(x) = self.as_mut().project().future.poll(cx) { - return Poll::Ready(Ok(x)) - } - - // Register to receive a wakeup if the future is aborted in the... future - self.inner.waker.register(cx.waker()); - - // Check to see if the future was aborted between the first check and - // registration. - // Checking with `Relaxed` is sufficient because `register` introduces an - // `AcqRel` barrier. - if self.inner.cancel.load(Ordering::Relaxed) { - return Poll::Ready(Err(Aborted)) - } - - Poll::Pending - } -} - -impl AbortHandle { - /// Abort the `Abortable` future associated with this handle. - /// - /// Notifies the Abortable future associated with this handle that it - /// should abort. Note that if the future is currently being polled on - /// another thread, it will not immediately stop running. Instead, it will - /// continue to run until its poll method returns. - pub fn abort(&self) { - self.inner.cancel.store(true, Ordering::Relaxed); - self.inner.waker.wake(); - } + let abortable = assert_future::<Result<Fut::Output, Aborted>, _>(Abortable::new(future, reg)); + (abortable, handle) } diff --git a/src/future/either.rs b/src/future/either.rs index 5f5b614..9602de7 100644 --- a/src/future/either.rs +++ b/src/future/either.rs @@ -5,8 +5,25 @@ use futures_core::stream::{FusedStream, Stream}; #[cfg(feature = "sink")] use futures_sink::Sink; -/// Combines two different futures, streams, or sinks having the same associated types into a single -/// type. +/// Combines two different futures, streams, or sinks having the same associated types into a single type. +/// +/// This is useful when conditionally choosing between two distinct future types: +/// +/// ```rust +/// use futures::future::Either; +/// +/// # futures::executor::block_on(async { +/// let cond = true; +/// +/// let fut = if cond { +/// Either::Left(async move { 12 }) +/// } else { +/// Either::Right(async move { 44 }) +/// }; +/// +/// assert_eq!(fut.await, 12); +/// # }) +/// ``` #[derive(Debug, Clone)] pub enum Either<A, B> { /// First branch of the type @@ -167,8 +184,6 @@ mod if_std { use core::pin::Pin; use core::task::{Context, Poll}; - #[cfg(feature = "read-initializer")] - use futures_io::Initializer; use futures_io::{ AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, Result, SeekFrom, }; @@ -178,14 +193,6 @@ mod if_std { A: AsyncRead, B: AsyncRead, { - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - match self { - Either::Left(x) => x.initializer(), - Either::Right(x) => x.initializer(), - } - } - fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, diff --git a/src/future/future/catch_unwind.rs b/src/future/future/catch_unwind.rs index 3f16577..0e09d6e 100644 --- a/src/future/future/catch_unwind.rs +++ b/src/future/future/catch_unwind.rs @@ -1,6 +1,6 @@ use core::any::Any; use core::pin::Pin; -use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; +use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe}; use futures_core::future::Future; use futures_core::task::{Context, Poll}; @@ -16,14 +16,18 @@ pin_project! { } } -impl<Fut> CatchUnwind<Fut> where Fut: Future + UnwindSafe { +impl<Fut> CatchUnwind<Fut> +where + Fut: Future + UnwindSafe, +{ pub(super) fn new(future: Fut) -> Self { Self { future } } } impl<Fut> Future for CatchUnwind<Fut> - where Fut: Future + UnwindSafe, +where + Fut: Future + UnwindSafe, { type Output = Result<Fut::Output, Box<dyn Any + Send>>; diff --git a/src/future/future/flatten.rs b/src/future/future/flatten.rs index 0c48a4f..bd767af 100644 --- a/src/future/future/flatten.rs +++ b/src/future/future/flatten.rs @@ -2,9 +2,9 @@ use core::pin::Pin; use futures_core::future::{FusedFuture, Future}; use futures_core::ready; use futures_core::stream::{FusedStream, Stream}; +use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; -use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; pin_project! { @@ -24,8 +24,9 @@ impl<Fut1, Fut2> Flatten<Fut1, Fut2> { } impl<Fut> FusedFuture for Flatten<Fut, Fut::Output> - where Fut: Future, - Fut::Output: Future, +where + Fut: Future, + Fut::Output: Future, { fn is_terminated(&self) -> bool { match self { @@ -36,8 +37,9 @@ impl<Fut> FusedFuture for Flatten<Fut, Fut::Output> } impl<Fut> Future for Flatten<Fut, Fut::Output> - where Fut: Future, - Fut::Output: Future, +where + Fut: Future, + Fut::Output: Future, { type Output = <Fut::Output as Future>::Output; @@ -47,12 +49,12 @@ impl<Fut> Future for Flatten<Fut, Fut::Output> FlattenProj::First { f } => { let f = ready!(f.poll(cx)); self.set(Self::Second { f }); - }, + } FlattenProj::Second { f } => { let output = ready!(f.poll(cx)); self.set(Self::Empty); break output; - }, + } FlattenProj::Empty => panic!("Flatten polled after completion"), } }) @@ -60,8 +62,9 @@ impl<Fut> Future for Flatten<Fut, Fut::Output> } impl<Fut> FusedStream for Flatten<Fut, Fut::Output> - where Fut: Future, - Fut::Output: Stream, +where + Fut: Future, + Fut::Output: Stream, { fn is_terminated(&self) -> bool { match self { @@ -72,32 +75,32 @@ impl<Fut> FusedStream for Flatten<Fut, Fut::Output> } impl<Fut> Stream for Flatten<Fut, Fut::Output> - where Fut: Future, - Fut::Output: Stream, +where + Fut: Future, + Fut::Output: Stream, { type Item = <Fut::Output as Stream>::Item; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { Poll::Ready(loop { match self.as_mut().project() { - FlattenProj::First { f } => { + FlattenProj::First { f } => { let f = ready!(f.poll(cx)); self.set(Self::Second { f }); - }, + } FlattenProj::Second { f } => { let output = ready!(f.poll_next(cx)); if output.is_none() { self.set(Self::Empty); } break output; - }, + } FlattenProj::Empty => break None, } }) } } - #[cfg(feature = "sink")] impl<Fut, Item> Sink<Item> for Flatten<Fut, Fut::Output> where @@ -106,19 +109,16 @@ where { type Error = <Fut::Output as Sink<Item>>::Error; - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(loop { match self.as_mut().project() { FlattenProj::First { f } => { let f = ready!(f.poll(cx)); self.set(Self::Second { f }); - }, + } FlattenProj::Second { f } => { break ready!(f.poll_ready(cx)); - }, + } FlattenProj::Empty => panic!("poll_ready called after eof"), } }) @@ -140,10 +140,7 @@ where } } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { let res = match self.as_mut().project() { FlattenProj::Second { f } => f.poll_close(cx), _ => Poll::Ready(Ok(())), diff --git a/src/future/future/fuse.rs b/src/future/future/fuse.rs index f4284ba..597aec1 100644 --- a/src/future/future/fuse.rs +++ b/src/future/future/fuse.rs @@ -1,5 +1,5 @@ use core::pin::Pin; -use futures_core::future::{Future, FusedFuture}; +use futures_core::future::{FusedFuture, Future}; use futures_core::ready; use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; @@ -86,7 +86,7 @@ impl<Fut: Future> Future for Fuse<Fut> { let output = ready!(fut.poll(cx)); self.project().inner.set(None); output - }, + } None => return Poll::Pending, }) } diff --git a/src/future/future/remote_handle.rs b/src/future/future/remote_handle.rs index 0d33ea5..1358902 100644 --- a/src/future/future/remote_handle.rs +++ b/src/future/future/remote_handle.rs @@ -1,23 +1,23 @@ use { crate::future::{CatchUnwind, FutureExt}, - futures_channel::oneshot::{self, Sender, Receiver}, + futures_channel::oneshot::{self, Receiver, Sender}, futures_core::{ future::Future, - task::{Context, Poll}, ready, + task::{Context, Poll}, }, + pin_project_lite::pin_project, std::{ any::Any, fmt, panic::{self, AssertUnwindSafe}, pin::Pin, sync::{ - Arc, atomic::{AtomicBool, Ordering}, + Arc, }, thread, }, - pin_project_lite::pin_project, }; /// The handle to a remote future returned by @@ -36,7 +36,7 @@ use { /// must be careful with regard to unwind safety because the thread in which the future /// is polled will keep running after the panic and the thread running the [RemoteHandle] /// will unwind. -#[must_use = "futures do nothing unless you `.await` or poll them"] +#[must_use = "dropping a remote handle cancels the underlying future"] #[derive(Debug)] #[cfg_attr(docsrs, doc(cfg(feature = "channel")))] pub struct RemoteHandle<T> { @@ -85,9 +85,7 @@ pin_project! { impl<Fut: Future + fmt::Debug> fmt::Debug for Remote<Fut> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Remote") - .field(&self.future) - .finish() + f.debug_tuple("Remote").field(&self.future).finish() } } diff --git a/src/future/future/shared.rs b/src/future/future/shared.rs index 74311a0..9b31932 100644 --- a/src/future/future/shared.rs +++ b/src/future/future/shared.rs @@ -29,6 +29,12 @@ struct Notifier { /// A weak reference to a [`Shared`] that can be upgraded much like an `Arc`. pub struct WeakShared<Fut: Future>(Weak<Inner<Fut>>); +impl<Fut: Future> Clone for WeakShared<Fut> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + // The future itself is polled behind the `Arc`, so it won't be moved // when `Shared` is moved. impl<Fut: Future> Unpin for Shared<Fut> {} @@ -90,10 +96,7 @@ impl<Fut: Future> Shared<Fut> { }), }; - Self { - inner: Some(Arc::new(inner)), - waker_key: NULL_WAKER_KEY, - } + Self { inner: Some(Arc::new(inner)), waker_key: NULL_WAKER_KEY } } } @@ -223,10 +226,7 @@ where fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let this = &mut *self; - let inner = this - .inner - .take() - .expect("Shared future polled again after completion"); + let inner = this.inner.take().expect("Shared future polled again after completion"); // Fast path for when the wrapped future has already completed if inner.notifier.state.load(Acquire) == COMPLETE { @@ -286,11 +286,7 @@ where match future.poll(&mut cx) { Poll::Pending => { - if inner - .notifier - .state - .compare_exchange(POLLING, IDLE, SeqCst, SeqCst) - .is_ok() + if inner.notifier.state.compare_exchange(POLLING, IDLE, SeqCst, SeqCst).is_ok() { // Success drop(_reset); @@ -330,10 +326,7 @@ where Fut: Future, { fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - waker_key: NULL_WAKER_KEY, - } + Self { inner: self.inner.clone(), waker_key: NULL_WAKER_KEY } } } @@ -367,16 +360,12 @@ impl ArcWake for Notifier { } } -impl<Fut: Future> WeakShared<Fut> -{ +impl<Fut: Future> WeakShared<Fut> { /// Attempts to upgrade this [`WeakShared`] into a [`Shared`]. /// /// Returns [`None`] if all clones of the [`Shared`] have been dropped or polled /// to completion. pub fn upgrade(&self) -> Option<Shared<Fut>> { - Some(Shared { - inner: Some(self.0.upgrade()?), - waker_key: NULL_WAKER_KEY, - }) + Some(Shared { inner: Some(self.0.upgrade()?), waker_key: NULL_WAKER_KEY }) } } diff --git a/src/future/join.rs b/src/future/join.rs index a818343..740ffbc 100644 --- a/src/future/join.rs +++ b/src/future/join.rs @@ -213,14 +213,5 @@ where Fut5: Future, { let f = Join5::new(future1, future2, future3, future4, future5); - assert_future::< - ( - Fut1::Output, - Fut2::Output, - Fut3::Output, - Fut4::Output, - Fut5::Output, - ), - _, - >(f) + assert_future::<(Fut1::Output, Fut2::Output, Fut3::Output, Fut4::Output, Fut5::Output), _>(f) } diff --git a/src/future/join_all.rs b/src/future/join_all.rs index 7ccf869..2e52ac1 100644 --- a/src/future/join_all.rs +++ b/src/future/join_all.rs @@ -1,33 +1,50 @@ //! Definition of the `JoinAll` combinator, waiting for all of a list of futures //! to finish. +use alloc::boxed::Box; +use alloc::vec::Vec; use core::fmt; use core::future::Future; use core::iter::FromIterator; use core::mem; use core::pin::Pin; use core::task::{Context, Poll}; -use alloc::boxed::Box; -use alloc::vec::Vec; -use super::{MaybeDone, assert_future}; +use super::{assert_future, MaybeDone}; + +#[cfg(not(futures_no_atomic_cas))] +use crate::stream::{Collect, FuturesOrdered, StreamExt}; fn iter_pin_mut<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> { // Safety: `std` _could_ make this unsound if it were to decide Pin's // invariants aren't required to transmit through slices. Otherwise this has // the same safety as a normal field pin projection. - unsafe { slice.get_unchecked_mut() } - .iter_mut() - .map(|t| unsafe { Pin::new_unchecked(t) }) + unsafe { slice.get_unchecked_mut() }.iter_mut().map(|t| unsafe { Pin::new_unchecked(t) }) } -/// Future for the [`join_all`] function. #[must_use = "futures do nothing unless you `.await` or poll them"] +/// Future for the [`join_all`] function. pub struct JoinAll<F> where F: Future, { - elems: Pin<Box<[MaybeDone<F>]>>, + kind: JoinAllKind<F>, +} + +#[cfg(not(futures_no_atomic_cas))] +const SMALL: usize = 30; + +pub(crate) enum JoinAllKind<F> +where + F: Future, +{ + Small { + elems: Pin<Box<[MaybeDone<F>]>>, + }, + #[cfg(not(futures_no_atomic_cas))] + Big { + fut: Collect<FuturesOrdered<F>, Vec<F::Output>>, + }, } impl<F> fmt::Debug for JoinAll<F> @@ -36,9 +53,13 @@ where F::Output: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("JoinAll") - .field("elems", &self.elems) - .finish() + match self.kind { + JoinAllKind::Small { ref elems } => { + f.debug_struct("JoinAll").field("elems", elems).finish() + } + #[cfg(not(futures_no_atomic_cas))] + JoinAllKind::Big { ref fut, .. } => fmt::Debug::fmt(fut, f), + } } } @@ -54,10 +75,9 @@ where /// /// # See Also /// -/// This is purposefully a very simple API for basic use-cases. In a lot of -/// cases you will want to use the more powerful -/// [`FuturesOrdered`][crate::stream::FuturesOrdered] APIs, or, if order does -/// not matter, [`FuturesUnordered`][crate::stream::FuturesUnordered]. +/// `join_all` will switch to the more powerful [`FuturesOrdered`] for performance +/// reasons if the number of futures is large. You may want to look into using it or +/// it's counterpart [`FuturesUnordered`][crate::stream::FuturesUnordered] directly. /// /// Some examples for additional functionality provided by these are: /// @@ -79,13 +99,33 @@ where /// assert_eq!(join_all(futures).await, [1, 2, 3]); /// # }); /// ``` -pub fn join_all<I>(i: I) -> JoinAll<I::Item> +pub fn join_all<I>(iter: I) -> JoinAll<I::Item> where I: IntoIterator, I::Item: Future, { - let elems: Box<[_]> = i.into_iter().map(MaybeDone::Future).collect(); - assert_future::<Vec<<I::Item as Future>::Output>, _>(JoinAll { elems: elems.into() }) + #[cfg(futures_no_atomic_cas)] + { + let elems = iter.into_iter().map(MaybeDone::Future).collect::<Box<[_]>>().into(); + let kind = JoinAllKind::Small { elems }; + assert_future::<Vec<<I::Item as Future>::Output>, _>(JoinAll { kind }) + } + #[cfg(not(futures_no_atomic_cas))] + { + let iter = iter.into_iter(); + let kind = match iter.size_hint().1 { + None => JoinAllKind::Big { fut: iter.collect::<FuturesOrdered<_>>().collect() }, + Some(max) => { + if max <= SMALL { + let elems = iter.map(MaybeDone::Future).collect::<Box<[_]>>().into(); + JoinAllKind::Small { elems } + } else { + JoinAllKind::Big { fut: iter.collect::<FuturesOrdered<_>>().collect() } + } + } + }; + assert_future::<Vec<<I::Item as Future>::Output>, _>(JoinAll { kind }) + } } impl<F> Future for JoinAll<F> @@ -95,22 +135,27 @@ where type Output = Vec<F::Output>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - let mut all_done = true; + match &mut self.kind { + JoinAllKind::Small { elems } => { + let mut all_done = true; - for elem in iter_pin_mut(self.elems.as_mut()) { - if elem.poll(cx).is_pending() { - all_done = false; - } - } + for elem in iter_pin_mut(elems.as_mut()) { + if elem.poll(cx).is_pending() { + all_done = false; + } + } - if all_done { - let mut elems = mem::replace(&mut self.elems, Box::pin([])); - let result = iter_pin_mut(elems.as_mut()) - .map(|e| e.take_output().unwrap()) - .collect(); - Poll::Ready(result) - } else { - Poll::Pending + if all_done { + let mut elems = mem::replace(elems, Box::pin([])); + let result = + iter_pin_mut(elems.as_mut()).map(|e| e.take_output().unwrap()).collect(); + Poll::Ready(result) + } else { + Poll::Pending + } + } + #[cfg(not(futures_no_atomic_cas))] + JoinAllKind::Big { fut } => Pin::new(fut).poll(cx), } } } diff --git a/src/future/lazy.rs b/src/future/lazy.rs index 42812d3..e9a8cf2 100644 --- a/src/future/lazy.rs +++ b/src/future/lazy.rs @@ -7,7 +7,7 @@ use futures_core::task::{Context, Poll}; #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Lazy<F> { - f: Option<F> + f: Option<F>, } // safe because we never generate `Pin<&mut F>` @@ -33,19 +33,24 @@ impl<F> Unpin for Lazy<F> {} /// # }); /// ``` pub fn lazy<F, R>(f: F) -> Lazy<F> - where F: FnOnce(&mut Context<'_>) -> R, +where + F: FnOnce(&mut Context<'_>) -> R, { assert_future::<R, _>(Lazy { f: Some(f) }) } impl<F, R> FusedFuture for Lazy<F> - where F: FnOnce(&mut Context<'_>) -> R, +where + F: FnOnce(&mut Context<'_>) -> R, { - fn is_terminated(&self) -> bool { self.f.is_none() } + fn is_terminated(&self) -> bool { + self.f.is_none() + } } impl<F, R> Future for Lazy<F> - where F: FnOnce(&mut Context<'_>) -> R, +where + F: FnOnce(&mut Context<'_>) -> R, { type Output = R; diff --git a/src/future/mod.rs b/src/future/mod.rs index 84e457c..374e365 100644 --- a/src/future/mod.rs +++ b/src/future/mod.rs @@ -21,7 +21,7 @@ pub use futures_task::{FutureObj, LocalFutureObj, UnsafeFutureObj}; #[allow(clippy::module_inception)] mod future; pub use self::future::{ - Flatten, Fuse, FutureExt, Inspect, IntoStream, Map, NeverError, Then, UnitError, MapInto, + Flatten, Fuse, FutureExt, Inspect, IntoStream, Map, MapInto, NeverError, Then, UnitError, }; #[deprecated(note = "This is now an alias for [Flatten](Flatten)")] @@ -40,8 +40,8 @@ pub use self::future::{Shared, WeakShared}; mod try_future; pub use self::try_future::{ - AndThen, ErrInto, OkInto, InspectErr, InspectOk, IntoFuture, MapErr, MapOk, OrElse, TryFlattenStream, - TryFutureExt, UnwrapOrElse, MapOkOrElse, TryFlatten, + AndThen, ErrInto, InspectErr, InspectOk, IntoFuture, MapErr, MapOk, MapOkOrElse, OkInto, + OrElse, TryFlatten, TryFlattenStream, TryFutureExt, UnwrapOrElse, }; #[cfg(feature = "sink")] @@ -68,6 +68,9 @@ pub use self::option::OptionFuture; mod poll_fn; pub use self::poll_fn::{poll_fn, PollFn}; +mod poll_immediate; +pub use self::poll_immediate::{poll_immediate, PollImmediate}; + mod ready; pub use self::ready::{err, ok, ready, Ready}; @@ -108,12 +111,15 @@ pub use self::select_ok::{select_ok, SelectOk}; mod either; pub use self::either::Either; -cfg_target_has_atomic! { - #[cfg(feature = "alloc")] - mod abortable; - #[cfg(feature = "alloc")] - pub use self::abortable::{abortable, Abortable, AbortHandle, AbortRegistration, Aborted}; -} +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod abortable; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted}; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use abortable::abortable; // Just a helper function to ensure the futures we're returning all have the // right implementations. diff --git a/src/future/option.rs b/src/future/option.rs index 85939d6..0bc3777 100644 --- a/src/future/option.rs +++ b/src/future/option.rs @@ -1,7 +1,7 @@ //! Definition of the `Option` (optional step) combinator use core::pin::Pin; -use futures_core::future::{Future, FusedFuture}; +use futures_core::future::{FusedFuture, Future}; use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; @@ -31,13 +31,16 @@ pin_project! { } } +impl<F> Default for OptionFuture<F> { + fn default() -> Self { + Self { inner: None } + } +} + impl<F: Future> Future for OptionFuture<F> { type Output = Option<F::Output>; - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { match self.project().inner.as_pin_mut() { Some(x) => x.poll(cx).map(Some), None => Poll::Ready(None), diff --git a/src/future/pending.rs b/src/future/pending.rs index 4311b9a..92c78d5 100644 --- a/src/future/pending.rs +++ b/src/future/pending.rs @@ -34,9 +34,7 @@ impl<T> FusedFuture for Pending<T> { /// # }); /// ``` pub fn pending<T>() -> Pending<T> { - assert_future::<T, _>(Pending { - _data: marker::PhantomData, - }) + assert_future::<T, _>(Pending { _data: marker::PhantomData }) } impl<T> Future for Pending<T> { @@ -47,8 +45,7 @@ impl<T> Future for Pending<T> { } } -impl<T> Unpin for Pending<T> { -} +impl<T> Unpin for Pending<T> {} impl<T> Clone for Pending<T> { fn clone(&self) -> Self { diff --git a/src/future/poll_fn.rs b/src/future/poll_fn.rs index 6ac1ab8..1931157 100644 --- a/src/future/poll_fn.rs +++ b/src/future/poll_fn.rs @@ -35,7 +35,7 @@ impl<F> Unpin for PollFn<F> {} /// ``` pub fn poll_fn<T, F>(f: F) -> PollFn<F> where - F: FnMut(&mut Context<'_>) -> Poll<T> + F: FnMut(&mut Context<'_>) -> Poll<T>, { assert_future::<T, _>(PollFn { f }) } @@ -47,7 +47,8 @@ impl<F> fmt::Debug for PollFn<F> { } impl<T, F> Future for PollFn<F> - where F: FnMut(&mut Context<'_>) -> Poll<T>, +where + F: FnMut(&mut Context<'_>) -> Poll<T>, { type Output = T; diff --git a/src/future/poll_immediate.rs b/src/future/poll_immediate.rs new file mode 100644 index 0000000..5ae555c --- /dev/null +++ b/src/future/poll_immediate.rs @@ -0,0 +1,126 @@ +use super::assert_future; +use core::pin::Pin; +use futures_core::task::{Context, Poll}; +use futures_core::{FusedFuture, Future, Stream}; +use pin_project_lite::pin_project; + +pin_project! { + /// Future for the [`poll_immediate`](poll_immediate()) function. + /// + /// It will never return [Poll::Pending](core::task::Poll::Pending) + #[derive(Debug, Clone)] + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct PollImmediate<T> { + #[pin] + future: Option<T> + } +} + +impl<T, F> Future for PollImmediate<F> +where + F: Future<Output = T>, +{ + type Output = Option<T>; + + #[inline] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> { + let mut this = self.project(); + let inner = + this.future.as_mut().as_pin_mut().expect("PollImmediate polled after completion"); + match inner.poll(cx) { + Poll::Ready(t) => { + this.future.set(None); + Poll::Ready(Some(t)) + } + Poll::Pending => Poll::Ready(None), + } + } +} + +impl<T: Future> FusedFuture for PollImmediate<T> { + fn is_terminated(&self) -> bool { + self.future.is_none() + } +} + +/// A [Stream](crate::stream::Stream) implementation that can be polled repeatedly until the future is done. +/// The stream will never return [Poll::Pending](core::task::Poll::Pending) +/// so polling it in a tight loop is worse than using a blocking synchronous function. +/// ``` +/// # futures::executor::block_on(async { +/// use futures::task::Poll; +/// use futures::{StreamExt, future, pin_mut}; +/// use future::FusedFuture; +/// +/// let f = async { 1_u32 }; +/// pin_mut!(f); +/// let mut r = future::poll_immediate(f); +/// assert_eq!(r.next().await, Some(Poll::Ready(1))); +/// +/// let f = async {futures::pending!(); 42_u8}; +/// pin_mut!(f); +/// let mut p = future::poll_immediate(f); +/// assert_eq!(p.next().await, Some(Poll::Pending)); +/// assert!(!p.is_terminated()); +/// assert_eq!(p.next().await, Some(Poll::Ready(42))); +/// assert!(p.is_terminated()); +/// assert_eq!(p.next().await, None); +/// # }); +/// ``` +impl<T, F> Stream for PollImmediate<F> +where + F: Future<Output = T>, +{ + type Item = Poll<T>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + let mut this = self.project(); + match this.future.as_mut().as_pin_mut() { + // inner is gone, so we can signal that the stream is closed. + None => Poll::Ready(None), + Some(fut) => Poll::Ready(Some(fut.poll(cx).map(|t| { + this.future.set(None); + t + }))), + } + } +} + +/// Creates a future that is immediately ready with an Option of a value. +/// Specifically this means that [poll](core::future::Future::poll()) always returns [Poll::Ready](core::task::Poll::Ready). +/// +/// # Caution +/// +/// When consuming the future by this function, note the following: +/// +/// - This function does not guarantee that the future will run to completion, so it is generally incompatible with passing the non-cancellation-safe future by value. +/// - Even if the future is cancellation-safe, creating and dropping new futures frequently may lead to performance problems. +/// +/// # Examples +/// +/// ``` +/// # futures::executor::block_on(async { +/// use futures::future; +/// +/// let r = future::poll_immediate(async { 1_u32 }); +/// assert_eq!(r.await, Some(1)); +/// +/// let p = future::poll_immediate(future::pending::<i32>()); +/// assert_eq!(p.await, None); +/// # }); +/// ``` +/// +/// ### Reusing a future +/// +/// ``` +/// # futures::executor::block_on(async { +/// use futures::{future, pin_mut}; +/// let f = async {futures::pending!(); 42_u8}; +/// pin_mut!(f); +/// assert_eq!(None, future::poll_immediate(&mut f).await); +/// assert_eq!(42, f.await); +/// # }); +/// ``` +pub fn poll_immediate<F: Future>(f: F) -> PollImmediate<F> { + assert_future::<Option<F::Output>, PollImmediate<F>>(PollImmediate { future: Some(f) }) +} diff --git a/src/future/select.rs b/src/future/select.rs index 043ed17..bd44f20 100644 --- a/src/future/select.rs +++ b/src/future/select.rs @@ -1,8 +1,8 @@ use super::assert_future; +use crate::future::{Either, FutureExt}; use core::pin::Pin; -use futures_core::future::{Future, FusedFuture}; +use futures_core::future::{FusedFuture, Future}; use futures_core::task::{Context, Poll}; -use crate::future::{Either, FutureExt}; /// Future for the [`select()`] function. #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -37,13 +37,13 @@ impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} /// future::Either, /// future::self, /// }; -/// +/// /// // These two futures have different types even though their outputs have the same type. /// let future1 = async { /// future::pending::<()>().await; // will never finish /// 1 /// }; -/// let future2 = async { +/// let future2 = async { /// future::ready(2).await /// }; /// @@ -82,9 +82,13 @@ impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} /// } /// ``` pub fn select<A, B>(future1: A, future2: B) -> Select<A, B> - where A: Future + Unpin, B: Future + Unpin +where + A: Future + Unpin, + B: Future + Unpin, { - assert_future::<Either<(A::Output, B), (B::Output, A)>, _>(Select { inner: Some((future1, future2)) }) + assert_future::<Either<(A::Output, B), (B::Output, A)>, _>(Select { + inner: Some((future1, future2)), + }) } impl<A, B> Future for Select<A, B> @@ -104,7 +108,7 @@ where self.inner = Some((a, b)); Poll::Pending } - } + }, } } } diff --git a/src/future/select_all.rs b/src/future/select_all.rs index 0db90a7..106e508 100644 --- a/src/future/select_all.rs +++ b/src/future/select_all.rs @@ -1,9 +1,9 @@ use super::assert_future; use crate::future::FutureExt; +use alloc::vec::Vec; use core::iter::FromIterator; use core::mem; use core::pin::Pin; -use alloc::vec::Vec; use futures_core::future::Future; use futures_core::task::{Context, Poll}; @@ -32,25 +32,29 @@ impl<Fut: Unpin> Unpin for SelectAll<Fut> {} /// /// This function will panic if the iterator specified contains no items. pub fn select_all<I>(iter: I) -> SelectAll<I::Item> - where I: IntoIterator, - I::Item: Future + Unpin, +where + I: IntoIterator, + I::Item: Future + Unpin, { - let ret = SelectAll { - inner: iter.into_iter().collect() - }; + let ret = SelectAll { inner: iter.into_iter().collect() }; assert!(!ret.inner.is_empty()); assert_future::<(<I::Item as Future>::Output, usize, Vec<I::Item>), _>(ret) } +impl<Fut> SelectAll<Fut> { + /// Consumes this combinator, returning the underlying futures. + pub fn into_inner(self) -> Vec<Fut> { + self.inner + } +} + impl<Fut: Future + Unpin> Future for SelectAll<Fut> { type Output = (Fut::Output, usize, Vec<Fut>); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| { - match f.poll_unpin(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - } + let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.poll_unpin(cx) { + Poll::Pending => None, + Poll::Ready(e) => Some((i, e)), }); match item { Some((idx, res)) => { diff --git a/src/future/select_ok.rs b/src/future/select_ok.rs index 52d393c..0ad83c6 100644 --- a/src/future/select_ok.rs +++ b/src/future/select_ok.rs @@ -1,9 +1,9 @@ use super::assert_future; use crate::future::TryFutureExt; +use alloc::vec::Vec; use core::iter::FromIterator; use core::mem; use core::pin::Pin; -use alloc::vec::Vec; use futures_core::future::{Future, TryFuture}; use futures_core::task::{Context, Poll}; @@ -30,14 +30,16 @@ impl<Fut: Unpin> Unpin for SelectOk<Fut> {} /// /// This function will panic if the iterator specified contains no items. pub fn select_ok<I>(iter: I) -> SelectOk<I::Item> - where I: IntoIterator, - I::Item: TryFuture + Unpin, +where + I: IntoIterator, + I::Item: TryFuture + Unpin, { - let ret = SelectOk { - inner: iter.into_iter().collect() - }; + let ret = SelectOk { inner: iter.into_iter().collect() }; assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty"); - assert_future::<Result<(<I::Item as TryFuture>::Ok, Vec<I::Item>), <I::Item as TryFuture>::Error>, _>(ret) + assert_future::< + Result<(<I::Item as TryFuture>::Ok, Vec<I::Item>), <I::Item as TryFuture>::Error>, + _, + >(ret) } impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> { @@ -46,12 +48,11 @@ impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // loop until we've either exhausted all errors, a success was hit, or nothing is ready loop { - let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| { - match f.try_poll_unpin(cx) { + let item = + self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.try_poll_unpin(cx) { Poll::Pending => None, Poll::Ready(e) => Some((i, e)), - } - }); + }); match item { Some((idx, res)) => { // always remove Ok or Err, if it's not the last Err continue looping @@ -59,18 +60,18 @@ impl<Fut: TryFuture + Unpin> Future for SelectOk<Fut> { match res { Ok(e) => { let rest = mem::replace(&mut self.inner, Vec::new()); - return Poll::Ready(Ok((e, rest))) + return Poll::Ready(Ok((e, rest))); } Err(e) => { if self.inner.is_empty() { - return Poll::Ready(Err(e)) + return Poll::Ready(Err(e)); } } } } None => { // based on the filter above, nothing is ready, return - return Poll::Pending + return Poll::Pending; } } } diff --git a/src/future/try_future/into_future.rs b/src/future/try_future/into_future.rs index e88d603..9f093d0 100644 --- a/src/future/try_future/into_future.rs +++ b/src/future/try_future/into_future.rs @@ -21,17 +21,16 @@ impl<Fut> IntoFuture<Fut> { } impl<Fut: TryFuture + FusedFuture> FusedFuture for IntoFuture<Fut> { - fn is_terminated(&self) -> bool { self.future.is_terminated() } + fn is_terminated(&self) -> bool { + self.future.is_terminated() + } } impl<Fut: TryFuture> Future for IntoFuture<Fut> { type Output = Result<Fut::Ok, Fut::Error>; #[inline] - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { self.project().future.try_poll(cx) } } diff --git a/src/future/try_future/try_flatten.rs b/src/future/try_future/try_flatten.rs index 5241b27..1ce4559 100644 --- a/src/future/try_future/try_flatten.rs +++ b/src/future/try_future/try_flatten.rs @@ -2,9 +2,9 @@ use core::pin::Pin; use futures_core::future::{FusedFuture, Future, TryFuture}; use futures_core::ready; use futures_core::stream::{FusedStream, Stream, TryStream}; +use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; -use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; pin_project! { @@ -24,8 +24,9 @@ impl<Fut1, Fut2> TryFlatten<Fut1, Fut2> { } impl<Fut> FusedFuture for TryFlatten<Fut, Fut::Ok> - where Fut: TryFuture, - Fut::Ok: TryFuture<Error=Fut::Error>, +where + Fut: TryFuture, + Fut::Ok: TryFuture<Error = Fut::Error>, { fn is_terminated(&self) -> bool { match self { @@ -36,28 +37,27 @@ impl<Fut> FusedFuture for TryFlatten<Fut, Fut::Ok> } impl<Fut> Future for TryFlatten<Fut, Fut::Ok> - where Fut: TryFuture, - Fut::Ok: TryFuture<Error=Fut::Error>, +where + Fut: TryFuture, + Fut::Ok: TryFuture<Error = Fut::Error>, { type Output = Result<<Fut::Ok as TryFuture>::Ok, Fut::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(loop { match self.as_mut().project() { - TryFlattenProj::First { f } => { - match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Err(e); - } + TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { + Ok(f) => self.set(Self::Second { f }), + Err(e) => { + self.set(Self::Empty); + break Err(e); } }, TryFlattenProj::Second { f } => { let output = ready!(f.try_poll(cx)); self.set(Self::Empty); break output; - }, + } TryFlattenProj::Empty => panic!("TryFlatten polled after completion"), } }) @@ -65,8 +65,9 @@ impl<Fut> Future for TryFlatten<Fut, Fut::Ok> } impl<Fut> FusedStream for TryFlatten<Fut, Fut::Ok> - where Fut: TryFuture, - Fut::Ok: TryStream<Error=Fut::Error>, +where + Fut: TryFuture, + Fut::Ok: TryStream<Error = Fut::Error>, { fn is_terminated(&self) -> bool { match self { @@ -77,21 +78,20 @@ impl<Fut> FusedStream for TryFlatten<Fut, Fut::Ok> } impl<Fut> Stream for TryFlatten<Fut, Fut::Ok> - where Fut: TryFuture, - Fut::Ok: TryStream<Error=Fut::Error>, +where + Fut: TryFuture, + Fut::Ok: TryStream<Error = Fut::Error>, { type Item = Result<<Fut::Ok as TryStream>::Ok, Fut::Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { Poll::Ready(loop { match self.as_mut().project() { - TryFlattenProj::First { f } => { - match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Some(Err(e)); - } + TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { + Ok(f) => self.set(Self::Second { f }), + Err(e) => { + self.set(Self::Empty); + break Some(Err(e)); } }, TryFlattenProj::Second { f } => { @@ -100,40 +100,34 @@ impl<Fut> Stream for TryFlatten<Fut, Fut::Ok> self.set(Self::Empty); } break output; - }, + } TryFlattenProj::Empty => break None, } }) } } - #[cfg(feature = "sink")] impl<Fut, Item> Sink<Item> for TryFlatten<Fut, Fut::Ok> where Fut: TryFuture, - Fut::Ok: Sink<Item, Error=Fut::Error>, + Fut::Ok: Sink<Item, Error = Fut::Error>, { type Error = Fut::Error; - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(loop { match self.as_mut().project() { - TryFlattenProj::First { f } => { - match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Err(e); - } + TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { + Ok(f) => self.set(Self::Second { f }), + Err(e) => { + self.set(Self::Empty); + break Err(e); } }, TryFlattenProj::Second { f } => { break ready!(f.poll_ready(cx)); - }, + } TryFlattenProj::Empty => panic!("poll_ready called after eof"), } }) @@ -155,10 +149,7 @@ where } } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { let res = match self.as_mut().project() { TryFlattenProj::Second { f } => f.poll_close(cx), _ => Poll::Ready(Ok(())), diff --git a/src/future/try_future/try_flatten_err.rs b/src/future/try_future/try_flatten_err.rs index 2e67f11..39b7d9f 100644 --- a/src/future/try_future/try_flatten_err.rs +++ b/src/future/try_future/try_flatten_err.rs @@ -21,8 +21,9 @@ impl<Fut1, Fut2> TryFlattenErr<Fut1, Fut2> { } impl<Fut> FusedFuture for TryFlattenErr<Fut, Fut::Error> - where Fut: TryFuture, - Fut::Error: TryFuture<Ok=Fut::Ok>, +where + Fut: TryFuture, + Fut::Error: TryFuture<Ok = Fut::Ok>, { fn is_terminated(&self) -> bool { match self { @@ -33,28 +34,27 @@ impl<Fut> FusedFuture for TryFlattenErr<Fut, Fut::Error> } impl<Fut> Future for TryFlattenErr<Fut, Fut::Error> - where Fut: TryFuture, - Fut::Error: TryFuture<Ok=Fut::Ok>, +where + Fut: TryFuture, + Fut::Error: TryFuture<Ok = Fut::Ok>, { type Output = Result<Fut::Ok, <Fut::Error as TryFuture>::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(loop { match self.as_mut().project() { - TryFlattenErrProj::First { f } => { - match ready!(f.try_poll(cx)) { - Err(f) => self.set(Self::Second { f }), - Ok(e) => { - self.set(Self::Empty); - break Ok(e); - } + TryFlattenErrProj::First { f } => match ready!(f.try_poll(cx)) { + Err(f) => self.set(Self::Second { f }), + Ok(e) => { + self.set(Self::Empty); + break Ok(e); } }, TryFlattenErrProj::Second { f } => { let output = ready!(f.try_poll(cx)); self.set(Self::Empty); break output; - }, + } TryFlattenErrProj::Empty => panic!("TryFlattenErr polled after completion"), } }) diff --git a/src/future/try_join_all.rs b/src/future/try_join_all.rs index 371f753..29244af 100644 --- a/src/future/try_join_all.rs +++ b/src/future/try_join_all.rs @@ -1,14 +1,14 @@ //! Definition of the `TryJoinAll` combinator, waiting for all of a list of //! futures to finish with either success or error. +use alloc::boxed::Box; +use alloc::vec::Vec; use core::fmt; use core::future::Future; use core::iter::FromIterator; use core::mem; use core::pin::Pin; use core::task::{Context, Poll}; -use alloc::boxed::Box; -use alloc::vec::Vec; use super::{assert_future, TryFuture, TryMaybeDone}; @@ -16,15 +16,13 @@ fn iter_pin_mut<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> { // Safety: `std` _could_ make this unsound if it were to decide Pin's // invariants aren't required to transmit through slices. Otherwise this has // the same safety as a normal field pin projection. - unsafe { slice.get_unchecked_mut() } - .iter_mut() - .map(|t| unsafe { Pin::new_unchecked(t) }) + unsafe { slice.get_unchecked_mut() }.iter_mut().map(|t| unsafe { Pin::new_unchecked(t) }) } enum FinalState<E = ()> { Pending, AllDone, - Error(E) + Error(E), } /// Future for the [`try_join_all`] function. @@ -43,9 +41,7 @@ where F::Error: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryJoinAll") - .field("elems", &self.elems) - .finish() + f.debug_struct("TryJoinAll").field("elems", &self.elems).finish() } } @@ -93,9 +89,9 @@ where I::Item: TryFuture, { let elems: Box<[_]> = i.into_iter().map(TryMaybeDone::Future).collect(); - assert_future::<Result<Vec<<I::Item as TryFuture>::Ok>, <I::Item as TryFuture>::Error>, _>(TryJoinAll { - elems: elems.into(), - }) + assert_future::<Result<Vec<<I::Item as TryFuture>::Ok>, <I::Item as TryFuture>::Error>, _>( + TryJoinAll { elems: elems.into() }, + ) } impl<F> Future for TryJoinAll<F> @@ -110,7 +106,7 @@ where for elem in iter_pin_mut(self.elems.as_mut()) { match elem.try_poll(cx) { Poll::Pending => state = FinalState::Pending, - Poll::Ready(Ok(())) => {}, + Poll::Ready(Ok(())) => {} Poll::Ready(Err(e)) => { state = FinalState::Error(e); break; @@ -122,15 +118,14 @@ where FinalState::Pending => Poll::Pending, FinalState::AllDone => { let mut elems = mem::replace(&mut self.elems, Box::pin([])); - let results = iter_pin_mut(elems.as_mut()) - .map(|e| e.take_output().unwrap()) - .collect(); + let results = + iter_pin_mut(elems.as_mut()).map(|e| e.take_output().unwrap()).collect(); Poll::Ready(Ok(results)) - }, + } FinalState::Error(e) => { let _ = mem::replace(&mut self.elems, Box::pin([])); Poll::Ready(Err(e)) - }, + } } } } diff --git a/src/future/try_maybe_done.rs b/src/future/try_maybe_done.rs index dfd2900..24044d2 100644 --- a/src/future/try_maybe_done.rs +++ b/src/future/try_maybe_done.rs @@ -49,13 +49,13 @@ impl<Fut: TryFuture> TryMaybeDone<Fut> { #[inline] pub fn take_output(self: Pin<&mut Self>) -> Option<Fut::Ok> { match &*self { - Self::Done(_) => {}, + Self::Done(_) => {} Self::Future(_) | Self::Gone => return None, } unsafe { match mem::replace(self.get_unchecked_mut(), Self::Gone) { TryMaybeDone::Done(output) => Some(output), - _ => unreachable!() + _ => unreachable!(), } } } @@ -76,16 +76,14 @@ impl<Fut: TryFuture> Future for TryMaybeDone<Fut> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { unsafe { match self.as_mut().get_unchecked_mut() { - TryMaybeDone::Future(f) => { - match ready!(Pin::new_unchecked(f).try_poll(cx)) { - Ok(res) => self.set(Self::Done(res)), - Err(e) => { - self.set(Self::Gone); - return Poll::Ready(Err(e)); - } + TryMaybeDone::Future(f) => match ready!(Pin::new_unchecked(f).try_poll(cx)) { + Ok(res) => self.set(Self::Done(res)), + Err(e) => { + self.set(Self::Gone); + return Poll::Ready(Err(e)); } }, - TryMaybeDone::Done(_) => {}, + TryMaybeDone::Done(_) => {} TryMaybeDone::Gone => panic!("TryMaybeDone polled after value taken"), } } diff --git a/src/future/try_select.rs b/src/future/try_select.rs index b26eed3..4d0b7ff 100644 --- a/src/future/try_select.rs +++ b/src/future/try_select.rs @@ -1,7 +1,7 @@ +use crate::future::{Either, TryFutureExt}; use core::pin::Pin; use futures_core::future::{Future, TryFuture}; use futures_core::task::{Context, Poll}; -use crate::future::{Either, TryFutureExt}; /// Future for the [`try_select()`] function. #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -48,22 +48,23 @@ impl<A: Unpin, B: Unpin> Unpin for TrySelect<A, B> {} /// } /// ``` pub fn try_select<A, B>(future1: A, future2: B) -> TrySelect<A, B> - where A: TryFuture + Unpin, B: TryFuture + Unpin +where + A: TryFuture + Unpin, + B: TryFuture + Unpin, { - super::assert_future::<Result< - Either<(A::Ok, B), (B::Ok, A)>, - Either<(A::Error, B), (B::Error, A)>, - >, _>(TrySelect { inner: Some((future1, future2)) }) + super::assert_future::< + Result<Either<(A::Ok, B), (B::Ok, A)>, Either<(A::Error, B), (B::Error, A)>>, + _, + >(TrySelect { inner: Some((future1, future2)) }) } impl<A: Unpin, B: Unpin> Future for TrySelect<A, B> - where A: TryFuture, B: TryFuture +where + A: TryFuture, + B: TryFuture, { #[allow(clippy::type_complexity)] - type Output = Result< - Either<(A::Ok, B), (B::Ok, A)>, - Either<(A::Error, B), (B::Error, A)>, - >; + type Output = Result<Either<(A::Ok, B), (B::Ok, A)>, Either<(A::Error, B), (B::Error, A)>>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice"); @@ -77,7 +78,7 @@ impl<A: Unpin, B: Unpin> Future for TrySelect<A, B> self.inner = Some((a, b)); Poll::Pending } - } + }, } } } diff --git a/src/io/allow_std.rs b/src/io/allow_std.rs index 9aa8eb4..ec30ee3 100644 --- a/src/io/allow_std.rs +++ b/src/io/allow_std.rs @@ -1,9 +1,7 @@ use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; -use futures_io::{AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead, IoSlice, IoSliceMut, SeekFrom}; -use std::{fmt, io}; +use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, SeekFrom}; use std::pin::Pin; +use std::{fmt, io}; /// A simple wrapper type which allows types which implement only /// implement `std::io::Read` or `std::io::Write` @@ -35,7 +33,7 @@ macro_rules! try_with_interrupt { } } } - } + }; } impl<T> AllowStdIo<T> { @@ -60,7 +58,10 @@ impl<T> AllowStdIo<T> { } } -impl<T> io::Write for AllowStdIo<T> where T: io::Write { +impl<T> io::Write for AllowStdIo<T> +where + T: io::Write, +{ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -78,16 +79,23 @@ impl<T> io::Write for AllowStdIo<T> where T: io::Write { } } -impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write { - fn poll_write(mut self: Pin<&mut Self>, _: &mut Context<'_>, buf: &[u8]) - -> Poll<io::Result<usize>> - { +impl<T> AsyncWrite for AllowStdIo<T> +where + T: io::Write, +{ + fn poll_write( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { Poll::Ready(Ok(try_with_interrupt!(self.0.write(buf)))) } - fn poll_write_vectored(mut self: Pin<&mut Self>, _: &mut Context<'_>, bufs: &[IoSlice<'_>]) - -> Poll<io::Result<usize>> - { + fn poll_write_vectored( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll<io::Result<usize>> { Poll::Ready(Ok(try_with_interrupt!(self.0.write_vectored(bufs)))) } @@ -101,17 +109,16 @@ impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write { } } -impl<T> io::Read for AllowStdIo<T> where T: io::Read { +impl<T> io::Read for AllowStdIo<T> +where + T: io::Read, +{ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - self.0.initializer() - } fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { self.0.read_to_end(buf) } @@ -123,40 +130,53 @@ impl<T> io::Read for AllowStdIo<T> where T: io::Read { } } -impl<T> AsyncRead for AllowStdIo<T> where T: io::Read { - fn poll_read(mut self: Pin<&mut Self>, _: &mut Context<'_>, buf: &mut [u8]) - -> Poll<io::Result<usize>> - { +impl<T> AsyncRead for AllowStdIo<T> +where + T: io::Read, +{ + fn poll_read( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + buf: &mut [u8], + ) -> Poll<io::Result<usize>> { Poll::Ready(Ok(try_with_interrupt!(self.0.read(buf)))) } - fn poll_read_vectored(mut self: Pin<&mut Self>, _: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>]) - -> Poll<io::Result<usize>> - { + fn poll_read_vectored( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + bufs: &mut [IoSliceMut<'_>], + ) -> Poll<io::Result<usize>> { Poll::Ready(Ok(try_with_interrupt!(self.0.read_vectored(bufs)))) } - - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - self.0.initializer() - } } -impl<T> io::Seek for AllowStdIo<T> where T: io::Seek { +impl<T> io::Seek for AllowStdIo<T> +where + T: io::Seek, +{ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.0.seek(pos) } } -impl<T> AsyncSeek for AllowStdIo<T> where T: io::Seek { - fn poll_seek(mut self: Pin<&mut Self>, _: &mut Context<'_>, pos: SeekFrom) - -> Poll<io::Result<u64>> - { +impl<T> AsyncSeek for AllowStdIo<T> +where + T: io::Seek, +{ + fn poll_seek( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + pos: SeekFrom, + ) -> Poll<io::Result<u64>> { Poll::Ready(Ok(try_with_interrupt!(self.0.seek(pos)))) } } -impl<T> io::BufRead for AllowStdIo<T> where T: io::BufRead { +impl<T> io::BufRead for AllowStdIo<T> +where + T: io::BufRead, +{ fn fill_buf(&mut self) -> io::Result<&[u8]> { self.0.fill_buf() } @@ -165,10 +185,11 @@ impl<T> io::BufRead for AllowStdIo<T> where T: io::BufRead { } } -impl<T> AsyncBufRead for AllowStdIo<T> where T: io::BufRead { - fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) - -> Poll<io::Result<&[u8]>> - { +impl<T> AsyncBufRead for AllowStdIo<T> +where + T: io::BufRead, +{ + fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<&[u8]>> { let this: *mut Self = &mut *self as *mut _; Poll::Ready(Ok(try_with_interrupt!(unsafe { &mut *this }.0.fill_buf()))) } diff --git a/src/io/buf_reader.rs b/src/io/buf_reader.rs index 270a086..0334a9f 100644 --- a/src/io/buf_reader.rs +++ b/src/io/buf_reader.rs @@ -1,13 +1,12 @@ +use super::DEFAULT_BUF_SIZE; +use futures_core::future::Future; use futures_core::ready; use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSliceMut, SeekFrom}; use pin_project_lite::pin_project; use std::io::{self, Read}; use std::pin::Pin; use std::{cmp, fmt}; -use super::DEFAULT_BUF_SIZE; pin_project! { /// The `BufReader` struct adds buffering to any reader. @@ -51,12 +50,7 @@ impl<R: AsyncRead> BufReader<R> { let mut buffer = Vec::with_capacity(capacity); buffer.set_len(capacity); super::initialize(&inner, &mut buffer); - Self { - inner, - buffer: buffer.into_boxed_slice(), - pos: 0, - cap: 0, - } + Self { inner, buffer: buffer.into_boxed_slice(), pos: 0, cap: 0 } } } @@ -78,6 +72,40 @@ impl<R: AsyncRead> BufReader<R> { } } +impl<R: AsyncRead + AsyncSeek> BufReader<R> { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + pub fn seek_relative(self: Pin<&mut Self>, offset: i64) -> SeeKRelative<'_, R> { + SeeKRelative { inner: self, offset, first: true } + } + + /// Attempts to seek relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + pub fn poll_seek_relative( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + offset: i64, + ) -> Poll<io::Result<()>> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + *self.project().pos = new_pos as usize; + return Poll::Ready(Ok(())); + } + } else if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + *self.project().pos = new_pos as usize; + return Poll::Ready(Ok(())); + } + } + self.poll_seek(cx, SeekFrom::Current(offset)).map(|res| res.map(|_| ())) + } +} + impl<R: AsyncRead> AsyncRead for BufReader<R> { fn poll_read( mut self: Pin<&mut Self>, @@ -114,19 +142,10 @@ impl<R: AsyncRead> AsyncRead for BufReader<R> { self.consume(nread); Poll::Ready(Ok(nread)) } - - // we can't skip unconditionally because of the large buffer case in read. - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } } impl<R: AsyncRead> AsyncBufRead for BufReader<R> { - fn poll_fill_buf( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<io::Result<&[u8]>> { + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> { let this = self.project(); // If we've reached the end of our internal buffer then we need to fetch @@ -171,6 +190,10 @@ impl<R: AsyncRead + AsyncSeek> AsyncSeek for BufReader<R> { /// `.into_inner()` immediately after a seek yields the underlying reader /// at the same position. /// + /// To seek without discarding the internal buffer, use + /// [`BufReader::seek_relative`](BufReader::seek_relative) or + /// [`BufReader::poll_seek_relative`](BufReader::poll_seek_relative). + /// /// See [`AsyncSeek`](futures_io::AsyncSeek) for more details. /// /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` @@ -192,7 +215,8 @@ impl<R: AsyncRead + AsyncSeek> AsyncSeek for BufReader<R> { // support seeking by i64::min_value() so we need to handle underflow when subtracting // remainder. if let Some(offset) = n.checked_sub(remainder) { - result = ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(offset)))?; + result = + ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(offset)))?; } else { // seek backwards by our remainder, and then by the offset ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(-remainder)))?; @@ -207,3 +231,33 @@ impl<R: AsyncRead + AsyncSeek> AsyncSeek for BufReader<R> { Poll::Ready(Ok(result)) } } + +/// Future for the [`BufReader::seek_relative`](self::BufReader::seek_relative) method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct SeeKRelative<'a, R> { + inner: Pin<&'a mut BufReader<R>>, + offset: i64, + first: bool, +} + +impl<R> Future for SeeKRelative<'_, R> +where + R: AsyncRead + AsyncSeek, +{ + type Output = io::Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + let offset = self.offset; + if self.first { + self.first = false; + self.inner.as_mut().poll_seek_relative(cx, offset) + } else { + self.inner + .as_mut() + .as_mut() + .poll_seek(cx, SeekFrom::Current(offset)) + .map(|res| res.map(|_| ())) + } + } +} diff --git a/src/io/buf_writer.rs b/src/io/buf_writer.rs index 991a365..cb74863 100644 --- a/src/io/buf_writer.rs +++ b/src/io/buf_writer.rs @@ -1,3 +1,4 @@ +use super::DEFAULT_BUF_SIZE; use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, SeekFrom}; @@ -5,7 +6,7 @@ use pin_project_lite::pin_project; use std::fmt; use std::io::{self, Write}; use std::pin::Pin; -use super::DEFAULT_BUF_SIZE; +use std::ptr; pin_project! { /// Wraps a writer and buffers its output. @@ -46,14 +47,10 @@ impl<W: AsyncWrite> BufWriter<W> { /// Creates a new `BufWriter` with the specified buffer capacity. pub fn with_capacity(cap: usize, inner: W) -> Self { - Self { - inner, - buf: Vec::with_capacity(cap), - written: 0, - } + Self { inner, buf: Vec::with_capacity(cap), written: 0 } } - fn flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + pub(super) fn flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { let mut this = self.project(); let len = this.buf.len(); @@ -87,6 +84,68 @@ impl<W: AsyncWrite> BufWriter<W> { pub fn buffer(&self) -> &[u8] { &self.buf } + + /// Capacity of `buf`. how many chars can be held in buffer + pub(super) fn capacity(&self) -> usize { + self.buf.capacity() + } + + /// Remaining number of bytes to reach `buf` 's capacity + #[inline] + pub(super) fn spare_capacity(&self) -> usize { + self.buf.capacity() - self.buf.len() + } + + /// Write a byte slice directly into buffer + /// + /// Will truncate the number of bytes written to `spare_capacity()` so you want to + /// calculate the size of your slice to avoid losing bytes + /// + /// Based on `std::io::BufWriter` + pub(super) fn write_to_buf(self: Pin<&mut Self>, buf: &[u8]) -> usize { + let available = self.spare_capacity(); + let amt_to_buffer = available.min(buf.len()); + + // SAFETY: `amt_to_buffer` is <= buffer's spare capacity by construction. + unsafe { + self.write_to_buffer_unchecked(&buf[..amt_to_buffer]); + } + + amt_to_buffer + } + + /// Write byte slice directly into `self.buf` + /// + /// Based on `std::io::BufWriter` + #[inline] + unsafe fn write_to_buffer_unchecked(self: Pin<&mut Self>, buf: &[u8]) { + debug_assert!(buf.len() <= self.spare_capacity()); + let this = self.project(); + let old_len = this.buf.len(); + let buf_len = buf.len(); + let src = buf.as_ptr(); + let dst = this.buf.as_mut_ptr().add(old_len); + ptr::copy_nonoverlapping(src, dst, buf_len); + this.buf.set_len(old_len + buf_len); + } + + /// Write directly using `inner`, bypassing buffering + pub(super) fn inner_poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { + self.project().inner.poll_write(cx, buf) + } + + /// Write directly using `inner`, bypassing buffering + pub(super) fn inner_poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll<io::Result<usize>> { + self.project().inner.poll_write_vectored(cx, bufs) + } } impl<W: AsyncWrite> AsyncWrite for BufWriter<W> { diff --git a/src/io/chain.rs b/src/io/chain.rs index 1b6a335..728a3d2 100644 --- a/src/io/chain.rs +++ b/src/io/chain.rs @@ -1,7 +1,5 @@ use futures_core::ready; use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; use futures_io::{AsyncBufRead, AsyncRead, IoSliceMut}; use pin_project_lite::pin_project; use std::fmt; @@ -26,11 +24,7 @@ where U: AsyncRead, { pub(super) fn new(first: T, second: U) -> Self { - Self { - first, - second, - done_first: false, - } + Self { first, second, done_first: false } } /// Gets references to the underlying readers in this `Chain`. @@ -115,16 +109,6 @@ where } this.second.poll_read_vectored(cx, bufs) } - - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - let initializer = self.first.initializer(); - if initializer.should_initialize() { - initializer - } else { - self.second.initializer() - } - } } impl<T, U> AsyncBufRead for Chain<T, U> diff --git a/src/io/copy.rs b/src/io/copy.rs index bc59255..c80add2 100644 --- a/src/io/copy.rs +++ b/src/io/copy.rs @@ -1,10 +1,10 @@ +use super::{copy_buf, BufReader, CopyBuf}; use futures_core::future::Future; use futures_core::task::{Context, Poll}; use futures_io::{AsyncRead, AsyncWrite}; +use pin_project_lite::pin_project; use std::io; use std::pin::Pin; -use super::{BufReader, copy_buf, CopyBuf}; -use pin_project_lite::pin_project; /// Creates a future which copies all the bytes from one object to another. /// @@ -36,9 +36,7 @@ where R: AsyncRead, W: AsyncWrite + Unpin + ?Sized, { - Copy { - inner: copy_buf(BufReader::new(reader), writer), - } + Copy { inner: copy_buf(BufReader::new(reader), writer) } } pin_project! { diff --git a/src/io/copy_buf.rs b/src/io/copy_buf.rs index 6adf594..50f7abd 100644 --- a/src/io/copy_buf.rs +++ b/src/io/copy_buf.rs @@ -2,9 +2,9 @@ use futures_core::future::Future; use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::{AsyncBufRead, AsyncWrite}; +use pin_project_lite::pin_project; use std::io; use std::pin::Pin; -use pin_project_lite::pin_project; /// Creates a future which copies all the bytes from one object to another. /// @@ -36,11 +36,7 @@ where R: AsyncBufRead, W: AsyncWrite + Unpin + ?Sized, { - CopyBuf { - reader, - writer, - amt: 0, - } + CopyBuf { reader, writer, amt: 0 } } pin_project! { @@ -56,8 +52,9 @@ pin_project! { } impl<R, W> Future for CopyBuf<'_, R, W> - where R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, +where + R: AsyncBufRead, + W: AsyncWrite + Unpin + ?Sized, { type Output = io::Result<u64>; @@ -72,7 +69,7 @@ impl<R, W> Future for CopyBuf<'_, R, W> let i = ready!(Pin::new(&mut this.writer).poll_write(cx, buffer))?; if i == 0 { - return Poll::Ready(Err(io::ErrorKind::WriteZero.into())) + return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); } *this.amt += i as u64; this.reader.as_mut().consume(i); diff --git a/src/io/cursor.rs b/src/io/cursor.rs index 084fb08..b6fb372 100644 --- a/src/io/cursor.rs +++ b/src/io/cursor.rs @@ -43,9 +43,7 @@ impl<T> Cursor<T> { /// # force_inference(&buff); /// ``` pub fn new(inner: T) -> Self { - Self { - inner: io::Cursor::new(inner), - } + Self { inner: io::Cursor::new(inner) } } /// Consumes this cursor, returning the underlying value. @@ -199,15 +197,19 @@ where macro_rules! delegate_async_write_to_stdio { () => { - fn poll_write(mut self: Pin<&mut Self>, _: &mut Context<'_>, buf: &[u8]) - -> Poll<io::Result<usize>> - { + fn poll_write( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { Poll::Ready(io::Write::write(&mut self.inner, buf)) } - fn poll_write_vectored(mut self: Pin<&mut Self>, _: &mut Context<'_>, bufs: &[IoSlice<'_>]) - -> Poll<io::Result<usize>> - { + fn poll_write_vectored( + mut self: Pin<&mut Self>, + _: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll<io::Result<usize>> { Poll::Ready(io::Write::write_vectored(&mut self.inner, bufs)) } @@ -218,7 +220,7 @@ macro_rules! delegate_async_write_to_stdio { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { self.poll_flush(cx) } - } + }; } impl AsyncWrite for Cursor<&mut [u8]> { diff --git a/src/io/empty.rs b/src/io/empty.rs index ab2395a..02f6103 100644 --- a/src/io/empty.rs +++ b/src/io/empty.rs @@ -1,6 +1,4 @@ use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; use futures_io::{AsyncBufRead, AsyncRead}; use std::fmt; use std::io; @@ -43,12 +41,6 @@ impl AsyncRead for Empty { ) -> Poll<io::Result<usize>> { Poll::Ready(Ok(0)) } - - #[cfg(feature = "read-initializer")] - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } impl AsyncBufRead for Empty { diff --git a/src/io/fill_buf.rs b/src/io/fill_buf.rs index 6fb3ec7..a1484c0 100644 --- a/src/io/fill_buf.rs +++ b/src/io/fill_buf.rs @@ -20,7 +20,8 @@ impl<'a, R: AsyncBufRead + ?Sized + Unpin> FillBuf<'a, R> { } impl<'a, R> Future for FillBuf<'a, R> - where R: AsyncBufRead + ?Sized + Unpin, +where + R: AsyncBufRead + ?Sized + Unpin, { type Output = io::Result<&'a [u8]>; @@ -29,7 +30,7 @@ impl<'a, R> Future for FillBuf<'a, R> let reader = this.reader.take().expect("Polled FillBuf after completion"); match Pin::new(&mut *reader).poll_fill_buf(cx) { - // With polinius it is possible to remove this inner match and just have the correct + // With polonius it is possible to remove this inner match and just have the correct // lifetime of the reference inferred based on which branch is taken Poll::Ready(Ok(_)) => match Pin::new(reader).poll_fill_buf(cx) { Poll::Ready(Ok(slice)) => Poll::Ready(Ok(slice)), diff --git a/src/io/flush.rs b/src/io/flush.rs index ece0a7c..b75d14c 100644 --- a/src/io/flush.rs +++ b/src/io/flush.rs @@ -20,7 +20,8 @@ impl<'a, W: AsyncWrite + ?Sized + Unpin> Flush<'a, W> { } impl<W> Future for Flush<'_, W> - where W: AsyncWrite + ?Sized + Unpin, +where + W: AsyncWrite + ?Sized + Unpin, { type Output = io::Result<()>; diff --git a/src/io/into_sink.rs b/src/io/into_sink.rs index 885ba2f..6a41ee2 100644 --- a/src/io/into_sink.rs +++ b/src/io/into_sink.rs @@ -2,9 +2,9 @@ use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::AsyncWrite; use futures_sink::Sink; +use pin_project_lite::pin_project; use std::io; use std::pin::Pin; -use pin_project_lite::pin_project; #[derive(Debug)] struct Block<Item> { @@ -36,8 +36,7 @@ impl<W: AsyncWrite, Item: AsRef<[u8]>> IntoSink<W, Item> { fn poll_flush_buffer( self: Pin<&mut Self>, cx: &mut Context<'_>, - ) -> Poll<Result<(), io::Error>> - { + ) -> Poll<Result<(), io::Error>> { let mut this = self.project(); if let Some(buffer) = this.buffer { @@ -53,47 +52,29 @@ impl<W: AsyncWrite, Item: AsRef<[u8]>> IntoSink<W, Item> { *this.buffer = None; Poll::Ready(Ok(())) } - } impl<W: AsyncWrite, Item: AsRef<[u8]>> Sink<Item> for IntoSink<W, Item> { type Error = io::Error; - fn poll_ready( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> - { + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.poll_flush_buffer(cx))?; Poll::Ready(Ok(())) } - #[allow(clippy::debug_assert_with_mut_call)] - fn start_send( - self: Pin<&mut Self>, - item: Item, - ) -> Result<(), Self::Error> - { + fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { debug_assert!(self.buffer.is_none()); *self.project().buffer = Some(Block { offset: 0, bytes: item }); Ok(()) } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> - { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().poll_flush_buffer(cx))?; ready!(self.project().writer.poll_flush(cx))?; Poll::Ready(Ok(())) } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> - { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().poll_flush_buffer(cx))?; ready!(self.project().writer.poll_close(cx))?; Poll::Ready(Ok(())) diff --git a/src/io/line_writer.rs b/src/io/line_writer.rs new file mode 100644 index 0000000..71cd668 --- /dev/null +++ b/src/io/line_writer.rs @@ -0,0 +1,155 @@ +use super::buf_writer::BufWriter; +use futures_core::ready; +use futures_core::task::{Context, Poll}; +use futures_io::AsyncWrite; +use futures_io::IoSlice; +use pin_project_lite::pin_project; +use std::io; +use std::pin::Pin; + +pin_project! { +/// Wrap a writer, like [`BufWriter`] does, but prioritizes buffering lines +/// +/// This was written based on `std::io::LineWriter` which goes into further details +/// explaining the code. +/// +/// Buffering is actually done using `BufWriter`. This class will leverage `BufWriter` +/// to write on-each-line. +#[derive(Debug)] +pub struct LineWriter<W: AsyncWrite> { + #[pin] + buf_writer: BufWriter<W>, +} +} + +impl<W: AsyncWrite> LineWriter<W> { + /// Create a new `LineWriter` with default buffer capacity. The default is currently 1KB + /// which was taken from `std::io::LineWriter` + pub fn new(inner: W) -> LineWriter<W> { + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with the specified buffer capacity. + pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> { + LineWriter { buf_writer: BufWriter::with_capacity(capacity, inner) } + } + + /// Flush `buf_writer` if last char is "new line" + fn flush_if_completed_line(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + let this = self.project(); + match this.buf_writer.buffer().last().copied() { + Some(b'\n') => this.buf_writer.flush_buf(cx), + _ => Poll::Ready(Ok(())), + } + } + + /// Returns a reference to `buf_writer`'s internally buffered data. + pub fn buffer(&self) -> &[u8] { + self.buf_writer.buffer() + } + + /// Acquires a reference to the underlying sink or stream that this combinator is + /// pulling from. + pub fn get_ref(&self) -> &W { + self.buf_writer.get_ref() + } +} + +impl<W: AsyncWrite> AsyncWrite for LineWriter<W> { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { + let mut this = self.as_mut().project(); + let newline_index = match memchr::memrchr(b'\n', buf) { + None => { + ready!(self.as_mut().flush_if_completed_line(cx)?); + return self.project().buf_writer.poll_write(cx, buf); + } + Some(newline_index) => newline_index + 1, + }; + + ready!(this.buf_writer.as_mut().poll_flush(cx)?); + + let lines = &buf[..newline_index]; + + let flushed = { ready!(this.buf_writer.as_mut().inner_poll_write(cx, lines))? }; + + if flushed == 0 { + return Poll::Ready(Ok(0)); + } + + let tail = if flushed >= newline_index { + &buf[flushed..] + } else if newline_index - flushed <= this.buf_writer.capacity() { + &buf[flushed..newline_index] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..this.buf_writer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_index) => &scan_area[..newline_index + 1], + None => scan_area, + } + }; + + let buffered = this.buf_writer.as_mut().write_to_buf(tail); + Poll::Ready(Ok(flushed + buffered)) + } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll<io::Result<usize>> { + let mut this = self.as_mut().project(); + // `is_write_vectored()` is handled in original code, but not in this crate + // see https://github.com/rust-lang/rust/issues/70436 + + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + let last_newline_buf_idx = match last_newline_buf_idx { + None => { + ready!(self.as_mut().flush_if_completed_line(cx)?); + return self.project().buf_writer.poll_write_vectored(cx, bufs); + } + Some(i) => i, + }; + + ready!(this.buf_writer.as_mut().poll_flush(cx)?); + + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + let flushed = { ready!(this.buf_writer.as_mut().inner_poll_write_vectored(cx, lines))? }; + if flushed == 0 { + return Poll::Ready(Ok(0)); + } + + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Poll::Ready(Ok(flushed)); + } + + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| this.buf_writer.as_mut().write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Poll::Ready(Ok(flushed + buffered)) + } + + /// Forward to `buf_writer` 's `BufWriter::poll_flush()` + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + self.as_mut().project().buf_writer.poll_flush(cx) + } + + /// Forward to `buf_writer` 's `BufWriter::poll_close()` + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + self.as_mut().project().buf_writer.poll_close(cx) + } +} diff --git a/src/io/lines.rs b/src/io/lines.rs index 6ae7392..13e70df 100644 --- a/src/io/lines.rs +++ b/src/io/lines.rs @@ -1,12 +1,12 @@ +use super::read_line::read_line_internal; use futures_core::ready; use futures_core::stream::Stream; use futures_core::task::{Context, Poll}; use futures_io::AsyncBufRead; +use pin_project_lite::pin_project; use std::io; use std::mem; use std::pin::Pin; -use super::read_line::read_line_internal; -use pin_project_lite::pin_project; pin_project! { /// Stream for the [`lines`](super::AsyncBufReadExt::lines) method. @@ -23,12 +23,7 @@ pin_project! { impl<R: AsyncBufRead> Lines<R> { pub(super) fn new(reader: R) -> Self { - Self { - reader, - buf: String::new(), - bytes: Vec::new(), - read: 0, - } + Self { reader, buf: String::new(), bytes: Vec::new(), read: 0 } } } @@ -39,7 +34,7 @@ impl<R: AsyncBufRead> Stream for Lines<R> { let this = self.project(); let n = ready!(read_line_internal(this.reader, cx, this.buf, this.bytes, this.read))?; if n == 0 && this.buf.is_empty() { - return Poll::Ready(None) + return Poll::Ready(None); } if this.buf.ends_with('\n') { this.buf.pop(); diff --git a/src/io/mod.rs b/src/io/mod.rs index 1437930..4dd2e02 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -21,18 +21,14 @@ use crate::compat::Compat; use crate::future::assert_future; use crate::stream::assert_stream; -use std::{ptr, pin::Pin}; +use std::{pin::Pin, ptr}; // Re-export some types from `std::io` so that users don't have to deal // with conflicts when `use`ing `futures::io` and `std::io`. #[doc(no_inline)] pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom}; -#[doc(no_inline)] -#[cfg(feature = "read-initializer")] -#[cfg_attr(docsrs, doc(cfg(feature = "read-initializer")))] -pub use std::io::Initializer; -pub use futures_io::{AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead}; +pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; // used by `BufReader` and `BufWriter` // https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1 @@ -40,15 +36,9 @@ const DEFAULT_BUF_SIZE: usize = 8 * 1024; /// Initializes a buffer if necessary. /// -/// A buffer is always initialized if `read-initializer` feature is disabled. +/// A buffer is currently always initialized. #[inline] unsafe fn initialize<R: AsyncRead>(_reader: &R, buf: &mut [u8]) { - #[cfg(feature = "read-initializer")] - { - if !_reader.initializer().should_initialize() { - return; - } - } ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) } @@ -56,11 +46,14 @@ mod allow_std; pub use self::allow_std::AllowStdIo; mod buf_reader; -pub use self::buf_reader::BufReader; +pub use self::buf_reader::{BufReader, SeeKRelative}; mod buf_writer; pub use self::buf_writer::BufWriter; +mod line_writer; +pub use self::line_writer::LineWriter; + mod chain; pub use self::chain::Chain; @@ -126,7 +119,7 @@ mod sink; pub use self::sink::{sink, Sink}; mod split; -pub use self::split::{ReadHalf, WriteHalf, ReuniteError}; +pub use self::split::{ReadHalf, ReuniteError, WriteHalf}; mod take; pub use self::take::Take; @@ -206,7 +199,8 @@ pub trait AsyncReadExt: AsyncRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<usize>, _>(Read::new(self, buf)) } @@ -217,7 +211,8 @@ pub trait AsyncReadExt: AsyncRead { /// The returned future will resolve to the number of bytes read once the read /// operation is completed. fn read_vectored<'a>(&'a mut self, bufs: &'a mut [IoSliceMut<'a>]) -> ReadVectored<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<usize>, _>(ReadVectored::new(self, bufs)) } @@ -259,11 +254,9 @@ pub trait AsyncReadExt: AsyncRead { /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof); /// # }); /// ``` - fn read_exact<'a>( - &'a mut self, - buf: &'a mut [u8], - ) -> ReadExact<'a, Self> - where Self: Unpin, + fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> + where + Self: Unpin, { assert_future::<Result<()>, _>(ReadExact::new(self, buf)) } @@ -287,11 +280,9 @@ pub trait AsyncReadExt: AsyncRead { /// assert_eq!(output, vec![1, 2, 3, 4]); /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` - fn read_to_end<'a>( - &'a mut self, - buf: &'a mut Vec<u8>, - ) -> ReadToEnd<'a, Self> - where Self: Unpin, + fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self> + where + Self: Unpin, { assert_future::<Result<usize>, _>(ReadToEnd::new(self, buf)) } @@ -315,11 +306,9 @@ pub trait AsyncReadExt: AsyncRead { /// assert_eq!(buffer, String::from("1234")); /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` - fn read_to_string<'a>( - &'a mut self, - buf: &'a mut String, - ) -> ReadToString<'a, Self> - where Self: Unpin, + fn read_to_string<'a>(&'a mut self, buf: &'a mut String) -> ReadToString<'a, Self> + where + Self: Unpin, { assert_future::<Result<usize>, _>(ReadToString::new(self, buf)) } @@ -354,7 +343,8 @@ pub trait AsyncReadExt: AsyncRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>) - where Self: AsyncWrite + Sized, + where + Self: AsyncWrite + Sized, { let (r, w) = split::split(self); (assert_read(r), assert_write(w)) @@ -380,7 +370,8 @@ pub trait AsyncReadExt: AsyncRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn take(self, limit: u64) -> Take<Self> - where Self: Sized + where + Self: Sized, { assert_read(Take::new(self, limit)) } @@ -394,7 +385,8 @@ pub trait AsyncReadExt: AsyncRead { #[cfg(feature = "io-compat")] #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] fn compat(self) -> Compat<Self> - where Self: Sized + Unpin, + where + Self: Sized + Unpin, { Compat::new(self) } @@ -427,14 +419,16 @@ pub trait AsyncWriteExt: AsyncWrite { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn flush(&mut self) -> Flush<'_, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<()>, _>(Flush::new(self)) } /// Creates a future which will entirely close this `AsyncWrite`. fn close(&mut self) -> Close<'_, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<()>, _>(Close::new(self)) } @@ -444,7 +438,8 @@ pub trait AsyncWriteExt: AsyncWrite { /// The returned future will resolve to the number of bytes written once the write /// operation is completed. fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<usize>, _>(Write::new(self, buf)) } @@ -455,7 +450,8 @@ pub trait AsyncWriteExt: AsyncWrite { /// The returned future will resolve to the number of bytes written once the write /// operation is completed. fn write_vectored<'a>(&'a mut self, bufs: &'a [IoSlice<'a>]) -> WriteVectored<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<usize>, _>(WriteVectored::new(self, bufs)) } @@ -481,7 +477,8 @@ pub trait AsyncWriteExt: AsyncWrite { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<()>, _>(WriteAll::new(self, buf)) } @@ -547,7 +544,8 @@ pub trait AsyncWriteExt: AsyncWrite { #[cfg(feature = "io-compat")] #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] fn compat_write(self) -> Compat<Self> - where Self: Sized + Unpin, + where + Self: Sized + Unpin, { Compat::new(self) } @@ -581,7 +579,8 @@ pub trait AsyncWriteExt: AsyncWrite { #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] fn into_sink<Item: AsRef<[u8]>>(self) -> IntoSink<Self, Item> - where Self: Sized, + where + Self: Sized, { crate::sink::assert_sink::<Item, Error, _>(IntoSink::new(self)) } @@ -597,10 +596,22 @@ pub trait AsyncSeekExt: AsyncSeek { /// In the case of an error the buffer and the object will be discarded, with /// the error yielded. fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<u64>, _>(Seek::new(self, pos)) } + + /// Creates a future which will return the current seek position from the + /// start of the stream. + /// + /// This is equivalent to `self.seek(SeekFrom::Current(0))`. + fn stream_position(&mut self) -> Seek<'_, Self> + where + Self: Unpin, + { + self.seek(SeekFrom::Current(0)) + } } impl<S: AsyncSeek + ?Sized> AsyncSeekExt for S {} @@ -631,7 +642,8 @@ pub trait AsyncBufReadExt: AsyncBufRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn fill_buf(&mut self) -> FillBuf<'_, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<&[u8]>, _>(FillBuf::new(self)) } @@ -654,7 +666,8 @@ pub trait AsyncBufReadExt: AsyncBufRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn consume_unpin(&mut self, amt: usize) - where Self: Unpin, + where + Self: Unpin, { Pin::new(self).consume(amt) } @@ -700,12 +713,9 @@ pub trait AsyncBufReadExt: AsyncBufRead { /// assert_eq!(buf, b""); /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` - fn read_until<'a>( - &'a mut self, - byte: u8, - buf: &'a mut Vec<u8>, - ) -> ReadUntil<'a, Self> - where Self: Unpin, + fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntil<'a, Self> + where + Self: Unpin, { assert_future::<Result<usize>, _>(ReadUntil::new(self, byte, buf)) } @@ -762,7 +772,8 @@ pub trait AsyncBufReadExt: AsyncBufRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self> - where Self: Unpin, + where + Self: Unpin, { assert_future::<Result<usize>, _>(ReadLine::new(self, buf)) } @@ -800,7 +811,8 @@ pub trait AsyncBufReadExt: AsyncBufRead { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` fn lines(self) -> Lines<Self> - where Self: Sized, + where + Self: Sized, { assert_stream::<Result<String>, _>(Lines::new(self)) } diff --git a/src/io/read_exact.rs b/src/io/read_exact.rs index f2e0440..02e38c3 100644 --- a/src/io/read_exact.rs +++ b/src/io/read_exact.rs @@ -1,6 +1,6 @@ use crate::io::AsyncRead; -use futures_core::ready; use futures_core::future::Future; +use futures_core::ready; use futures_core::task::{Context, Poll}; use std::io; use std::mem; @@ -34,7 +34,7 @@ impl<R: AsyncRead + ?Sized + Unpin> Future for ReadExact<'_, R> { this.buf = rest; } if n == 0 { - return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into())) + return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into())); } } Poll::Ready(Ok(())) diff --git a/src/io/read_line.rs b/src/io/read_line.rs index d402c96..c75af94 100644 --- a/src/io/read_line.rs +++ b/src/io/read_line.rs @@ -1,12 +1,12 @@ -use futures_core::ready; +use super::read_until::read_until_internal; use futures_core::future::Future; +use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::AsyncBufRead; use std::io; use std::mem; use std::pin::Pin; use std::str; -use super::read_until::read_until_internal; /// Future for the [`read_line`](super::AsyncBufReadExt::read_line) method. #[derive(Debug)] @@ -22,12 +22,7 @@ impl<R: ?Sized + Unpin> Unpin for ReadLine<'_, R> {} impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadLine<'a, R> { pub(super) fn new(reader: &'a mut R, buf: &'a mut String) -> Self { - Self { - reader, - bytes: mem::replace(buf, String::new()).into_bytes(), - buf, - read: 0, - } + Self { reader, bytes: mem::replace(buf, String::new()).into_bytes(), buf, read: 0 } } } diff --git a/src/io/read_to_end.rs b/src/io/read_to_end.rs index 7bd2c89..919d7d1 100644 --- a/src/io/read_to_end.rs +++ b/src/io/read_to_end.rs @@ -20,11 +20,7 @@ impl<R: ?Sized + Unpin> Unpin for ReadToEnd<'_, R> {} impl<'a, R: AsyncRead + ?Sized + Unpin> ReadToEnd<'a, R> { pub(super) fn new(reader: &'a mut R, buf: &'a mut Vec<u8>) -> Self { let start_len = buf.len(); - Self { - reader, - buf, - start_len, - } + Self { reader, buf, start_len } } } @@ -56,10 +52,7 @@ pub(super) fn read_to_end_internal<R: AsyncRead + ?Sized>( buf: &mut Vec<u8>, start_len: usize, ) -> Poll<io::Result<usize>> { - let mut g = Guard { - len: buf.len(), - buf, - }; + let mut g = Guard { len: buf.len(), buf }; loop { if g.len == g.buf.len() { unsafe { diff --git a/src/io/read_to_string.rs b/src/io/read_to_string.rs index 9242654..457af59 100644 --- a/src/io/read_to_string.rs +++ b/src/io/read_to_string.rs @@ -1,6 +1,6 @@ use super::read_to_end::read_to_end_internal; -use futures_core::ready; use futures_core::future::Future; +use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::AsyncRead; use std::pin::Pin; @@ -22,12 +22,7 @@ impl<R: ?Sized + Unpin> Unpin for ReadToString<'_, R> {} impl<'a, R: AsyncRead + ?Sized + Unpin> ReadToString<'a, R> { pub(super) fn new(reader: &'a mut R, buf: &'a mut String) -> Self { let start_len = buf.len(); - Self { - reader, - bytes: mem::replace(buf, String::new()).into_bytes(), - buf, - start_len, - } + Self { reader, bytes: mem::replace(buf, String::new()).into_bytes(), buf, start_len } } } @@ -41,10 +36,7 @@ fn read_to_string_internal<R: AsyncRead + ?Sized>( let ret = ready!(read_to_end_internal(reader, cx, bytes, start_len)); if str::from_utf8(bytes).is_err() { Poll::Ready(ret.and_then(|_| { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "stream did not contain valid UTF-8", - )) + Err(io::Error::new(io::ErrorKind::InvalidData, "stream did not contain valid UTF-8")) })) } else { debug_assert!(buf.is_empty()); diff --git a/src/io/repeat.rs b/src/io/repeat.rs index 4cefcb2..2828bf0 100644 --- a/src/io/repeat.rs +++ b/src/io/repeat.rs @@ -1,7 +1,5 @@ use futures_core::ready; use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; use futures_io::{AsyncRead, IoSliceMut}; use std::fmt; use std::io; @@ -59,12 +57,6 @@ impl AsyncRead for Repeat { } Poll::Ready(Ok(nwritten)) } - - #[cfg(feature = "read-initializer")] - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } impl fmt::Debug for Repeat { diff --git a/src/io/split.rs b/src/io/split.rs index 185c21c..3f1b9af 100644 --- a/src/io/split.rs +++ b/src/io/split.rs @@ -1,8 +1,8 @@ use crate::lock::BiLock; +use core::fmt; use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::{AsyncRead, AsyncWrite, IoSlice, IoSliceMut}; -use core::fmt; use std::io; use std::pin::Pin; @@ -18,12 +18,9 @@ pub struct WriteHalf<T> { handle: BiLock<T>, } -fn lock_and_then<T, U, E, F>( - lock: &BiLock<T>, - cx: &mut Context<'_>, - f: F -) -> Poll<Result<U, E>> - where F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> Poll<Result<U, E>> +fn lock_and_then<T, U, E, F>(lock: &BiLock<T>, cx: &mut Context<'_>, f: F) -> Poll<Result<U, E>> +where + F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> Poll<Result<U, E>>, { let mut l = ready!(lock.poll_lock(cx)); f(l.as_pin_mut(), cx) @@ -39,9 +36,9 @@ impl<T: Unpin> ReadHalf<T> { /// together. Succeeds only if the `ReadHalf<T>` and `WriteHalf<T>` are /// a matching pair originating from the same call to `AsyncReadExt::split`. pub fn reunite(self, other: WriteHalf<T>) -> Result<T, ReuniteError<T>> { - self.handle.reunite(other.handle).map_err(|err| { - ReuniteError(ReadHalf { handle: err.0 }, WriteHalf { handle: err.1 }) - }) + self.handle + .reunite(other.handle) + .map_err(|err| ReuniteError(ReadHalf { handle: err.0 }, WriteHalf { handle: err.1 })) } } @@ -55,29 +52,37 @@ impl<T: Unpin> WriteHalf<T> { } impl<R: AsyncRead> AsyncRead for ReadHalf<R> { - fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) - -> Poll<io::Result<usize>> - { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut [u8], + ) -> Poll<io::Result<usize>> { lock_and_then(&self.handle, cx, |l, cx| l.poll_read(cx, buf)) } - fn poll_read_vectored(self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>]) - -> Poll<io::Result<usize>> - { + fn poll_read_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &mut [IoSliceMut<'_>], + ) -> Poll<io::Result<usize>> { lock_and_then(&self.handle, cx, |l, cx| l.poll_read_vectored(cx, bufs)) } } impl<W: AsyncWrite> AsyncWrite for WriteHalf<W> { - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) - -> Poll<io::Result<usize>> - { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { lock_and_then(&self.handle, cx, |l, cx| l.poll_write(cx, buf)) } - fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>]) - -> Poll<io::Result<usize>> - { + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll<io::Result<usize>> { lock_and_then(&self.handle, cx, |l, cx| l.poll_write_vectored(cx, bufs)) } @@ -96,9 +101,7 @@ pub struct ReuniteError<T>(pub ReadHalf<T>, pub WriteHalf<T>); impl<T> fmt::Debug for ReuniteError<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError") - .field(&"...") - .finish() + f.debug_tuple("ReuniteError").field(&"...").finish() } } diff --git a/src/io/take.rs b/src/io/take.rs index 687a697..2c49480 100644 --- a/src/io/take.rs +++ b/src/io/take.rs @@ -1,11 +1,9 @@ use futures_core::ready; use futures_core::task::{Context, Poll}; -#[cfg(feature = "read-initializer")] -use futures_io::Initializer; -use futures_io::{AsyncRead, AsyncBufRead}; +use futures_io::{AsyncBufRead, AsyncRead}; use pin_project_lite::pin_project; -use std::{cmp, io}; use std::pin::Pin; +use std::{cmp, io}; pin_project! { /// Reader for the [`take`](super::AsyncReadExt::take) method. @@ -14,14 +12,13 @@ pin_project! { pub struct Take<R> { #[pin] inner: R, - // Add '_' to avoid conflicts with `limit` method. - limit_: u64, + limit: u64, } } impl<R: AsyncRead> Take<R> { pub(super) fn new(inner: R, limit: u64) -> Self { - Self { inner, limit_: limit } + Self { inner, limit } } /// Returns the remaining number of bytes that can be @@ -48,7 +45,7 @@ impl<R: AsyncRead> Take<R> { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` pub fn limit(&self) -> u64 { - self.limit_ + self.limit } /// Sets the number of bytes that can be read before this instance will @@ -78,7 +75,7 @@ impl<R: AsyncRead> Take<R> { /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` pub fn set_limit(&mut self, limit: u64) { - self.limit_ = limit + self.limit = limit } delegate_access_inner!(inner, R, ()); @@ -92,20 +89,15 @@ impl<R: AsyncRead> AsyncRead for Take<R> { ) -> Poll<Result<usize, io::Error>> { let this = self.project(); - if *this.limit_ == 0 { + if *this.limit == 0 { return Poll::Ready(Ok(0)); } - let max = cmp::min(buf.len() as u64, *this.limit_) as usize; + let max = cmp::min(buf.len() as u64, *this.limit) as usize; let n = ready!(this.inner.poll_read(cx, &mut buf[..max]))?; - *this.limit_ -= n as u64; + *this.limit -= n as u64; Poll::Ready(Ok(n)) } - - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } } impl<R: AsyncBufRead> AsyncBufRead for Take<R> { @@ -113,12 +105,12 @@ impl<R: AsyncBufRead> AsyncBufRead for Take<R> { let this = self.project(); // Don't call into inner reader at all at EOF because it may still block - if *this.limit_ == 0 { + if *this.limit == 0 { return Poll::Ready(Ok(&[])); } let buf = ready!(this.inner.poll_fill_buf(cx)?); - let cap = cmp::min(buf.len() as u64, *this.limit_) as usize; + let cap = cmp::min(buf.len() as u64, *this.limit) as usize; Poll::Ready(Ok(&buf[..cap])) } @@ -126,8 +118,8 @@ impl<R: AsyncBufRead> AsyncBufRead for Take<R> { let this = self.project(); // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt as u64, *this.limit_) as usize; - *this.limit_ -= amt as u64; + let amt = cmp::min(amt as u64, *this.limit) as usize; + *this.limit -= amt as u64; this.inner.consume(amt); } } diff --git a/src/io/window.rs b/src/io/window.rs index 3424197..77b7267 100644 --- a/src/io/window.rs +++ b/src/io/window.rs @@ -30,10 +30,7 @@ impl<T: AsRef<[u8]>> Window<T> { /// Further methods can be called on the returned `Window<T>` to alter the /// window into the data provided. pub fn new(t: T) -> Self { - Self { - range: 0..t.as_ref().len(), - inner: t, - } + Self { range: 0..t.as_ref().len(), inner: t } } /// Gets a shared reference to the underlying buffer inside of this diff --git a/src/io/write_all_vectored.rs b/src/io/write_all_vectored.rs index 380604d..a8fc4c6 100644 --- a/src/io/write_all_vectored.rs +++ b/src/io/write_all_vectored.rs @@ -1,10 +1,9 @@ -use futures_core::ready; use futures_core::future::Future; +use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::AsyncWrite; use futures_io::IoSlice; use std::io; -use std::mem; use std::pin::Pin; /// Future for the @@ -19,8 +18,9 @@ pub struct WriteAllVectored<'a, W: ?Sized + Unpin> { impl<W: ?Sized + Unpin> Unpin for WriteAllVectored<'_, W> {} impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteAllVectored<'a, W> { - pub(super) fn new(writer: &'a mut W, bufs: &'a mut [IoSlice<'a>]) -> Self { - Self { writer, bufs: IoSlice::advance(bufs, 0) } + pub(super) fn new(writer: &'a mut W, mut bufs: &'a mut [IoSlice<'a>]) -> Self { + IoSlice::advance_slices(&mut bufs, 0); + Self { writer, bufs } } } @@ -34,7 +34,7 @@ impl<W: AsyncWrite + ?Sized + Unpin> Future for WriteAllVectored<'_, W> { if n == 0 { return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); } else { - this.bufs = IoSlice::advance(mem::take(&mut this.bufs), n); + IoSlice::advance_slices(&mut this.bufs, n); } } @@ -56,11 +56,7 @@ mod tests { /// Create a new writer that reads from at most `n_bufs` and reads /// `per_call` bytes (in total) per call to write. fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { - TestWriter { - n_bufs, - per_call, - written: Vec::new(), - } + TestWriter { n_bufs, per_call, written: Vec::new() } } // TODO: maybe move this the future-test crate? @@ -110,10 +106,9 @@ mod tests { let expected = $expected; match $e { Poll::Ready(Ok(ok)) if ok == expected => {} - got => panic!( - "unexpected result, got: {:?}, wanted: Ready(Ok({:?}))", - got, expected - ), + got => { + panic!("unexpected result, got: {:?}, wanted: Ready(Ok({:?}))", got, expected) + } } }; } @@ -154,11 +149,7 @@ mod tests { assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 3); // Read at most 3 bytes from three buffers. - let bufs = &[ - IoSlice::new(&[3]), - IoSlice::new(&[4]), - IoSlice::new(&[5, 5]), - ]; + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 3); assert_eq!(dst.written, &[1, 2, 2, 3, 4, 5]); @@ -1,31 +1,27 @@ //! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s, //! and the `AsyncRead` and `AsyncWrite` traits. -#![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))] -#![cfg_attr(feature = "read-initializer", feature(read_initializer))] #![cfg_attr(feature = "write-all-vectored", feature(io_slice_advance))] #![cfg_attr(not(feature = "std"), no_std)] #![warn( - missing_docs, missing_debug_implementations, + missing_docs, rust_2018_idioms, + single_use_lifetimes, unreachable_pub )] -// It cannot be included in the published code because this lints have false positives in the minimum required version. -#![cfg_attr(test, warn(single_use_lifetimes))] -#![warn(clippy::all)] -#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))] +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms, single_use_lifetimes), + allow(dead_code, unused_assignments, unused_variables) + ) +))] #![cfg_attr(docsrs, feature(doc_cfg))] -#[cfg(all(feature = "cfg-target-has-atomic", not(feature = "unstable")))] -compile_error!("The `cfg-target-has-atomic` feature requires the `unstable` feature as an explicit opt-in to unstable features"); - #[cfg(all(feature = "bilock", not(feature = "unstable")))] compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features"); -#[cfg(all(feature = "read-initializer", not(feature = "unstable")))] -compile_error!("The `read-initializer` feature requires the `unstable` feature as an explicit opt-in to unstable features"); - #[cfg(feature = "alloc")] extern crate alloc; @@ -56,13 +52,6 @@ pub mod __private { } } -macro_rules! cfg_target_has_atomic { - ($($item:item)*) => {$( - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] - $item - )*}; -} - #[cfg(feature = "sink")] macro_rules! delegate_sink { ($field:ident, $item:ty) => { @@ -155,11 +144,6 @@ macro_rules! delegate_async_write { #[cfg(feature = "std")] macro_rules! delegate_async_read { ($field:ident) => { - #[cfg(feature = "read-initializer")] - unsafe fn initializer(&self) -> $crate::io::Initializer { - self.$field.initializer() - } - fn poll_read( self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, @@ -308,19 +292,19 @@ macro_rules! delegate_all { } pub mod future; -#[doc(hidden)] -pub use crate::future::{FutureExt, TryFutureExt}; +#[doc(no_inline)] +pub use crate::future::{Future, FutureExt, TryFuture, TryFutureExt}; pub mod stream; -#[doc(hidden)] -pub use crate::stream::{StreamExt, TryStreamExt}; +#[doc(no_inline)] +pub use crate::stream::{Stream, StreamExt, TryStream, TryStreamExt}; #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] pub mod sink; #[cfg(feature = "sink")] -#[doc(hidden)] -pub use crate::sink::SinkExt; +#[doc(no_inline)] +pub use crate::sink::{Sink, SinkExt}; pub mod task; @@ -336,11 +320,18 @@ pub mod compat; pub mod io; #[cfg(feature = "io")] #[cfg(feature = "std")] -#[doc(hidden)] -pub use crate::io::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; +#[doc(no_inline)] +pub use crate::io::{ + AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, + AsyncWriteExt, +}; #[cfg(feature = "alloc")] pub mod lock; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod abortable; + mod fns; mod unfold_state; diff --git a/src/lock/bilock.rs b/src/lock/bilock.rs index 600e16e..2f51ae7 100644 --- a/src/lock/bilock.rs +++ b/src/lock/bilock.rs @@ -1,16 +1,16 @@ //! Futures-powered synchronization primitives. -#[cfg(feature = "bilock")] -use futures_core::future::Future; -use futures_core::task::{Context, Poll, Waker}; +use alloc::boxed::Box; +use alloc::sync::Arc; use core::cell::UnsafeCell; use core::fmt; use core::ops::{Deref, DerefMut}; use core::pin::Pin; use core::sync::atomic::AtomicUsize; use core::sync::atomic::Ordering::SeqCst; -use alloc::boxed::Box; -use alloc::sync::Arc; +#[cfg(feature = "bilock")] +use futures_core::future::Future; +use futures_core::task::{Context, Poll, Waker}; /// A type of futures-powered synchronization primitive which is a mutex between /// two possible owners. @@ -61,10 +61,7 @@ impl<T> BiLock<T> { /// Similarly, reuniting the lock and extracting the inner value is only /// possible when `T` is `Unpin`. pub fn new(t: T) -> (Self, Self) { - let arc = Arc::new(Inner { - state: AtomicUsize::new(0), - value: Some(UnsafeCell::new(t)), - }); + let arc = Arc::new(Inner { state: AtomicUsize::new(0), value: Some(UnsafeCell::new(t)) }); (Self { arc: arc.clone() }, Self { arc }) } @@ -103,11 +100,11 @@ impl<T> BiLock<T> { let mut prev = Box::from_raw(n as *mut Waker); *prev = cx.waker().clone(); waker = Some(prev); - } + }, } // type ascription for safety's sake! - let me: Box<Waker> = waker.take().unwrap_or_else(||Box::new(cx.waker().clone())); + let me: Box<Waker> = waker.take().unwrap_or_else(|| Box::new(cx.waker().clone())); let me = Box::into_raw(me) as usize; match self.arc.state.compare_exchange(1, me, SeqCst, SeqCst) { @@ -145,9 +142,7 @@ impl<T> BiLock<T> { #[cfg(feature = "bilock")] #[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] pub fn lock(&self) -> BiLockAcquire<'_, T> { - BiLockAcquire { - bilock: self, - } + BiLockAcquire { bilock: self } } /// Attempts to put the two "halves" of a `BiLock<T>` back together and @@ -181,7 +176,7 @@ impl<T> BiLock<T> { // up as its now their turn. n => unsafe { Box::from_raw(n as *mut Waker).wake(); - } + }, } } } @@ -205,9 +200,7 @@ pub struct ReuniteError<T>(pub BiLock<T>, pub BiLock<T>); impl<T> fmt::Debug for ReuniteError<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError") - .field(&"...") - .finish() + f.debug_tuple("ReuniteError").field(&"...").finish() } } diff --git a/src/lock/mod.rs b/src/lock/mod.rs index 071eef6..cf374c0 100644 --- a/src/lock/mod.rs +++ b/src/lock/mod.rs @@ -3,20 +3,23 @@ //! This module is only available when the `std` or `alloc` feature of this //! library is activated, and it is activated by default. -cfg_target_has_atomic! { - #[cfg(feature = "std")] - mod mutex; - #[cfg(feature = "std")] - pub use self::mutex::{MappedMutexGuard, Mutex, MutexLockFuture, MutexGuard}; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "std")] +mod mutex; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "std")] +pub use self::mutex::{MappedMutexGuard, Mutex, MutexGuard, MutexLockFuture}; - #[cfg(any(feature = "bilock", feature = "sink", feature = "io"))] - #[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] - #[cfg_attr(not(feature = "bilock"), allow(unreachable_pub))] - mod bilock; - #[cfg(feature = "bilock")] - #[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] - pub use self::bilock::{BiLock, BiLockAcquire, BiLockGuard, ReuniteError}; - #[cfg(any(feature = "sink", feature = "io"))] - #[cfg(not(feature = "bilock"))] - pub(crate) use self::bilock::BiLock; -} +#[cfg(not(futures_no_atomic_cas))] +#[cfg(any(feature = "bilock", feature = "sink", feature = "io"))] +#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] +#[cfg_attr(not(feature = "bilock"), allow(unreachable_pub))] +mod bilock; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(any(feature = "sink", feature = "io"))] +#[cfg(not(feature = "bilock"))] +pub(crate) use self::bilock::BiLock; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "bilock")] +#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] +pub use self::bilock::{BiLock, BiLockAcquire, BiLockGuard, ReuniteError}; diff --git a/src/lock/mutex.rs b/src/lock/mutex.rs index a78de62..85dcb15 100644 --- a/src/lock/mutex.rs +++ b/src/lock/mutex.rs @@ -1,13 +1,13 @@ use futures_core::future::{FusedFuture, Future}; use futures_core::task::{Context, Poll, Waker}; use slab::Slab; -use std::{fmt, mem}; use std::cell::UnsafeCell; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::pin::Pin; -use std::sync::Mutex as StdMutex; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex as StdMutex; +use std::{fmt, mem}; /// A futures-aware mutex. /// @@ -53,7 +53,7 @@ enum Waiter { impl Waiter { fn register(&mut self, waker: &Waker) { match self { - Self::Waiting(w) if waker.will_wake(w) => {}, + Self::Waiting(w) if waker.will_wake(w) => {} _ => *self = Self::Waiting(waker.clone()), } } @@ -61,12 +61,11 @@ impl Waiter { fn wake(&mut self) { match mem::replace(self, Self::Woken) { Self::Waiting(waker) => waker.wake(), - Self::Woken => {}, + Self::Woken => {} } } } -#[allow(clippy::identity_op)] // https://github.com/rust-lang/rust-clippy/issues/3445 const IS_LOCKED: usize = 1 << 0; const HAS_WAITERS: usize = 1 << 1; @@ -113,10 +112,7 @@ impl<T: ?Sized> Mutex<T> { /// This method returns a future that will resolve once the lock has been /// successfully acquired. pub fn lock(&self) -> MutexLockFuture<'_, T> { - MutexLockFuture { - mutex: Some(self), - wait_key: WAIT_KEY_NONE, - } + MutexLockFuture { mutex: Some(self), wait_key: WAIT_KEY_NONE } } /// Returns a mutable reference to the underlying data. @@ -145,7 +141,7 @@ impl<T: ?Sized> Mutex<T> { if wait_key != WAIT_KEY_NONE { let mut waiters = self.waiters.lock().unwrap(); match waiters.remove(wait_key) { - Waiter::Waiting(_) => {}, + Waiter::Waiting(_) => {} Waiter::Woken => { // We were awoken, but then dropped before we could // wake up to acquire the lock. Wake up another @@ -191,13 +187,10 @@ impl<T: ?Sized> fmt::Debug for MutexLockFuture<'_, T> { f.debug_struct("MutexLockFuture") .field("was_acquired", &self.mutex.is_none()) .field("mutex", &self.mutex) - .field("wait_key", &( - if self.wait_key == WAIT_KEY_NONE { - None - } else { - Some(self.wait_key) - } - )) + .field( + "wait_key", + &(if self.wait_key == WAIT_KEY_NONE { None } else { Some(self.wait_key) }), + ) .finish() } } @@ -295,10 +288,7 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> { impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MutexGuard") - .field("value", &&**self) - .field("mutex", &self.mutex) - .finish() + f.debug_struct("MutexGuard").field("value", &&**self).field("mutex", &self.mutex).finish() } } diff --git a/src/sink/buffer.rs b/src/sink/buffer.rs index 8c58f4f..4aa6c36 100644 --- a/src/sink/buffer.rs +++ b/src/sink/buffer.rs @@ -1,10 +1,10 @@ +use alloc::collections::VecDeque; +use core::pin::Pin; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use futures_sink::Sink; use pin_project_lite::pin_project; -use core::pin::Pin; -use alloc::collections::VecDeque; pin_project! { /// Sink for the [`buffer`](super::SinkExt::buffer) method. @@ -22,19 +22,12 @@ pin_project! { impl<Si: Sink<Item>, Item> Buffer<Si, Item> { pub(super) fn new(sink: Si, capacity: usize) -> Self { - Self { - sink, - buf: VecDeque::with_capacity(capacity), - capacity, - } + Self { sink, buf: VecDeque::with_capacity(capacity), capacity } } delegate_access_inner!(sink, Si, ()); - fn try_empty_buffer( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Si::Error>> { + fn try_empty_buffer(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Si::Error>> { let mut this = self.project(); ready!(this.sink.as_mut().poll_ready(cx))?; while let Some(item) = this.buf.pop_front() { @@ -48,7 +41,10 @@ impl<Si: Sink<Item>, Item> Buffer<Si, Item> { } // Forwarding impl of Stream from the underlying sink -impl<S, Item> Stream for Buffer<S, Item> where S: Sink<Item> + Stream { +impl<S, Item> Stream for Buffer<S, Item> +where + S: Sink<Item> + Stream, +{ type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> { @@ -60,7 +56,10 @@ impl<S, Item> Stream for Buffer<S, Item> where S: Sink<Item> + Stream { } } -impl<S, Item> FusedStream for Buffer<S, Item> where S: Sink<Item> + FusedStream { +impl<S, Item> FusedStream for Buffer<S, Item> +where + S: Sink<Item> + FusedStream, +{ fn is_terminated(&self) -> bool { self.sink.is_terminated() } @@ -69,10 +68,7 @@ impl<S, Item> FusedStream for Buffer<S, Item> where S: Sink<Item> + FusedStream impl<Si: Sink<Item>, Item> Sink<Item> for Buffer<Si, Item> { type Error = Si::Error; - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { if self.capacity == 0 { return self.project().sink.poll_ready(cx); } @@ -86,10 +82,7 @@ impl<Si: Sink<Item>, Item> Sink<Item> for Buffer<Si, Item> { } } - fn start_send( - self: Pin<&mut Self>, - item: Item, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { if self.capacity == 0 { self.project().sink.start_send(item) } else { @@ -98,21 +91,13 @@ impl<Si: Sink<Item>, Item> Sink<Item> for Buffer<Si, Item> { } } - #[allow(clippy::debug_assert_with_mut_call)] - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().try_empty_buffer(cx))?; debug_assert!(self.buf.is_empty()); self.project().sink.poll_flush(cx) } - #[allow(clippy::debug_assert_with_mut_call)] - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().try_empty_buffer(cx))?; debug_assert!(self.buf.is_empty()); self.project().sink.poll_close(cx) diff --git a/src/sink/close.rs b/src/sink/close.rs index 4fc99f5..43eea74 100644 --- a/src/sink/close.rs +++ b/src/sink/close.rs @@ -19,20 +19,14 @@ impl<Si: Unpin + ?Sized, Item> Unpin for Close<'_, Si, Item> {} /// The sink itself is returned after closing is complete. impl<'a, Si: Sink<Item> + Unpin + ?Sized, Item> Close<'a, Si, Item> { pub(super) fn new(sink: &'a mut Si) -> Self { - Self { - sink, - _phantom: PhantomData, - } + Self { sink, _phantom: PhantomData } } } impl<Si: Sink<Item> + Unpin + ?Sized, Item> Future for Close<'_, Si, Item> { type Output = Result<(), Si::Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { Pin::new(&mut self.sink).poll_close(cx) } } diff --git a/src/sink/drain.rs b/src/sink/drain.rs index 33c5b31..5295115 100644 --- a/src/sink/drain.rs +++ b/src/sink/drain.rs @@ -35,31 +35,19 @@ impl<T> Unpin for Drain<T> {} impl<T> Sink<T> for Drain<T> { type Error = Never; - fn poll_ready( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } - fn start_send( - self: Pin<&mut Self>, - _item: T, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, _item: T) -> Result<(), Self::Error> { Ok(()) } - fn poll_flush( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } - fn poll_close( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } } diff --git a/src/sink/err_into.rs b/src/sink/err_into.rs index 3eb9940..a64d133 100644 --- a/src/sink/err_into.rs +++ b/src/sink/err_into.rs @@ -1,6 +1,6 @@ use crate::sink::{SinkExt, SinkMapErr}; -use futures_core::stream::{Stream, FusedStream}; -use futures_sink::{Sink}; +use futures_core::stream::{FusedStream, Stream}; +use futures_sink::Sink; use pin_project_lite::pin_project; pin_project! { @@ -14,21 +14,21 @@ pin_project! { } impl<Si, E, Item> SinkErrInto<Si, Item, E> - where Si: Sink<Item>, - Si::Error: Into<E>, +where + Si: Sink<Item>, + Si::Error: Into<E>, { pub(super) fn new(sink: Si) -> Self { - Self { - sink: SinkExt::sink_map_err(sink, Into::into), - } + Self { sink: SinkExt::sink_map_err(sink, Into::into) } } delegate_access_inner!(sink, Si, (.)); } impl<Si, Item, E> Sink<Item> for SinkErrInto<Si, Item, E> - where Si: Sink<Item>, - Si::Error: Into<E>, +where + Si: Sink<Item>, + Si::Error: Into<E>, { type Error = E; @@ -37,8 +37,9 @@ impl<Si, Item, E> Sink<Item> for SinkErrInto<Si, Item, E> // Forwarding impl of Stream from the underlying sink impl<S, Item, E> Stream for SinkErrInto<S, Item, E> - where S: Sink<Item> + Stream, - S::Error: Into<E> +where + S: Sink<Item> + Stream, + S::Error: Into<E>, { type Item = S::Item; @@ -46,8 +47,9 @@ impl<S, Item, E> Stream for SinkErrInto<S, Item, E> } impl<S, Item, E> FusedStream for SinkErrInto<S, Item, E> - where S: Sink<Item> + FusedStream, - S::Error: Into<E> +where + S: Sink<Item> + FusedStream, + S::Error: Into<E>, { fn is_terminated(&self) -> bool { self.sink.is_terminated() diff --git a/src/sink/fanout.rs b/src/sink/fanout.rs index f351e86..fe2038f 100644 --- a/src/sink/fanout.rs +++ b/src/sink/fanout.rs @@ -50,36 +50,32 @@ impl<Si1, Si2> Fanout<Si1, Si2> { impl<Si1: Debug, Si2: Debug> Debug for Fanout<Si1, Si2> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_struct("Fanout") - .field("sink1", &self.sink1) - .field("sink2", &self.sink2) - .finish() + f.debug_struct("Fanout").field("sink1", &self.sink1).field("sink2", &self.sink2).finish() } } impl<Si1, Si2, Item> Sink<Item> for Fanout<Si1, Si2> - where Si1: Sink<Item>, - Item: Clone, - Si2: Sink<Item, Error=Si1::Error> +where + Si1: Sink<Item>, + Item: Clone, + Si2: Sink<Item, Error = Si1::Error>, { type Error = Si1::Error; - fn poll_ready( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { let this = self.project(); let sink1_ready = this.sink1.poll_ready(cx)?.is_ready(); let sink2_ready = this.sink2.poll_ready(cx)?.is_ready(); let ready = sink1_ready && sink2_ready; - if ready { Poll::Ready(Ok(())) } else { Poll::Pending } + if ready { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } } - fn start_send( - self: Pin<&mut Self>, - item: Item, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { let this = self.project(); this.sink1.start_send(item.clone())?; @@ -87,27 +83,29 @@ impl<Si1, Si2, Item> Sink<Item> for Fanout<Si1, Si2> Ok(()) } - fn poll_flush( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { let this = self.project(); let sink1_ready = this.sink1.poll_flush(cx)?.is_ready(); let sink2_ready = this.sink2.poll_flush(cx)?.is_ready(); let ready = sink1_ready && sink2_ready; - if ready { Poll::Ready(Ok(())) } else { Poll::Pending } + if ready { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } } - fn poll_close( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { let this = self.project(); let sink1_ready = this.sink1.poll_close(cx)?.is_ready(); let sink2_ready = this.sink2.poll_close(cx)?.is_ready(); let ready = sink1_ready && sink2_ready; - if ready { Poll::Ready(Ok(())) } else { Poll::Pending } + if ready { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } } } diff --git a/src/sink/feed.rs b/src/sink/feed.rs index 06df9a9..6701f7a 100644 --- a/src/sink/feed.rs +++ b/src/sink/feed.rs @@ -17,10 +17,7 @@ impl<Si: Unpin + ?Sized, Item> Unpin for Feed<'_, Si, Item> {} impl<'a, Si: Sink<Item> + Unpin + ?Sized, Item> Feed<'a, Si, Item> { pub(super) fn new(sink: &'a mut Si, item: Item) -> Self { - Feed { - sink, - item: Some(item), - } + Feed { sink, item: Some(item) } } pub(super) fn sink_pin_mut(&mut self) -> Pin<&mut Si> { @@ -35,10 +32,7 @@ impl<'a, Si: Sink<Item> + Unpin + ?Sized, Item> Feed<'a, Si, Item> { impl<Si: Sink<Item> + Unpin + ?Sized, Item> Future for Feed<'_, Si, Item> { type Output = Result<(), Si::Error>; - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let this = self.get_mut(); let mut sink = Pin::new(&mut this.sink); ready!(sink.as_mut().poll_ready(cx))?; diff --git a/src/sink/flush.rs b/src/sink/flush.rs index c06a221..35a8372 100644 --- a/src/sink/flush.rs +++ b/src/sink/flush.rs @@ -23,20 +23,14 @@ impl<Si: Unpin + ?Sized, Item> Unpin for Flush<'_, Si, Item> {} /// all current requests are processed. impl<'a, Si: Sink<Item> + Unpin + ?Sized, Item> Flush<'a, Si, Item> { pub(super) fn new(sink: &'a mut Si) -> Self { - Self { - sink, - _phantom: PhantomData, - } + Self { sink, _phantom: PhantomData } } } impl<Si: Sink<Item> + Unpin + ?Sized, Item> Future for Flush<'_, Si, Item> { type Output = Result<(), Si::Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { Pin::new(&mut self.sink).poll_flush(cx) } } diff --git a/src/sink/map_err.rs b/src/sink/map_err.rs index 2829344..9d2ab7b 100644 --- a/src/sink/map_err.rs +++ b/src/sink/map_err.rs @@ -1,7 +1,7 @@ use core::pin::Pin; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; -use futures_sink::{Sink}; +use futures_sink::Sink; use pin_project_lite::pin_project; pin_project! { @@ -28,36 +28,25 @@ impl<Si, F> SinkMapErr<Si, F> { } impl<Si, F, E, Item> Sink<Item> for SinkMapErr<Si, F> - where Si: Sink<Item>, - F: FnOnce(Si::Error) -> E, +where + Si: Sink<Item>, + F: FnOnce(Si::Error) -> E, { type Error = E; - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.as_mut().project().sink.poll_ready(cx).map_err(|e| self.as_mut().take_f()(e)) } - fn start_send( - mut self: Pin<&mut Self>, - item: Item, - ) -> Result<(), Self::Error> { + fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { self.as_mut().project().sink.start_send(item).map_err(|e| self.as_mut().take_f()(e)) } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.as_mut().project().sink.poll_flush(cx).map_err(|e| self.as_mut().take_f()(e)) } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.as_mut().project().sink.poll_close(cx).map_err(|e| self.as_mut().take_f()(e)) } } diff --git a/src/sink/mod.rs b/src/sink/mod.rs index e5b515b..147e9ad 100644 --- a/src/sink/mod.rs +++ b/src/sink/mod.rs @@ -243,7 +243,8 @@ pub trait SinkExt<Item>: Sink<Item> { /// This future will drive the stream to keep producing items until it is /// exhausted, sending each item to the sink. It will complete once both the /// stream is exhausted, the sink has received all items, and the sink has - /// been flushed. Note that the sink is **not** closed. + /// been flushed. Note that the sink is **not** closed. If the stream produces + /// an error, that error will be returned by this future without flushing the sink. /// /// Doing `sink.send_all(stream)` is roughly equivalent to /// `stream.forward(sink)`. The returned future will exhaust all items from diff --git a/src/sink/send.rs b/src/sink/send.rs index 384c22c..6d21f33 100644 --- a/src/sink/send.rs +++ b/src/sink/send.rs @@ -17,19 +17,14 @@ impl<Si: Unpin + ?Sized, Item> Unpin for Send<'_, Si, Item> {} impl<'a, Si: Sink<Item> + Unpin + ?Sized, Item> Send<'a, Si, Item> { pub(super) fn new(sink: &'a mut Si, item: Item) -> Self { - Self { - feed: Feed::new(sink, item), - } + Self { feed: Feed::new(sink, item) } } } impl<Si: Sink<Item> + Unpin + ?Sized, Item> Future for Send<'_, Si, Item> { type Output = Result<(), Si::Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let this = &mut *self; if this.feed.is_item_pending() { diff --git a/src/sink/send_all.rs b/src/sink/send_all.rs index 6a33459..1302dd2 100644 --- a/src/sink/send_all.rs +++ b/src/sink/send_all.rs @@ -1,9 +1,9 @@ -use crate::stream::{StreamExt, TryStreamExt, Fuse}; +use crate::stream::{Fuse, StreamExt, TryStreamExt}; use core::fmt; use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; -use futures_core::stream::{TryStream, Stream}; +use futures_core::stream::{Stream, TryStream}; use futures_core::task::{Context, Poll}; use futures_sink::Sink; @@ -40,22 +40,16 @@ impl<Si, St> Unpin for SendAll<'_, Si, St> where Si: Unpin + ?Sized, St: TryStream + Unpin + ?Sized, -{} +{ +} impl<'a, Si, St, Ok, Error> SendAll<'a, Si, St> where Si: Sink<Ok, Error = Error> + Unpin + ?Sized, St: TryStream<Ok = Ok, Error = Error> + Stream + Unpin + ?Sized, { - pub(super) fn new( - sink: &'a mut Si, - stream: &'a mut St, - ) -> Self { - Self { - sink, - stream: stream.fuse(), - buffered: None, - } + pub(super) fn new(sink: &'a mut Si, stream: &'a mut St) -> Self { + Self { sink, stream: stream.fuse(), buffered: None } } fn try_start_send( @@ -65,9 +59,7 @@ where ) -> Poll<Result<(), Si::Error>> { debug_assert!(self.buffered.is_none()); match Pin::new(&mut self.sink).poll_ready(cx)? { - Poll::Ready(()) => { - Poll::Ready(Pin::new(&mut self.sink).start_send(item)) - } + Poll::Ready(()) => Poll::Ready(Pin::new(&mut self.sink).start_send(item)), Poll::Pending => { self.buffered = Some(item); Poll::Pending @@ -83,10 +75,7 @@ where { type Output = Result<(), Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let this = &mut *self; // If we've got an item buffered already, we need to write it to the // sink before we can do anything else @@ -96,16 +85,14 @@ where loop { match this.stream.try_poll_next_unpin(cx)? { - Poll::Ready(Some(item)) => { - ready!(this.try_start_send(cx, item))? - } + Poll::Ready(Some(item)) => ready!(this.try_start_send(cx, item))?, Poll::Ready(None) => { ready!(Pin::new(&mut this.sink).poll_flush(cx))?; - return Poll::Ready(Ok(())) + return Poll::Ready(Ok(())); } Poll::Pending => { ready!(Pin::new(&mut this.sink).poll_flush(cx))?; - return Poll::Pending + return Poll::Pending; } } } diff --git a/src/sink/unfold.rs b/src/sink/unfold.rs index 3903716..330a068 100644 --- a/src/sink/unfold.rs +++ b/src/sink/unfold.rs @@ -41,10 +41,7 @@ where F: FnMut(T, Item) -> R, R: Future<Output = Result<T, E>>, { - assert_sink::<Item, E, _>(Unfold { - function, - state: UnfoldState::Value { value: init }, - }) + assert_sink::<Item, E, _>(Unfold { function, state: UnfoldState::Value { value: init } }) } impl<T, F, R, Item, E> Sink<Item> for Unfold<T, F, R> diff --git a/src/sink/with.rs b/src/sink/with.rs index 73b87b7..86d3dcc 100644 --- a/src/sink/with.rs +++ b/src/sink/with.rs @@ -27,29 +27,22 @@ where Fut: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("With") - .field("sink", &self.sink) - .field("state", &self.state) - .finish() + f.debug_struct("With").field("sink", &self.sink).field("state", &self.state).finish() } } impl<Si, Item, U, Fut, F> With<Si, Item, U, Fut, F> -where Si: Sink<Item>, - F: FnMut(U) -> Fut, - Fut: Future, +where + Si: Sink<Item>, + F: FnMut(U) -> Fut, + Fut: Future, { pub(super) fn new<E>(sink: Si, f: F) -> Self - where - Fut: Future<Output = Result<Item, E>>, - E: From<Si::Error>, + where + Fut: Future<Output = Result<Item, E>>, + E: From<Si::Error>, { - Self { - state: None, - sink, - f, - _phantom: PhantomData, - } + Self { state: None, sink, f, _phantom: PhantomData } } } @@ -71,9 +64,10 @@ where // Forwarding impl of Stream from the underlying sink impl<S, Item, U, Fut, F> Stream for With<S, Item, U, Fut, F> - where S: Stream + Sink<Item>, - F: FnMut(U) -> Fut, - Fut: Future +where + S: Stream + Sink<Item>, + F: FnMut(U) -> Fut, + Fut: Future, { type Item = S::Item; @@ -81,18 +75,16 @@ impl<S, Item, U, Fut, F> Stream for With<S, Item, U, Fut, F> } impl<Si, Item, U, Fut, F, E> With<Si, Item, U, Fut, F> - where Si: Sink<Item>, - F: FnMut(U) -> Fut, - Fut: Future<Output = Result<Item, E>>, - E: From<Si::Error>, +where + Si: Sink<Item>, + F: FnMut(U) -> Fut, + Fut: Future<Output = Result<Item, E>>, + E: From<Si::Error>, { delegate_access_inner!(sink, Si, ()); /// Completes the processing of previous item if any. - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), E>> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), E>> { let mut this = self.project(); let item = match this.state.as_mut().as_pin_mut() { @@ -106,26 +98,21 @@ impl<Si, Item, U, Fut, F, E> With<Si, Item, U, Fut, F> } impl<Si, Item, U, Fut, F, E> Sink<U> for With<Si, Item, U, Fut, F> - where Si: Sink<Item>, - F: FnMut(U) -> Fut, - Fut: Future<Output = Result<Item, E>>, - E: From<Si::Error>, +where + Si: Sink<Item>, + F: FnMut(U) -> Fut, + Fut: Future<Output = Result<Item, E>>, + E: From<Si::Error>, { type Error = E; - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().poll(cx))?; ready!(self.project().sink.poll_ready(cx)?); Poll::Ready(Ok(())) } - fn start_send( - self: Pin<&mut Self>, - item: U, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: U) -> Result<(), Self::Error> { let mut this = self.project(); assert!(this.state.is_none()); @@ -133,19 +120,13 @@ impl<Si, Item, U, Fut, F, E> Sink<U> for With<Si, Item, U, Fut, F> Ok(()) } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().poll(cx))?; ready!(self.project().sink.poll_flush(cx)?); Poll::Ready(Ok(())) } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().poll(cx))?; ready!(self.project().sink.poll_close(cx)?); Poll::Ready(Ok(())) diff --git a/src/sink/with_flat_map.rs b/src/sink/with_flat_map.rs index 4b8d3a2..2ae877a 100644 --- a/src/sink/with_flat_map.rs +++ b/src/sink/with_flat_map.rs @@ -2,7 +2,7 @@ use core::fmt; use core::marker::PhantomData; use core::pin::Pin; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use futures_sink::Sink; use pin_project_lite::pin_project; @@ -43,21 +43,12 @@ where St: Stream<Item = Result<Item, Si::Error>>, { pub(super) fn new(sink: Si, f: F) -> Self { - Self { - sink, - f, - stream: None, - buffer: None, - _marker: PhantomData, - } + Self { sink, f, stream: None, buffer: None, _marker: PhantomData } } delegate_access_inner!(sink, Si, ()); - fn try_empty_stream( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Si::Error>> { + fn try_empty_stream(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Si::Error>> { let mut this = self.project(); if this.buffer.is_some() { @@ -112,17 +103,11 @@ where { type Error = Si::Error; - fn poll_ready( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.try_empty_stream(cx) } - fn start_send( - self: Pin<&mut Self>, - item: U, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: U) -> Result<(), Self::Error> { let mut this = self.project(); assert!(this.stream.is_none()); @@ -130,18 +115,12 @@ where Ok(()) } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().try_empty_stream(cx)?); self.project().sink.poll_flush(cx) } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<(), Self::Error>> { + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ready!(self.as_mut().try_empty_stream(cx)?); self.project().sink.poll_close(cx) } diff --git a/src/stream/abortable.rs b/src/stream/abortable.rs new file mode 100644 index 0000000..1fea895 --- /dev/null +++ b/src/stream/abortable.rs @@ -0,0 +1,19 @@ +use super::assert_stream; +use crate::stream::{AbortHandle, Abortable}; +use crate::Stream; + +/// Creates a new `Abortable` stream and an `AbortHandle` which can be used to stop it. +/// +/// This function is a convenient (but less flexible) alternative to calling +/// `AbortHandle::new` and `Abortable::new` manually. +/// +/// This function is only available when the `std` or `alloc` feature of this +/// library is activated, and it is activated by default. +pub fn abortable<St>(stream: St) -> (Abortable<St>, AbortHandle) +where + St: Stream, +{ + let (handle, reg) = AbortHandle::new_pair(); + let abortable = assert_stream::<St::Item, _>(Abortable::new(stream, reg)); + (abortable, handle) +} diff --git a/src/stream/empty.rs b/src/stream/empty.rs index c629a4b..e4fd873 100644 --- a/src/stream/empty.rs +++ b/src/stream/empty.rs @@ -8,16 +8,14 @@ use futures_core::task::{Context, Poll}; #[derive(Debug)] #[must_use = "streams do nothing unless polled"] pub struct Empty<T> { - _phantom: PhantomData<T> + _phantom: PhantomData<T>, } /// Creates a stream which contains no elements. /// /// The returned stream will always return `Ready(None)` when polled. pub fn empty<T>() -> Empty<T> { - assert_stream::<T, _>(Empty { - _phantom: PhantomData - }) + assert_stream::<T, _>(Empty { _phantom: PhantomData }) } impl<T> Unpin for Empty<T> {} diff --git a/src/stream/futures_ordered.rs b/src/stream/futures_ordered.rs index eda3b27..f596b3b 100644 --- a/src/stream/futures_ordered.rs +++ b/src/stream/futures_ordered.rs @@ -52,10 +52,7 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let index = self.index; - self.project().data.poll(cx).map(|output| OrderWrapper { - data: output, - index, - }) + self.project().data.poll(cx).map(|output| OrderWrapper { data: output, index }) } } @@ -139,10 +136,7 @@ impl<Fut: Future> FuturesOrdered<Fut> { /// must ensure that `FuturesOrdered::poll` is called in order to receive /// task notifications. pub fn push(&mut self, future: Fut) { - let wrapped = OrderWrapper { - data: future, - index: self.next_incoming_index, - }; + let wrapped = OrderWrapper { data: future, index: self.next_incoming_index }; self.next_incoming_index += 1; self.in_progress_queue.push(wrapped); } diff --git a/src/stream/futures_unordered/iter.rs b/src/stream/futures_unordered/iter.rs index ef7b15a..04db5ee 100644 --- a/src/stream/futures_unordered/iter.rs +++ b/src/stream/futures_unordered/iter.rs @@ -1,41 +1,83 @@ -use super::FuturesUnordered; use super::task::Task; +use super::FuturesUnordered; use core::marker::PhantomData; use core::pin::Pin; use core::sync::atomic::Ordering::Relaxed; -#[derive(Debug)] /// Mutable iterator over all futures in the unordered set. +#[derive(Debug)] pub struct IterPinMut<'a, Fut> { pub(super) task: *const Task<Fut>, pub(super) len: usize, - pub(super) _marker: PhantomData<&'a mut FuturesUnordered<Fut>> + pub(super) _marker: PhantomData<&'a mut FuturesUnordered<Fut>>, } -#[derive(Debug)] /// Mutable iterator over all futures in the unordered set. -pub struct IterMut<'a, Fut: Unpin> (pub(super) IterPinMut<'a, Fut>); - #[derive(Debug)] +pub struct IterMut<'a, Fut: Unpin>(pub(super) IterPinMut<'a, Fut>); + /// Immutable iterator over all futures in the unordered set. +#[derive(Debug)] pub struct IterPinRef<'a, Fut> { pub(super) task: *const Task<Fut>, pub(super) len: usize, pub(super) pending_next_all: *mut Task<Fut>, - pub(super) _marker: PhantomData<&'a FuturesUnordered<Fut>> + pub(super) _marker: PhantomData<&'a FuturesUnordered<Fut>>, } -#[derive(Debug)] /// Immutable iterator over all the futures in the unordered set. -pub struct Iter<'a, Fut: Unpin> (pub(super) IterPinRef<'a, Fut>); +#[derive(Debug)] +pub struct Iter<'a, Fut: Unpin>(pub(super) IterPinRef<'a, Fut>); + +/// Owned iterator over all futures in the unordered set. +#[derive(Debug)] +pub struct IntoIter<Fut: Unpin> { + pub(super) len: usize, + pub(super) inner: FuturesUnordered<Fut>, +} + +impl<Fut: Unpin> Iterator for IntoIter<Fut> { + type Item = Fut; + + fn next(&mut self) -> Option<Self::Item> { + // `head_all` can be accessed directly and we don't need to spin on + // `Task::next_all` since we have exclusive access to the set. + let task = self.inner.head_all.get_mut(); + + if (*task).is_null() { + return None; + } + + unsafe { + // Moving out of the future is safe because it is `Unpin` + let future = (*(**task).future.get()).take().unwrap(); + + // Mutable access to a previously shared `FuturesUnordered` implies + // that the other threads already released the object before the + // current thread acquired it, so relaxed ordering can be used and + // valid `next_all` checks can be skipped. + let next = (**task).next_all.load(Relaxed); + *task = next; + self.len -= 1; + Some(future) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len, Some(self.len)) + } +} + +impl<Fut: Unpin> ExactSizeIterator for IntoIter<Fut> {} impl<'a, Fut> Iterator for IterPinMut<'a, Fut> { type Item = Pin<&'a mut Fut>; - fn next(&mut self) -> Option<Pin<&'a mut Fut>> { + fn next(&mut self) -> Option<Self::Item> { if self.task.is_null() { return None; } + unsafe { let future = (*(*self.task).future.get()).as_mut().unwrap(); @@ -60,7 +102,7 @@ impl<Fut> ExactSizeIterator for IterPinMut<'_, Fut> {} impl<'a, Fut: Unpin> Iterator for IterMut<'a, Fut> { type Item = &'a mut Fut; - fn next(&mut self) -> Option<&'a mut Fut> { + fn next(&mut self) -> Option<Self::Item> { self.0.next().map(Pin::get_mut) } @@ -74,10 +116,11 @@ impl<Fut: Unpin> ExactSizeIterator for IterMut<'_, Fut> {} impl<'a, Fut> Iterator for IterPinRef<'a, Fut> { type Item = Pin<&'a Fut>; - fn next(&mut self) -> Option<Pin<&'a Fut>> { + fn next(&mut self) -> Option<Self::Item> { if self.task.is_null() { return None; } + unsafe { let future = (*(*self.task).future.get()).as_ref().unwrap(); @@ -85,10 +128,7 @@ impl<'a, Fut> Iterator for IterPinRef<'a, Fut> { // `head_all` was initially read for this iterator implies acquire // ordering for all previously inserted nodes (and we don't need to // read `len_all` again for any other nodes). - let next = (*self.task).spin_next_all( - self.pending_next_all, - Relaxed, - ); + let next = (*self.task).spin_next_all(self.pending_next_all, Relaxed); self.task = next; self.len -= 1; Some(Pin::new_unchecked(future)) @@ -105,7 +145,7 @@ impl<Fut> ExactSizeIterator for IterPinRef<'_, Fut> {} impl<'a, Fut: Unpin> Iterator for Iter<'a, Fut> { type Item = &'a Fut; - fn next(&mut self) -> Option<&'a Fut> { + fn next(&mut self) -> Option<Self::Item> { self.0.next().map(Pin::get_ref) } @@ -115,3 +155,14 @@ impl<'a, Fut: Unpin> Iterator for Iter<'a, Fut> { } impl<Fut: Unpin> ExactSizeIterator for Iter<'_, Fut> {} + +// SAFETY: we do nothing thread-local and there is no interior mutability, +// so the usual structural `Send`/`Sync` apply. +unsafe impl<Fut: Send> Send for IterPinRef<'_, Fut> {} +unsafe impl<Fut: Sync> Sync for IterPinRef<'_, Fut> {} + +unsafe impl<Fut: Send> Send for IterPinMut<'_, Fut> {} +unsafe impl<Fut: Sync> Sync for IterPinMut<'_, Fut> {} + +unsafe impl<Fut: Send + Unpin> Send for IntoIter<Fut> {} +unsafe impl<Fut: Sync + Unpin> Sync for IntoIter<Fut> {} diff --git a/src/stream/futures_unordered/mod.rs b/src/stream/futures_unordered/mod.rs index 8dcc551..fdbd53d 100644 --- a/src/stream/futures_unordered/mod.rs +++ b/src/stream/futures_unordered/mod.rs @@ -3,11 +3,8 @@ //! This module is only available when the `std` or `alloc` feature of this //! library is activated, and it is activated by default. -use futures_core::future::Future; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_task::{FutureObj, LocalFutureObj, Spawn, LocalSpawn, SpawnError}; use crate::task::AtomicWaker; +use alloc::sync::{Arc, Weak}; use core::cell::UnsafeCell; use core::fmt::{self, Debug}; use core::iter::FromIterator; @@ -16,20 +13,22 @@ use core::mem; use core::pin::Pin; use core::ptr; use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst}; -use core::sync::atomic::{AtomicPtr, AtomicBool}; -use alloc::sync::{Arc, Weak}; +use core::sync::atomic::{AtomicBool, AtomicPtr}; +use futures_core::future::Future; +use futures_core::stream::{FusedStream, Stream}; +use futures_core::task::{Context, Poll}; +use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError}; mod abort; mod iter; -pub use self::iter::{Iter, IterMut, IterPinMut, IterPinRef}; +pub use self::iter::{IntoIter, Iter, IterMut, IterPinMut, IterPinRef}; mod task; use self::task::Task; mod ready_to_run_queue; -use self::ready_to_run_queue::{ReadyToRunQueue, Dequeue}; - +use self::ready_to_run_queue::{Dequeue, ReadyToRunQueue}; /// A set of futures which may complete in any order. /// @@ -63,18 +62,14 @@ unsafe impl<Fut: Sync> Sync for FuturesUnordered<Fut> {} impl<Fut> Unpin for FuturesUnordered<Fut> {} impl Spawn for FuturesUnordered<FutureObj<'_, ()>> { - fn spawn_obj(&self, future_obj: FutureObj<'static, ()>) - -> Result<(), SpawnError> - { + fn spawn_obj(&self, future_obj: FutureObj<'static, ()>) -> Result<(), SpawnError> { self.push(future_obj); Ok(()) } } impl LocalSpawn for FuturesUnordered<LocalFutureObj<'_, ()>> { - fn spawn_local_obj(&self, future_obj: LocalFutureObj<'static, ()>) - -> Result<(), SpawnError> - { + fn spawn_local_obj(&self, future_obj: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { self.push(future_obj); Ok(()) } @@ -102,7 +97,7 @@ impl LocalSpawn for FuturesUnordered<LocalFutureObj<'_, ()>> { // Each task is wrapped in an `Arc` and thereby atomically reference counted. // Also, each task contains an `AtomicBool` which acts as a flag that indicates // whether the task is currently inserted in the atomic queue. When a wake-up -// notifiaction is received, the task will only be inserted into the ready to +// notification is received, the task will only be inserted into the ready to // run queue if it isn't inserted already. impl<Fut> Default for FuturesUnordered<Fut> { @@ -126,8 +121,9 @@ impl<Fut> FuturesUnordered<Fut> { next_ready_to_run: AtomicPtr::new(ptr::null_mut()), queued: AtomicBool::new(true), ready_to_run_queue: Weak::new(), + woken: AtomicBool::new(false), }); - let stub_ptr = &*stub as *const Task<Fut>; + let stub_ptr = Arc::as_ptr(&stub); let ready_to_run_queue = Arc::new(ReadyToRunQueue { waker: AtomicWaker::new(), head: AtomicPtr::new(stub_ptr as *mut _), @@ -172,6 +168,7 @@ impl<Fut> FuturesUnordered<Fut> { next_ready_to_run: AtomicPtr::new(ptr::null_mut()), queued: AtomicBool::new(true), ready_to_run_queue: Arc::downgrade(&self.ready_to_run_queue), + woken: AtomicBool::new(false), }); // Reset the `is_terminated` flag if we've previously marked ourselves @@ -191,24 +188,26 @@ impl<Fut> FuturesUnordered<Fut> { } /// Returns an iterator that allows inspecting each future in the set. - pub fn iter(&self) -> Iter<'_, Fut> where Fut: Unpin { + pub fn iter(&self) -> Iter<'_, Fut> + where + Fut: Unpin, + { Iter(Pin::new(self).iter_pin_ref()) } /// Returns an iterator that allows inspecting each future in the set. - fn iter_pin_ref(self: Pin<&Self>) -> IterPinRef<'_, Fut> { + pub fn iter_pin_ref(self: Pin<&Self>) -> IterPinRef<'_, Fut> { let (task, len) = self.atomic_load_head_and_len_all(); + let pending_next_all = self.pending_next_all(); - IterPinRef { - task, - len, - pending_next_all: self.pending_next_all(), - _marker: PhantomData, - } + IterPinRef { task, len, pending_next_all, _marker: PhantomData } } /// Returns an iterator that allows modifying each future in the set. - pub fn iter_mut(&mut self) -> IterMut<'_, Fut> where Fut: Unpin { + pub fn iter_mut(&mut self) -> IterMut<'_, Fut> + where + Fut: Unpin, + { IterMut(Pin::new(self).iter_pin_mut()) } @@ -217,19 +216,9 @@ impl<Fut> FuturesUnordered<Fut> { // `head_all` can be accessed directly and we don't need to spin on // `Task::next_all` since we have exclusive access to the set. let task = *self.head_all.get_mut(); - let len = if task.is_null() { - 0 - } else { - unsafe { - *(*task).len_all.get() - } - }; + let len = if task.is_null() { 0 } else { unsafe { *(*task).len_all.get() } }; - IterPinMut { - task, - len, - _marker: PhantomData - } + IterPinMut { task, len, _marker: PhantomData } } /// Returns the current head node and number of futures in the list of all @@ -249,7 +238,7 @@ impl<Fut> FuturesUnordered<Fut> { (task, len) } - /// Releases the task. It destorys the future inside and either drops + /// Releases the task. It destroys the future inside and either drops /// the `Arc<Task>` or transfers ownership to the ready to run queue. /// The task this method is called on must have been unlinked before. fn release_task(&mut self, task: Arc<Task<Fut>>) { @@ -388,35 +377,20 @@ impl<Fut> FuturesUnordered<Fut> { // The `ReadyToRunQueue` stub is never inserted into the `head_all` // list, and its pointer value will remain valid for the lifetime of // this `FuturesUnordered`, so we can make use of its value here. - &*self.ready_to_run_queue.stub as *const _ as *mut _ + Arc::as_ptr(&self.ready_to_run_queue.stub) as *mut _ } } impl<Fut: Future> Stream for FuturesUnordered<Fut> { type Item = Fut::Output; - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) - -> Poll<Option<Self::Item>> - { - // Variable to determine how many times it is allowed to poll underlying - // futures without yielding. - // - // A single call to `poll_next` may potentially do a lot of work before - // yielding. This happens in particular if the underlying futures are awoken - // frequently but continue to return `Pending`. This is problematic if other - // tasks are waiting on the executor, since they do not get to run. This value - // caps the number of calls to `poll` on underlying futures a single call to - // `poll_next` is allowed to make. - // - // The value is the length of FuturesUnordered. This ensures that each - // future is polled only once at most per iteration. - // - // See also https://github.com/rust-lang/futures-rs/issues/2047. - let yield_every = self.len(); + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + let len = self.len(); // Keep track of how many child futures we have polled, // in case we want to forcibly yield. let mut polled = 0; + let mut yielded = 0; // Ensure `parent` is correctly set. self.ready_to_run_queue.waker.register(cx.waker()); @@ -469,14 +443,11 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> { // Double check that the call to `release_task` really // happened. Calling it required the task to be unlinked. - debug_assert_eq!( - task.next_all.load(Relaxed), - self.pending_next_all() - ); + debug_assert_eq!(task.next_all.load(Relaxed), self.pending_next_all()); unsafe { debug_assert!((*task.prev_all.get()).is_null()); } - continue + continue; } }; @@ -516,10 +487,7 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> { } } - let mut bomb = Bomb { - task: Some(task), - queue: &mut *self, - }; + let mut bomb = Bomb { task: Some(task), queue: &mut *self }; // Poll the underlying future with the appropriate waker // implementation. This is where a large bit of the unsafety @@ -533,7 +501,11 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> { // the internal allocation, appropriately accessing fields and // deallocating the task if need be. let res = { - let waker = Task::waker_ref(bomb.task.as_ref().unwrap()); + let task = bomb.task.as_ref().unwrap(); + // We are only interested in whether the future is awoken before it + // finishes polling, so reset the flag here. + task.woken.store(false, Relaxed); + let waker = Task::waker_ref(task); let mut cx = Context::from_waker(&waker); // Safety: We won't move the future ever again @@ -546,20 +518,23 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> { match res { Poll::Pending => { let task = bomb.task.take().unwrap(); + // If the future was awoken during polling, we assume + // the future wanted to explicitly yield. + yielded += task.woken.load(Relaxed) as usize; bomb.queue.link(task); - if polled == yield_every { - // We have polled a large number of futures in a row without yielding. - // To ensure we do not starve other tasks waiting on the executor, - // we yield here, but immediately wake ourselves up to continue. + // If a future yields, we respect it and yield here. + // If all futures have been polled, we also yield here to + // avoid starving other tasks waiting on the executor. + // (polling the same future twice per iteration may cause + // the problem: https://github.com/rust-lang/futures-rs/pull/2333) + if yielded >= 2 || polled == len { cx.waker().wake_by_ref(); return Poll::Pending; } - continue - } - Poll::Ready(output) => { - return Poll::Ready(Some(output)) + continue; } + Poll::Ready(output) => return Poll::Ready(Some(output)), } } } @@ -576,19 +551,33 @@ impl<Fut> Debug for FuturesUnordered<Fut> { } } +impl<Fut> FuturesUnordered<Fut> { + /// Clears the set, removing all futures. + pub fn clear(&mut self) { + self.clear_head_all(); + + // we just cleared all the tasks, and we have &mut self, so this is safe. + unsafe { self.ready_to_run_queue.clear() }; + + self.is_terminated.store(false, Relaxed); + } + + fn clear_head_all(&mut self) { + while !self.head_all.get_mut().is_null() { + let head = *self.head_all.get_mut(); + let task = unsafe { self.unlink(head) }; + self.release_task(task); + } + } +} + impl<Fut> Drop for FuturesUnordered<Fut> { fn drop(&mut self) { // When a `FuturesUnordered` is dropped we want to drop all futures // associated with it. At the same time though there may be tons of // wakers flying around which contain `Task<Fut>` references // inside them. We'll let those naturally get deallocated. - unsafe { - while !self.head_all.get_mut().is_null() { - let head = *self.head_all.get_mut(); - let task = self.unlink(head); - self.release_task(task); - } - } + self.clear_head_all(); // Note that at this point we could still have a bunch of tasks in the // ready to run queue. None of those tasks, however, have futures @@ -605,13 +594,48 @@ impl<Fut> Drop for FuturesUnordered<Fut> { } } +impl<'a, Fut: Unpin> IntoIterator for &'a FuturesUnordered<Fut> { + type Item = &'a Fut; + type IntoIter = Iter<'a, Fut>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, Fut: Unpin> IntoIterator for &'a mut FuturesUnordered<Fut> { + type Item = &'a mut Fut; + type IntoIter = IterMut<'a, Fut>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<Fut: Unpin> IntoIterator for FuturesUnordered<Fut> { + type Item = Fut; + type IntoIter = IntoIter<Fut>; + + fn into_iter(mut self) -> Self::IntoIter { + // `head_all` can be accessed directly and we don't need to spin on + // `Task::next_all` since we have exclusive access to the set. + let task = *self.head_all.get_mut(); + let len = if task.is_null() { 0 } else { unsafe { *(*task).len_all.get() } }; + + IntoIter { len, inner: self } + } +} + impl<Fut> FromIterator<Fut> for FuturesUnordered<Fut> { fn from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = Fut>, { let acc = Self::new(); - iter.into_iter().fold(acc, |acc, item| { acc.push(item); acc }) + iter.into_iter().fold(acc, |acc, item| { + acc.push(item); + acc + }) } } diff --git a/src/stream/futures_unordered/ready_to_run_queue.rs b/src/stream/futures_unordered/ready_to_run_queue.rs index 2105195..4518705 100644 --- a/src/stream/futures_unordered/ready_to_run_queue.rs +++ b/src/stream/futures_unordered/ready_to_run_queue.rs @@ -1,9 +1,9 @@ use crate::task::AtomicWaker; +use alloc::sync::Arc; use core::cell::UnsafeCell; use core::ptr; use core::sync::atomic::AtomicPtr; -use core::sync::atomic::Ordering::{Relaxed, Acquire, Release, AcqRel}; -use alloc::sync::Arc; +use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use super::abort::abort; use super::task::Task; @@ -83,7 +83,28 @@ impl<Fut> ReadyToRunQueue<Fut> { } pub(super) fn stub(&self) -> *const Task<Fut> { - &*self.stub + Arc::as_ptr(&self.stub) + } + + // Clear the queue of tasks. + // + // Note that each task has a strong reference count associated with it + // which is owned by the ready to run queue. This method just pulls out + // tasks and drops their refcounts. + // + // # Safety + // + // - All tasks **must** have had their futures dropped already (by FuturesUnordered::clear) + // - The caller **must** guarantee unique access to `self` + pub(crate) unsafe fn clear(&self) { + loop { + // SAFETY: We have the guarantee of mutual exclusion required by `dequeue`. + match self.dequeue() { + Dequeue::Empty => break, + Dequeue::Inconsistent => abort("inconsistent in drop"), + Dequeue::Data(ptr) => drop(Arc::from_raw(ptr)), + } + } } } @@ -91,19 +112,11 @@ impl<Fut> Drop for ReadyToRunQueue<Fut> { fn drop(&mut self) { // Once we're in the destructor for `Inner<Fut>` we need to clear out // the ready to run queue of tasks if there's anything left in there. - // - // Note that each task has a strong reference count associated with it - // which is owned by the ready to run queue. All tasks should have had - // their futures dropped already by the `FuturesUnordered` destructor - // above, so we're just pulling out tasks and dropping their refcounts. + + // All tasks have had their futures dropped already by the `FuturesUnordered` + // destructor above, and we have &mut self, so this is safe. unsafe { - loop { - match self.dequeue() { - Dequeue::Empty => break, - Dequeue::Inconsistent => abort("inconsistent in drop"), - Dequeue::Data(ptr) => drop(Arc::from_raw(ptr)), - } - } + self.clear(); } } } diff --git a/src/stream/futures_unordered/task.rs b/src/stream/futures_unordered/task.rs index 261408f..ec2114e 100644 --- a/src/stream/futures_unordered/task.rs +++ b/src/stream/futures_unordered/task.rs @@ -1,11 +1,11 @@ -use core::cell::UnsafeCell; -use core::sync::atomic::{AtomicPtr, AtomicBool}; -use core::sync::atomic::Ordering::{self, SeqCst}; use alloc::sync::{Arc, Weak}; +use core::cell::UnsafeCell; +use core::sync::atomic::Ordering::{self, Relaxed, SeqCst}; +use core::sync::atomic::{AtomicBool, AtomicPtr}; -use crate::task::{ArcWake, WakerRef, waker_ref}; -use super::ReadyToRunQueue; use super::abort::abort; +use super::ReadyToRunQueue; +use crate::task::{waker_ref, ArcWake, WakerRef}; pub(super) struct Task<Fut> { // The future @@ -31,6 +31,11 @@ pub(super) struct Task<Fut> { // Whether or not this task is currently in the ready to run queue pub(super) queued: AtomicBool, + + // Whether the future was awoken during polling + // It is possible for this flag to be set to true after the polling, + // but it will be ignored. + pub(super) woken: AtomicBool, } // `Task` can be sent across threads safely because it ensures that @@ -48,6 +53,8 @@ impl<Fut> ArcWake for Task<Fut> { None => return, }; + arc_self.woken.store(true, Relaxed); + // It's our job to enqueue this task it into the ready to run queue. To // do this we set the `queued` flag, and if successful we then do the // actual queueing operation, ensuring that we're only queued once. @@ -62,7 +69,7 @@ impl<Fut> ArcWake for Task<Fut> { // still. let prev = arc_self.queued.swap(true, SeqCst); if !prev { - inner.enqueue(&**arc_self); + inner.enqueue(Arc::as_ptr(arc_self)); inner.waker.wake(); } } diff --git a/src/stream/iter.rs b/src/stream/iter.rs index 033dae1..20471c2 100644 --- a/src/stream/iter.rs +++ b/src/stream/iter.rs @@ -27,15 +27,15 @@ impl<I> Unpin for Iter<I> {} /// # }); /// ``` pub fn iter<I>(i: I) -> Iter<I::IntoIter> - where I: IntoIterator, +where + I: IntoIterator, { - assert_stream::<I::Item, _>(Iter { - iter: i.into_iter(), - }) + assert_stream::<I::Item, _>(Iter { iter: i.into_iter() }) } impl<I> Stream for Iter<I> - where I: Iterator, +where + I: Iterator, { type Item = I::Item; diff --git a/src/stream/mod.rs b/src/stream/mod.rs index f3b2baa..ec685b9 100644 --- a/src/stream/mod.rs +++ b/src/stream/mod.rs @@ -19,8 +19,8 @@ pub use futures_core::stream::{FusedStream, Stream, TryStream}; mod stream; pub use self::stream::{ Chain, Collect, Concat, Cycle, Enumerate, Filter, FilterMap, FlatMap, Flatten, Fold, ForEach, - Fuse, Inspect, Map, Next, Peek, Peekable, Scan, SelectNextSome, Skip, SkipWhile, StreamExt, - StreamFuture, Take, TakeUntil, TakeWhile, Then, Unzip, Zip, + Fuse, Inspect, Map, Next, NextIf, NextIfEq, Peek, PeekMut, Peekable, Scan, SelectNextSome, + Skip, SkipWhile, StreamExt, StreamFuture, Take, TakeUntil, TakeWhile, Then, Unzip, Zip, }; #[cfg(feature = "std")] @@ -36,11 +36,11 @@ pub use self::stream::ReadyChunks; #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] pub use self::stream::Forward; -#[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] +#[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] pub use self::stream::{BufferUnordered, Buffered, ForEachConcurrent}; -#[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] +#[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] #[cfg(feature = "alloc")] @@ -58,10 +58,13 @@ pub use self::try_stream::{ #[cfg(feature = "std")] pub use self::try_stream::IntoAsyncRead; -#[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] +#[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] pub use self::try_stream::{TryBufferUnordered, TryBuffered, TryForEachConcurrent}; +#[cfg(feature = "alloc")] +pub use self::try_stream::{TryChunks, TryChunksError}; + // Primitive streams mod iter; @@ -85,29 +88,50 @@ pub use self::pending::{pending, Pending}; mod poll_fn; pub use self::poll_fn::{poll_fn, PollFn}; +mod poll_immediate; +pub use self::poll_immediate::{poll_immediate, PollImmediate}; + mod select; pub use self::select::{select, Select}; +mod select_with_strategy; +pub use self::select_with_strategy::{select_with_strategy, PollNext, SelectWithStrategy}; + mod unfold; pub use self::unfold::{unfold, Unfold}; -cfg_target_has_atomic! { - #[cfg(feature = "alloc")] - mod futures_ordered; - #[cfg(feature = "alloc")] - pub use self::futures_ordered::FuturesOrdered; - - #[cfg(feature = "alloc")] - pub mod futures_unordered; - #[cfg(feature = "alloc")] - #[doc(inline)] - pub use self::futures_unordered::FuturesUnordered; - - #[cfg(feature = "alloc")] - mod select_all; - #[cfg(feature = "alloc")] - pub use self::select_all::{select_all, SelectAll}; -} +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod futures_ordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use self::futures_ordered::FuturesOrdered; + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub mod futures_unordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[doc(inline)] +pub use self::futures_unordered::FuturesUnordered; + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub mod select_all; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[doc(inline)] +pub use self::select_all::{select_all, SelectAll}; + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod abortable; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted}; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use abortable::abortable; // Just a helper function to ensure the streams we're returning all have the // right implementations. diff --git a/src/stream/once.rs b/src/stream/once.rs index e16fe00..ee21c8b 100644 --- a/src/stream/once.rs +++ b/src/stream/once.rs @@ -2,7 +2,7 @@ use super::assert_stream; use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; diff --git a/src/stream/poll_immediate.rs b/src/stream/poll_immediate.rs new file mode 100644 index 0000000..c7e8a5b --- /dev/null +++ b/src/stream/poll_immediate.rs @@ -0,0 +1,80 @@ +use core::pin::Pin; +use futures_core::task::{Context, Poll}; +use futures_core::Stream; +use pin_project_lite::pin_project; + +pin_project! { + /// Stream for the [poll_immediate](poll_immediate()) function. + /// + /// It will never return [Poll::Pending](core::task::Poll::Pending) + #[derive(Debug, Clone)] + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct PollImmediate<S> { + #[pin] + stream: Option<S> + } +} + +impl<T, S> Stream for PollImmediate<S> +where + S: Stream<Item = T>, +{ + type Item = Poll<T>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + let mut this = self.project(); + let stream = match this.stream.as_mut().as_pin_mut() { + // inner is gone, so we can continue to signal that the stream is closed. + None => return Poll::Ready(None), + Some(inner) => inner, + }; + + match stream.poll_next(cx) { + Poll::Ready(Some(t)) => Poll::Ready(Some(Poll::Ready(t))), + Poll::Ready(None) => { + this.stream.set(None); + Poll::Ready(None) + } + Poll::Pending => Poll::Ready(Some(Poll::Pending)), + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.stream.as_ref().map_or((0, Some(0)), Stream::size_hint) + } +} + +impl<S: Stream> super::FusedStream for PollImmediate<S> { + fn is_terminated(&self) -> bool { + self.stream.is_none() + } +} + +/// Creates a new stream that always immediately returns [Poll::Ready](core::task::Poll::Ready) when awaiting it. +/// +/// This is useful when immediacy is more important than waiting for the next item to be ready. +/// +/// # Examples +/// +/// ``` +/// # futures::executor::block_on(async { +/// use futures::stream::{self, StreamExt}; +/// use futures::task::Poll; +/// +/// let mut r = stream::poll_immediate(Box::pin(stream::iter(1_u32..3))); +/// assert_eq!(r.next().await, Some(Poll::Ready(1))); +/// assert_eq!(r.next().await, Some(Poll::Ready(2))); +/// assert_eq!(r.next().await, None); +/// +/// let mut p = stream::poll_immediate(Box::pin(stream::once(async { +/// futures::pending!(); +/// 42_u8 +/// }))); +/// assert_eq!(p.next().await, Some(Poll::Pending)); +/// assert_eq!(p.next().await, Some(Poll::Ready(42))); +/// assert_eq!(p.next().await, None); +/// # }); +/// ``` +pub fn poll_immediate<S: Stream>(s: S) -> PollImmediate<S> { + super::assert_stream::<Poll<S::Item>, PollImmediate<S>>(PollImmediate { stream: Some(s) }) +} diff --git a/src/stream/repeat.rs b/src/stream/repeat.rs index cf9f21b..3f9aa87 100644 --- a/src/stream/repeat.rs +++ b/src/stream/repeat.rs @@ -1,6 +1,6 @@ use super::assert_stream; use core::pin::Pin; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; /// Stream for the [`repeat`] function. @@ -25,7 +25,8 @@ pub struct Repeat<T> { /// # }); /// ``` pub fn repeat<T>(item: T) -> Repeat<T> - where T: Clone +where + T: Clone, { assert_stream::<T, _>(Repeat { item }) } @@ -33,7 +34,8 @@ pub fn repeat<T>(item: T) -> Repeat<T> impl<T> Unpin for Repeat<T> {} impl<T> Stream for Repeat<T> - where T: Clone +where + T: Clone, { type Item = T; @@ -47,7 +49,8 @@ impl<T> Stream for Repeat<T> } impl<T> FusedStream for Repeat<T> - where T: Clone, +where + T: Clone, { fn is_terminated(&self) -> bool { false diff --git a/src/stream/repeat_with.rs b/src/stream/repeat_with.rs index 0255643..f5a81b4 100644 --- a/src/stream/repeat_with.rs +++ b/src/stream/repeat_with.rs @@ -1,6 +1,6 @@ use super::assert_stream; use core::pin::Pin; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; /// An stream that repeats elements of type `A` endlessly by @@ -28,8 +28,7 @@ impl<A, F: FnMut() -> A> Stream for RepeatWith<F> { } } -impl<A, F: FnMut() -> A> FusedStream for RepeatWith<F> -{ +impl<A, F: FnMut() -> A> FusedStream for RepeatWith<F> { fn is_terminated(&self) -> bool { false } diff --git a/src/stream/select.rs b/src/stream/select.rs index 2942494..0c1e3af 100644 --- a/src/stream/select.rs +++ b/src/stream/select.rs @@ -1,5 +1,5 @@ use super::assert_stream; -use crate::stream::{StreamExt, Fuse}; +use crate::stream::{select_with_strategy, PollNext, SelectWithStrategy}; use core::pin::Pin; use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; @@ -11,10 +11,7 @@ pin_project! { #[must_use = "streams do nothing unless polled"] pub struct Select<St1, St2> { #[pin] - stream1: Fuse<St1>, - #[pin] - stream2: Fuse<St2>, - flag: bool, + inner: SelectWithStrategy<St1, St2, fn(&mut PollNext)-> PollNext, PollNext>, } } @@ -22,20 +19,42 @@ pin_project! { /// stream will be polled in a round-robin fashion, and whenever a stream is /// ready to yield an item that item is yielded. /// -/// After one of the two input stream completes, the remaining one will be +/// After one of the two input streams completes, the remaining one will be /// polled exclusively. The returned stream completes when both input /// streams have completed. /// /// Note that this function consumes both streams and returns a wrapped /// version of them. +/// +/// ## Examples +/// +/// ```rust +/// # futures::executor::block_on(async { +/// use futures::stream::{ repeat, select, StreamExt }; +/// +/// let left = repeat(1); +/// let right = repeat(2); +/// +/// let mut out = select(left, right); +/// +/// for _ in 0..100 { +/// // We should be alternating. +/// assert_eq!(1, out.select_next_some().await); +/// assert_eq!(2, out.select_next_some().await); +/// } +/// # }); +/// ``` pub fn select<St1, St2>(stream1: St1, stream2: St2) -> Select<St1, St2> - where St1: Stream, - St2: Stream<Item = St1::Item> +where + St1: Stream, + St2: Stream<Item = St1::Item>, { + fn round_robin(last: &mut PollNext) -> PollNext { + last.toggle() + } + assert_stream::<St1::Item, _>(Select { - stream1: stream1.fuse(), - stream2: stream2.fuse(), - flag: false, + inner: select_with_strategy(stream1, stream2, round_robin), }) } @@ -43,7 +62,7 @@ impl<St1, St2> Select<St1, St2> { /// Acquires a reference to the underlying streams that this combinator is /// pulling from. pub fn get_ref(&self) -> (&St1, &St2) { - (self.stream1.get_ref(), self.stream2.get_ref()) + self.inner.get_ref() } /// Acquires a mutable reference to the underlying streams that this @@ -52,7 +71,7 @@ impl<St1, St2> Select<St1, St2> { /// Note that care must be taken to avoid tampering with the state of the /// stream which may otherwise confuse this combinator. pub fn get_mut(&mut self) -> (&mut St1, &mut St2) { - (self.stream1.get_mut(), self.stream2.get_mut()) + self.inner.get_mut() } /// Acquires a pinned mutable reference to the underlying streams that this @@ -62,7 +81,7 @@ impl<St1, St2> Select<St1, St2> { /// stream which may otherwise confuse this combinator. pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut St1>, Pin<&mut St2>) { let this = self.project(); - (this.stream1.get_pin_mut(), this.stream2.get_pin_mut()) + this.inner.get_pin_mut() } /// Consumes this combinator, returning the underlying streams. @@ -70,61 +89,29 @@ impl<St1, St2> Select<St1, St2> { /// Note that this may discard intermediate state of this combinator, so /// care should be taken to avoid losing resources when this is called. pub fn into_inner(self) -> (St1, St2) { - (self.stream1.into_inner(), self.stream2.into_inner()) + self.inner.into_inner() } } impl<St1, St2> FusedStream for Select<St1, St2> - where St1: Stream, - St2: Stream<Item = St1::Item> +where + St1: Stream, + St2: Stream<Item = St1::Item>, { fn is_terminated(&self) -> bool { - self.stream1.is_terminated() && self.stream2.is_terminated() + self.inner.is_terminated() } } impl<St1, St2> Stream for Select<St1, St2> - where St1: Stream, - St2: Stream<Item = St1::Item> +where + St1: Stream, + St2: Stream<Item = St1::Item>, { type Item = St1::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St1::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St1::Item>> { let this = self.project(); - if !*this.flag { - poll_inner(this.flag, this.stream1, this.stream2, cx) - } else { - poll_inner(this.flag, this.stream2, this.stream1, cx) - } - } -} - -fn poll_inner<St1, St2>( - flag: &mut bool, - a: Pin<&mut St1>, - b: Pin<&mut St2>, - cx: &mut Context<'_> -) -> Poll<Option<St1::Item>> - where St1: Stream, St2: Stream<Item = St1::Item> -{ - let a_done = match a.poll_next(cx) { - Poll::Ready(Some(item)) => { - // give the other stream a chance to go first next time - *flag = !*flag; - return Poll::Ready(Some(item)) - }, - Poll::Ready(None) => true, - Poll::Pending => false, - }; - - match b.poll_next(cx) { - Poll::Ready(Some(item)) => { - Poll::Ready(Some(item)) - } - Poll::Ready(None) if a_done => Poll::Ready(None), - Poll::Ready(None) | Poll::Pending => Poll::Pending, + this.inner.poll_next(cx) } } diff --git a/src/stream/select_all.rs b/src/stream/select_all.rs index c0b92fa..3474331 100644 --- a/src/stream/select_all.rs +++ b/src/stream/select_all.rs @@ -5,27 +5,32 @@ use core::iter::FromIterator; use core::pin::Pin; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; +use pin_project_lite::pin_project; + use super::assert_stream; -use crate::stream::{StreamExt, StreamFuture, FuturesUnordered}; +use crate::stream::{futures_unordered, FuturesUnordered, StreamExt, StreamFuture}; -/// An unbounded set of streams -/// -/// This "combinator" provides the ability to maintain a set of streams -/// and drive them all to completion. -/// -/// Streams are pushed into this set and their realized values are -/// yielded as they become ready. Streams will only be polled when they -/// generate notifications. This allows to coordinate a large number of streams. -/// -/// Note that you can create a ready-made `SelectAll` via the -/// `select_all` function in the `stream` module, or you can start with an -/// empty set with the `SelectAll::new` constructor. -#[must_use = "streams do nothing unless polled"] -pub struct SelectAll<St> { - inner: FuturesUnordered<StreamFuture<St>>, +pin_project! { + /// An unbounded set of streams + /// + /// This "combinator" provides the ability to maintain a set of streams + /// and drive them all to completion. + /// + /// Streams are pushed into this set and their realized values are + /// yielded as they become ready. Streams will only be polled when they + /// generate notifications. This allows to coordinate a large number of streams. + /// + /// Note that you can create a ready-made `SelectAll` via the + /// `select_all` function in the `stream` module, or you can start with an + /// empty set with the `SelectAll::new` constructor. + #[must_use = "streams do nothing unless polled"] + pub struct SelectAll<St> { + #[pin] + inner: FuturesUnordered<StreamFuture<St>>, + } } impl<St: Debug> Debug for SelectAll<St> { @@ -64,6 +69,21 @@ impl<St: Stream + Unpin> SelectAll<St> { pub fn push(&mut self, stream: St) { self.inner.push(stream.into_future()); } + + /// Returns an iterator that allows inspecting each stream in the set. + pub fn iter(&self) -> Iter<'_, St> { + Iter(self.inner.iter()) + } + + /// Returns an iterator that allows modifying each stream in the set. + pub fn iter_mut(&mut self) -> IterMut<'_, St> { + IterMut(self.inner.iter_mut()) + } + + /// Clears the set, removing all streams. + pub fn clear(&mut self) { + self.inner.clear() + } } impl<St: Stream + Unpin> Default for SelectAll<St> { @@ -75,10 +95,7 @@ impl<St: Stream + Unpin> Default for SelectAll<St> { impl<St: Stream + Unpin> Stream for SelectAll<St> { type Item = St::Item; - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { loop { match ready!(self.inner.poll_next_unpin(cx)) { Some((Some(item), remaining)) => { @@ -111,13 +128,14 @@ impl<St: Stream + Unpin> FusedStream for SelectAll<St> { /// streams internally, in the order they become available. /// /// Note that the returned set can also be used to dynamically push more -/// futures into the set as they become available. +/// streams into the set as they become available. /// /// This function is only available when the `std` or `alloc` feature of this /// library is activated, and it is activated by default. pub fn select_all<I>(streams: I) -> SelectAll<I::Item> - where I: IntoIterator, - I::Item: Stream + Unpin +where + I: IntoIterator, + I::Item: Stream + Unpin, { let mut set = SelectAll::new(); @@ -141,3 +159,96 @@ impl<St: Stream + Unpin> Extend<St> for SelectAll<St> { } } } + +impl<St: Stream + Unpin> IntoIterator for SelectAll<St> { + type Item = St; + type IntoIter = IntoIter<St>; + + fn into_iter(self) -> Self::IntoIter { + IntoIter(self.inner.into_iter()) + } +} + +impl<'a, St: Stream + Unpin> IntoIterator for &'a SelectAll<St> { + type Item = &'a St; + type IntoIter = Iter<'a, St>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, St: Stream + Unpin> IntoIterator for &'a mut SelectAll<St> { + type Item = &'a mut St; + type IntoIter = IterMut<'a, St>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +/// Immutable iterator over all streams in the unordered set. +#[derive(Debug)] +pub struct Iter<'a, St: Unpin>(futures_unordered::Iter<'a, StreamFuture<St>>); + +/// Mutable iterator over all streams in the unordered set. +#[derive(Debug)] +pub struct IterMut<'a, St: Unpin>(futures_unordered::IterMut<'a, StreamFuture<St>>); + +/// Owned iterator over all streams in the unordered set. +#[derive(Debug)] +pub struct IntoIter<St: Unpin>(futures_unordered::IntoIter<StreamFuture<St>>); + +impl<'a, St: Stream + Unpin> Iterator for Iter<'a, St> { + type Item = &'a St; + + fn next(&mut self) -> Option<Self::Item> { + let st = self.0.next()?; + let next = st.get_ref(); + // This should always be true because FuturesUnordered removes completed futures. + debug_assert!(next.is_some()); + next + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl<St: Stream + Unpin> ExactSizeIterator for Iter<'_, St> {} + +impl<'a, St: Stream + Unpin> Iterator for IterMut<'a, St> { + type Item = &'a mut St; + + fn next(&mut self) -> Option<Self::Item> { + let st = self.0.next()?; + let next = st.get_mut(); + // This should always be true because FuturesUnordered removes completed futures. + debug_assert!(next.is_some()); + next + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl<St: Stream + Unpin> ExactSizeIterator for IterMut<'_, St> {} + +impl<St: Stream + Unpin> Iterator for IntoIter<St> { + type Item = St; + + fn next(&mut self) -> Option<Self::Item> { + let st = self.0.next()?; + let next = st.into_inner(); + // This should always be true because FuturesUnordered removes completed futures. + debug_assert!(next.is_some()); + next + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl<St: Stream + Unpin> ExactSizeIterator for IntoIter<St> {} diff --git a/src/stream/select_with_strategy.rs b/src/stream/select_with_strategy.rs new file mode 100644 index 0000000..bd86990 --- /dev/null +++ b/src/stream/select_with_strategy.rs @@ -0,0 +1,229 @@ +use super::assert_stream; +use crate::stream::{Fuse, StreamExt}; +use core::{fmt, pin::Pin}; +use futures_core::stream::{FusedStream, Stream}; +use futures_core::task::{Context, Poll}; +use pin_project_lite::pin_project; + +/// Type to tell [`SelectWithStrategy`] which stream to poll next. +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub enum PollNext { + /// Poll the first stream. + Left, + /// Poll the second stream. + Right, +} + +impl PollNext { + /// Toggle the value and return the old one. + pub fn toggle(&mut self) -> Self { + let old = *self; + + match self { + PollNext::Left => *self = PollNext::Right, + PollNext::Right => *self = PollNext::Left, + } + + old + } +} + +impl Default for PollNext { + fn default() -> Self { + PollNext::Left + } +} + +pin_project! { + /// Stream for the [`select_with_strategy()`] function. See function docs for details. + #[must_use = "streams do nothing unless polled"] + pub struct SelectWithStrategy<St1, St2, Clos, State> { + #[pin] + stream1: Fuse<St1>, + #[pin] + stream2: Fuse<St2>, + state: State, + clos: Clos, + } +} + +/// This function will attempt to pull items from both streams. You provide a +/// closure to tell [`SelectWithStrategy`] which stream to poll. The closure can +/// store state on `SelectWithStrategy` to which it will receive a `&mut` on every +/// invocation. This allows basing the strategy on prior choices. +/// +/// After one of the two input streams completes, the remaining one will be +/// polled exclusively. The returned stream completes when both input +/// streams have completed. +/// +/// Note that this function consumes both streams and returns a wrapped +/// version of them. +/// +/// ## Examples +/// +/// ### Priority +/// This example shows how to always prioritize the left stream. +/// +/// ```rust +/// # futures::executor::block_on(async { +/// use futures::stream::{ repeat, select_with_strategy, PollNext, StreamExt }; +/// +/// let left = repeat(1); +/// let right = repeat(2); +/// +/// // We don't need any state, so let's make it an empty tuple. +/// // We must provide some type here, as there is no way for the compiler +/// // to infer it. As we don't need to capture variables, we can just +/// // use a function pointer instead of a closure. +/// fn prio_left(_: &mut ()) -> PollNext { PollNext::Left } +/// +/// let mut out = select_with_strategy(left, right, prio_left); +/// +/// for _ in 0..100 { +/// // Whenever we poll out, we will alwas get `1`. +/// assert_eq!(1, out.select_next_some().await); +/// } +/// # }); +/// ``` +/// +/// ### Round Robin +/// This example shows how to select from both streams round robin. +/// Note: this special case is provided by [`futures-util::stream::select`]. +/// +/// ```rust +/// # futures::executor::block_on(async { +/// use futures::stream::{ repeat, select_with_strategy, PollNext, StreamExt }; +/// +/// let left = repeat(1); +/// let right = repeat(2); +/// +/// let rrobin = |last: &mut PollNext| last.toggle(); +/// +/// let mut out = select_with_strategy(left, right, rrobin); +/// +/// for _ in 0..100 { +/// // We should be alternating now. +/// assert_eq!(1, out.select_next_some().await); +/// assert_eq!(2, out.select_next_some().await); +/// } +/// # }); +/// ``` +pub fn select_with_strategy<St1, St2, Clos, State>( + stream1: St1, + stream2: St2, + which: Clos, +) -> SelectWithStrategy<St1, St2, Clos, State> +where + St1: Stream, + St2: Stream<Item = St1::Item>, + Clos: FnMut(&mut State) -> PollNext, + State: Default, +{ + assert_stream::<St1::Item, _>(SelectWithStrategy { + stream1: stream1.fuse(), + stream2: stream2.fuse(), + state: Default::default(), + clos: which, + }) +} + +impl<St1, St2, Clos, State> SelectWithStrategy<St1, St2, Clos, State> { + /// Acquires a reference to the underlying streams that this combinator is + /// pulling from. + pub fn get_ref(&self) -> (&St1, &St2) { + (self.stream1.get_ref(), self.stream2.get_ref()) + } + + /// Acquires a mutable reference to the underlying streams that this + /// combinator is pulling from. + /// + /// Note that care must be taken to avoid tampering with the state of the + /// stream which may otherwise confuse this combinator. + pub fn get_mut(&mut self) -> (&mut St1, &mut St2) { + (self.stream1.get_mut(), self.stream2.get_mut()) + } + + /// Acquires a pinned mutable reference to the underlying streams that this + /// combinator is pulling from. + /// + /// Note that care must be taken to avoid tampering with the state of the + /// stream which may otherwise confuse this combinator. + pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut St1>, Pin<&mut St2>) { + let this = self.project(); + (this.stream1.get_pin_mut(), this.stream2.get_pin_mut()) + } + + /// Consumes this combinator, returning the underlying streams. + /// + /// Note that this may discard intermediate state of this combinator, so + /// care should be taken to avoid losing resources when this is called. + pub fn into_inner(self) -> (St1, St2) { + (self.stream1.into_inner(), self.stream2.into_inner()) + } +} + +impl<St1, St2, Clos, State> FusedStream for SelectWithStrategy<St1, St2, Clos, State> +where + St1: Stream, + St2: Stream<Item = St1::Item>, + Clos: FnMut(&mut State) -> PollNext, +{ + fn is_terminated(&self) -> bool { + self.stream1.is_terminated() && self.stream2.is_terminated() + } +} + +impl<St1, St2, Clos, State> Stream for SelectWithStrategy<St1, St2, Clos, State> +where + St1: Stream, + St2: Stream<Item = St1::Item>, + Clos: FnMut(&mut State) -> PollNext, +{ + type Item = St1::Item; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St1::Item>> { + let this = self.project(); + + match (this.clos)(this.state) { + PollNext::Left => poll_inner(this.stream1, this.stream2, cx), + PollNext::Right => poll_inner(this.stream2, this.stream1, cx), + } + } +} + +fn poll_inner<St1, St2>( + a: Pin<&mut St1>, + b: Pin<&mut St2>, + cx: &mut Context<'_>, +) -> Poll<Option<St1::Item>> +where + St1: Stream, + St2: Stream<Item = St1::Item>, +{ + let a_done = match a.poll_next(cx) { + Poll::Ready(Some(item)) => return Poll::Ready(Some(item)), + Poll::Ready(None) => true, + Poll::Pending => false, + }; + + match b.poll_next(cx) { + Poll::Ready(Some(item)) => Poll::Ready(Some(item)), + Poll::Ready(None) if a_done => Poll::Ready(None), + Poll::Ready(None) | Poll::Pending => Poll::Pending, + } +} + +impl<St1, St2, Clos, State> fmt::Debug for SelectWithStrategy<St1, St2, Clos, State> +where + St1: fmt::Debug, + St2: fmt::Debug, + State: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SelectWithStrategy") + .field("stream1", &self.stream1) + .field("stream2", &self.stream2) + .field("state", &self.state) + .finish() + } +} diff --git a/src/stream/stream/all.rs b/src/stream/stream/all.rs new file mode 100644 index 0000000..ba2baa5 --- /dev/null +++ b/src/stream/stream/all.rs @@ -0,0 +1,92 @@ +use core::fmt; +use core::pin::Pin; +use futures_core::future::{FusedFuture, Future}; +use futures_core::ready; +use futures_core::stream::Stream; +use futures_core::task::{Context, Poll}; +use pin_project_lite::pin_project; + +pin_project! { + /// Future for the [`all`](super::StreamExt::all) method. + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct All<St, Fut, F> { + #[pin] + stream: St, + f: F, + accum: Option<bool>, + #[pin] + future: Option<Fut>, + } +} + +impl<St, Fut, F> fmt::Debug for All<St, Fut, F> +where + St: fmt::Debug, + Fut: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("All") + .field("stream", &self.stream) + .field("accum", &self.accum) + .field("future", &self.future) + .finish() + } +} + +impl<St, Fut, F> All<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + pub(super) fn new(stream: St, f: F) -> Self { + Self { stream, f, accum: Some(true), future: None } + } +} + +impl<St, Fut, F> FusedFuture for All<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + fn is_terminated(&self) -> bool { + self.accum.is_none() && self.future.is_none() + } +} + +impl<St, Fut, F> Future for All<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + type Output = bool; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<bool> { + let mut this = self.project(); + Poll::Ready(loop { + if let Some(fut) = this.future.as_mut().as_pin_mut() { + // we're currently processing a future to produce a new accum value + let acc = this.accum.unwrap() && ready!(fut.poll(cx)); + if !acc { + break false; + } // early exit + *this.accum = Some(acc); + this.future.set(None); + } else if this.accum.is_some() { + // we're waiting on a new item from the stream + match ready!(this.stream.as_mut().poll_next(cx)) { + Some(item) => { + this.future.set(Some((this.f)(item))); + } + None => { + break this.accum.take().unwrap(); + } + } + } else { + panic!("All polled after completion") + } + }) + } +} diff --git a/src/stream/stream/any.rs b/src/stream/stream/any.rs new file mode 100644 index 0000000..f023125 --- /dev/null +++ b/src/stream/stream/any.rs @@ -0,0 +1,92 @@ +use core::fmt; +use core::pin::Pin; +use futures_core::future::{FusedFuture, Future}; +use futures_core::ready; +use futures_core::stream::Stream; +use futures_core::task::{Context, Poll}; +use pin_project_lite::pin_project; + +pin_project! { + /// Future for the [`any`](super::StreamExt::any) method. + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct Any<St, Fut, F> { + #[pin] + stream: St, + f: F, + accum: Option<bool>, + #[pin] + future: Option<Fut>, + } +} + +impl<St, Fut, F> fmt::Debug for Any<St, Fut, F> +where + St: fmt::Debug, + Fut: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Any") + .field("stream", &self.stream) + .field("accum", &self.accum) + .field("future", &self.future) + .finish() + } +} + +impl<St, Fut, F> Any<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + pub(super) fn new(stream: St, f: F) -> Self { + Self { stream, f, accum: Some(false), future: None } + } +} + +impl<St, Fut, F> FusedFuture for Any<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + fn is_terminated(&self) -> bool { + self.accum.is_none() && self.future.is_none() + } +} + +impl<St, Fut, F> Future for Any<St, Fut, F> +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = bool>, +{ + type Output = bool; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<bool> { + let mut this = self.project(); + Poll::Ready(loop { + if let Some(fut) = this.future.as_mut().as_pin_mut() { + // we're currently processing a future to produce a new accum value + let acc = this.accum.unwrap() || ready!(fut.poll(cx)); + if acc { + break true; + } // early exit + *this.accum = Some(acc); + this.future.set(None); + } else if this.accum.is_some() { + // we're waiting on a new item from the stream + match ready!(this.stream.as_mut().poll_next(cx)) { + Some(item) => { + this.future.set(Some((this.f)(item))); + } + None => { + break this.accum.take().unwrap(); + } + } + } else { + panic!("Any polled after completion") + } + }) + } +} diff --git a/src/stream/stream/buffer_unordered.rs b/src/stream/stream/buffer_unordered.rs index de42cfd..d64c142 100644 --- a/src/stream/stream/buffer_unordered.rs +++ b/src/stream/stream/buffer_unordered.rs @@ -1,12 +1,12 @@ use crate::stream::{Fuse, FuturesUnordered, StreamExt}; +use core::fmt; +use core::pin::Pin; use futures_core::future::Future; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::fmt; -use core::pin::Pin; pin_project! { /// Stream for the [`buffer_unordered`](super::StreamExt::buffer_unordered) @@ -63,10 +63,7 @@ where { type Item = <St::Item as Future>::Output; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); // First up, try to spawn off as many futures as possible by filling up diff --git a/src/stream/stream/buffered.rs b/src/stream/stream/buffered.rs index 1af9f49..6052a73 100644 --- a/src/stream/stream/buffered.rs +++ b/src/stream/stream/buffered.rs @@ -1,4 +1,6 @@ use crate::stream::{Fuse, FuturesOrdered, StreamExt}; +use core::fmt; +use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; use futures_core::stream::Stream; @@ -6,8 +8,6 @@ use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::fmt; -use core::pin::Pin; pin_project! { /// Stream for the [`buffered`](super::StreamExt::buffered) method. @@ -44,11 +44,7 @@ where St::Item: Future, { pub(super) fn new(stream: St, n: usize) -> Self { - Self { - stream: super::Fuse::new(stream), - in_progress_queue: FuturesOrdered::new(), - max: n, - } + Self { stream: super::Fuse::new(stream), in_progress_queue: FuturesOrdered::new(), max: n } } delegate_access_inner!(stream, St, (.)); @@ -61,10 +57,7 @@ where { type Item = <St::Item as Future>::Output; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); // First up, try to spawn off as many futures as possible by filling up @@ -79,7 +72,7 @@ where // Attempt to pull the next value from the in_progress_queue let res = this.in_progress_queue.poll_next_unpin(cx); if let Some(val) = ready!(res) { - return Poll::Ready(Some(val)) + return Poll::Ready(Some(val)); } // If more values are still coming from the stream, we're not done yet diff --git a/src/stream/stream/catch_unwind.rs b/src/stream/stream/catch_unwind.rs index d87a40a..09a6dc1 100644 --- a/src/stream/stream/catch_unwind.rs +++ b/src/stream/stream/catch_unwind.rs @@ -1,9 +1,9 @@ -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; use std::any::Any; +use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe}; use std::pin::Pin; -use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; pin_project! { /// Stream for the [`catch_unwind`](super::StreamExt::catch_unwind) method. @@ -27,25 +27,20 @@ impl<St: Stream + UnwindSafe> CatchUnwind<St> { impl<St: Stream + UnwindSafe> Stream for CatchUnwind<St> { type Item = Result<St::Item, Box<dyn Any + Send>>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); if *this.caught_unwind { Poll::Ready(None) } else { - let res = catch_unwind(AssertUnwindSafe(|| { - this.stream.as_mut().poll_next(cx) - })); + let res = catch_unwind(AssertUnwindSafe(|| this.stream.as_mut().poll_next(cx))); match res { Ok(poll) => poll.map(|opt| opt.map(Ok)), Err(e) => { *this.caught_unwind = true; Poll::Ready(Some(Err(e))) - }, + } } } } diff --git a/src/stream/stream/chain.rs b/src/stream/stream/chain.rs index 2be7104..c5da35e 100644 --- a/src/stream/stream/chain.rs +++ b/src/stream/stream/chain.rs @@ -18,20 +18,19 @@ pin_project! { // All interactions with `Pin<&mut Chain<..>>` happen through these methods impl<St1, St2> Chain<St1, St2> -where St1: Stream, - St2: Stream<Item = St1::Item>, +where + St1: Stream, + St2: Stream<Item = St1::Item>, { pub(super) fn new(stream1: St1, stream2: St2) -> Self { - Self { - first: Some(stream1), - second: stream2, - } + Self { first: Some(stream1), second: stream2 } } } impl<St1, St2> FusedStream for Chain<St1, St2> -where St1: Stream, - St2: FusedStream<Item=St1::Item>, +where + St1: Stream, + St2: FusedStream<Item = St1::Item>, { fn is_terminated(&self) -> bool { self.first.is_none() && self.second.is_terminated() @@ -39,19 +38,17 @@ where St1: Stream, } impl<St1, St2> Stream for Chain<St1, St2> -where St1: Stream, - St2: Stream<Item=St1::Item>, +where + St1: Stream, + St2: Stream<Item = St1::Item>, { type Item = St1::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); if let Some(first) = this.first.as_mut().as_pin_mut() { if let Some(item) = ready!(first.poll_next(cx)) { - return Poll::Ready(Some(item)) + return Poll::Ready(Some(item)); } } this.first.set(None); @@ -67,7 +64,7 @@ where St1: Stream, let upper = match (first_upper, second_upper) { (Some(x), Some(y)) => x.checked_add(y), - _ => None + _ => None, }; (lower, upper) diff --git a/src/stream/stream/chunks.rs b/src/stream/stream/chunks.rs index 45a3212..8457869 100644 --- a/src/stream/stream/chunks.rs +++ b/src/stream/stream/chunks.rs @@ -1,13 +1,13 @@ use crate::stream::Fuse; +use alloc::vec::Vec; +use core::mem; +use core::pin::Pin; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::mem; -use core::pin::Pin; -use alloc::vec::Vec; pin_project! { /// Stream for the [`chunks`](super::StreamExt::chunks) method. @@ -21,7 +21,10 @@ pin_project! { } } -impl<St: Stream> Chunks<St> where St: Stream { +impl<St: Stream> Chunks<St> +where + St: Stream, +{ pub(super) fn new(stream: St, capacity: usize) -> Self { assert!(capacity > 0); @@ -43,10 +46,7 @@ impl<St: Stream> Chunks<St> where St: Stream { impl<St: Stream> Stream for Chunks<St> { type Item = Vec<St::Item>; - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.as_mut().project(); loop { match ready!(this.stream.as_mut().poll_next(cx)) { @@ -56,7 +56,7 @@ impl<St: Stream> Stream for Chunks<St> { Some(item) => { this.items.push(item); if this.items.len() >= *this.cap { - return Poll::Ready(Some(self.take())) + return Poll::Ready(Some(self.take())); } } diff --git a/src/stream/stream/collect.rs b/src/stream/stream/collect.rs index 774b34b..b0e81b9 100644 --- a/src/stream/stream/collect.rs +++ b/src/stream/stream/collect.rs @@ -23,16 +23,14 @@ impl<St: Stream, C: Default> Collect<St, C> { } pub(super) fn new(stream: St) -> Self { - Self { - stream, - collection: Default::default(), - } + Self { stream, collection: Default::default() } } } impl<St, C> FusedFuture for Collect<St, C> -where St: FusedStream, - C: Default + Extend<St:: Item> +where + St: FusedStream, + C: Default + Extend<St::Item>, { fn is_terminated(&self) -> bool { self.stream.is_terminated() @@ -40,8 +38,9 @@ where St: FusedStream, } impl<St, C> Future for Collect<St, C> -where St: Stream, - C: Default + Extend<St:: Item> +where + St: Stream, + C: Default + Extend<St::Item>, { type Output = C; diff --git a/src/stream/stream/concat.rs b/src/stream/stream/concat.rs index ee1349f..7e058b2 100644 --- a/src/stream/stream/concat.rs +++ b/src/stream/stream/concat.rs @@ -1,7 +1,7 @@ use core::pin::Pin; -use futures_core::future::{Future, FusedFuture}; +use futures_core::future::{FusedFuture, Future}; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use pin_project_lite::pin_project; @@ -17,35 +17,28 @@ pin_project! { } impl<St> Concat<St> -where St: Stream, - St::Item: Extend<<St::Item as IntoIterator>::Item> + - IntoIterator + Default, +where + St: Stream, + St::Item: Extend<<St::Item as IntoIterator>::Item> + IntoIterator + Default, { pub(super) fn new(stream: St) -> Self { - Self { - stream, - accum: None, - } + Self { stream, accum: None } } } impl<St> Future for Concat<St> -where St: Stream, - St::Item: Extend<<St::Item as IntoIterator>::Item> + - IntoIterator + Default, +where + St: Stream, + St::Item: Extend<<St::Item as IntoIterator>::Item> + IntoIterator + Default, { type Output = St::Item; - fn poll( - self: Pin<&mut Self>, cx: &mut Context<'_> - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let mut this = self.project(); loop { match ready!(this.stream.as_mut().poll_next(cx)) { - None => { - return Poll::Ready(this.accum.take().unwrap_or_default()) - } + None => return Poll::Ready(this.accum.take().unwrap_or_default()), Some(e) => { if let Some(a) = this.accum { a.extend(e) @@ -59,9 +52,9 @@ where St: Stream, } impl<St> FusedFuture for Concat<St> -where St: FusedStream, - St::Item: Extend<<St::Item as IntoIterator>::Item> + - IntoIterator + Default, +where + St: FusedStream, + St::Item: Extend<<St::Item as IntoIterator>::Item> + IntoIterator + Default, { fn is_terminated(&self) -> bool { self.accum.is_none() && self.stream.is_terminated() diff --git a/src/stream/stream/count.rs b/src/stream/stream/count.rs new file mode 100644 index 0000000..513cab7 --- /dev/null +++ b/src/stream/stream/count.rs @@ -0,0 +1,53 @@ +use core::fmt; +use core::pin::Pin; +use futures_core::future::{FusedFuture, Future}; +use futures_core::ready; +use futures_core::stream::{FusedStream, Stream}; +use futures_core::task::{Context, Poll}; +use pin_project_lite::pin_project; + +pin_project! { + /// Future for the [`count`](super::StreamExt::count) method. + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct Count<St> { + #[pin] + stream: St, + count: usize + } +} + +impl<St> fmt::Debug for Count<St> +where + St: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Count").field("stream", &self.stream).field("count", &self.count).finish() + } +} + +impl<St: Stream> Count<St> { + pub(super) fn new(stream: St) -> Self { + Self { stream, count: 0 } + } +} + +impl<St: FusedStream> FusedFuture for Count<St> { + fn is_terminated(&self) -> bool { + self.stream.is_terminated() + } +} + +impl<St: Stream> Future for Count<St> { + type Output = usize; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + let mut this = self.project(); + + Poll::Ready(loop { + match ready!(this.stream.as_mut().poll_next(cx)) { + Some(_) => *this.count += 1, + None => break *this.count, + } + }) + } +} diff --git a/src/stream/stream/cycle.rs b/src/stream/stream/cycle.rs index a5b7dc0..507431d 100644 --- a/src/stream/stream/cycle.rs +++ b/src/stream/stream/cycle.rs @@ -21,10 +21,7 @@ where St: Clone + Stream, { pub(super) fn new(stream: St) -> Self { - Self { - orig: stream.clone(), - stream, - } + Self { orig: stream.clone(), stream } } } diff --git a/src/stream/stream/enumerate.rs b/src/stream/stream/enumerate.rs index 7d4c9cb..1cf9d49 100644 --- a/src/stream/stream/enumerate.rs +++ b/src/stream/stream/enumerate.rs @@ -19,10 +19,7 @@ pin_project! { impl<St: Stream> Enumerate<St> { pub(super) fn new(stream: St) -> Self { - Self { - stream, - count: 0, - } + Self { stream, count: 0 } } delegate_access_inner!(stream, St, ()); @@ -37,10 +34,7 @@ impl<St: Stream + FusedStream> FusedStream for Enumerate<St> { impl<St: Stream> Stream for Enumerate<St> { type Item = (usize, St::Item); - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let this = self.project(); match ready!(this.stream.poll_next(cx)) { diff --git a/src/stream/stream/filter.rs b/src/stream/stream/filter.rs index 57de025..ccf1a51 100644 --- a/src/stream/stream/filter.rs +++ b/src/stream/stream/filter.rs @@ -1,3 +1,4 @@ +use crate::fns::FnMut1; use core::fmt; use core::pin::Pin; use futures_core::future::Future; @@ -7,7 +8,6 @@ use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use crate::fns::FnMut1; pin_project! { /// Stream for the [`filter`](super::StreamExt::filter) method. @@ -41,26 +41,23 @@ where #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 impl<St, Fut, F> Filter<St, Fut, F> -where St: Stream, - F: for<'a> FnMut1<&'a St::Item, Output=Fut>, - Fut: Future<Output = bool>, +where + St: Stream, + F: for<'a> FnMut1<&'a St::Item, Output = Fut>, + Fut: Future<Output = bool>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - } + Self { stream, f, pending_fut: None, pending_item: None } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> FusedStream for Filter<St, Fut, F> - where St: Stream + FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: Stream + FusedStream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { fn is_terminated(&self) -> bool { self.pending_fut.is_none() && self.stream.is_terminated() @@ -69,16 +66,14 @@ impl<St, Fut, F> FusedStream for Filter<St, Fut, F> #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 impl<St, Fut, F> Stream for Filter<St, Fut, F> - where St: Stream, - F: for<'a> FnMut1<&'a St::Item, Output=Fut>, - Fut: Future<Output = bool>, +where + St: Stream, + F: for<'a> FnMut1<&'a St::Item, Output = Fut>, + Fut: Future<Output = bool>, { type Item = St::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St::Item>> { let mut this = self.project(); Poll::Ready(loop { if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { @@ -111,9 +106,10 @@ impl<St, Fut, F> Stream for Filter<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for Filter<S, Fut, F> - where S: Stream + Sink<Item>, - F: FnMut(&S::Item) -> Fut, - Fut: Future<Output = bool>, +where + S: Stream + Sink<Item>, + F: FnMut(&S::Item) -> Fut, + Fut: Future<Output = bool>, { type Error = S::Error; diff --git a/src/stream/stream/filter_map.rs b/src/stream/stream/filter_map.rs index b762fac..02a0a43 100644 --- a/src/stream/stream/filter_map.rs +++ b/src/stream/stream/filter_map.rs @@ -1,3 +1,4 @@ +use crate::fns::FnMut1; use core::fmt; use core::pin::Pin; use futures_core::future::Future; @@ -7,7 +8,6 @@ use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use crate::fns::FnMut1; pin_project! { /// Stream for the [`filter_map`](super::StreamExt::filter_map) method. @@ -35,9 +35,10 @@ where } impl<St, Fut, F> FilterMap<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future, { pub(super) fn new(stream: St, f: F) -> Self { Self { stream, f, pending: None } @@ -47,9 +48,10 @@ impl<St, Fut, F> FilterMap<St, Fut, F> } impl<St, Fut, F, T> FusedStream for FilterMap<St, Fut, F> - where St: Stream + FusedStream, - F: FnMut1<St::Item, Output=Fut>, - Fut: Future<Output = Option<T>>, +where + St: Stream + FusedStream, + F: FnMut1<St::Item, Output = Fut>, + Fut: Future<Output = Option<T>>, { fn is_terminated(&self) -> bool { self.pending.is_none() && self.stream.is_terminated() @@ -57,16 +59,14 @@ impl<St, Fut, F, T> FusedStream for FilterMap<St, Fut, F> } impl<St, Fut, F, T> Stream for FilterMap<St, Fut, F> - where St: Stream, - F: FnMut1<St::Item, Output=Fut>, - Fut: Future<Output = Option<T>>, +where + St: Stream, + F: FnMut1<St::Item, Output = Fut>, + Fut: Future<Output = Option<T>>, { type Item = T; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<T>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> { let mut this = self.project(); Poll::Ready(loop { if let Some(p) = this.pending.as_mut().as_pin_mut() { @@ -100,9 +100,10 @@ impl<St, Fut, F, T> Stream for FilterMap<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for FilterMap<S, Fut, F> - where S: Stream + Sink<Item>, - F: FnMut1<S::Item, Output=Fut>, - Fut: Future, +where + S: Stream + Sink<Item>, + F: FnMut1<S::Item, Output = Fut>, + Fut: Future, { type Error = S::Error; diff --git a/src/stream/stream/flatten_unordered.rs b/src/stream/stream/flatten_unordered.rs new file mode 100644 index 0000000..07f971c --- /dev/null +++ b/src/stream/stream/flatten_unordered.rs @@ -0,0 +1,509 @@ +use alloc::sync::Arc; +use core::{ + cell::UnsafeCell, + convert::identity, + fmt, + num::NonZeroUsize, + pin::Pin, + sync::atomic::{AtomicU8, Ordering}, +}; + +use pin_project_lite::pin_project; + +use futures_core::{ + future::Future, + ready, + stream::{FusedStream, Stream}, + task::{Context, Poll, Waker}, +}; +#[cfg(feature = "sink")] +use futures_sink::Sink; +use futures_task::{waker, ArcWake}; + +use crate::stream::FuturesUnordered; + +/// There is nothing to poll and stream isn't being +/// polled or waking at the moment. +const NONE: u8 = 0; + +/// Inner streams need to be polled. +const NEED_TO_POLL_INNER_STREAMS: u8 = 1; + +/// The base stream needs to be polled. +const NEED_TO_POLL_STREAM: u8 = 0b10; + +/// It needs to poll base stream and inner streams. +const NEED_TO_POLL_ALL: u8 = NEED_TO_POLL_INNER_STREAMS | NEED_TO_POLL_STREAM; + +/// The current stream is being polled at the moment. +const POLLING: u8 = 0b100; + +/// Inner streams are being woken at the moment. +const WAKING_INNER_STREAMS: u8 = 0b1000; + +/// The base stream is being woken at the moment. +const WAKING_STREAM: u8 = 0b10000; + +/// The base stream and inner streams are being woken at the moment. +const WAKING_ALL: u8 = WAKING_STREAM | WAKING_INNER_STREAMS; + +/// The stream was waked and will be polled. +const WOKEN: u8 = 0b100000; + +/// Determines what needs to be polled, and is stream being polled at the +/// moment or not. +#[derive(Clone, Debug)] +struct SharedPollState { + state: Arc<AtomicU8>, +} + +impl SharedPollState { + /// Constructs new `SharedPollState` with the given state. + fn new(value: u8) -> SharedPollState { + SharedPollState { state: Arc::new(AtomicU8::new(value)) } + } + + /// Attempts to start polling, returning stored state in case of success. + /// Returns `None` if some waker is waking at the moment. + fn start_polling( + &self, + ) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&SharedPollState) -> u8>)> { + let value = self + .state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { + if value & WAKING_ALL == NONE { + Some(POLLING) + } else { + None + } + }) + .ok()?; + let bomb = PollStateBomb::new(self, SharedPollState::reset); + + Some((value, bomb)) + } + + /// Starts the waking process and performs bitwise or with the given value. + fn start_waking( + &self, + to_poll: u8, + waking: u8, + ) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&SharedPollState) -> u8>)> { + let value = self + .state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { + // Waking process for this waker already started + if value & waking != NONE { + return None; + } + let mut next_value = value | to_poll; + // Only start the waking process if we're not in the polling phase and the stream isn't woken already + if value & (WOKEN | POLLING) == NONE { + next_value |= waking; + } + + if next_value != value { + Some(next_value) + } else { + None + } + }) + .ok()?; + + if value & (WOKEN | POLLING) == NONE { + let bomb = PollStateBomb::new(self, move |state| state.stop_waking(waking)); + + Some((value, bomb)) + } else { + None + } + } + + /// Sets current state to + /// - `!POLLING` allowing to use wakers + /// - `WOKEN` if the state was changed during `POLLING` phase as waker will be called, + /// or `will_be_woken` flag supplied + /// - `!WAKING_ALL` as + /// * Wakers called during the `POLLING` phase won't propagate their calls + /// * `POLLING` phase can't start if some of the wakers are active + /// So no wrapped waker can touch the inner waker's cell, it's safe to poll again. + fn stop_polling(&self, to_poll: u8, will_be_woken: bool) -> u8 { + self.state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |mut value| { + let mut next_value = to_poll; + + value &= NEED_TO_POLL_ALL; + if value != NONE || will_be_woken { + next_value |= WOKEN; + } + next_value |= value; + + Some(next_value & !POLLING & !WAKING_ALL) + }) + .unwrap() + } + + /// Toggles state to non-waking, allowing to start polling. + fn stop_waking(&self, waking: u8) -> u8 { + self.state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { + let mut next_value = value & !waking; + // Waker will be called only if the current waking state is the same as the specified waker state + if value & WAKING_ALL == waking { + next_value |= WOKEN; + } + + if next_value != value { + Some(next_value) + } else { + None + } + }) + .unwrap_or_else(identity) + } + + /// Resets current state allowing to poll the stream and wake up wakers. + fn reset(&self) -> u8 { + self.state.swap(NEED_TO_POLL_ALL, Ordering::AcqRel) + } +} + +/// Used to execute some function on the given state when dropped. +struct PollStateBomb<'a, F: FnOnce(&SharedPollState) -> u8> { + state: &'a SharedPollState, + drop: Option<F>, +} + +impl<'a, F: FnOnce(&SharedPollState) -> u8> PollStateBomb<'a, F> { + /// Constructs new bomb with the given state. + fn new(state: &'a SharedPollState, drop: F) -> Self { + Self { state, drop: Some(drop) } + } + + /// Deactivates bomb, forces it to not call provided function when dropped. + fn deactivate(mut self) { + self.drop.take(); + } + + /// Manually fires the bomb, returning supplied state. + fn fire(mut self) -> Option<u8> { + self.drop.take().map(|drop| (drop)(self.state)) + } +} + +impl<F: FnOnce(&SharedPollState) -> u8> Drop for PollStateBomb<'_, F> { + fn drop(&mut self) { + if let Some(drop) = self.drop.take() { + (drop)(self.state); + } + } +} + +/// Will update state with the provided value on `wake_by_ref` call +/// and then, if there is a need, call `inner_waker`. +struct InnerWaker { + inner_waker: UnsafeCell<Option<Waker>>, + poll_state: SharedPollState, + need_to_poll: u8, +} + +unsafe impl Send for InnerWaker {} +unsafe impl Sync for InnerWaker {} + +impl InnerWaker { + /// Replaces given waker's inner_waker for polling stream/futures which will + /// update poll state on `wake_by_ref` call. Use only if you need several + /// contexts. + /// + /// ## Safety + /// + /// This function will modify waker's `inner_waker` via `UnsafeCell`, so + /// it should be used only during `POLLING` phase. + unsafe fn replace_waker(self_arc: &mut Arc<Self>, cx: &Context<'_>) -> Waker { + *self_arc.inner_waker.get() = cx.waker().clone().into(); + waker(self_arc.clone()) + } + + /// Attempts to start the waking process for the waker with the given value. + /// If succeeded, then the stream isn't yet woken and not being polled at the moment. + fn start_waking(&self) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&SharedPollState) -> u8>)> { + self.poll_state.start_waking(self.need_to_poll, self.waking_state()) + } + + /// Returns the corresponding waking state toggled by this waker. + fn waking_state(&self) -> u8 { + self.need_to_poll << 3 + } +} + +impl ArcWake for InnerWaker { + fn wake_by_ref(self_arc: &Arc<Self>) { + if let Some((_, state_bomb)) = self_arc.start_waking() { + // Safety: now state is not `POLLING` + let waker_opt = unsafe { self_arc.inner_waker.get().as_ref().unwrap() }; + + if let Some(inner_waker) = waker_opt.clone() { + // Stop waking to allow polling stream + let poll_state_value = state_bomb.fire().unwrap(); + + // Here we want to call waker only if stream isn't woken yet and + // also to optimize the case when two wakers are called at the same time. + // + // In this case the best strategy will be to propagate only the latest waker's awake, + // and then poll both entities in a single `poll_next` call + if poll_state_value & (WOKEN | WAKING_ALL) == self_arc.waking_state() { + // Wake up inner waker + inner_waker.wake(); + } + } + } + } +} + +pin_project! { + /// Future which contains optional stream. + /// + /// If it's `Some`, it will attempt to call `poll_next` on it, + /// returning `Some((item, next_item_fut))` in case of `Poll::Ready(Some(...))` + /// or `None` in case of `Poll::Ready(None)`. + /// + /// If `poll_next` will return `Poll::Pending`, it will be forwarded to + /// the future and current task will be notified by waker. + #[must_use = "futures do nothing unless you `.await` or poll them"] + struct PollStreamFut<St> { + #[pin] + stream: Option<St>, + } +} + +impl<St> PollStreamFut<St> { + /// Constructs new `PollStreamFut` using given `stream`. + fn new(stream: impl Into<Option<St>>) -> Self { + Self { stream: stream.into() } + } +} + +impl<St: Stream + Unpin> Future for PollStreamFut<St> { + type Output = Option<(St::Item, PollStreamFut<St>)>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + let mut stream = self.project().stream; + + let item = if let Some(stream) = stream.as_mut().as_pin_mut() { + ready!(stream.poll_next(cx)) + } else { + None + }; + let next_item_fut = PollStreamFut::new(stream.get_mut().take()); + let out = item.map(|item| (item, next_item_fut)); + + Poll::Ready(out) + } +} + +pin_project! { + /// Stream for the [`flatten_unordered`](super::StreamExt::flatten_unordered) + /// method. + #[project = FlattenUnorderedProj] + #[must_use = "streams do nothing unless polled"] + pub struct FlattenUnordered<St> where St: Stream { + #[pin] + inner_streams: FuturesUnordered<PollStreamFut<St::Item>>, + #[pin] + stream: St, + poll_state: SharedPollState, + limit: Option<NonZeroUsize>, + is_stream_done: bool, + inner_streams_waker: Arc<InnerWaker>, + stream_waker: Arc<InnerWaker>, + } +} + +impl<St> fmt::Debug for FlattenUnordered<St> +where + St: Stream + fmt::Debug, + St::Item: Stream + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FlattenUnordered") + .field("poll_state", &self.poll_state) + .field("inner_streams", &self.inner_streams) + .field("limit", &self.limit) + .field("stream", &self.stream) + .field("is_stream_done", &self.is_stream_done) + .finish() + } +} + +impl<St> FlattenUnordered<St> +where + St: Stream, + St::Item: Stream + Unpin, +{ + pub(super) fn new(stream: St, limit: Option<usize>) -> FlattenUnordered<St> { + let poll_state = SharedPollState::new(NEED_TO_POLL_STREAM); + + FlattenUnordered { + inner_streams: FuturesUnordered::new(), + stream, + is_stream_done: false, + limit: limit.and_then(NonZeroUsize::new), + inner_streams_waker: Arc::new(InnerWaker { + inner_waker: UnsafeCell::new(None), + poll_state: poll_state.clone(), + need_to_poll: NEED_TO_POLL_INNER_STREAMS, + }), + stream_waker: Arc::new(InnerWaker { + inner_waker: UnsafeCell::new(None), + poll_state: poll_state.clone(), + need_to_poll: NEED_TO_POLL_STREAM, + }), + poll_state, + } + } + + delegate_access_inner!(stream, St, ()); +} + +impl<St> FlattenUnorderedProj<'_, St> +where + St: Stream, +{ + /// Checks if current `inner_streams` size is less than optional limit. + fn is_exceeded_limit(&self) -> bool { + self.limit.map_or(false, |limit| self.inner_streams.len() >= limit.get()) + } +} + +impl<St> FusedStream for FlattenUnordered<St> +where + St: FusedStream, + St::Item: FusedStream + Unpin, +{ + fn is_terminated(&self) -> bool { + self.stream.is_terminated() && self.inner_streams.is_empty() + } +} + +impl<St> Stream for FlattenUnordered<St> +where + St: Stream, + St::Item: Stream + Unpin, +{ + type Item = <St::Item as Stream>::Item; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + let mut next_item = None; + let mut need_to_poll_next = NONE; + + let mut this = self.as_mut().project(); + + let (mut poll_state_value, state_bomb) = match this.poll_state.start_polling() { + Some(value) => value, + _ => { + // Waker was called, just wait for the next poll + return Poll::Pending; + } + }; + + if poll_state_value & NEED_TO_POLL_STREAM != NONE { + // Safety: now state is `POLLING`. + let stream_waker = unsafe { InnerWaker::replace_waker(this.stream_waker, cx) }; + + // Here we need to poll the base stream. + // + // To improve performance, we will attempt to place as many items as we can + // to the `FuturesUnordered` bucket before polling inner streams + loop { + if this.is_exceeded_limit() || *this.is_stream_done { + // We either exceeded the limit or the stream is exhausted + if !*this.is_stream_done { + // The stream needs to be polled in the next iteration + need_to_poll_next |= NEED_TO_POLL_STREAM; + } + + break; + } else { + match this.stream.as_mut().poll_next(&mut Context::from_waker(&stream_waker)) { + Poll::Ready(Some(inner_stream)) => { + // Add new stream to the inner streams bucket + this.inner_streams.as_mut().push(PollStreamFut::new(inner_stream)); + // Inner streams must be polled afterward + poll_state_value |= NEED_TO_POLL_INNER_STREAMS; + } + Poll::Ready(None) => { + // Mark the stream as done + *this.is_stream_done = true; + } + Poll::Pending => { + break; + } + } + } + } + } + + if poll_state_value & NEED_TO_POLL_INNER_STREAMS != NONE { + // Safety: now state is `POLLING`. + let inner_streams_waker = + unsafe { InnerWaker::replace_waker(this.inner_streams_waker, cx) }; + + match this + .inner_streams + .as_mut() + .poll_next(&mut Context::from_waker(&inner_streams_waker)) + { + Poll::Ready(Some(Some((item, next_item_fut)))) => { + // Push next inner stream item future to the list of inner streams futures + this.inner_streams.as_mut().push(next_item_fut); + // Take the received item + next_item = Some(item); + // On the next iteration, inner streams must be polled again + need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS; + } + Poll::Ready(Some(None)) => { + // On the next iteration, inner streams must be polled again + need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS; + } + _ => {} + } + } + + // We didn't have any `poll_next` panic, so it's time to deactivate the bomb + state_bomb.deactivate(); + + let mut force_wake = + // we need to poll the stream and didn't reach the limit yet + need_to_poll_next & NEED_TO_POLL_STREAM != NONE && !this.is_exceeded_limit() + // or we need to poll inner streams again + || need_to_poll_next & NEED_TO_POLL_INNER_STREAMS != NONE; + + // Stop polling and swap the latest state + poll_state_value = this.poll_state.stop_polling(need_to_poll_next, force_wake); + // If state was changed during `POLLING` phase, need to manually call a waker + force_wake |= poll_state_value & NEED_TO_POLL_ALL != NONE; + + let is_done = *this.is_stream_done && this.inner_streams.is_empty(); + + if next_item.is_some() || is_done { + Poll::Ready(next_item) + } else { + if force_wake { + cx.waker().wake_by_ref(); + } + + Poll::Pending + } + } +} + +// Forwarding impl of Sink from the underlying stream +#[cfg(feature = "sink")] +impl<St, Item> Sink<Item> for FlattenUnordered<St> +where + St: Stream + Sink<Item>, +{ + type Error = St::Error; + + delegate_sink!(stream, Item); +} diff --git a/src/stream/stream/fold.rs b/src/stream/stream/fold.rs index e109c3b..b8b55ec 100644 --- a/src/stream/stream/fold.rs +++ b/src/stream/stream/fold.rs @@ -35,24 +35,21 @@ where } impl<St, Fut, T, F> Fold<St, Fut, T, F> -where St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future<Output = T>, +where + St: Stream, + F: FnMut(T, St::Item) -> Fut, + Fut: Future<Output = T>, { pub(super) fn new(stream: St, f: F, t: T) -> Self { - Self { - stream, - f, - accum: Some(t), - future: None, - } + Self { stream, f, accum: Some(t), future: None } } } impl<St, Fut, T, F> FusedFuture for Fold<St, Fut, T, F> - where St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future<Output = T>, +where + St: Stream, + F: FnMut(T, St::Item) -> Fut, + Fut: Future<Output = T>, { fn is_terminated(&self) -> bool { self.accum.is_none() && self.future.is_none() @@ -60,9 +57,10 @@ impl<St, Fut, T, F> FusedFuture for Fold<St, Fut, T, F> } impl<St, Fut, T, F> Future for Fold<St, Fut, T, F> - where St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future<Output = T>, +where + St: Stream, + F: FnMut(T, St::Item) -> Fut, + Fut: Future<Output = T>, { type Output = T; diff --git a/src/stream/stream/for_each.rs b/src/stream/stream/for_each.rs index ee90e66..5302b0e 100644 --- a/src/stream/stream/for_each.rs +++ b/src/stream/stream/for_each.rs @@ -32,23 +32,21 @@ where } impl<St, Fut, F> ForEach<St, Fut, F> -where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - future: None, - } + Self { stream, f, future: None } } } impl<St, Fut, F> FusedFuture for ForEach<St, Fut, F> - where St: FusedStream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: FusedStream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { fn is_terminated(&self) -> bool { self.future.is_none() && self.stream.is_terminated() @@ -56,9 +54,10 @@ impl<St, Fut, F> FusedFuture for ForEach<St, Fut, F> } impl<St, Fut, F> Future for ForEach<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { type Output = (); diff --git a/src/stream/stream/for_each_concurrent.rs b/src/stream/stream/for_each_concurrent.rs index cee0ba1..6c18753 100644 --- a/src/stream/stream/for_each_concurrent.rs +++ b/src/stream/stream/for_each_concurrent.rs @@ -1,7 +1,7 @@ use crate::stream::{FuturesUnordered, StreamExt}; use core::fmt; -use core::pin::Pin; use core::num::NonZeroUsize; +use core::pin::Pin; use futures_core::future::{FusedFuture, Future}; use futures_core::stream::Stream; use futures_core::task::{Context, Poll}; @@ -35,9 +35,10 @@ where } impl<St, Fut, F> ForEachConcurrent<St, Fut, F> -where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { pub(super) fn new(stream: St, limit: Option<usize>, f: F) -> Self { Self { @@ -51,9 +52,10 @@ where St: Stream, } impl<St, Fut, F> FusedFuture for ForEachConcurrent<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { fn is_terminated(&self) -> bool { self.stream.is_none() && self.futures.is_empty() @@ -61,9 +63,10 @@ impl<St, Fut, F> FusedFuture for ForEachConcurrent<St, Fut, F> } impl<St, Fut, F> Future for ForEachConcurrent<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future<Output = ()>, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future<Output = ()>, { type Output = (); @@ -80,7 +83,7 @@ impl<St, Fut, F> Future for ForEachConcurrent<St, Fut, F> Poll::Ready(Some(elem)) => { made_progress_this_iter = true; Some(elem) - }, + } Poll::Ready(None) => { stream_completed = true; None @@ -102,9 +105,9 @@ impl<St, Fut, F> Future for ForEachConcurrent<St, Fut, F> Poll::Ready(Some(())) => made_progress_this_iter = true, Poll::Ready(None) => { if this.stream.is_none() { - return Poll::Ready(()) + return Poll::Ready(()); } - }, + } Poll::Pending => {} } diff --git a/src/stream/stream/forward.rs b/src/stream/stream/forward.rs index 2247b21..1fe2427 100644 --- a/src/stream/stream/forward.rs +++ b/src/stream/stream/forward.rs @@ -23,11 +23,7 @@ pin_project! { impl<St, Si, Item> Forward<St, Si, Item> { pub(crate) fn new(stream: St, sink: Si) -> Self { - Self { - sink: Some(sink), - stream: Fuse::new(stream), - buffered_item: None, - } + Self { sink: Some(sink), stream: Fuse::new(stream), buffered_item: None } } } @@ -48,10 +44,7 @@ where { type Output = Result<(), E>; - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let ForwardProj { mut sink, mut stream, buffered_item } = self.project(); let mut si = sink.as_mut().as_pin_mut().expect("polled `Forward` after completion"); @@ -70,11 +63,11 @@ where Poll::Ready(None) => { ready!(si.poll_close(cx))?; sink.set(None); - return Poll::Ready(Ok(())) + return Poll::Ready(Ok(())); } Poll::Pending => { ready!(si.poll_flush(cx))?; - return Poll::Pending + return Poll::Pending; } } } diff --git a/src/stream/stream/fuse.rs b/src/stream/stream/fuse.rs index e1d8c12..fe67813 100644 --- a/src/stream/stream/fuse.rs +++ b/src/stream/stream/fuse.rs @@ -43,10 +43,7 @@ impl<S: Stream> FusedStream for Fuse<S> { impl<S: Stream> Stream for Fuse<S> { type Item = S::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<S::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> { let this = self.project(); if *this.done { diff --git a/src/stream/stream/into_future.rs b/src/stream/stream/into_future.rs index a9a1e23..8abfddc 100644 --- a/src/stream/stream/into_future.rs +++ b/src/stream/stream/into_future.rs @@ -79,10 +79,7 @@ impl<St: Stream + Unpin> FusedFuture for StreamFuture<St> { impl<St: Stream + Unpin> Future for StreamFuture<St> { type Output = (Option<St::Item>, St); - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let item = { let s = self.stream.as_mut().expect("polling StreamFuture twice"); ready!(s.poll_next_unpin(cx)) diff --git a/src/stream/stream/map.rs b/src/stream/stream/map.rs index 1a269f0..88bb612 100644 --- a/src/stream/stream/map.rs +++ b/src/stream/stream/map.rs @@ -24,9 +24,7 @@ where St: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Map") - .field("stream", &self.stream) - .finish() + f.debug_struct("Map").field("stream", &self.stream).finish() } } @@ -39,8 +37,9 @@ impl<St, F> Map<St, F> { } impl<St, F> FusedStream for Map<St, F> - where St: FusedStream, - F: FnMut1<St::Item>, +where + St: FusedStream, + F: FnMut1<St::Item>, { fn is_terminated(&self) -> bool { self.stream.is_terminated() @@ -48,15 +47,13 @@ impl<St, F> FusedStream for Map<St, F> } impl<St, F> Stream for Map<St, F> - where St: Stream, - F: FnMut1<St::Item>, +where + St: Stream, + F: FnMut1<St::Item>, { type Item = F::Output; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); let res = ready!(this.stream.as_mut().poll_next(cx)); Poll::Ready(res.map(|x| this.f.call_mut(x))) @@ -70,8 +67,9 @@ impl<St, F> Stream for Map<St, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<St, F, Item> Sink<Item> for Map<St, F> - where St: Stream + Sink<Item>, - F: FnMut1<St::Item>, +where + St: Stream + Sink<Item>, + F: FnMut1<St::Item>, { type Error = St::Error; diff --git a/src/stream/stream/mod.rs b/src/stream/stream/mod.rs index c3340ec..642b91e 100644 --- a/src/stream/stream/mod.rs +++ b/src/stream/stream/mod.rs @@ -40,6 +40,10 @@ mod concat; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::concat::Concat; +mod count; +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::count::Count; + mod cycle; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::cycle::Cycle; @@ -70,6 +74,14 @@ mod fold; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::fold::Fold; +mod any; +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::any::Any; + +mod all; +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::all::All; + #[cfg(feature = "sink")] mod forward; @@ -123,7 +135,7 @@ pub use self::select_next_some::SelectNextSome; mod peek; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 -pub use self::peek::{Peek, Peekable}; +pub use self::peek::{NextIf, NextIfEq, Peek, PeekMut, Peekable}; mod skip; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 @@ -169,35 +181,60 @@ mod scan; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::scan::Scan; -cfg_target_has_atomic! { - #[cfg(feature = "alloc")] - mod buffer_unordered; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::buffer_unordered::BufferUnordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod buffer_unordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::buffer_unordered::BufferUnordered; - #[cfg(feature = "alloc")] - mod buffered; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::buffered::Buffered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod buffered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::buffered::Buffered; - #[cfg(feature = "alloc")] - mod for_each_concurrent; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::for_each_concurrent::ForEachConcurrent; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod flatten_unordered; - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - #[cfg(feature = "alloc")] - mod split; - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::split::{SplitStream, SplitSink, ReuniteError}; -} +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] +pub use self::flatten_unordered::FlattenUnordered; + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +delegate_all!( + /// Stream for the [`flat_map_unordered`](StreamExt::flat_map_unordered) method. + FlatMapUnordered<St, U, F>( + FlattenUnordered<Map<St, F>> + ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, limit: Option<usize>, f: F| FlattenUnordered::new(Map::new(x, f), limit)] + where St: Stream, U: Stream, U: Unpin, F: FnMut(St::Item) -> U +); + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod for_each_concurrent; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::for_each_concurrent::ForEachConcurrent; + +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "sink")] +#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] +#[cfg(feature = "alloc")] +mod split; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "sink")] +#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::split::{ReuniteError, SplitSink, SplitStream}; #[cfg(feature = "std")] mod catch_unwind; @@ -372,9 +409,9 @@ pub trait StreamExt: Stream { /// use futures::stream::{self, StreamExt}; /// /// let stream = stream::iter(1..=10); - /// let evens = stream.filter(|x| future::ready(x % 2 == 0)); + /// let events = stream.filter(|x| future::ready(x % 2 == 0)); /// - /// assert_eq!(vec![2, 4, 6, 8, 10], evens.collect::<Vec<_>>().await); + /// assert_eq!(vec![2, 4, 6, 8, 10], events.collect::<Vec<_>>().await); /// # }); /// ``` fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F> @@ -404,11 +441,11 @@ pub trait StreamExt: Stream { /// use futures::stream::{self, StreamExt}; /// /// let stream = stream::iter(1..=10); - /// let evens = stream.filter_map(|x| async move { + /// let events = stream.filter_map(|x| async move { /// if x % 2 == 0 { Some(x + 1) } else { None } /// }); /// - /// assert_eq!(vec![3, 5, 7, 9, 11], evens.collect::<Vec<_>>().await); + /// assert_eq!(vec![3, 5, 7, 9, 11], events.collect::<Vec<_>>().await); /// # }); /// ``` fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F> @@ -562,6 +599,38 @@ pub trait StreamExt: Stream { assert_future::<Self::Item, _>(Concat::new(self)) } + /// Drives the stream to completion, counting the number of items. + /// + /// # Overflow Behavior + /// + /// The method does no guarding against overflows, so counting elements of a + /// stream with more than [`usize::MAX`] elements either produces the wrong + /// result or panics. If debug assertions are enabled, a panic is guaranteed. + /// + /// # Panics + /// + /// This function might panic if the iterator has more than [`usize::MAX`] + /// elements. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// + /// let stream = stream::iter(1..=10); + /// let count = stream.count().await; + /// + /// assert_eq!(count, 10); + /// # }); + /// ``` + fn count(self) -> Count<Self> + where + Self: Sized, + { + assert_future::<usize, _>(Count::new(self)) + } + /// Repeats a stream endlessly. /// /// The stream never terminates. Note that you likely want to avoid @@ -621,6 +690,50 @@ pub trait StreamExt: Stream { assert_future::<T, _>(Fold::new(self, f, init)) } + /// Execute predicate over asynchronous stream, and return `true` if any element in stream satisfied a predicate. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// + /// let number_stream = stream::iter(0..10); + /// let contain_three = number_stream.any(|i| async move { i == 3 }); + /// assert_eq!(contain_three.await, true); + /// # }); + /// ``` + fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F> + where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized, + { + assert_future::<bool, _>(Any::new(self, f)) + } + + /// Execute predicate over asynchronous stream, and return `true` if all element in stream satisfied a predicate. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// + /// let number_stream = stream::iter(0..10); + /// let less_then_twenty = number_stream.all(|i| async move { i < 20 }); + /// assert_eq!(less_then_twenty.await, true); + /// # }); + /// ``` + fn all<Fut, F>(self, f: F) -> All<Self, Fut, F> + where + F: FnMut(Self::Item) -> Fut, + Fut: Future<Output = bool>, + Self: Sized, + { + assert_future::<bool, _>(All::new(self, f)) + } + /// Flattens a stream of streams into just one continuous stream. /// /// # Examples @@ -660,13 +773,57 @@ pub trait StreamExt: Stream { assert_stream::<<Self::Item as Stream>::Item, _>(Flatten::new(self)) } + /// Flattens a stream of streams into just one continuous stream. Polls + /// inner streams concurrently. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::channel::mpsc; + /// use futures::stream::StreamExt; + /// use std::thread; + /// + /// let (tx1, rx1) = mpsc::unbounded(); + /// let (tx2, rx2) = mpsc::unbounded(); + /// let (tx3, rx3) = mpsc::unbounded(); + /// + /// thread::spawn(move || { + /// tx1.unbounded_send(1).unwrap(); + /// tx1.unbounded_send(2).unwrap(); + /// }); + /// thread::spawn(move || { + /// tx2.unbounded_send(3).unwrap(); + /// tx2.unbounded_send(4).unwrap(); + /// }); + /// thread::spawn(move || { + /// tx3.unbounded_send(rx1).unwrap(); + /// tx3.unbounded_send(rx2).unwrap(); + /// }); + /// + /// let mut output = rx3.flatten_unordered(None).collect::<Vec<i32>>().await; + /// output.sort(); + /// + /// assert_eq!(output, vec![1, 2, 3, 4]); + /// # }); + /// ``` + #[cfg(not(futures_no_atomic_cas))] + #[cfg(feature = "alloc")] + fn flatten_unordered(self, limit: impl Into<Option<usize>>) -> FlattenUnordered<Self> + where + Self::Item: Stream + Unpin, + Self: Sized, + { + FlattenUnordered::new(self, limit.into()) + } + /// Maps a stream like [`StreamExt::map`] but flattens nested `Stream`s. /// /// [`StreamExt::map`] is very useful, but if it produces a `Stream` instead, /// you would have to chain combinators like `.map(f).flatten()` while this /// combinator provides ability to write `.flat_map(f)` instead of chaining. /// - /// The provided closure which produce inner streams is executed over all elements + /// The provided closure which produces inner streams is executed over all elements /// of stream as last inner stream is terminated and next stream item is available. /// /// Note that this function consumes the stream passed into it and returns a @@ -694,6 +851,59 @@ pub trait StreamExt: Stream { assert_stream::<U::Item, _>(FlatMap::new(self, f)) } + /// Maps a stream like [`StreamExt::map`] but flattens nested `Stream`s + /// and polls them concurrently, yielding items in any order, as they made + /// available. + /// + /// [`StreamExt::map`] is very useful, but if it produces `Stream`s + /// instead, and you need to poll all of them concurrently, you would + /// have to use something like `for_each_concurrent` and merge values + /// by hand. This combinator provides ability to collect all values + /// from concurrently polled streams into one stream. + /// + /// The first argument is an optional limit on the number of concurrently + /// polled streams. If this limit is not `None`, no more than `limit` streams + /// will be polled concurrently. The `limit` argument is of type + /// `Into<Option<usize>>`, and so can be provided as either `None`, + /// `Some(10)`, or just `10`. Note: a limit of zero is interpreted as + /// no limit at all, and will have the same result as passing in `None`. + /// + /// The provided closure which produces inner streams is executed over + /// all elements of stream as next stream item is available and limit + /// of concurrently processed streams isn't exceeded. + /// + /// Note that this function consumes the stream passed into it and + /// returns a wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// + /// let stream = stream::iter(1..5); + /// let stream = stream.flat_map_unordered(1, |x| stream::iter(vec![x; x])); + /// let mut values = stream.collect::<Vec<_>>().await; + /// values.sort(); + /// + /// assert_eq!(vec![1usize, 2, 2, 3, 3, 3, 4, 4, 4, 4], values); + /// # }); + /// ``` + #[cfg(not(futures_no_atomic_cas))] + #[cfg(feature = "alloc")] + fn flat_map_unordered<U, F>( + self, + limit: impl Into<Option<usize>>, + f: F, + ) -> FlatMapUnordered<Self, U, F> + where + U: Stream + Unpin, + F: FnMut(Self::Item) -> U, + Self: Sized, + { + FlatMapUnordered::new(self, limit.into(), f) + } + /// Combinator similar to [`StreamExt::fold`] that holds internal state /// and produces a new stream. /// @@ -919,7 +1129,7 @@ pub trait StreamExt: Stream { /// fut.await; /// # }) /// ``` - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn for_each_concurrent<Fut, F>( self, @@ -1142,7 +1352,7 @@ pub trait StreamExt: Stream { /// /// This method is only available when the `std` or `alloc` feature of this /// library is activated, and it is activated by default. - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn buffered(self, n: usize) -> Buffered<Self> where @@ -1187,7 +1397,7 @@ pub trait StreamExt: Stream { /// assert_eq!(buffered.next().await, None); /// # Ok::<(), i32>(()) }).unwrap(); /// ``` - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn buffer_unordered(self, n: usize) -> BufferUnordered<Self> where @@ -1329,7 +1539,8 @@ pub trait StreamExt: Stream { /// the sink is closed. Note that neither the original stream nor provided /// sink will be output by this future. Pass the sink by `Pin<&mut S>` /// (for example, via `forward(&mut sink)` inside an `async` fn/block) in - /// order to preserve access to the `Sink`. + /// order to preserve access to the `Sink`. If the stream produces an error, + /// that error will be returned by this future without flushing/closing the sink. #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] fn forward<S>(self, sink: S) -> Forward<Self, S> @@ -1354,7 +1565,7 @@ pub trait StreamExt: Stream { /// library is activated, and it is activated by default. #[cfg(feature = "sink")] #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>) where diff --git a/src/stream/stream/next.rs b/src/stream/stream/next.rs index 6949878..8d8347a 100644 --- a/src/stream/stream/next.rs +++ b/src/stream/stream/next.rs @@ -28,10 +28,7 @@ impl<St: ?Sized + FusedStream + Unpin> FusedFuture for Next<'_, St> { impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> { type Output = Option<St::Item>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { self.stream.poll_next_unpin(cx) } } diff --git a/src/stream/stream/peek.rs b/src/stream/stream/peek.rs index a403110..c72dfc3 100644 --- a/src/stream/stream/peek.rs +++ b/src/stream/stream/peek.rs @@ -1,5 +1,7 @@ +use crate::fns::FnOnce1; use crate::stream::{Fuse, StreamExt}; use core::fmt; +use core::marker::PhantomData; use core::pin::Pin; use futures_core::future::{FusedFuture, Future}; use futures_core::ready; @@ -26,15 +28,12 @@ pin_project! { impl<St: Stream> Peekable<St> { pub(super) fn new(stream: St) -> Self { - Self { - stream: stream.fuse(), - peeked: None, - } + Self { stream: stream.fuse(), peeked: None } } delegate_access_inner!(stream, St, (.)); - /// Produces a `Peek` future which retrieves a reference to the next item + /// Produces a future which retrieves a reference to the next item /// in the stream, or `None` if the underlying stream terminates. pub fn peek(self: Pin<&mut Self>) -> Peek<'_, St> { Peek { inner: Some(self) } @@ -44,15 +43,60 @@ impl<St: Stream> Peekable<St> { /// /// This method polls the underlying stream and return either a reference /// to the next item if the stream is ready or passes through any errors. - pub fn poll_peek( + pub fn poll_peek(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<&St::Item>> { + let mut this = self.project(); + + Poll::Ready(loop { + if this.peeked.is_some() { + break this.peeked.as_ref(); + } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { + *this.peeked = Some(item); + } else { + break None; + } + }) + } + + /// Produces a future which retrieves a mutable reference to the next item + /// in the stream, or `None` if the underlying stream terminates. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// use futures::pin_mut; + /// + /// let stream = stream::iter(vec![1, 2, 3]).peekable(); + /// pin_mut!(stream); + /// + /// assert_eq!(stream.as_mut().peek_mut().await, Some(&mut 1)); + /// assert_eq!(stream.as_mut().next().await, Some(1)); + /// + /// // Peek into the stream and modify the value which will be returned next + /// if let Some(p) = stream.as_mut().peek_mut().await { + /// if *p == 2 { + /// *p = 5; + /// } + /// } + /// + /// assert_eq!(stream.collect::<Vec<_>>().await, vec![5, 3]); + /// # }); + /// ``` + pub fn peek_mut(self: Pin<&mut Self>) -> PeekMut<'_, St> { + PeekMut { inner: Some(self) } + } + + /// Peek retrieves a mutable reference to the next item in the stream. + pub fn poll_peek_mut( self: Pin<&mut Self>, cx: &mut Context<'_>, - ) -> Poll<Option<&St::Item>> { + ) -> Poll<Option<&mut St::Item>> { let mut this = self.project(); Poll::Ready(loop { if this.peeked.is_some() { - break this.peeked.as_ref(); + break this.peeked.as_mut(); } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { *this.peeked = Some(item); } else { @@ -60,6 +104,86 @@ impl<St: Stream> Peekable<St> { } }) } + + /// Creates a future which will consume and return the next value of this + /// stream if a condition is true. + /// + /// If `func` returns `true` for the next value of this stream, consume and + /// return it. Otherwise, return `None`. + /// + /// # Examples + /// + /// Consume a number if it's equal to 0. + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// use futures::pin_mut; + /// + /// let stream = stream::iter(0..5).peekable(); + /// pin_mut!(stream); + /// // The first item of the stream is 0; consume it. + /// assert_eq!(stream.as_mut().next_if(|&x| x == 0).await, Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(stream.as_mut().next_if(|&x| x == 0).await, None); + /// // `next_if` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(stream.next().await, Some(1)); + /// # }); + /// ``` + /// + /// Consume any number less than 10. + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// use futures::pin_mut; + /// + /// let stream = stream::iter(1..20).peekable(); + /// pin_mut!(stream); + /// // Consume all numbers less than 10 + /// while stream.as_mut().next_if(|&x| x < 10).await.is_some() {} + /// // The next value returned will be 10 + /// assert_eq!(stream.next().await, Some(10)); + /// # }); + /// ``` + pub fn next_if<F>(self: Pin<&mut Self>, func: F) -> NextIf<'_, St, F> + where + F: FnOnce(&St::Item) -> bool, + { + NextIf { inner: Some((self, func)) } + } + + /// Creates a future which will consume and return the next item if it is + /// equal to `expected`. + /// + /// # Example + /// + /// Consume a number if it's equal to 0. + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, StreamExt}; + /// use futures::pin_mut; + /// + /// let stream = stream::iter(0..5).peekable(); + /// pin_mut!(stream); + /// // The first item of the stream is 0; consume it. + /// assert_eq!(stream.as_mut().next_if_eq(&0).await, Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(stream.as_mut().next_if_eq(&0).await, None); + /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(stream.next().await, Some(1)); + /// # }); + /// ``` + pub fn next_if_eq<'a, T>(self: Pin<&'a mut Self>, expected: &'a T) -> NextIfEq<'a, St, T> + where + T: ?Sized, + St::Item: PartialEq<T>, + { + NextIfEq { + inner: NextIf { inner: Some((self, NextIfEqFn { expected, _next: PhantomData })) }, + } + } } impl<St: Stream> FusedStream for Peekable<St> { @@ -103,7 +227,7 @@ where } pin_project! { - /// Future for the [`Peekable::peek()`](self::Peekable::peek) function from [`Peekable`] + /// Future for the [`Peekable::peek`](self::Peekable::peek) method. #[must_use = "futures do nothing unless polled"] pub struct Peek<'a, St: Stream> { inner: Option<Pin<&'a mut Peekable<St>>>, @@ -116,9 +240,7 @@ where St::Item: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Peek") - .field("inner", &self.inner) - .finish() + f.debug_struct("Peek").field("inner", &self.inner).finish() } } @@ -133,6 +255,7 @@ where St: Stream, { type Output = Option<&'a St::Item>; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let inner = self.project().inner; if let Some(peekable) = inner { @@ -144,3 +267,167 @@ where } } } + +pin_project! { + /// Future for the [`Peekable::peek_mut`](self::Peekable::peek_mut) method. + #[must_use = "futures do nothing unless polled"] + pub struct PeekMut<'a, St: Stream> { + inner: Option<Pin<&'a mut Peekable<St>>>, + } +} + +impl<St> fmt::Debug for PeekMut<'_, St> +where + St: Stream + fmt::Debug, + St::Item: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PeekMut").field("inner", &self.inner).finish() + } +} + +impl<St: Stream> FusedFuture for PeekMut<'_, St> { + fn is_terminated(&self) -> bool { + self.inner.is_none() + } +} + +impl<'a, St> Future for PeekMut<'a, St> +where + St: Stream, +{ + type Output = Option<&'a mut St::Item>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + let inner = self.project().inner; + if let Some(peekable) = inner { + ready!(peekable.as_mut().poll_peek_mut(cx)); + + inner.take().unwrap().poll_peek_mut(cx) + } else { + panic!("PeekMut polled after completion") + } + } +} + +pin_project! { + /// Future for the [`Peekable::next_if`](self::Peekable::next_if) method. + #[must_use = "futures do nothing unless polled"] + pub struct NextIf<'a, St: Stream, F> { + inner: Option<(Pin<&'a mut Peekable<St>>, F)>, + } +} + +impl<St, F> fmt::Debug for NextIf<'_, St, F> +where + St: Stream + fmt::Debug, + St::Item: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NextIf").field("inner", &self.inner.as_ref().map(|(s, _f)| s)).finish() + } +} + +#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 +impl<St, F> FusedFuture for NextIf<'_, St, F> +where + St: Stream, + F: for<'a> FnOnce1<&'a St::Item, Output = bool>, +{ + fn is_terminated(&self) -> bool { + self.inner.is_none() + } +} + +#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 +impl<St, F> Future for NextIf<'_, St, F> +where + St: Stream, + F: for<'a> FnOnce1<&'a St::Item, Output = bool>, +{ + type Output = Option<St::Item>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + let inner = self.project().inner; + if let Some((peekable, _)) = inner { + let res = ready!(peekable.as_mut().poll_next(cx)); + + let (peekable, func) = inner.take().unwrap(); + match res { + Some(ref matched) if func.call_once(matched) => Poll::Ready(res), + other => { + let peekable = peekable.project(); + // Since we called `self.next()`, we consumed `self.peeked`. + assert!(peekable.peeked.is_none()); + *peekable.peeked = other; + Poll::Ready(None) + } + } + } else { + panic!("NextIf polled after completion") + } + } +} + +pin_project! { + /// Future for the [`Peekable::next_if_eq`](self::Peekable::next_if_eq) method. + #[must_use = "futures do nothing unless polled"] + pub struct NextIfEq<'a, St: Stream, T: ?Sized> { + #[pin] + inner: NextIf<'a, St, NextIfEqFn<'a, T, St::Item>>, + } +} + +impl<St, T> fmt::Debug for NextIfEq<'_, St, T> +where + St: Stream + fmt::Debug, + St::Item: fmt::Debug, + T: ?Sized, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NextIfEq") + .field("inner", &self.inner.inner.as_ref().map(|(s, _f)| s)) + .finish() + } +} + +impl<St, T> FusedFuture for NextIfEq<'_, St, T> +where + St: Stream, + T: ?Sized, + St::Item: PartialEq<T>, +{ + fn is_terminated(&self) -> bool { + self.inner.is_terminated() + } +} + +impl<St, T> Future for NextIfEq<'_, St, T> +where + St: Stream, + T: ?Sized, + St::Item: PartialEq<T>, +{ + type Output = Option<St::Item>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.project().inner.poll(cx) + } +} + +struct NextIfEqFn<'a, T: ?Sized, Item> { + expected: &'a T, + _next: PhantomData<Item>, +} + +impl<T, Item> FnOnce1<&Item> for NextIfEqFn<'_, T, Item> +where + T: ?Sized, + Item: PartialEq<T>, +{ + type Output = bool; + + fn call_once(self, next: &Item) -> Self::Output { + next == self.expected + } +} diff --git a/src/stream/stream/ready_chunks.rs b/src/stream/stream/ready_chunks.rs index b6e3e5c..5ebc958 100644 --- a/src/stream/stream/ready_chunks.rs +++ b/src/stream/stream/ready_chunks.rs @@ -1,12 +1,12 @@ use crate::stream::Fuse; -use futures_core::stream::{Stream, FusedStream}; +use alloc::vec::Vec; +use core::mem; +use core::pin::Pin; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::mem; -use core::pin::Pin; -use alloc::vec::Vec; pin_project! { /// Stream for the [`ready_chunks`](super::StreamExt::ready_chunks) method. @@ -20,7 +20,10 @@ pin_project! { } } -impl<St: Stream> ReadyChunks<St> where St: Stream { +impl<St: Stream> ReadyChunks<St> +where + St: Stream, +{ pub(super) fn new(stream: St, capacity: usize) -> Self { assert!(capacity > 0); @@ -37,10 +40,7 @@ impl<St: Stream> ReadyChunks<St> where St: Stream { impl<St: Stream> Stream for ReadyChunks<St> { type Item = Vec<St::Item>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); loop { @@ -61,7 +61,10 @@ impl<St: Stream> Stream for ReadyChunks<St> { Poll::Ready(Some(item)) => { this.items.push(item); if this.items.len() >= *this.cap { - return Poll::Ready(Some(mem::replace(this.items, Vec::with_capacity(*this.cap)))) + return Poll::Ready(Some(mem::replace( + this.items, + Vec::with_capacity(*this.cap), + ))); } } diff --git a/src/stream/stream/scan.rs b/src/stream/stream/scan.rs index 2097280..f5cfde9 100644 --- a/src/stream/stream/scan.rs +++ b/src/stream/stream/scan.rs @@ -56,14 +56,7 @@ where Fut: Future<Output = Option<B>>, { pub(super) fn new(stream: St, initial_state: S, f: F) -> Self { - Self { - stream, - state_f: Some(StateFn { - state: initial_state, - f, - }), - future: None, - } + Self { stream, state_f: Some(StateFn { state: initial_state, f }), future: None } } delegate_access_inner!(stream, St, ()); @@ -125,11 +118,11 @@ where // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] -impl<S, Fut, F, Item> Sink<Item> for Scan<S, S, Fut, F> +impl<St, S, Fut, F, Item> Sink<Item> for Scan<St, S, Fut, F> where - S: Stream + Sink<Item>, + St: Stream + Sink<Item>, { - type Error = S::Error; + type Error = St::Error; delegate_sink!(stream, Item); } diff --git a/src/stream/stream/select_next_some.rs b/src/stream/stream/select_next_some.rs index fe7a089..3115e14 100644 --- a/src/stream/stream/select_next_some.rs +++ b/src/stream/stream/select_next_some.rs @@ -1,9 +1,9 @@ +use crate::stream::StreamExt; use core::pin::Pin; +use futures_core::future::{FusedFuture, Future}; use futures_core::ready; use futures_core::stream::FusedStream; -use futures_core::future::{Future, FusedFuture}; use futures_core::task::{Context, Poll}; -use crate::stream::StreamExt; /// Future for the [`select_next_some`](super::StreamExt::select_next_some) /// method. diff --git a/src/stream/stream/skip.rs b/src/stream/stream/skip.rs index 6ffcf57..f495779 100644 --- a/src/stream/stream/skip.rs +++ b/src/stream/stream/skip.rs @@ -19,10 +19,7 @@ pin_project! { impl<St: Stream> Skip<St> { pub(super) fn new(stream: St, n: usize) -> Self { - Self { - stream, - remaining: n, - } + Self { stream, remaining: n } } delegate_access_inner!(stream, St, ()); @@ -37,10 +34,7 @@ impl<St: FusedStream> FusedStream for Skip<St> { impl<St: Stream> Stream for Skip<St> { type Item = St::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St::Item>> { let mut this = self.project(); while *this.remaining > 0 { @@ -57,11 +51,8 @@ impl<St: Stream> Stream for Skip<St> { fn size_hint(&self) -> (usize, Option<usize>) { let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_sub(self.remaining as usize); - let upper = match upper { - Some(x) => Some(x.saturating_sub(self.remaining as usize)), - None => None, - }; + let lower = lower.saturating_sub(self.remaining); + let upper = upper.map(|x| x.saturating_sub(self.remaining)); (lower, upper) } diff --git a/src/stream/stream/skip_while.rs b/src/stream/stream/skip_while.rs index e1aa3f9..50a21a2 100644 --- a/src/stream/stream/skip_while.rs +++ b/src/stream/stream/skip_while.rs @@ -39,27 +39,23 @@ where } impl<St, Fut, F> SkipWhile<St, Fut, F> - where St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: Stream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - done_skipping: false, - } + Self { stream, f, pending_fut: None, pending_item: None, done_skipping: false } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> FusedStream for SkipWhile<St, Fut, F> - where St: FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: FusedStream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { fn is_terminated(&self) -> bool { self.pending_item.is_none() && self.stream.is_terminated() @@ -67,16 +63,14 @@ impl<St, Fut, F> FusedStream for SkipWhile<St, Fut, F> } impl<St, Fut, F> Stream for SkipWhile<St, Fut, F> - where St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: Stream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { type Item = St::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St::Item>> { let mut this = self.project(); if *this.done_skipping { @@ -119,9 +113,10 @@ impl<St, Fut, F> Stream for SkipWhile<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for SkipWhile<S, Fut, F> - where S: Stream + Sink<Item>, - F: FnMut(&S::Item) -> Fut, - Fut: Future<Output = bool>, +where + S: Stream + Sink<Item>, + F: FnMut(&S::Item) -> Fut, + Fut: Future<Output = bool>, { type Error = S::Error; diff --git a/src/stream/stream/split.rs b/src/stream/stream/split.rs index 997b974..3a72fee 100644 --- a/src/stream/stream/split.rs +++ b/src/stream/stream/split.rs @@ -1,9 +1,9 @@ +use core::fmt; +use core::pin::Pin; use futures_core::ready; use futures_core::stream::Stream; use futures_core::task::{Context, Poll}; use futures_sink::Sink; -use core::fmt; -use core::pin::Pin; use crate::lock::BiLock; @@ -20,7 +20,8 @@ impl<S: Unpin> SplitStream<S> { /// together. Succeeds only if the `SplitStream<S>` and `SplitSink<S>` are /// a matching pair originating from the same call to `StreamExt::split`. pub fn reunite<Item>(self, other: SplitSink<S, Item>) -> Result<S, ReuniteError<S, Item>> - where S: Sink<Item>, + where + S: Sink<Item>, { other.reunite(self) } @@ -36,10 +37,7 @@ impl<S: Stream> Stream for SplitStream<S> { #[allow(bad_style)] fn SplitSink<S: Sink<Item>, Item>(lock: BiLock<S>) -> SplitSink<S, Item> { - SplitSink { - lock, - slot: None, - } + SplitSink { lock, slot: None } } /// A `Sink` part of the split pair @@ -58,14 +56,16 @@ impl<S: Sink<Item> + Unpin, Item> SplitSink<S, Item> { /// together. Succeeds only if the `SplitStream<S>` and `SplitSink<S>` are /// a matching pair originating from the same call to `StreamExt::split`. pub fn reunite(self, other: SplitStream<S>) -> Result<S, ReuniteError<S, Item>> { - self.lock.reunite(other.0).map_err(|err| { - ReuniteError(SplitSink(err.0), SplitStream(err.1)) - }) + self.lock.reunite(other.0).map_err(|err| ReuniteError(SplitSink(err.0), SplitStream(err.1))) } } impl<S: Sink<Item>, Item> SplitSink<S, Item> { - fn poll_flush_slot(mut inner: Pin<&mut S>, slot: &mut Option<Item>, cx: &mut Context<'_>) -> Poll<Result<(), S::Error>> { + fn poll_flush_slot( + mut inner: Pin<&mut S>, + slot: &mut Option<Item>, + cx: &mut Context<'_>, + ) -> Poll<Result<(), S::Error>> { if slot.is_some() { ready!(inner.as_mut().poll_ready(cx))?; Poll::Ready(inner.start_send(slot.take().unwrap())) @@ -74,7 +74,10 @@ impl<S: Sink<Item>, Item> SplitSink<S, Item> { } } - fn poll_lock_and_flush_slot(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), S::Error>> { + fn poll_lock_and_flush_slot( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<(), S::Error>> { let this = &mut *self; let mut inner = ready!(this.lock.poll_lock(cx)); Self::poll_flush_slot(inner.as_pin_mut(), &mut this.slot, cx) @@ -127,9 +130,7 @@ pub struct ReuniteError<T, Item>(pub SplitSink<T, Item>, pub SplitStream<T>); impl<T, Item> fmt::Debug for ReuniteError<T, Item> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError") - .field(&"...") - .finish() + f.debug_tuple("ReuniteError").field(&"...").finish() } } diff --git a/src/stream/stream/take.rs b/src/stream/stream/take.rs index 124d397..b1c728e 100644 --- a/src/stream/stream/take.rs +++ b/src/stream/stream/take.rs @@ -1,7 +1,7 @@ use core::cmp; use core::pin::Pin; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -20,24 +20,19 @@ pin_project! { impl<St: Stream> Take<St> { pub(super) fn new(stream: St, n: usize) -> Self { - Self { - stream, - remaining: n, - } + Self { stream, remaining: n } } delegate_access_inner!(stream, St, ()); } impl<St> Stream for Take<St> - where St: Stream, +where + St: Stream, { type Item = St::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St::Item>> { if self.remaining == 0 { Poll::Ready(None) } else { @@ -63,7 +58,7 @@ impl<St> Stream for Take<St> let upper = match upper { Some(x) if x < self.remaining as usize => Some(x), - _ => Some(self.remaining as usize) + _ => Some(self.remaining as usize), }; (lower, upper) @@ -71,7 +66,8 @@ impl<St> Stream for Take<St> } impl<St> FusedStream for Take<St> - where St: FusedStream, +where + St: FusedStream, { fn is_terminated(&self) -> bool { self.remaining == 0 || self.stream.is_terminated() @@ -81,7 +77,8 @@ impl<St> FusedStream for Take<St> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Item> Sink<Item> for Take<S> - where S: Stream + Sink<Item>, +where + S: Stream + Sink<Item>, { type Error = S::Error; diff --git a/src/stream/stream/take_until.rs b/src/stream/stream/take_until.rs index 4dea01a..d14f9ce 100644 --- a/src/stream/stream/take_until.rs +++ b/src/stream/stream/take_until.rs @@ -34,10 +34,7 @@ where Fut: Future + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TakeUntil") - .field("stream", &self.stream) - .field("fut", &self.fut) - .finish() + f.debug_struct("TakeUntil").field("stream", &self.stream).field("fut", &self.fut).finish() } } @@ -47,12 +44,7 @@ where Fut: Future, { pub(super) fn new(stream: St, fut: Fut) -> Self { - Self { - stream, - fut: Some(fut), - fut_result: None, - free: false, - } + Self { stream, fut: Some(fut), fut_result: None, free: false } } delegate_access_inner!(stream, St, ()); diff --git a/src/stream/stream/take_while.rs b/src/stream/stream/take_while.rs index 4cdba83..01b2765 100644 --- a/src/stream/stream/take_while.rs +++ b/src/stream/stream/take_while.rs @@ -2,7 +2,7 @@ use core::fmt; use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; -use futures_core::stream::{Stream, FusedStream}; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -39,34 +39,27 @@ where } impl<St, Fut, F> TakeWhile<St, Fut, F> - where St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: Stream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - done_taking: false, - } + Self { stream, f, pending_fut: None, pending_item: None, done_taking: false } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> Stream for TakeWhile<St, Fut, F> - where St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: Stream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { type Item = St::Item; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<St::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<St::Item>> { if self.done_taking { return Poll::Ready(None); } @@ -109,9 +102,10 @@ impl<St, Fut, F> Stream for TakeWhile<St, Fut, F> } impl<St, Fut, F> FusedStream for TakeWhile<St, Fut, F> - where St: FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future<Output = bool>, +where + St: FusedStream, + F: FnMut(&St::Item) -> Fut, + Fut: Future<Output = bool>, { fn is_terminated(&self) -> bool { self.done_taking || self.pending_item.is_none() && self.stream.is_terminated() @@ -121,7 +115,8 @@ impl<St, Fut, F> FusedStream for TakeWhile<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for TakeWhile<S, Fut, F> - where S: Stream + Sink<Item>, +where + S: Stream + Sink<Item>, { type Error = S::Error; diff --git a/src/stream/stream/then.rs b/src/stream/stream/then.rs index 3d42bdd..d4531d4 100644 --- a/src/stream/stream/then.rs +++ b/src/stream/stream/then.rs @@ -26,32 +26,27 @@ where Fut: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Then") - .field("stream", &self.stream) - .field("future", &self.future) - .finish() + f.debug_struct("Then").field("stream", &self.stream).field("future", &self.future).finish() } } impl<St, Fut, F> Then<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, +where + St: Stream, + F: FnMut(St::Item) -> Fut, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - future: None, - f, - } + Self { stream, future: None, f } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> FusedStream for Then<St, Fut, F> - where St: FusedStream, - F: FnMut(St::Item) -> Fut, - Fut: Future, +where + St: FusedStream, + F: FnMut(St::Item) -> Fut, + Fut: Future, { fn is_terminated(&self) -> bool { self.future.is_none() && self.stream.is_terminated() @@ -59,16 +54,14 @@ impl<St, Fut, F> FusedStream for Then<St, Fut, F> } impl<St, Fut, F> Stream for Then<St, Fut, F> - where St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, +where + St: Stream, + F: FnMut(St::Item) -> Fut, + Fut: Future, { type Item = Fut::Output; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); Poll::Ready(loop { @@ -99,7 +92,8 @@ impl<St, Fut, F> Stream for Then<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for Then<S, Fut, F> - where S: Sink<Item>, +where + S: Sink<Item>, { type Error = S::Error; diff --git a/src/stream/stream/unzip.rs b/src/stream/stream/unzip.rs index 5024770..15f22e8 100644 --- a/src/stream/stream/unzip.rs +++ b/src/stream/stream/unzip.rs @@ -21,25 +21,19 @@ pin_project! { impl<St: Stream, FromA: Default, FromB: Default> Unzip<St, FromA, FromB> { fn finish(self: Pin<&mut Self>) -> (FromA, FromB) { let this = self.project(); - ( - mem::replace(this.left, Default::default()), - mem::replace(this.right, Default::default()), - ) + (mem::replace(this.left, Default::default()), mem::replace(this.right, Default::default())) } pub(super) fn new(stream: St) -> Self { - Self { - stream, - left: Default::default(), - right: Default::default(), - } + Self { stream, left: Default::default(), right: Default::default() } } } impl<St, A, B, FromA, FromB> FusedFuture for Unzip<St, FromA, FromB> -where St: FusedStream<Item = (A, B)>, - FromA: Default + Extend<A>, - FromB: Default + Extend<B>, +where + St: FusedStream<Item = (A, B)>, + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, { fn is_terminated(&self) -> bool { self.stream.is_terminated() @@ -47,9 +41,10 @@ where St: FusedStream<Item = (A, B)>, } impl<St, A, B, FromA, FromB> Future for Unzip<St, FromA, FromB> -where St: Stream<Item = (A, B)>, - FromA: Default + Extend<A>, - FromB: Default + Extend<B>, +where + St: Stream<Item = (A, B)>, + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, { type Output = (FromA, FromB); @@ -60,7 +55,7 @@ where St: Stream<Item = (A, B)>, Some(e) => { this.left.extend(Some(e.0)); this.right.extend(Some(e.1)); - }, + } None => return Poll::Ready(self.finish()), } } diff --git a/src/stream/stream/zip.rs b/src/stream/stream/zip.rs index 588531a..360a8b6 100644 --- a/src/stream/stream/zip.rs +++ b/src/stream/stream/zip.rs @@ -1,4 +1,4 @@ -use crate::stream::{StreamExt, Fuse}; +use crate::stream::{Fuse, StreamExt}; use core::cmp; use core::pin::Pin; use futures_core::stream::{FusedStream, Stream}; @@ -21,12 +21,7 @@ pin_project! { impl<St1: Stream, St2: Stream> Zip<St1, St2> { pub(super) fn new(stream1: St1, stream2: St2) -> Self { - Self { - stream1: stream1.fuse(), - stream2: stream2.fuse(), - queued1: None, - queued2: None, - } + Self { stream1: stream1.fuse(), stream2: stream2.fuse(), queued1: None, queued2: None } } /// Acquires a reference to the underlying streams that this combinator is @@ -64,7 +59,9 @@ impl<St1: Stream, St2: Stream> Zip<St1, St2> { } impl<St1, St2> FusedStream for Zip<St1, St2> - where St1: Stream, St2: Stream, +where + St1: Stream, + St2: Stream, { fn is_terminated(&self) -> bool { self.stream1.is_terminated() && self.stream2.is_terminated() @@ -72,14 +69,13 @@ impl<St1, St2> FusedStream for Zip<St1, St2> } impl<St1, St2> Stream for Zip<St1, St2> - where St1: Stream, St2: Stream +where + St1: Stream, + St2: Stream, { type Item = (St1::Item, St2::Item); - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); if this.queued1.is_none() { @@ -124,7 +120,7 @@ impl<St1, St2> Stream for Zip<St1, St2> } (Some(x), None) => x.checked_add(queued1_len), (None, Some(y)) => y.checked_add(queued2_len), - (None, None) => None + (None, None) => None, }; (lower, upper) diff --git a/src/stream/try_stream/and_then.rs b/src/stream/try_stream/and_then.rs index b185646..a7b50db 100644 --- a/src/stream/try_stream/and_then.rs +++ b/src/stream/try_stream/and_then.rs @@ -2,7 +2,7 @@ use core::fmt; use core::pin::Pin; use futures_core::future::TryFuture; use futures_core::ready; -use futures_core::stream::{Stream, TryStream, FusedStream}; +use futures_core::stream::{FusedStream, Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -34,9 +34,10 @@ where } impl<St, Fut, F> AndThen<St, Fut, F> - where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture<Error = St::Error>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: TryFuture<Error = St::Error>, { pub(super) fn new(stream: St, f: F) -> Self { Self { stream, future: None, f } @@ -46,16 +47,14 @@ impl<St, Fut, F> AndThen<St, Fut, F> } impl<St, Fut, F> Stream for AndThen<St, Fut, F> - where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture<Error = St::Error>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: TryFuture<Error = St::Error>, { type Item = Result<Fut::Ok, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); Poll::Ready(loop { @@ -84,9 +83,10 @@ impl<St, Fut, F> Stream for AndThen<St, Fut, F> } impl<St, Fut, F> FusedStream for AndThen<St, Fut, F> - where St: TryStream + FusedStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture<Error = St::Error>, +where + St: TryStream + FusedStream, + F: FnMut(St::Ok) -> Fut, + Fut: TryFuture<Error = St::Error>, { fn is_terminated(&self) -> bool { self.future.is_none() && self.stream.is_terminated() @@ -96,7 +96,8 @@ impl<St, Fut, F> FusedStream for AndThen<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for AndThen<S, Fut, F> - where S: Sink<Item>, +where + S: Sink<Item>, { type Error = S::Error; diff --git a/src/stream/try_stream/into_async_read.rs b/src/stream/try_stream/into_async_read.rs index 197c105..914b277 100644 --- a/src/stream/try_stream/into_async_read.rs +++ b/src/stream/try_stream/into_async_read.rs @@ -3,7 +3,7 @@ use core::pin::Pin; use futures_core::ready; use futures_core::stream::TryStream; use futures_core::task::{Context, Poll}; -use futures_io::{AsyncRead, AsyncWrite, AsyncBufRead}; +use futures_io::{AsyncBufRead, AsyncRead, AsyncWrite}; use std::cmp; use std::io::{Error, Result}; @@ -40,10 +40,7 @@ where St::Ok: AsRef<[u8]>, { pub(super) fn new(stream: St) -> Self { - Self { - stream, - state: ReadState::PendingChunk, - } + Self { stream, state: ReadState::PendingChunk } } } @@ -63,9 +60,7 @@ where let chunk = chunk.as_ref(); let len = cmp::min(buf.len(), chunk.len() - *chunk_start); - buf[..len].copy_from_slice( - &chunk[*chunk_start..*chunk_start + len], - ); + buf[..len].copy_from_slice(&chunk[*chunk_start..*chunk_start + len]); *chunk_start += len; if chunk.len() == *chunk_start { @@ -74,26 +69,21 @@ where return Poll::Ready(Ok(len)); } - ReadState::PendingChunk => { - match ready!(self.stream.try_poll_next_unpin(cx)) { - Some(Ok(chunk)) => { - if !chunk.as_ref().is_empty() { - self.state = ReadState::Ready { - chunk, - chunk_start: 0, - }; - } - } - Some(Err(err)) => { - self.state = ReadState::Eof; - return Poll::Ready(Err(err)); - } - None => { - self.state = ReadState::Eof; - return Poll::Ready(Ok(0)); + ReadState::PendingChunk => match ready!(self.stream.try_poll_next_unpin(cx)) { + Some(Ok(chunk)) => { + if !chunk.as_ref().is_empty() { + self.state = ReadState::Ready { chunk, chunk_start: 0 }; } } - } + Some(Err(err)) => { + self.state = ReadState::Eof; + return Poll::Ready(Err(err)); + } + None => { + self.state = ReadState::Eof; + return Poll::Ready(Ok(0)); + } + }, ReadState::Eof => { return Poll::Ready(Ok(0)); } @@ -110,23 +100,17 @@ where fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, - buf: &[u8] + buf: &[u8], ) -> Poll<Result<usize>> { - Pin::new( &mut self.stream ).poll_write( cx, buf ) + Pin::new(&mut self.stream).poll_write(cx, buf) } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll<Result<()>> { - Pin::new( &mut self.stream ).poll_flush( cx ) + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> { + Pin::new(&mut self.stream).poll_flush(cx) } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll<Result<()>> { - Pin::new( &mut self.stream ).poll_close( cx ) + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> { + Pin::new(&mut self.stream).poll_close(cx) } } @@ -135,18 +119,12 @@ where St: TryStream<Error = Error> + Unpin, St::Ok: AsRef<[u8]>, { - fn poll_fill_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Result<&[u8]>> { + fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { while let ReadState::PendingChunk = self.state { match ready!(self.stream.try_poll_next_unpin(cx)) { Some(Ok(chunk)) => { if !chunk.as_ref().is_empty() { - self.state = ReadState::Ready { - chunk, - chunk_start: 0, - }; + self.state = ReadState::Ready { chunk, chunk_start: 0 }; } } Some(Err(err)) => { @@ -169,12 +147,11 @@ where Poll::Ready(Ok(&[])) } - fn consume( - mut self: Pin<&mut Self>, - amount: usize, - ) { - // https://github.com/rust-lang/futures-rs/pull/1556#discussion_r281644295 - if amount == 0 { return } + fn consume(mut self: Pin<&mut Self>, amount: usize) { + // https://github.com/rust-lang/futures-rs/pull/1556#discussion_r281644295 + if amount == 0 { + return; + } if let ReadState::Ready { chunk, chunk_start } = &mut self.state { *chunk_start += amount; debug_assert!(*chunk_start <= chunk.as_ref().len()); diff --git a/src/stream/try_stream/into_stream.rs b/src/stream/try_stream/into_stream.rs index 89bc3ef..2126258 100644 --- a/src/stream/try_stream/into_stream.rs +++ b/src/stream/try_stream/into_stream.rs @@ -34,10 +34,7 @@ impl<St: TryStream> Stream for IntoStream<St> { type Item = Result<St::Ok, St::Error>; #[inline] - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { self.project().stream.try_poll_next(cx) } diff --git a/src/stream/try_stream/mod.rs b/src/stream/try_stream/mod.rs index b7353d9..6bf2cb7 100644 --- a/src/stream/try_stream/mod.rs +++ b/src/stream/try_stream/mod.rs @@ -5,18 +5,21 @@ #[cfg(feature = "compat")] use crate::compat::Compat; +use crate::fns::{ + inspect_err_fn, inspect_ok_fn, into_fn, map_err_fn, map_ok_fn, InspectErrFn, InspectOkFn, + IntoFn, MapErrFn, MapOkFn, +}; +use crate::future::assert_future; +use crate::stream::assert_stream; +use crate::stream::{Inspect, Map}; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; use core::pin::Pin; use futures_core::{ future::{Future, TryFuture}, stream::TryStream, task::{Context, Poll}, }; -use crate::fns::{ - InspectOkFn, inspect_ok_fn, InspectErrFn, inspect_err_fn, MapErrFn, map_err_fn, IntoFn, into_fn, MapOkFn, map_ok_fn, -}; -use crate::future::assert_future; -use crate::stream::{Map, Inspect}; -use crate::stream::assert_stream; mod and_then; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 @@ -93,6 +96,12 @@ mod try_concat; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::try_concat::TryConcat; +#[cfg(feature = "alloc")] +mod try_chunks; +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::try_chunks::{TryChunks, TryChunksError}; + mod try_fold; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::try_fold::TryFold; @@ -109,25 +118,29 @@ mod try_take_while; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::try_take_while::TryTakeWhile; -cfg_target_has_atomic! { - #[cfg(feature = "alloc")] - mod try_buffer_unordered; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::try_buffer_unordered::TryBufferUnordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod try_buffer_unordered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::try_buffer_unordered::TryBufferUnordered; - #[cfg(feature = "alloc")] - mod try_buffered; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::try_buffered::TryBuffered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod try_buffered; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::try_buffered::TryBuffered; - #[cfg(feature = "alloc")] - mod try_for_each_concurrent; - #[cfg(feature = "alloc")] - #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 - pub use self::try_for_each_concurrent::TryForEachConcurrent; -} +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +mod try_for_each_concurrent; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +pub use self::try_for_each_concurrent::TryForEachConcurrent; #[cfg(feature = "io")] #[cfg(feature = "std")] @@ -515,7 +528,7 @@ pub trait TryStreamExt: TryStream { /// assert_eq!(Err(oneshot::Canceled), fut.await); /// # }) /// ``` - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn try_for_each_concurrent<Fut, F>( self, @@ -571,6 +584,53 @@ pub trait TryStreamExt: TryStream { assert_future::<Result<C, Self::Error>, _>(TryCollect::new(self)) } + /// An adaptor for chunking up successful items of the stream inside a vector. + /// + /// This combinator will attempt to pull successful items from this stream and buffer + /// them into a local vector. At most `capacity` items will get buffered + /// before they're yielded from the returned stream. + /// + /// Note that the vectors returned from this iterator may not always have + /// `capacity` elements. If the underlying stream ended and only a partial + /// vector was created, it'll be returned. Additionally if an error happens + /// from the underlying stream then the currently buffered items will be + /// yielded. + /// + /// This method is only available when the `std` or `alloc` feature of this + /// library is activated, and it is activated by default. + /// + /// This function is similar to + /// [`StreamExt::chunks`](crate::stream::StreamExt::chunks) but exits + /// early if an error occurs. + /// + /// # Examples + /// + /// ``` + /// # futures::executor::block_on(async { + /// use futures::stream::{self, TryChunksError, TryStreamExt}; + /// + /// let stream = stream::iter(vec![Ok::<i32, i32>(1), Ok(2), Ok(3), Err(4), Ok(5), Ok(6)]); + /// let mut stream = stream.try_chunks(2); + /// + /// assert_eq!(stream.try_next().await, Ok(Some(vec![1, 2]))); + /// assert_eq!(stream.try_next().await, Err(TryChunksError(vec![3], 4))); + /// assert_eq!(stream.try_next().await, Ok(Some(vec![5, 6]))); + /// # }) + /// ``` + /// + /// # Panics + /// + /// This method will panic if `capacity` is zero. + #[cfg(feature = "alloc")] + fn try_chunks(self, capacity: usize) -> TryChunks<Self> + where + Self: Sized, + { + assert_stream::<Result<Vec<Self::Ok>, TryChunksError<Self::Ok, Self::Error>>, _>( + TryChunks::new(self, capacity), + ) + } + /// Attempt to filter the values produced by this stream according to the /// provided asynchronous closure. /// @@ -676,17 +736,21 @@ pub trait TryStreamExt: TryStream { /// thread::spawn(move || { /// tx2.unbounded_send(Ok(2)).unwrap(); /// tx2.unbounded_send(Err(3)).unwrap(); + /// tx2.unbounded_send(Ok(4)).unwrap(); /// }); /// thread::spawn(move || { /// tx3.unbounded_send(Ok(rx1)).unwrap(); /// tx3.unbounded_send(Ok(rx2)).unwrap(); - /// tx3.unbounded_send(Err(4)).unwrap(); + /// tx3.unbounded_send(Err(5)).unwrap(); /// }); /// /// let mut stream = rx3.try_flatten(); /// assert_eq!(stream.next().await, Some(Ok(1))); /// assert_eq!(stream.next().await, Some(Ok(2))); /// assert_eq!(stream.next().await, Some(Err(3))); + /// assert_eq!(stream.next().await, Some(Ok(4))); + /// assert_eq!(stream.next().await, Some(Err(5))); + /// assert_eq!(stream.next().await, None); /// # }); /// ``` fn try_flatten(self) -> TryFlatten<Self> @@ -836,7 +900,7 @@ pub trait TryStreamExt: TryStream { /// assert_eq!(buffered.next().await, Some(Err("error in the stream"))); /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn try_buffer_unordered(self, n: usize) -> TryBufferUnordered<Self> where @@ -912,14 +976,16 @@ pub trait TryStreamExt: TryStream { /// assert_eq!(buffered.next().await, Some(Err("error in the stream"))); /// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap(); /// ``` - #[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))] + #[cfg(not(futures_no_atomic_cas))] #[cfg(feature = "alloc")] fn try_buffered(self, n: usize) -> TryBuffered<Self> where Self::Ok: TryFuture<Error = Self::Error>, Self: Sized, { - assert_stream::<Result<<Self::Ok as TryFuture>::Ok, Self::Error>, _>(TryBuffered::new(self, n)) + assert_stream::<Result<<Self::Ok as TryFuture>::Ok, Self::Error>, _>(TryBuffered::new( + self, n, + )) } // TODO: false positive warning from rustdoc. Verify once #43466 settles @@ -939,6 +1005,7 @@ pub trait TryStreamExt: TryStream { /// Wraps a [`TryStream`] into a stream compatible with libraries using /// futures 0.1 `Stream`. Requires the `compat` feature to be enabled. /// ``` + /// # if cfg!(miri) { return; } // Miri does not support epoll /// use futures::future::{FutureExt, TryFutureExt}; /// # let (tx, rx) = futures::channel::oneshot::channel(); /// diff --git a/src/stream/try_stream/or_else.rs b/src/stream/try_stream/or_else.rs index 999123a..cb69e81 100644 --- a/src/stream/try_stream/or_else.rs +++ b/src/stream/try_stream/or_else.rs @@ -2,7 +2,7 @@ use core::fmt; use core::pin::Pin; use futures_core::future::TryFuture; use futures_core::ready; -use futures_core::stream::{Stream, TryStream, FusedStream}; +use futures_core::stream::{FusedStream, Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -34,9 +34,10 @@ where } impl<St, Fut, F> OrElse<St, Fut, F> - where St: TryStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture<Ok = St::Ok>, +where + St: TryStream, + F: FnMut(St::Error) -> Fut, + Fut: TryFuture<Ok = St::Ok>, { pub(super) fn new(stream: St, f: F) -> Self { Self { stream, future: None, f } @@ -46,16 +47,14 @@ impl<St, Fut, F> OrElse<St, Fut, F> } impl<St, Fut, F> Stream for OrElse<St, Fut, F> - where St: TryStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture<Ok = St::Ok>, +where + St: TryStream, + F: FnMut(St::Error) -> Fut, + Fut: TryFuture<Ok = St::Ok>, { type Item = Result<St::Ok, Fut::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); Poll::Ready(loop { @@ -68,7 +67,7 @@ impl<St, Fut, F> Stream for OrElse<St, Fut, F> Some(Ok(item)) => break Some(Ok(item)), Some(Err(e)) => { this.future.set(Some((this.f)(e))); - }, + } None => break None, } } @@ -88,9 +87,10 @@ impl<St, Fut, F> Stream for OrElse<St, Fut, F> } impl<St, Fut, F> FusedStream for OrElse<St, Fut, F> - where St: TryStream + FusedStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture<Ok = St::Ok>, +where + St: TryStream + FusedStream, + F: FnMut(St::Error) -> Fut, + Fut: TryFuture<Ok = St::Ok>, { fn is_terminated(&self) -> bool { self.future.is_none() && self.stream.is_terminated() @@ -100,7 +100,8 @@ impl<St, Fut, F> FusedStream for OrElse<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for OrElse<S, Fut, F> - where S: Sink<Item>, +where + S: Sink<Item>, { type Error = S::Error; diff --git a/src/stream/try_stream/try_buffer_unordered.rs b/src/stream/try_stream/try_buffer_unordered.rs index 71c6fc7..9a899d4 100644 --- a/src/stream/try_stream/try_buffer_unordered.rs +++ b/src/stream/try_stream/try_buffer_unordered.rs @@ -1,12 +1,12 @@ -use crate::stream::{Fuse, FuturesUnordered, StreamExt, IntoStream}; use crate::future::{IntoFuture, TryFutureExt}; +use crate::stream::{Fuse, FuturesUnordered, IntoStream, StreamExt}; +use core::pin::Pin; use futures_core::future::TryFuture; use futures_core::stream::{Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::pin::Pin; pin_project! { /// Stream for the @@ -24,8 +24,9 @@ pin_project! { } impl<St> TryBufferUnordered<St> - where St: TryStream, - St::Ok: TryFuture, +where + St: TryStream, + St::Ok: TryFuture, { pub(super) fn new(stream: St, n: usize) -> Self { Self { @@ -39,15 +40,13 @@ impl<St> TryBufferUnordered<St> } impl<St> Stream for TryBufferUnordered<St> - where St: TryStream, - St::Ok: TryFuture<Error = St::Error>, +where + St: TryStream, + St::Ok: TryFuture<Error = St::Error>, { type Item = Result<<St::Ok as TryFuture>::Ok, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); // First up, try to spawn off as many futures as possible by filling up @@ -77,8 +76,9 @@ impl<St> Stream for TryBufferUnordered<St> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Item, E> Sink<Item> for TryBufferUnordered<S> - where S: TryStream + Sink<Item, Error = E>, - S::Ok: TryFuture<Error = E>, +where + S: TryStream + Sink<Item, Error = E>, + S::Ok: TryFuture<Error = E>, { type Error = E; diff --git a/src/stream/try_stream/try_buffered.rs b/src/stream/try_stream/try_buffered.rs index ff7e844..45bd3f8 100644 --- a/src/stream/try_stream/try_buffered.rs +++ b/src/stream/try_stream/try_buffered.rs @@ -1,12 +1,12 @@ -use crate::stream::{Fuse, FuturesOrdered, StreamExt, IntoStream}; use crate::future::{IntoFuture, TryFutureExt}; +use crate::stream::{Fuse, FuturesOrdered, IntoStream, StreamExt}; +use core::pin::Pin; use futures_core::future::TryFuture; use futures_core::stream::{Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; use pin_project_lite::pin_project; -use core::pin::Pin; pin_project! { /// Stream for the [`try_buffered`](super::TryStreamExt::try_buffered) method. @@ -47,10 +47,7 @@ where { type Item = Result<<St::Ok as TryFuture>::Ok, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); // First up, try to spawn off as many futures as possible by filling up diff --git a/src/stream/try_stream/try_chunks.rs b/src/stream/try_stream/try_chunks.rs new file mode 100644 index 0000000..07d4425 --- /dev/null +++ b/src/stream/try_stream/try_chunks.rs @@ -0,0 +1,131 @@ +use crate::stream::{Fuse, IntoStream, StreamExt}; + +use alloc::vec::Vec; +use core::pin::Pin; +use core::{fmt, mem}; +use futures_core::ready; +use futures_core::stream::{FusedStream, Stream, TryStream}; +use futures_core::task::{Context, Poll}; +#[cfg(feature = "sink")] +use futures_sink::Sink; +use pin_project_lite::pin_project; + +pin_project! { + /// Stream for the [`try_chunks`](super::TryStreamExt::try_chunks) method. + #[derive(Debug)] + #[must_use = "streams do nothing unless polled"] + pub struct TryChunks<St: TryStream> { + #[pin] + stream: Fuse<IntoStream<St>>, + items: Vec<St::Ok>, + cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 + } +} + +impl<St: TryStream> TryChunks<St> { + pub(super) fn new(stream: St, capacity: usize) -> Self { + assert!(capacity > 0); + + Self { + stream: IntoStream::new(stream).fuse(), + items: Vec::with_capacity(capacity), + cap: capacity, + } + } + + fn take(self: Pin<&mut Self>) -> Vec<St::Ok> { + let cap = self.cap; + mem::replace(self.project().items, Vec::with_capacity(cap)) + } + + delegate_access_inner!(stream, St, (. .)); +} + +impl<St: TryStream> Stream for TryChunks<St> { + #[allow(clippy::type_complexity)] + type Item = Result<Vec<St::Ok>, TryChunksError<St::Ok, St::Error>>; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + let mut this = self.as_mut().project(); + loop { + match ready!(this.stream.as_mut().try_poll_next(cx)) { + // Push the item into the buffer and check whether it is full. + // If so, replace our buffer with a new and empty one and return + // the full one. + Some(item) => match item { + Ok(item) => { + this.items.push(item); + if this.items.len() >= *this.cap { + return Poll::Ready(Some(Ok(self.take()))); + } + } + Err(e) => { + return Poll::Ready(Some(Err(TryChunksError(self.take(), e)))); + } + }, + + // Since the underlying stream ran out of values, return what we + // have buffered, if we have anything. + None => { + let last = if this.items.is_empty() { + None + } else { + let full_buf = mem::replace(this.items, Vec::new()); + Some(full_buf) + }; + + return Poll::Ready(last.map(Ok)); + } + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let chunk_len = if self.items.is_empty() { 0 } else { 1 }; + let (lower, upper) = self.stream.size_hint(); + let lower = lower.saturating_add(chunk_len); + let upper = match upper { + Some(x) => x.checked_add(chunk_len), + None => None, + }; + (lower, upper) + } +} + +impl<St: TryStream + FusedStream> FusedStream for TryChunks<St> { + fn is_terminated(&self) -> bool { + self.stream.is_terminated() && self.items.is_empty() + } +} + +// Forwarding impl of Sink from the underlying stream +#[cfg(feature = "sink")] +impl<S, Item> Sink<Item> for TryChunks<S> +where + S: TryStream + Sink<Item>, +{ + type Error = <S as Sink<Item>>::Error; + + delegate_sink!(stream, Item); +} + +/// Error indicating, that while chunk was collected inner stream produced an error. +/// +/// Contains all items that were collected before an error occurred, and the stream error itself. +#[derive(PartialEq, Eq)] +pub struct TryChunksError<T, E>(pub Vec<T>, pub E); + +impl<T, E: fmt::Debug> fmt::Debug for TryChunksError<T, E> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.1.fmt(f) + } +} + +impl<T, E: fmt::Display> fmt::Display for TryChunksError<T, E> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.1.fmt(f) + } +} + +#[cfg(feature = "std")] +impl<T, E: fmt::Debug + fmt::Display> std::error::Error for TryChunksError<T, E> {} diff --git a/src/stream/try_stream/try_collect.rs b/src/stream/try_stream/try_collect.rs index 387de97..5d3b3d7 100644 --- a/src/stream/try_stream/try_collect.rs +++ b/src/stream/try_stream/try_collect.rs @@ -19,10 +19,7 @@ pin_project! { impl<St: TryStream, C: Default> TryCollect<St, C> { pub(super) fn new(s: St) -> Self { - Self { - stream: s, - items: Default::default(), - } + Self { stream: s, items: Default::default() } } } @@ -43,10 +40,7 @@ where { type Output = Result<C, St::Error>; - fn poll( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let mut this = self.project(); Poll::Ready(Ok(loop { match ready!(this.stream.as_mut().try_poll_next(cx)?) { diff --git a/src/stream/try_stream/try_concat.rs b/src/stream/try_stream/try_concat.rs index 2451332..58fb6a5 100644 --- a/src/stream/try_stream/try_concat.rs +++ b/src/stream/try_stream/try_concat.rs @@ -22,10 +22,7 @@ where St::Ok: Extend<<St::Ok as IntoIterator>::Item> + IntoIterator + Default, { pub(super) fn new(stream: St) -> Self { - Self { - stream, - accum: None, - } + Self { stream, accum: None } } } diff --git a/src/stream/try_stream/try_filter.rs b/src/stream/try_stream/try_filter.rs index eacefd2..61e6105 100644 --- a/src/stream/try_stream/try_filter.rs +++ b/src/stream/try_stream/try_filter.rs @@ -2,7 +2,7 @@ use core::fmt; use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; -use futures_core::stream::{Stream, TryStream, FusedStream}; +use futures_core::stream::{FusedStream, Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -40,24 +40,21 @@ where } impl<St, Fut, F> TryFilter<St, Fut, F> - where St: TryStream +where + St: TryStream, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - } + Self { stream, f, pending_fut: None, pending_item: None } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> FusedStream for TryFilter<St, Fut, F> - where St: TryStream + FusedStream, - F: FnMut(&St::Ok) -> Fut, - Fut: Future<Output = bool>, +where + St: TryStream + FusedStream, + F: FnMut(&St::Ok) -> Fut, + Fut: Future<Output = bool>, { fn is_terminated(&self) -> bool { self.pending_fut.is_none() && self.stream.is_terminated() @@ -65,16 +62,14 @@ impl<St, Fut, F> FusedStream for TryFilter<St, Fut, F> } impl<St, Fut, F> Stream for TryFilter<St, Fut, F> - where St: TryStream, - Fut: Future<Output = bool>, - F: FnMut(&St::Ok) -> Fut, +where + St: TryStream, + Fut: Future<Output = bool>, + F: FnMut(&St::Ok) -> Fut, { type Item = Result<St::Ok, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); Poll::Ready(loop { @@ -108,7 +103,8 @@ impl<St, Fut, F> Stream for TryFilter<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item, E> Sink<Item> for TryFilter<S, Fut, F> - where S: TryStream + Sink<Item, Error = E>, +where + S: TryStream + Sink<Item, Error = E>, { type Error = E; diff --git a/src/stream/try_stream/try_filter_map.rs b/src/stream/try_stream/try_filter_map.rs index 335649b..bb1b5b9 100644 --- a/src/stream/try_stream/try_filter_map.rs +++ b/src/stream/try_stream/try_filter_map.rs @@ -1,8 +1,8 @@ use core::fmt; use core::pin::Pin; -use futures_core::future::{TryFuture}; +use futures_core::future::TryFuture; use futures_core::ready; -use futures_core::stream::{Stream, TryStream, FusedStream}; +use futures_core::stream::{FusedStream, Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -43,9 +43,10 @@ impl<St, Fut, F> TryFilterMap<St, Fut, F> { } impl<St, Fut, F, T> FusedStream for TryFilterMap<St, Fut, F> - where St: TryStream + FusedStream, - Fut: TryFuture<Ok = Option<T>, Error = St::Error>, - F: FnMut(St::Ok) -> Fut, +where + St: TryStream + FusedStream, + Fut: TryFuture<Ok = Option<T>, Error = St::Error>, + F: FnMut(St::Ok) -> Fut, { fn is_terminated(&self) -> bool { self.pending.is_none() && self.stream.is_terminated() @@ -53,16 +54,14 @@ impl<St, Fut, F, T> FusedStream for TryFilterMap<St, Fut, F> } impl<St, Fut, F, T> Stream for TryFilterMap<St, Fut, F> - where St: TryStream, - Fut: TryFuture<Ok = Option<T>, Error = St::Error>, - F: FnMut(St::Ok) -> Fut, +where + St: TryStream, + Fut: TryFuture<Ok = Option<T>, Error = St::Error>, + F: FnMut(St::Ok) -> Fut, { type Item = Result<T, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); Poll::Ready(loop { @@ -98,7 +97,8 @@ impl<St, Fut, F, T> Stream for TryFilterMap<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item> Sink<Item> for TryFilterMap<S, Fut, F> - where S: Sink<Item>, +where + S: Sink<Item>, { type Error = S::Error; diff --git a/src/stream/try_stream/try_fold.rs b/src/stream/try_stream/try_fold.rs index 1d41e4b..d344d96 100644 --- a/src/stream/try_stream/try_fold.rs +++ b/src/stream/try_stream/try_fold.rs @@ -35,24 +35,21 @@ where } impl<St, Fut, T, F> TryFold<St, Fut, T, F> -where St: TryStream, - F: FnMut(T, St::Ok) -> Fut, - Fut: TryFuture<Ok = T, Error = St::Error>, +where + St: TryStream, + F: FnMut(T, St::Ok) -> Fut, + Fut: TryFuture<Ok = T, Error = St::Error>, { pub(super) fn new(stream: St, f: F, t: T) -> Self { - Self { - stream, - f, - accum: Some(t), - future: None, - } + Self { stream, f, accum: Some(t), future: None } } } impl<St, Fut, T, F> FusedFuture for TryFold<St, Fut, T, F> - where St: TryStream, - F: FnMut(T, St::Ok) -> Fut, - Fut: TryFuture<Ok = T, Error = St::Error>, +where + St: TryStream, + F: FnMut(T, St::Ok) -> Fut, + Fut: TryFuture<Ok = T, Error = St::Error>, { fn is_terminated(&self) -> bool { self.accum.is_none() && self.future.is_none() @@ -60,9 +57,10 @@ impl<St, Fut, T, F> FusedFuture for TryFold<St, Fut, T, F> } impl<St, Fut, T, F> Future for TryFold<St, Fut, T, F> - where St: TryStream, - F: FnMut(T, St::Ok) -> Fut, - Fut: TryFuture<Ok = T, Error = St::Error>, +where + St: TryStream, + F: FnMut(T, St::Ok) -> Fut, + Fut: TryFuture<Ok = T, Error = St::Error>, { type Output = Result<T, St::Error>; diff --git a/src/stream/try_stream/try_for_each.rs b/src/stream/try_stream/try_for_each.rs index 0a814ae..6a081d8 100644 --- a/src/stream/try_stream/try_for_each.rs +++ b/src/stream/try_stream/try_for_each.rs @@ -32,23 +32,21 @@ where } impl<St, Fut, F> TryForEach<St, Fut, F> -where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture<Ok = (), Error = St::Error>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: TryFuture<Ok = (), Error = St::Error>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - future: None, - } + Self { stream, f, future: None } } } impl<St, Fut, F> Future for TryForEach<St, Fut, F> - where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture<Ok = (), Error = St::Error>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: TryFuture<Ok = (), Error = St::Error>, { type Output = Result<(), St::Error>; diff --git a/src/stream/try_stream/try_for_each_concurrent.rs b/src/stream/try_stream/try_for_each_concurrent.rs index d2f4b0f..62734c7 100644 --- a/src/stream/try_stream/try_for_each_concurrent.rs +++ b/src/stream/try_stream/try_for_each_concurrent.rs @@ -1,8 +1,8 @@ use crate::stream::{FuturesUnordered, StreamExt}; use core::fmt; use core::mem; -use core::pin::Pin; use core::num::NonZeroUsize; +use core::pin::Pin; use futures_core::future::{FusedFuture, Future}; use futures_core::stream::TryStream; use futures_core::task::{Context, Poll}; @@ -37,9 +37,10 @@ where } impl<St, Fut, F> FusedFuture for TryForEachConcurrent<St, Fut, F> - where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future<Output = Result<(), St::Error>>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: Future<Output = Result<(), St::Error>>, { fn is_terminated(&self) -> bool { self.stream.is_none() && self.futures.is_empty() @@ -47,9 +48,10 @@ impl<St, Fut, F> FusedFuture for TryForEachConcurrent<St, Fut, F> } impl<St, Fut, F> TryForEachConcurrent<St, Fut, F> -where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future<Output = Result<(), St::Error>>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: Future<Output = Result<(), St::Error>>, { pub(super) fn new(stream: St, limit: Option<usize>, f: F) -> Self { Self { @@ -63,9 +65,10 @@ where St: TryStream, } impl<St, Fut, F> Future for TryForEachConcurrent<St, Fut, F> - where St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future<Output = Result<(), St::Error>>, +where + St: TryStream, + F: FnMut(St::Ok) -> Fut, + Fut: Future<Output = Result<(), St::Error>>, { type Output = Result<(), St::Error>; @@ -85,7 +88,7 @@ impl<St, Fut, F> Future for TryForEachConcurrent<St, Fut, F> Poll::Ready(Some(Ok(elem))) => { made_progress_this_iter = true; Some(elem) - }, + } Poll::Ready(None) => { this.stream.set(None); None @@ -109,9 +112,9 @@ impl<St, Fut, F> Future for TryForEachConcurrent<St, Fut, F> Poll::Ready(Some(Ok(()))) => made_progress_this_iter = true, Poll::Ready(None) => { if this.stream.is_none() { - return Poll::Ready(Ok(())) + return Poll::Ready(Ok(())); } - }, + } Poll::Pending => {} Poll::Ready(Some(Err(e))) => { // Empty the stream and futures so that we know diff --git a/src/stream/try_stream/try_next.rs b/src/stream/try_stream/try_next.rs index 1bc00fb..13fcf80 100644 --- a/src/stream/try_stream/try_next.rs +++ b/src/stream/try_stream/try_next.rs @@ -28,10 +28,7 @@ impl<St: ?Sized + TryStream + Unpin + FusedStream> FusedFuture for TryNext<'_, S impl<St: ?Sized + TryStream + Unpin> Future for TryNext<'_, St> { type Output = Result<Option<St::Ok>, St::Error>; - fn poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Self::Output> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { self.stream.try_poll_next_unpin(cx)?.map(Ok) } } diff --git a/src/stream/try_stream/try_skip_while.rs b/src/stream/try_stream/try_skip_while.rs index 0603b10..a424b6c 100644 --- a/src/stream/try_stream/try_skip_while.rs +++ b/src/stream/try_stream/try_skip_while.rs @@ -2,7 +2,7 @@ use core::fmt; use core::pin::Pin; use futures_core::future::TryFuture; use futures_core::ready; -use futures_core::stream::{Stream, TryStream, FusedStream}; +use futures_core::stream::{FusedStream, Stream, TryStream}; use futures_core::task::{Context, Poll}; #[cfg(feature = "sink")] use futures_sink::Sink; @@ -40,34 +40,27 @@ where } impl<St, Fut, F> TrySkipWhile<St, Fut, F> - where St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture<Ok = bool, Error = St::Error>, +where + St: TryStream, + F: FnMut(&St::Ok) -> Fut, + Fut: TryFuture<Ok = bool, Error = St::Error>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - done_skipping: false, - } + Self { stream, f, pending_fut: None, pending_item: None, done_skipping: false } } delegate_access_inner!(stream, St, ()); } impl<St, Fut, F> Stream for TrySkipWhile<St, Fut, F> - where St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture<Ok = bool, Error = St::Error>, +where + St: TryStream, + F: FnMut(&St::Ok) -> Fut, + Fut: TryFuture<Ok = bool, Error = St::Error>, { type Item = Result<St::Ok, St::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); if *this.done_skipping { @@ -105,9 +98,10 @@ impl<St, Fut, F> Stream for TrySkipWhile<St, Fut, F> } impl<St, Fut, F> FusedStream for TrySkipWhile<St, Fut, F> - where St: TryStream + FusedStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture<Ok = bool, Error = St::Error>, +where + St: TryStream + FusedStream, + F: FnMut(&St::Ok) -> Fut, + Fut: TryFuture<Ok = bool, Error = St::Error>, { fn is_terminated(&self) -> bool { self.pending_item.is_none() && self.stream.is_terminated() @@ -117,7 +111,8 @@ impl<St, Fut, F> FusedStream for TrySkipWhile<St, Fut, F> // Forwarding impl of Sink from the underlying stream #[cfg(feature = "sink")] impl<S, Fut, F, Item, E> Sink<Item> for TrySkipWhile<S, Fut, F> - where S: TryStream + Sink<Item, Error = E>, +where + S: TryStream + Sink<Item, Error = E>, { type Error = E; diff --git a/src/stream/try_stream/try_take_while.rs b/src/stream/try_stream/try_take_while.rs index 6241572..3375960 100644 --- a/src/stream/try_stream/try_take_while.rs +++ b/src/stream/try_stream/try_take_while.rs @@ -49,13 +49,7 @@ where Fut: TryFuture<Ok = bool, Error = St::Error>, { pub(super) fn new(stream: St, f: F) -> Self { - Self { - stream, - f, - pending_fut: None, - pending_item: None, - done_taking: false, - } + Self { stream, f, pending_fut: None, pending_item: None, done_taking: false } } delegate_access_inner!(stream, St, ()); diff --git a/src/stream/try_stream/try_unfold.rs b/src/stream/try_stream/try_unfold.rs index 258c18e..fd9cdf1 100644 --- a/src/stream/try_stream/try_unfold.rs +++ b/src/stream/try_stream/try_unfold.rs @@ -61,11 +61,7 @@ where F: FnMut(T) -> Fut, Fut: TryFuture<Ok = Option<(Item, T)>>, { - assert_stream::<Result<Item, Fut::Error>, _>(TryUnfold { - f, - state: Some(init), - fut: None, - }) + assert_stream::<Result<Item, Fut::Error>, _>(TryUnfold { f, state: Some(init), fut: None }) } pin_project! { @@ -85,10 +81,7 @@ where Fut: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryUnfold") - .field("state", &self.state) - .field("fut", &self.fut) - .finish() + f.debug_struct("TryUnfold").field("state", &self.state).field("fut", &self.fut).finish() } } @@ -99,10 +92,7 @@ where { type Item = Result<Item, Fut::Error>; - fn poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<Option<Self::Item>> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { let mut this = self.project(); if let Some(state) = this.state.take() { diff --git a/src/stream/unfold.rs b/src/stream/unfold.rs index e17d465..7d8ef6b 100644 --- a/src/stream/unfold.rs +++ b/src/stream/unfold.rs @@ -52,10 +52,7 @@ where F: FnMut(T) -> Fut, Fut: Future<Output = Option<(Item, T)>>, { - assert_stream::<Item, _>(Unfold { - f, - state: UnfoldState::Value { value: init }, - }) + assert_stream::<Item, _>(Unfold { f, state: UnfoldState::Value { value: init } }) } pin_project! { @@ -74,9 +71,7 @@ where Fut: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Unfold") - .field("state", &self.state) - .finish() + f.debug_struct("Unfold").field("state", &self.state).finish() } } @@ -105,9 +100,7 @@ where let mut this = self.project(); if let Some(state) = this.state.as_mut().take_value() { - this.state.set(UnfoldState::Future { - future: (this.f)(state), - }); + this.state.set(UnfoldState::Future { future: (this.f)(state) }); } let step = match this.state.as_mut().project_future() { diff --git a/src/task/mod.rs b/src/task/mod.rs index dd1515c..0a31eea 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -11,29 +11,27 @@ //! executors or dealing with synchronization issues around task wakeup. #[doc(no_inline)] -pub use core::task::{Context, Poll, Waker, RawWaker, RawWakerVTable}; +pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; -pub use futures_task::{ - Spawn, LocalSpawn, SpawnError, - FutureObj, LocalFutureObj, UnsafeFutureObj, -}; +pub use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError, UnsafeFutureObj}; pub use futures_task::noop_waker; -#[cfg(feature = "std")] pub use futures_task::noop_waker_ref; -cfg_target_has_atomic! { - #[cfg(feature = "alloc")] - pub use futures_task::ArcWake; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use futures_task::ArcWake; - #[cfg(feature = "alloc")] - pub use futures_task::waker; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use futures_task::waker; - #[cfg(feature = "alloc")] - pub use futures_task::{waker_ref, WakerRef}; +#[cfg(not(futures_no_atomic_cas))] +#[cfg(feature = "alloc")] +pub use futures_task::{waker_ref, WakerRef}; - pub use futures_core::task::__internal::AtomicWaker; -} +#[cfg(not(futures_no_atomic_cas))] +pub use futures_core::task::__internal::AtomicWaker; mod spawn; -pub use self::spawn::{SpawnExt, LocalSpawnExt}; +pub use self::spawn::{LocalSpawnExt, SpawnExt}; diff --git a/src/task/spawn.rs b/src/task/spawn.rs index f877923..87ca360 100644 --- a/src/task/spawn.rs +++ b/src/task/spawn.rs @@ -34,6 +34,7 @@ pub trait SpawnExt: Spawn { /// today. Feel free to use this method in the meantime. /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038 /// use futures::executor::ThreadPool; /// use futures::task::SpawnExt; /// @@ -58,6 +59,7 @@ pub trait SpawnExt: Spawn { /// resolves to the output of the spawned future. /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038 /// use futures::executor::{block_on, ThreadPool}; /// use futures::future; /// use futures::task::SpawnExt; @@ -136,6 +138,7 @@ pub trait LocalSpawnExt: LocalSpawn { /// resolves to the output of the spawned future. /// /// ``` + /// # if cfg!(miri) { return; } // https://github.com/rust-lang/miri/issues/1038 /// use futures::executor::LocalPool; /// use futures::task::LocalSpawnExt; /// |