aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:03:04 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:03:04 +0000
commite7e72cafadcee9bcdcf04850409ea0b0fc7d8e93 (patch)
tree7b826874213015b98b9e0383a89c88be66b64b11
parent5a2ead4f79e3b4c604edd450714bd1d925de1d4e (diff)
parente177aca7d9e335e8989e592627752459e00df418 (diff)
downloadfutures-util-android13-mainline-sdkext-release.tar.gz
Change-Id: Icbb1ad497834173b19d13f58a3e0ccd66bfe492b
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp102
-rw-r--r--Cargo.toml99
-rw-r--r--Cargo.toml.orig27
-rw-r--r--METADATA8
-rw-r--r--README.md23
-rw-r--r--TEST_MAPPING48
-rw-r--r--benches/flatten_unordered.rs66
-rw-r--r--benches/futures_unordered.rs4
-rw-r--r--benches_disabled/bilock.rs208
-rw-r--r--build.rs41
-rw-r--r--cargo2android.json5
-rw-r--r--no_atomic_cas.rs13
-rw-r--r--src/abortable.rs185
-rw-r--r--src/async_await/join_mod.rs6
-rw-r--r--src/async_await/mod.rs11
-rw-r--r--src/async_await/pending.rs2
-rw-r--r--src/async_await/poll.rs2
-rw-r--r--src/async_await/select_mod.rs9
-rw-r--r--src/async_await/stream_select_mod.rs40
-rw-r--r--src/compat/compat01as03.rs92
-rw-r--r--src/compat/compat03as01.rs68
-rw-r--r--src/compat/executor.rs5
-rw-r--r--src/compat/mod.rs8
-rw-r--r--src/fns.rs61
-rw-r--r--src/future/abortable.rs170
-rw-r--r--src/future/either.rs31
-rw-r--r--src/future/future/catch_unwind.rs10
-rw-r--r--src/future/future/flatten.rs47
-rw-r--r--src/future/future/fuse.rs4
-rw-r--r--src/future/future/remote_handle.rs14
-rw-r--r--src/future/future/shared.rs35
-rw-r--r--src/future/join.rs11
-rw-r--r--src/future/join_all.rs109
-rw-r--r--src/future/lazy.rs15
-rw-r--r--src/future/mod.rs24
-rw-r--r--src/future/option.rs13
-rw-r--r--src/future/pending.rs7
-rw-r--r--src/future/poll_fn.rs5
-rw-r--r--src/future/poll_immediate.rs126
-rw-r--r--src/future/select.rs18
-rw-r--r--src/future/select_all.rs26
-rw-r--r--src/future/select_ok.rs29
-rw-r--r--src/future/try_future/into_future.rs9
-rw-r--r--src/future/try_future/try_flatten.rs77
-rw-r--r--src/future/try_future/try_flatten_err.rs24
-rw-r--r--src/future/try_join_all.rs31
-rw-r--r--src/future/try_maybe_done.rs18
-rw-r--r--src/future/try_select.rs25
-rw-r--r--src/io/allow_std.rs101
-rw-r--r--src/io/buf_reader.rs94
-rw-r--r--src/io/buf_writer.rs73
-rw-r--r--src/io/chain.rs18
-rw-r--r--src/io/copy.rs8
-rw-r--r--src/io/copy_buf.rs15
-rw-r--r--src/io/cursor.rs22
-rw-r--r--src/io/empty.rs8
-rw-r--r--src/io/fill_buf.rs5
-rw-r--r--src/io/flush.rs3
-rw-r--r--src/io/into_sink.rs31
-rw-r--r--src/io/line_writer.rs155
-rw-r--r--src/io/lines.rs13
-rw-r--r--src/io/mod.rs118
-rw-r--r--src/io/read_exact.rs4
-rw-r--r--src/io/read_line.rs11
-rw-r--r--src/io/read_to_end.rs11
-rw-r--r--src/io/read_to_string.rs14
-rw-r--r--src/io/repeat.rs8
-rw-r--r--src/io/split.rs53
-rw-r--r--src/io/take.rs34
-rw-r--r--src/io/window.rs5
-rw-r--r--src/io/write_all_vectored.rs29
-rw-r--r--src/lib.rs57
-rw-r--r--src/lock/bilock.rs29
-rw-r--r--src/lock/mod.rs35
-rw-r--r--src/lock/mutex.rs32
-rw-r--r--src/sink/buffer.rs49
-rw-r--r--src/sink/close.rs10
-rw-r--r--src/sink/drain.rs20
-rw-r--r--src/sink/err_into.rs28
-rw-r--r--src/sink/fanout.rs50
-rw-r--r--src/sink/feed.rs10
-rw-r--r--src/sink/flush.rs10
-rw-r--r--src/sink/map_err.rs29
-rw-r--r--src/sink/mod.rs3
-rw-r--r--src/sink/send.rs9
-rw-r--r--src/sink/send_all.rs35
-rw-r--r--src/sink/unfold.rs5
-rw-r--r--src/sink/with.rs75
-rw-r--r--src/sink/with_flat_map.rs35
-rw-r--r--src/stream/abortable.rs19
-rw-r--r--src/stream/empty.rs6
-rw-r--r--src/stream/futures_ordered.rs10
-rw-r--r--src/stream/futures_unordered/iter.rs85
-rw-r--r--src/stream/futures_unordered/mod.rs192
-rw-r--r--src/stream/futures_unordered/ready_to_run_queue.rs43
-rw-r--r--src/stream/futures_unordered/task.rs19
-rw-r--r--src/stream/iter.rs10
-rw-r--r--src/stream/mod.rs68
-rw-r--r--src/stream/once.rs2
-rw-r--r--src/stream/poll_immediate.rs80
-rw-r--r--src/stream/repeat.rs11
-rw-r--r--src/stream/repeat_with.rs5
-rw-r--r--src/stream/select.rs99
-rw-r--r--src/stream/select_all.rs159
-rw-r--r--src/stream/select_with_strategy.rs229
-rw-r--r--src/stream/stream/all.rs92
-rw-r--r--src/stream/stream/any.rs92
-rw-r--r--src/stream/stream/buffer_unordered.rs11
-rw-r--r--src/stream/stream/buffered.rs17
-rw-r--r--src/stream/stream/catch_unwind.rs15
-rw-r--r--src/stream/stream/chain.rs29
-rw-r--r--src/stream/stream/chunks.rs20
-rw-r--r--src/stream/stream/collect.rs15
-rw-r--r--src/stream/stream/concat.rs35
-rw-r--r--src/stream/stream/count.rs53
-rw-r--r--src/stream/stream/cycle.rs5
-rw-r--r--src/stream/stream/enumerate.rs10
-rw-r--r--src/stream/stream/filter.rs42
-rw-r--r--src/stream/stream/filter_map.rs35
-rw-r--r--src/stream/stream/flatten_unordered.rs509
-rw-r--r--src/stream/stream/fold.rs28
-rw-r--r--src/stream/stream/for_each.rs27
-rw-r--r--src/stream/stream/for_each_concurrent.rs29
-rw-r--r--src/stream/stream/forward.rs15
-rw-r--r--src/stream/stream/fuse.rs5
-rw-r--r--src/stream/stream/into_future.rs5
-rw-r--r--src/stream/stream/map.rs24
-rw-r--r--src/stream/stream/mod.rs285
-rw-r--r--src/stream/stream/next.rs5
-rw-r--r--src/stream/stream/peek.rs311
-rw-r--r--src/stream/stream/ready_chunks.rs23
-rw-r--r--src/stream/stream/scan.rs15
-rw-r--r--src/stream/stream/select_next_some.rs4
-rw-r--r--src/stream/stream/skip.rs17
-rw-r--r--src/stream/stream/skip_while.rs41
-rw-r--r--src/stream/stream/split.rs31
-rw-r--r--src/stream/stream/take.rs23
-rw-r--r--src/stream/stream/take_until.rs12
-rw-r--r--src/stream/stream/take_while.rs39
-rw-r--r--src/stream/stream/then.rs38
-rw-r--r--src/stream/stream/unzip.rs27
-rw-r--r--src/stream/stream/zip.rs24
-rw-r--r--src/stream/try_stream/and_then.rs31
-rw-r--r--src/stream/try_stream/into_async_read.rs81
-rw-r--r--src/stream/try_stream/into_stream.rs5
-rw-r--r--src/stream/try_stream/mod.rs123
-rw-r--r--src/stream/try_stream/or_else.rs33
-rw-r--r--src/stream/try_stream/try_buffer_unordered.rs24
-rw-r--r--src/stream/try_stream/try_buffered.rs9
-rw-r--r--src/stream/try_stream/try_chunks.rs131
-rw-r--r--src/stream/try_stream/try_collect.rs10
-rw-r--r--src/stream/try_stream/try_concat.rs5
-rw-r--r--src/stream/try_stream/try_filter.rs34
-rw-r--r--src/stream/try_stream/try_filter_map.rs26
-rw-r--r--src/stream/try_stream/try_fold.rs28
-rw-r--r--src/stream/try_stream/try_for_each.rs20
-rw-r--r--src/stream/try_stream/try_for_each_concurrent.rs29
-rw-r--r--src/stream/try_stream/try_next.rs5
-rw-r--r--src/stream/try_stream/try_skip_while.rs39
-rw-r--r--src/stream/try_stream/try_take_while.rs8
-rw-r--r--src/stream/try_stream/try_unfold.rs16
-rw-r--r--src/stream/unfold.rs13
-rw-r--r--src/task/mod.rs30
-rw-r--r--src/task/spawn.rs3
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
diff --git a/Android.bp b/Android.bp
index 5f4d572..9d3dea9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index 9b87df6..a148319 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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" }
diff --git a/METADATA b/METADATA
index 36be8c4..ed41eb9 100644
--- a/METADATA
+++ b/METADATA
@@ -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;
diff --git a/src/fns.rs b/src/fns.rs
index cb62391..37ee03e 100644
--- a/src/fns.rs
+++ b/src/fns.rs
@@ -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]);
diff --git a/src/lib.rs b/src/lib.rs
index 44823cc..9a10c93 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
///