From 15c2472c239936070ebf27047c8d1ff4991b9df5 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 8 Oct 2024 02:32:42 +0900 Subject: [PATCH 01/33] Update changelog and clarify about yanking --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 992a457a1c..a14e0bb9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +Releases may yanked if there is a security bug, a soundness bug, or a regression. + + + # 0.3.31 - 2024-10-05 * Fix use after free of task in `FuturesUnordered` when dropped future panics (#2886) @@ -13,6 +23,8 @@ # 0.3.30 - 2023-12-24 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `{BiLock,SplitStream,SplitSink,ReadHalf,WriteHalf}::is_pair_of` (#2797) * Fix panic in `FuturesUnordered::clear` (#2809) * Fix panic in `AsyncBufReadExt::fill_buf` (#2801, #2812) @@ -21,6 +33,8 @@ # 0.3.29 - 2023-10-26 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `TryStreamExt::try_ready_chunks` (#2757) * Add `TryStreamExt::{try_all,try_any}` (#2783) * Add `UnboundedSender::{len,is_empty}` (#2750) @@ -30,11 +44,15 @@ # 0.3.28 - 2023-03-30 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Update to syn 2. This raises MSRV of utility crates to 1.56. (#2730, #2733) * Fix bug in `FlattenUnordered` (#2726, #2728) # 0.3.27 - 2023-03-11 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `TryFlattenUnordered` (#2577, #2590, #2606, #2607) * Add `AbortHandle::is_aborted` (#2710) * Add `AbortRegistration::handle` (#2712) @@ -42,6 +60,8 @@ # 0.3.26 - 2023-01-30 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `Either::as_pin_mut` and `Either::as_pin_ref` (#2691) * Add `Shared::ptr_eq` and `Shared::ptr_hash` (#2691) * Implement `FusedStream` for `Buffered` (#2676) @@ -52,19 +72,27 @@ # 0.3.25 - 2022-10-20 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fix soundness issue in `join!` and `try_join!` macros (#2649) * Implement `Clone` for `sink::Drain` (#2650) # 0.3.24 - 2022-08-29 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fix incorrect termination of `select_with_strategy` streams (#2635) # 0.3.23 - 2022-08-14 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Work around MSRV increase due to a cargo bug. # 0.3.22 - 2022-08-14 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fix `Sync` impl of `BiLockGuard` (#2570) * Fix partial iteration in `FuturesUnordered` (#2574) * Fix false detection of inner panics in `Shared` (#2576) @@ -82,11 +110,13 @@ # 0.3.21 - 2022-02-06 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fix potential data race in `FlattenUnordered` that introduced in 0.3.20 (#2566) # 0.3.20 - 2022-02-06 -NOTE: This release has been yanked due to a bug fixed in 0.3.21. +**Note:** This release has been yanked due to a bug fixed in 0.3.21. * Fix stacked borrows violations when `-Zmiri-tag-raw-pointers` is enabled. This raises MSRV of `futures-task` to 1.45. (#2548, #2550) * Change `FuturesUnordered` to respect yielding from future (#2551) @@ -94,6 +124,8 @@ NOTE: This release has been yanked due to a bug fixed in 0.3.21. # 0.3.19 - 2021-12-18 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Remove unstable `read-initializer` feature (#2534) * Fix panic in `FuturesUnordered` (#2535) * Fix compatibility issue with `FuturesUnordered` and tokio's cooperative scheduling (#2527) @@ -101,7 +133,7 @@ NOTE: This release has been yanked due to a bug fixed in 0.3.21. # 0.3.18 - 2021-11-23 -NOTE: This release has been yanked. See #2529 for details. +**Note:** This release has been yanked. See #2529 for details. * Fix unusable `Sink` implementation on `stream::Scan` (#2499) * Make `task::noop_waker_ref` available without `std` feature (#2505) @@ -110,6 +142,8 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.17 - 2021-08-30 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Use `FuturesOrdered` in `join_all` (#2412) * Add `{future, stream}::poll_immediate` (#2452) * Add `stream_select!` macro (#2262) @@ -119,6 +153,8 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.16 - 2021-07-23 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `TryStreamExt::try_chunks` (#2438) * Add `StreamExt::{all, any}` (#2460) * Add `stream::select_with_strategy` (#2450) @@ -126,6 +162,8 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.15 - 2021-05-11 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Use `#[proc_macro]` at Rust 1.45+ to fix an issue where proc macros don't work with rust-analyzer (#2407) * Support targets that do not have atomic CAS on stable Rust (#2400) * futures-test: Add async `#[test]` function attribute (#2409) @@ -141,6 +179,8 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.14 - 2021-04-10 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Add `future::SelectAll::into_inner` (#2363) * Allow calling `UnboundedReceiver::try_next` after `None` (#2369) * Reexport non-Ext traits from the root of `futures_util` (#2377) @@ -149,6 +189,8 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.13 - 2021-02-23 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Mitigated starvation issues in `FuturesUnordered` (#2333) * Fixed race with dropping `mpsc::Receiver` (#2304) * Added `Shared::{strong_count, weak_count}` (#2346) @@ -157,21 +199,25 @@ NOTE: This release has been yanked. See #2529 for details. # 0.3.12 - 2021-01-15 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fixed `Unpin` impl of `future::{MaybeDone, TryMaybeDone}` where trait bounds were accidentally added in 0.3.9. (#2317) # 0.3.11 - 2021-01-14 +**Note:** This release of futures-util has been yanked due to a bug fixed in 0.3.31 and a compile failure with futures-task 0.3.31 and later. + * Fixed heap buffer overflow in `AsyncReadExt::{read_to_end, read_to_string}` (#2314) # 0.3.10 - 2021-01-13 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fixed type-inference in `sink::unfold` by specifying more of its types (breaking change -- see #2311) # 0.3.9 - 2021-01-08 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Significantly improved compile time when `async-await` crate feature is disabled (#2273) * Added `stream::repeat_with` (#2279) @@ -184,7 +230,7 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.8 - 2020-11-04 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Switched proc-macros to use native `#[proc_macro]` at Rust 1.45+ (#2243) * Added `WeakShared` (#2169) @@ -195,7 +241,7 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.7 - 2020-10-23 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fixed unsoundness in `MappedMutexGuard` (#2240) * Re-exported `TakeUntil` (#2235) @@ -203,7 +249,7 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.6 - 2020-10-06 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fixed UB due to missing 'static on `task::waker` (#2206) * Added `AsyncBufReadExt::fill_buf` (#2225) @@ -219,7 +265,7 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.5 - 2020-05-08 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Added `StreamExt::flat_map`. * Added `StreamExt::ready_chunks`. @@ -239,19 +285,19 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.4 - 2020-02-06 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fixed missing `Drop` for `UnboundedReceiver` (#2064) # 0.3.3 - 2020-02-04 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fixed compatibility issue with pinned facade (#2062) # 0.3.2 - 2020-02-03 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Improved buffering performance of `SplitSink` (#1969) * Added `select_biased!` macro (#1976) @@ -272,13 +318,13 @@ NOTE: This release has been yanked. See #2310 for details. # 0.3.1 - 2019-11-07 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Fix signature of `SpawnExt` and `LocalSpawnExt` trait (breaking change -- see #1959) # 0.3.0 - 2019-11-05 -NOTE: This release has been yanked. See #2310 for details. +**Note:** This release has been yanked. See #2310 for details. * Stable release along with stable async/await! * Added async/await to default features (#1953) From 9d442fe19f0f327277619f12ce5fbbe800402cff Mon Sep 17 00:00:00 2001 From: "@brodycj - C. Jonathan Brody" Date: Sun, 12 Jan 2025 10:38:27 -0500 Subject: [PATCH 02/33] Bump MSRV of utility crates to 1.63 (#2907) --- .github/workflows/ci.yml | 2 +- README.md | 2 +- futures-channel/Cargo.toml | 2 +- futures-channel/README.md | 2 +- futures-executor/Cargo.toml | 2 +- futures-executor/README.md | 2 +- futures-macro/Cargo.toml | 2 +- futures-task/Cargo.toml | 2 +- futures-task/README.md | 2 +- futures-test/Cargo.toml | 2 +- futures-test/README.md | 2 +- futures-util/Cargo.toml | 2 +- futures-util/README.md | 2 +- futures/Cargo.toml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae34fc33a8..3f80dbf36e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: rust: # This is the minimum Rust version supported by futures, futures-util, futures-task, futures-macro, futures-executor, futures-channel, futures-test. # When updating this, the reminder to update the minimum required version in README.md and Cargo.toml. - - '1.56' + - '1.63' runs-on: ubuntu-latest timeout-minutes: 60 steps: diff --git a/README.md b/README.md index 355d6078e3..1ddedca895 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Add this to your `Cargo.toml`: futures = "0.3" ``` -The current `futures` requires Rust 1.56 or later. +The current `futures` requires Rust 1.63 or later. ### Feature `std` diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml index 4d430b78d7..eab7a0bd2d 100644 --- a/futures-channel/Cargo.toml +++ b/futures-channel/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-channel" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-channel/README.md b/futures-channel/README.md index e886bd1cad..e465482ac8 100644 --- a/futures-channel/README.md +++ b/futures-channel/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-channel = "0.3" ``` -The current `futures-channel` requires Rust 1.56 or later. +The current `futures-channel` requires Rust 1.63 or later. ## License diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index 978f8ae018..9bfd2dcb78 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-executor" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-executor/README.md b/futures-executor/README.md index 724ff5bb33..bc4a3fcb0f 100644 --- a/futures-executor/README.md +++ b/futures-executor/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-executor = "0.3" ``` -The current `futures-executor` requires Rust 1.56 or later. +The current `futures-executor` requires Rust 1.63 or later. ## License diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml index fdd7be3dd8..cc7aaf4a49 100644 --- a/futures-macro/Cargo.toml +++ b/futures-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-macro" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml index f1848dacbd..130e438fa7 100644 --- a/futures-task/Cargo.toml +++ b/futures-task/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-task" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/README.md b/futures-task/README.md index 1ebec2d73d..6a8ca2dd4e 100644 --- a/futures-task/README.md +++ b/futures-task/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-task = "0.3" ``` -The current `futures-task` requires Rust 1.56 or later. +The current `futures-task` requires Rust 1.63 or later. ## License diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml index 46d933415f..ab307b3805 100644 --- a/futures-test/Cargo.toml +++ b/futures-test/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-test" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-test/README.md b/futures-test/README.md index 34595aaf30..078457d873 100644 --- a/futures-test/README.md +++ b/futures-test/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-test = "0.3" ``` -The current `futures-test` requires Rust 1.56 or later. +The current `futures-test` requires Rust 1.63 or later. ## License diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 825a204125..ebe67b8dcc 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-util" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-util/README.md b/futures-util/README.md index 60e2c2109a..fc1b6d6b0c 100644 --- a/futures-util/README.md +++ b/futures-util/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-util = "0.3" ``` -The current `futures-util` requires Rust 1.56 or later. +The current `futures-util` requires Rust 1.63 or later. ## License diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 102f9215cc..c8c65134db 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -2,7 +2,7 @@ name = "futures" version = "0.3.31" edition = "2018" -rust-version = "1.56" +rust-version = "1.63" license = "MIT OR Apache-2.0" readme = "../README.md" keywords = ["futures", "async", "future"] From 56aee25b131b4944cc6341c5f9645754481070c4 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 13 Jan 2025 01:02:59 +0900 Subject: [PATCH 03/33] Use const thread_local --- futures-executor/src/enter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-executor/src/enter.rs b/futures-executor/src/enter.rs index b0e43e0593..46e1bd147e 100644 --- a/futures-executor/src/enter.rs +++ b/futures-executor/src/enter.rs @@ -1,7 +1,7 @@ use std::cell::Cell; use std::fmt; -std::thread_local!(static ENTERED: Cell = Cell::new(false)); +std::thread_local!(static ENTERED: Cell = const { Cell::new(false) }); /// Represents an executor context. /// From eb6e831d2a0a1d11b029ca99fbb56459024c6123 Mon Sep 17 00:00:00 2001 From: Alison Davis <148170853+adavis628@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:51:00 -0600 Subject: [PATCH 04/33] Support shared futures on no_std (#2868) --- futures-util/Cargo.toml | 7 +++-- futures-util/src/future/future/mod.rs | 9 +++--- futures-util/src/future/future/shared.rs | 37 +++++++++++++++++++----- futures-util/src/future/mod.rs | 2 +- futures/Cargo.toml | 1 + 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index ebe67b8dcc..52dc49fe2d 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -12,8 +12,8 @@ Common utilities and extension traits for the futures-rs library. [features] default = ["std", "async-await", "async-await-macro"] -std = ["alloc", "futures-core/std", "futures-task/std", "slab"] -alloc = ["futures-core/alloc", "futures-task/alloc"] +std = ["alloc", "futures-core/std", "futures-task/std", "slab/std"] +alloc = ["futures-core/alloc", "futures-task/alloc", "slab"] async-await = [] async-await-macro = ["async-await", "futures-macro"] compat = ["std", "futures_01"] @@ -41,12 +41,13 @@ futures-channel = { path = "../futures-channel", version = "0.3.31", default-fea futures-io = { path = "../futures-io", version = "0.3.31", default-features = false, features = ["std"], optional = true } futures-sink = { path = "../futures-sink", version = "0.3.31", default-features = false, optional = true } futures-macro = { path = "../futures-macro", version = "=0.3.31", default-features = false, optional = true } -slab = { version = "0.4.2", optional = true } +slab = { version = "0.4.2", default-features = false, optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } tokio-io = { version = "0.1.9", optional = true } pin-utils = "0.1.0" pin-project-lite = "0.2.6" +spin = { version = "0.9.8", optional = true } [dev-dependencies] futures = { path = "../futures", features = ["async-await", "thread-pool"] } diff --git a/futures-util/src/future/future/mod.rs b/futures-util/src/future/future/mod.rs index 955af3776a..bcf2ec8156 100644 --- a/futures-util/src/future/future/mod.rs +++ b/futures-util/src/future/future/mod.rs @@ -110,10 +110,9 @@ mod remote_handle; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::remote_handle::{Remote, RemoteHandle}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] mod shared; -#[cfg(feature = "std")] -#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 +#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] pub use self::shared::{Shared, WeakShared}; impl FutureExt for T where T: Future {} @@ -444,7 +443,7 @@ pub trait FutureExt: Future { /// into a cloneable future. It enables a future to be polled by multiple /// threads. /// - /// This method is only available when the `std` feature of this + /// This method is only available when the `std` or 'spin' feature of this /// library is activated, and it is activated by default. /// /// # Examples @@ -478,7 +477,7 @@ pub trait FutureExt: Future { /// join_handle.join().unwrap(); /// # }); /// ``` - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] fn shared(self) -> Shared where Self: Sized, diff --git a/futures-util/src/future/future/shared.rs b/futures-util/src/future/future/shared.rs index 158fa70761..ed8fceab3e 100644 --- a/futures-util/src/future/future/shared.rs +++ b/futures-util/src/future/future/shared.rs @@ -1,15 +1,20 @@ use crate::task::{waker_ref, ArcWake}; +use alloc::sync::{Arc, Weak}; +use core::cell::UnsafeCell; +use core::fmt; +use core::hash::Hasher; +use core::pin::Pin; +use core::ptr; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering::{Acquire, SeqCst}; use futures_core::future::{FusedFuture, Future}; use futures_core::task::{Context, Poll, Waker}; use slab::Slab; -use std::cell::UnsafeCell; -use std::fmt; -use std::hash::Hasher; -use std::pin::Pin; -use std::ptr; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::{Acquire, SeqCst}; -use std::sync::{Arc, Mutex, Weak}; + +#[cfg(feature = "std")] +type Mutex = std::sync::Mutex; +#[cfg(not(feature = "std"))] +type Mutex = spin::Mutex; /// Future for the [`shared`](super::FutureExt::shared) method. #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -206,7 +211,10 @@ where { /// Registers the current task to receive a wakeup when we are awoken. fn record_waker(&self, waker_key: &mut usize, cx: &mut Context<'_>) { + #[cfg(feature = "std")] let mut wakers_guard = self.notifier.wakers.lock().unwrap(); + #[cfg(not(feature = "std"))] + let mut wakers_guard = self.notifier.wakers.lock(); let wakers = match wakers_guard.as_mut() { Some(wakers) => wakers, @@ -345,7 +353,11 @@ where inner.notifier.state.store(COMPLETE, SeqCst); // Wake all tasks and drop the slab + #[cfg(feature = "std")] let mut wakers_guard = inner.notifier.wakers.lock().unwrap(); + #[cfg(not(feature = "std"))] + let mut wakers_guard = inner.notifier.wakers.lock(); + let mut wakers = wakers_guard.take().unwrap(); for waker in wakers.drain().flatten() { waker.wake(); @@ -375,11 +387,16 @@ where fn drop(&mut self) { if self.waker_key != NULL_WAKER_KEY { if let Some(ref inner) = self.inner { + #[cfg(feature = "std")] if let Ok(mut wakers) = inner.notifier.wakers.lock() { if let Some(wakers) = wakers.as_mut() { wakers.remove(self.waker_key); } } + #[cfg(not(feature = "std"))] + if let Some(wakers) = inner.notifier.wakers.lock().as_mut() { + wakers.remove(self.waker_key); + } } } } @@ -387,7 +404,11 @@ where impl ArcWake for Notifier { fn wake_by_ref(arc_self: &Arc) { + #[cfg(feature = "std")] let wakers = &mut *arc_self.wakers.lock().unwrap(); + #[cfg(not(feature = "std"))] + let wakers = &mut *arc_self.wakers.lock(); + if let Some(wakers) = wakers.as_mut() { for (_key, opt_waker) in wakers { if let Some(waker) = opt_waker.take() { diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs index 873d2b2d10..6913c928c5 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/future/mod.rs @@ -35,7 +35,7 @@ pub use self::future::CatchUnwind; #[cfg(feature = "std")] pub use self::future::{Remote, RemoteHandle}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] pub use self::future::{Shared, WeakShared}; mod try_future; diff --git a/futures/Cargo.toml b/futures/Cargo.toml index c8c65134db..6511d8951d 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -40,6 +40,7 @@ compat = ["std", "futures-util/compat"] io-compat = ["compat", "futures-util/io-compat"] executor = ["std", "futures-executor/std"] thread-pool = ["executor", "futures-executor/thread-pool"] +spin = ["futures-util/spin"] # Unstable features # These features are outside of the normal semver guarantees and require the From fcdde2213167f7a4ab56e585eda997db84c97cac Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 18 Jan 2025 01:41:19 +0900 Subject: [PATCH 05/33] ci: Test AArch64 Linux on ubuntu-24.04-arm runner https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/ --- .github/workflows/ci.yml | 55 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f80dbf36e..a9dd6a8a51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,8 +38,7 @@ jobs: - os: ubuntu-latest - os: macos-latest - os: windows-latest - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu + - os: ubuntu-24.04-arm - os: ubuntu-latest target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest @@ -49,18 +48,19 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: + # https://github.com/orgs/community/discussions/148648#discussioncomment-11867019 + - name: Workaround for AArch64 Linux runner bug + run: for var in PATH XDG_CONFIG_HOME; do sed -Ee "s/^/${var}=/" -e 's/(runner)admin/\1/g' <<< "${!var}"; done | tee -a -- "${GITHUB_ENV}" + if: endsWith(matrix.os, '-arm') - uses: taiki-e/checkout-action@v1 - name: Install Rust - # --no-self-update is necessary because the windows environment cannot self-update rustup.exe. - run: rustup update nightly --no-self-update && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly - uses: taiki-e/setup-cross-toolchain-action@v1 with: target: ${{ matrix.target }} if: matrix.target != '' - run: cargo test --workspace --all-features $DOCTEST_XCOMPILE - run: cargo test --workspace --all-features --release $DOCTEST_XCOMPILE - # TODO: https://github.com/rust-lang/futures-rs/issues/2451 - if: matrix.target != 'aarch64-unknown-linux-gnu' core-msrv: name: cargo +${{ matrix.rust }} build (futures-{core, io, sink}) @@ -75,7 +75,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + uses: taiki-e/github-actions/install-rust@main + with: + toolchain: ${{ matrix.rust }} # cargo does not support for --features/--no-default-features with workspace, so use cargo-hack instead. # Refs: cargo#3620, cargo#4106, cargo#4463, cargo#4753, cargo#5015, cargo#5364, cargo#6195 - name: Install cargo-hack @@ -110,7 +112,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + uses: taiki-e/github-actions/install-rust@main + with: + toolchain: ${{ matrix.rust }} - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack # remove dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866 @@ -143,7 +147,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + uses: taiki-e/github-actions/install-rust@main + with: + toolchain: ${{ matrix.rust }} - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack - run: cargo hack build --workspace --no-dev-deps @@ -156,7 +162,7 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update nightly && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack - name: Install cargo-minimal-versions @@ -178,8 +184,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update nightly && rustup default nightly - - run: rustup target add ${{ matrix.target }} + uses: taiki-e/github-actions/install-rust@nightly + with: + target: ${{ matrix.target }} - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack # remove dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866 @@ -211,7 +218,7 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update nightly && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly - run: cargo bench --workspace - run: cargo bench --manifest-path futures-util/Cargo.toml --features=bilock,unstable @@ -222,7 +229,7 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update nightly && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack # Check each specified feature works properly @@ -245,7 +252,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup toolchain install nightly --component miri && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly + with: + component: miri - run: cargo miri test --workspace --all-features -- --skip panic_on_drop_fut env: MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation @@ -271,7 +280,9 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup toolchain install nightly --component rust-src && rustup default nightly + uses: taiki-e/github-actions/install-rust@nightly + with: + component: rust-src # https://github.com/google/sanitizers/issues/1716 / https://github.com/actions/runner-images/issues/9491 - run: sudo sysctl vm.mmap_rnd_bits=28 # Exclude futures-macro to work around upstream bug since nightly-2024-10-06. @@ -291,7 +302,9 @@ jobs: # steps: # - uses: taiki-e/checkout-action@v1 # - name: Install Rust - # run: rustup toolchain install nightly --component clippy && rustup default nightly + # uses: taiki-e/github-actions/install-rust@nightly + # with: + # component: clippy # - run: cargo clippy --workspace --all-features --all-targets fmt: @@ -301,7 +314,7 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update stable + uses: taiki-e/github-actions/install-rust@stable - run: cargo fmt --all -- --check docs: @@ -311,5 +324,7 @@ jobs: steps: - uses: taiki-e/checkout-action@v1 - name: Install Rust - run: rustup update nightly && rustup default nightly - - run: RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc --workspace --no-deps --all-features + uses: taiki-e/github-actions/install-rust@nightly + - run: cargo doc --workspace --no-deps --all-features + env: + RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} --cfg docsrs From 1f3aa12bc5e512d3fd6be902cfd20264eca8ef4c Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 18 Jan 2025 12:39:13 +0900 Subject: [PATCH 06/33] ci: Remove workaround for fixed AArch64 Linux runner bug --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9dd6a8a51..4ee433205d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,10 +48,6 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: - # https://github.com/orgs/community/discussions/148648#discussioncomment-11867019 - - name: Workaround for AArch64 Linux runner bug - run: for var in PATH XDG_CONFIG_HOME; do sed -Ee "s/^/${var}=/" -e 's/(runner)admin/\1/g' <<< "${!var}"; done | tee -a -- "${GITHUB_ENV}" - if: endsWith(matrix.os, '-arm') - uses: taiki-e/checkout-action@v1 - name: Install Rust uses: taiki-e/github-actions/install-rust@nightly From edddd4161f0e59d9ec1d7ee38522dd6806498150 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 18 Jan 2025 19:21:33 +0900 Subject: [PATCH 07/33] ci: Test armv7hf Linux on ubuntu-24.04-arm runner https://github.com/taiki-e/setup-cross-toolchain-action/releases/tag/v1.27.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ee433205d..15c344452f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: - os: macos-latest - os: windows-latest - os: ubuntu-24.04-arm - - os: ubuntu-latest + - os: ubuntu-24.04-arm target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest target: armv5te-unknown-linux-gnueabi From a0adbf5e3768a871bf04207604132e2f50705a77 Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 17 Feb 2025 23:50:27 +0800 Subject: [PATCH 08/33] chore: recommend to use core lib's ready macro (#2925) Signed-off-by: tison --- futures-core/src/task/poll.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/futures-core/src/task/poll.rs b/futures-core/src/task/poll.rs index 607e78e060..bde0f8a5fe 100644 --- a/futures-core/src/task/poll.rs +++ b/futures-core/src/task/poll.rs @@ -1,6 +1,9 @@ -/// Extracts the successful type of a `Poll`. +/// Extracts the successful type of `Poll`. /// /// This macro bakes in propagation of `Pending` signals by returning early. +/// +/// **Note:** Since Rust 1.64, this macro is soft-deprecated in favor of +/// [`ready!`](core::task::ready) macro in the standard library. #[macro_export] macro_rules! ready { ($e:expr $(,)?) => { From d7fe0e18cf51af0b771f478ec2516305377fb425 Mon Sep 17 00:00:00 2001 From: Tobias Bengtsson Date: Tue, 25 Feb 2025 17:54:56 +0100 Subject: [PATCH 09/33] Make assert in select_biased documentation clearer (#2926) --- futures-util/src/async_await/select_mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-util/src/async_await/select_mod.rs b/futures-util/src/async_await/select_mod.rs index 80c3c7504a..26528c07b3 100644 --- a/futures-util/src/async_await/select_mod.rs +++ b/futures-util/src/async_await/select_mod.rs @@ -231,7 +231,7 @@ macro_rules! document_select_macro { /// a_res = async_identity_fn(62).fuse() => a_res + 1, /// b_res = async_identity_fn(13).fuse() => b_res, /// }; - /// assert!(res == 63 || res == 12); + /// assert_eq!(res, 63); /// # }); /// ``` /// From 3b746ddecb9904d1448729cec3aa6c2e8a219713 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 26 Feb 2025 02:39:04 +0100 Subject: [PATCH 10/33] futures ordered: add `clear` fn (#2927) --- futures-util/src/stream/futures_ordered.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/futures-util/src/stream/futures_ordered.rs b/futures-util/src/stream/futures_ordered.rs index 2cc144e81d..460b352676 100644 --- a/futures-util/src/stream/futures_ordered.rs +++ b/futures-util/src/stream/futures_ordered.rs @@ -169,6 +169,17 @@ impl FuturesOrdered { self.next_outgoing_index -= 1; self.in_progress_queue.push(wrapped); } + + /// Clear the whole `FuturesOrdered` queue. + /// + /// This function clears the pending futures and the queued outputs + /// to make it fully empty. + pub fn clear(&mut self) { + self.in_progress_queue.clear(); + self.queued_outputs.clear(); + self.next_incoming_index = 0; + self.next_outgoing_index = 0; + } } impl Default for FuturesOrdered { From d1877ba8837f29597be01aaa47e07ad7ef778b6c Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 23 Mar 2025 21:17:51 +0800 Subject: [PATCH 11/33] chore: remove dependency to pin-utils (#2929) Signed-off-by: tison --- futures-util/Cargo.toml | 1 - futures-util/src/future/future/mod.rs | 2 +- futures-util/src/lib.rs | 4 ++-- futures-util/src/macros.rs | 31 +++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 futures-util/src/macros.rs diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 52dc49fe2d..4e2b10ba2a 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -45,7 +45,6 @@ slab = { version = "0.4.2", default-features = false, optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } tokio-io = { version = "0.1.9", optional = true } -pin-utils = "0.1.0" pin-project-lite = "0.2.6" spin = { version = "0.9.8", optional = true } diff --git a/futures-util/src/future/future/mod.rs b/futures-util/src/future/future/mod.rs index bcf2ec8156..815c9c751a 100644 --- a/futures-util/src/future/future/mod.rs +++ b/futures-util/src/future/future/mod.rs @@ -10,6 +10,7 @@ use core::pin::Pin; use crate::fns::{inspect_fn, into_fn, ok_fn, InspectFn, IntoFn, OkFn}; use crate::future::{assert_future, Either}; use crate::never::Never; +use crate::pin_mut; use crate::stream::assert_stream; #[cfg(feature = "alloc")] use futures_core::future::{BoxFuture, LocalBoxFuture}; @@ -18,7 +19,6 @@ use futures_core::{ stream::Stream, task::{Context, Poll}, }; -use pin_utils::pin_mut; // Combinators diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index 2201e4f2c9..1949e5a630 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -22,7 +22,6 @@ extern crate std; // Macro re-exports pub use futures_core::ready; -pub use pin_utils::pin_mut; #[cfg(feature = "async-await")] #[macro_use] @@ -32,7 +31,6 @@ mod async_await; pub use self::async_await::*; // Not public API. -#[cfg(feature = "async-await")] #[doc(hidden)] pub mod __private { pub use crate::*; @@ -42,6 +40,7 @@ pub mod __private { result::Result::{Err, Ok}, }; + #[cfg(feature = "async-await")] pub mod async_await { pub use crate::async_await::*; } @@ -329,4 +328,5 @@ pub mod lock; mod abortable; mod fns; +mod macros; mod unfold_state; diff --git a/futures-util/src/macros.rs b/futures-util/src/macros.rs new file mode 100644 index 0000000000..0f5cba99e3 --- /dev/null +++ b/futures-util/src/macros.rs @@ -0,0 +1,31 @@ +/// Pins a value on the stack. +/// +/// Can safely pin values that are not `Unpin` by taking ownership. +/// +/// **Note:** Since Rust 1.68, this macro is soft-deprecated in favor of +/// [`pin!`](https://doc.rust-lang.org/std/pin/macro.pin.html) macro +/// in the standard library. +/// +/// # Example +/// +/// ```rust +/// # use futures_util::pin_mut; +/// # use core::pin::Pin; +/// # struct Foo {} +/// let foo = Foo { /* ... */ }; +/// pin_mut!(foo); +/// let _: Pin<&mut Foo> = foo; +/// ``` +#[macro_export] +macro_rules! pin_mut { + ($($x:ident),* $(,)?) => { $( + // Move the value to ensure that it is owned + let mut $x = $x; + // Shadow the original binding so that it can't be directly accessed + // ever again. + #[allow(unused_mut)] + let mut $x = unsafe { + $crate::__private::Pin::new_unchecked(&mut $x) + }; + )* } +} From 05e912accd5167c70c706fd34bb163063c322cae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 03:56:06 +0000 Subject: [PATCH 12/33] Update spin requirement from 0.9.8 to 0.10.0 --- updated-dependencies: - dependency-name: spin dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- futures-util/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 4e2b10ba2a..65b6468472 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -46,7 +46,7 @@ memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } tokio-io = { version = "0.1.9", optional = true } pin-project-lite = "0.2.6" -spin = { version = "0.9.8", optional = true } +spin = { version = "0.10.0", optional = true } [dev-dependencies] futures = { path = "../futures", features = ["async-await", "thread-pool"] } From 50c8db4a7a67a024ada6609b2286de318303732c Mon Sep 17 00:00:00 2001 From: tison Date: Sat, 5 Apr 2025 15:25:39 +0800 Subject: [PATCH 13/33] chore: replace all doctest usage of pin_mut with pin (#2940) Signed-off-by: tison --- futures-test/src/assert.rs | 33 ++++++++++++---------- futures-test/src/future/mod.rs | 10 ++++--- futures-test/src/io/read/mod.rs | 15 ++++++---- futures-test/src/io/write/mod.rs | 10 ++++--- futures-test/src/stream/mod.rs | 5 ++-- futures-test/src/task/context.rs | 5 ++-- futures-util/src/async_await/select_mod.rs | 22 ++++++++------- futures-util/src/future/future/fuse.rs | 5 ++-- futures-util/src/future/maybe_done.rs | 5 ++-- futures-util/src/future/poll_immediate.rs | 15 ++++++---- futures-util/src/future/select.rs | 13 ++++----- futures-util/src/sink/unfold.rs | 7 +++-- futures-util/src/stream/stream/peek.rs | 32 +++++++++++++-------- futures-util/src/stream/try_stream/mod.rs | 9 ++++-- 14 files changed, 110 insertions(+), 76 deletions(-) diff --git a/futures-test/src/assert.rs b/futures-test/src/assert.rs index 75d7832482..16037aee49 100644 --- a/futures-test/src/assert.rs +++ b/futures-test/src/assert.rs @@ -9,15 +9,16 @@ pub fn assert_is_unpin_stream(_: &mut S) {} /// # Examples /// /// ``` +/// use core::pin::pin; +/// /// use futures::stream; /// use futures_test::future::FutureTestExt; -/// use futures_test::{ -/// assert_stream_pending, assert_stream_next, assert_stream_done, -/// }; -/// use futures::pin_mut; +/// use futures_test::assert_stream_pending; +/// use futures_test::assert_stream_next; +/// use futures_test::assert_stream_done; /// /// let stream = stream::once((async { 5 }).pending_once()); -/// pin_mut!(stream); +/// let mut stream = pin!(stream); /// /// assert_stream_pending!(stream); /// assert_stream_next!(stream, 5); @@ -43,15 +44,16 @@ macro_rules! assert_stream_pending { /// # Examples /// /// ``` +/// use core::pin::pin; +/// /// use futures::stream; /// use futures_test::future::FutureTestExt; -/// use futures_test::{ -/// assert_stream_pending, assert_stream_next, assert_stream_done, -/// }; -/// use futures::pin_mut; +/// use futures_test::assert_stream_pending; +/// use futures_test::assert_stream_next; +/// use futures_test::assert_stream_done; /// /// let stream = stream::once((async { 5 }).pending_once()); -/// pin_mut!(stream); +/// let mut stream = pin!(stream); /// /// assert_stream_pending!(stream); /// assert_stream_next!(stream, 5); @@ -87,15 +89,16 @@ macro_rules! assert_stream_next { /// # Examples /// /// ``` +/// use core::pin::pin; +/// /// use futures::stream; /// use futures_test::future::FutureTestExt; -/// use futures_test::{ -/// assert_stream_pending, assert_stream_next, assert_stream_done, -/// }; -/// use futures::pin_mut; +/// use futures_test::assert_stream_pending; +/// use futures_test::assert_stream_next; +/// use futures_test::assert_stream_done; /// /// let stream = stream::once((async { 5 }).pending_once()); -/// pin_mut!(stream); +/// let mut stream = pin!(stream); /// /// assert_stream_pending!(stream); /// assert_stream_next!(stream, 5); diff --git a/futures-test/src/future/mod.rs b/futures-test/src/future/mod.rs index 0f52f62bb9..b066443ae4 100644 --- a/futures-test/src/future/mod.rs +++ b/futures-test/src/future/mod.rs @@ -32,14 +32,15 @@ pub trait FutureTestExt: Future { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::future::FutureExt; /// use futures_test::task::noop_context; /// use futures_test::future::FutureTestExt; - /// use futures::pin_mut; /// /// let future = (async { 5 }).pending_once(); - /// pin_mut!(future); + /// let mut future = pin!(future); /// /// let mut cx = noop_context(); /// @@ -84,14 +85,15 @@ pub trait FutureTestExt: Future { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::future::{self, Future}; /// use futures_test::task::noop_context; /// use futures_test::future::FutureTestExt; - /// use futures::pin_mut; /// /// let future = future::ready(1).interleave_pending(); - /// pin_mut!(future); + /// let mut future = pin!(future); /// /// let mut cx = noop_context(); /// diff --git a/futures-test/src/io/read/mod.rs b/futures-test/src/io/read/mod.rs index cb5f1d3f86..28a25f5a9f 100644 --- a/futures-test/src/io/read/mod.rs +++ b/futures-test/src/io/read/mod.rs @@ -29,14 +29,15 @@ pub trait AsyncReadTestExt: AsyncRead { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::io::{AsyncRead, Cursor}; /// use futures_test::task::noop_context; /// use futures_test::io::AsyncReadTestExt; - /// use futures::pin_mut; /// /// let reader = Cursor::new(&[1, 2, 3]).interleave_pending(); - /// pin_mut!(reader); + /// let mut reader = pin!(reader); /// /// let mut cx = noop_context(); /// @@ -59,14 +60,15 @@ pub trait AsyncReadTestExt: AsyncRead { /// The returned reader will also implement `AsyncBufRead` if the underlying reader does. /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::io::{AsyncBufRead, Cursor}; /// use futures_test::task::noop_context; /// use futures_test::io::AsyncReadTestExt; - /// use futures::pin_mut; /// /// let reader = Cursor::new(&[1, 2, 3]).interleave_pending(); - /// pin_mut!(reader); + /// let mut reader = pin!(reader); /// /// let mut cx = noop_context(); /// @@ -93,14 +95,15 @@ pub trait AsyncReadTestExt: AsyncRead { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::io::{AsyncRead, Cursor}; /// use futures_test::task::noop_context; /// use futures_test::io::AsyncReadTestExt; - /// use futures::pin_mut; /// /// let reader = Cursor::new(&[1, 2, 3, 4, 5]).limited(2); - /// pin_mut!(reader); + /// let mut reader = pin!(reader); /// /// let mut cx = noop_context(); /// diff --git a/futures-test/src/io/write/mod.rs b/futures-test/src/io/write/mod.rs index 01ca4b2fef..3c1b96eb8a 100644 --- a/futures-test/src/io/write/mod.rs +++ b/futures-test/src/io/write/mod.rs @@ -30,14 +30,15 @@ pub trait AsyncWriteTestExt: AsyncWrite { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::io::{AsyncWrite, Cursor}; /// use futures_test::task::noop_context; /// use futures_test::io::AsyncWriteTestExt; - /// use futures::pin_mut; /// /// let writer = Cursor::new(vec![0u8; 4].into_boxed_slice()).interleave_pending_write(); - /// pin_mut!(writer); + /// let mut writer = pin!(writer); /// /// let mut cx = noop_context(); /// @@ -70,14 +71,15 @@ pub trait AsyncWriteTestExt: AsyncWrite { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::io::{AsyncWrite, Cursor}; /// use futures_test::task::noop_context; /// use futures_test::io::AsyncWriteTestExt; - /// use futures::pin_mut; /// /// let writer = Cursor::new(vec![0u8; 4].into_boxed_slice()).limited_write(2); - /// pin_mut!(writer); + /// let mut writer = pin!(writer); /// /// let mut cx = noop_context(); /// diff --git a/futures-test/src/stream/mod.rs b/futures-test/src/stream/mod.rs index 9151a21c89..904f802875 100644 --- a/futures-test/src/stream/mod.rs +++ b/futures-test/src/stream/mod.rs @@ -28,14 +28,15 @@ pub trait StreamTestExt: Stream { /// # Examples /// /// ``` + /// use core::pin::pin; + /// /// use futures::task::Poll; /// use futures::stream::{self, Stream}; /// use futures_test::task::noop_context; /// use futures_test::stream::StreamTestExt; - /// use futures::pin_mut; /// /// let stream = stream::iter(vec![1, 2]).interleave_pending(); - /// pin_mut!(stream); + /// let mut stream = pin!(stream); /// /// let mut cx = noop_context(); /// diff --git a/futures-test/src/task/context.rs b/futures-test/src/task/context.rs index b2b0dfe31e..408dfdfef7 100644 --- a/futures-test/src/task/context.rs +++ b/futures-test/src/task/context.rs @@ -22,13 +22,14 @@ pub fn panic_context() -> Context<'static> { /// # Examples /// /// ``` +/// use core::pin::pin; +/// /// use futures::future::Future; /// use futures::task::Poll; /// use futures_test::task::noop_context; -/// use futures::pin_mut; /// /// let future = async { 5 }; -/// pin_mut!(future); +/// let future = pin!(future); /// /// assert_eq!(future.poll(&mut noop_context()), Poll::Ready(5)); /// ``` diff --git a/futures-util/src/async_await/select_mod.rs b/futures-util/src/async_await/select_mod.rs index 26528c07b3..a554a696e6 100644 --- a/futures-util/src/async_await/select_mod.rs +++ b/futures-util/src/async_await/select_mod.rs @@ -58,7 +58,7 @@ macro_rules! document_select_macro { /// select! { /// x = st.next() => assert_eq!(Some(2), x), /// _ = fut => panic!(), - /// }; + /// } /// # }); /// ``` /// @@ -87,14 +87,15 @@ macro_rules! document_select_macro { /// If a similar async function is called outside of `select` to produce /// a `Future`, the `Future` must be pinned in order to be able to pass /// it to `select`. This can be achieved via `Box::pin` for pinning a - /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future` + /// `Future` on the heap or the `pin!` macro for pinning a `Future` /// on the stack. /// /// ``` /// # futures::executor::block_on(async { + /// use core::pin::pin; + /// /// use futures::future::FutureExt; /// use futures::select; - /// use futures::pin_mut; /// /// // Calling the following async fn returns a Future which does not /// // implement Unpin @@ -105,7 +106,7 @@ macro_rules! document_select_macro { /// let fut_1 = async_identity_fn(1).fuse(); /// let fut_2 = async_identity_fn(2).fuse(); /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap - /// pin_mut!(fut_2); // Pins the Future on the stack + /// let mut fut_2 = pin!(fut_2); // Pins the Future on the stack /// /// let res = select! { /// a_res = fut_1 => a_res, @@ -138,7 +139,7 @@ macro_rules! document_select_macro { /// b = b_fut => total += b, /// complete => break, /// default => panic!(), // never runs (futures run first, then complete) - /// }; + /// } /// } /// assert_eq!(total, 10); /// # }); @@ -209,7 +210,7 @@ macro_rules! document_select_macro { /// select_biased! { /// x = st.next() => assert_eq!(Some(2), x), /// _ = fut => panic!(), - /// }; + /// } /// # }); /// ``` /// @@ -238,14 +239,15 @@ macro_rules! document_select_macro { /// If a similar async function is called outside of `select_biased` to produce /// a `Future`, the `Future` must be pinned in order to be able to pass /// it to `select_biased`. This can be achieved via `Box::pin` for pinning a - /// `Future` on the heap or the `pin_mut!` macro for pinning a `Future` + /// `Future` on the heap or the `pin!` macro for pinning a `Future` /// on the stack. /// /// ``` /// # futures::executor::block_on(async { + /// use core::pin::pin; + /// /// use futures::future::FutureExt; /// use futures::select_biased; - /// use futures::pin_mut; /// /// // Calling the following async fn returns a Future which does not /// // implement Unpin @@ -256,7 +258,7 @@ macro_rules! document_select_macro { /// let fut_1 = async_identity_fn(1).fuse(); /// let fut_2 = async_identity_fn(2).fuse(); /// let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap - /// pin_mut!(fut_2); // Pins the Future on the stack + /// let mut fut_2 = pin!(fut_2); // Pins the Future on the stack /// /// let res = select_biased! { /// a_res = fut_1 => a_res, @@ -289,7 +291,7 @@ macro_rules! document_select_macro { /// b = b_fut => total += b, /// complete => break, /// default => panic!(), // never runs (futures run first, then complete) - /// }; + /// } /// } /// assert_eq!(total, 10); /// # }); diff --git a/futures-util/src/future/future/fuse.rs b/futures-util/src/future/future/fuse.rs index 2257906726..100e910776 100644 --- a/futures-util/src/future/future/fuse.rs +++ b/futures-util/src/future/future/fuse.rs @@ -29,11 +29,12 @@ impl Fuse { /// /// ``` /// # futures::executor::block_on(async { + /// use core::pin::pin; + /// /// use futures::channel::mpsc; /// use futures::future::{Fuse, FusedFuture, FutureExt}; /// use futures::select; /// use futures::stream::StreamExt; - /// use futures::pin_mut; /// /// let (sender, mut stream) = mpsc::unbounded(); /// @@ -45,7 +46,7 @@ impl Fuse { /// // Use `Fuse::terminated()` to create an already-terminated future /// // which may be instantiated later. /// let foo_printer = Fuse::terminated(); - /// pin_mut!(foo_printer); + /// let mut foo_printer = pin!(foo_printer); /// /// loop { /// select! { diff --git a/futures-util/src/future/maybe_done.rs b/futures-util/src/future/maybe_done.rs index 1e21e66f5e..fa8787a874 100644 --- a/futures-util/src/future/maybe_done.rs +++ b/futures-util/src/future/maybe_done.rs @@ -29,11 +29,12 @@ impl Unpin for MaybeDone {} /// /// ``` /// # futures::executor::block_on(async { +/// use core::pin::pin; +/// /// use futures::future; -/// use futures::pin_mut; /// /// let future = future::maybe_done(async { 5 }); -/// pin_mut!(future); +/// let mut future = pin!(future); /// assert_eq!(future.as_mut().take_output(), None); /// let () = future.as_mut().await; /// assert_eq!(future.as_mut().take_output(), Some(5)); diff --git a/futures-util/src/future/poll_immediate.rs b/futures-util/src/future/poll_immediate.rs index 5ae555c73e..8247011375 100644 --- a/futures-util/src/future/poll_immediate.rs +++ b/futures-util/src/future/poll_immediate.rs @@ -48,17 +48,19 @@ impl FusedFuture for PollImmediate { /// so polling it in a tight loop is worse than using a blocking synchronous function. /// ``` /// # futures::executor::block_on(async { +/// use core::pin::pin; +/// /// use futures::task::Poll; -/// use futures::{StreamExt, future, pin_mut}; +/// use futures::{StreamExt, future}; /// use future::FusedFuture; /// /// let f = async { 1_u32 }; -/// pin_mut!(f); +/// let f = pin!(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 f = pin!(f); /// let mut p = future::poll_immediate(f); /// assert_eq!(p.next().await, Some(Poll::Pending)); /// assert!(!p.is_terminated()); @@ -114,9 +116,12 @@ where /// /// ``` /// # futures::executor::block_on(async { -/// use futures::{future, pin_mut}; +/// use core::pin::pin; +/// +/// use futures::future; +/// /// let f = async {futures::pending!(); 42_u8}; -/// pin_mut!(f); +/// let mut f = pin!(f); /// assert_eq!(None, future::poll_immediate(&mut f).await); /// assert_eq!(42, f.await); /// # }); diff --git a/futures-util/src/future/select.rs b/futures-util/src/future/select.rs index 7e33d195f7..4aa539e8ab 100644 --- a/futures-util/src/future/select.rs +++ b/futures-util/src/future/select.rs @@ -32,11 +32,10 @@ impl Unpin for Select {} /// /// ``` /// # futures::executor::block_on(async { -/// use futures::{ -/// pin_mut, -/// future::Either, -/// future::self, -/// }; +/// use core::pin::pin; +/// +/// use futures::future; +/// use futures::future::Either; /// /// // These two futures have different types even though their outputs have the same type. /// let future1 = async { @@ -48,8 +47,8 @@ impl Unpin for Select {} /// }; /// /// // 'select' requires Future + Unpin bounds -/// pin_mut!(future1); -/// pin_mut!(future2); +/// let future1 = pin!(future1); +/// let future2 = pin!(future2); /// /// let value = match future::select(future1, future2).await { /// Either::Left((value1, _)) => value1, // `value1` is resolved from `future1` diff --git a/futures-util/src/sink/unfold.rs b/futures-util/src/sink/unfold.rs index dea1307b66..008962ebab 100644 --- a/futures-util/src/sink/unfold.rs +++ b/futures-util/src/sink/unfold.rs @@ -23,7 +23,10 @@ pin_project! { /// /// ``` /// # futures::executor::block_on(async { -/// use futures::sink::{self, SinkExt}; +/// use core::pin::pin; +/// +/// use futures::sink; +/// use futures::sink::SinkExt; /// /// let unfold = sink::unfold(0, |mut sum, i: i32| { /// async move { @@ -32,7 +35,7 @@ pin_project! { /// Ok::<_, futures::never::Never>(sum) /// } /// }); -/// futures::pin_mut!(unfold); +/// let mut unfold = pin!(unfold); /// unfold.send(5).await?; /// # Ok::<(), futures::never::Never>(()) }).unwrap(); /// ``` diff --git a/futures-util/src/stream/stream/peek.rs b/futures-util/src/stream/stream/peek.rs index ea3d6243f3..d696acb5f5 100644 --- a/futures-util/src/stream/stream/peek.rs +++ b/futures-util/src/stream/stream/peek.rs @@ -64,11 +64,13 @@ impl Peekable { /// /// ``` /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// use futures::pin_mut; + /// use core::pin::pin; + /// + /// use futures::stream; + /// use futures::stream::StreamExt; /// /// let stream = stream::iter(vec![1, 2, 3]).peekable(); - /// pin_mut!(stream); + /// let mut stream = pin!(stream); /// /// assert_eq!(stream.as_mut().peek_mut().await, Some(&mut 1)); /// assert_eq!(stream.as_mut().next().await, Some(1)); @@ -117,11 +119,13 @@ impl Peekable { /// /// ``` /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// use futures::pin_mut; + /// use core::pin::pin; + /// + /// use futures::stream; + /// use futures::stream::StreamExt; /// /// let stream = stream::iter(0..5).peekable(); - /// pin_mut!(stream); + /// let mut stream = pin!(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`. @@ -135,11 +139,13 @@ impl Peekable { /// /// ``` /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// use futures::pin_mut; + /// use core::pin::pin; + /// + /// use futures::stream; + /// use futures::stream::StreamExt; /// /// let stream = stream::iter(1..20).peekable(); - /// pin_mut!(stream); + /// let mut stream = pin!(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 @@ -162,11 +168,13 @@ impl Peekable { /// /// ``` /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// use futures::pin_mut; + /// use core::pin::pin; + /// + /// use futures::stream; + /// use futures::stream::StreamExt; /// /// let stream = stream::iter(0..5).peekable(); - /// pin_mut!(stream); + /// let mut stream = pin!(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`. diff --git a/futures-util/src/stream/try_stream/mod.rs b/futures-util/src/stream/try_stream/mod.rs index ee004b51e8..311bfb33d0 100644 --- a/futures-util/src/stream/try_stream/mod.rs +++ b/futures-util/src/stream/try_stream/mod.rs @@ -760,8 +760,11 @@ pub trait TryStreamExt: TryStream { /// # Examples /// ``` /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// use futures::pin_mut; + /// use core::pin::pin; + /// + /// use futures::stream; + /// use futures::stream::StreamExt; + /// use futures::stream::TryStreamExt; /// /// let stream = stream::iter(vec![Ok(1i32), Ok(6i32), Err("error")]); /// let halves = stream.try_filter_map(|x| async move { @@ -769,7 +772,7 @@ pub trait TryStreamExt: TryStream { /// Ok(ret) /// }); /// - /// pin_mut!(halves); + /// let mut halves = pin!(halves); /// assert_eq!(halves.next().await, Some(Ok(3))); /// assert_eq!(halves.next().await, Some(Err("error"))); /// # }) From f127c611b8a7ac6dcad10d6530413bf58bc4cc53 Mon Sep 17 00:00:00 2001 From: tison Date: Sat, 5 Apr 2025 17:44:15 +0800 Subject: [PATCH 14/33] chore: replace all test usage of pin_mut (#2942) Signed-off-by: tison --- futures-channel/tests/mpsc.rs | 5 +++-- futures/tests/async_await_macros.rs | 9 ++++----- futures/tests/future_join_all.rs | 5 ++--- futures/tests/future_try_join_all.rs | 5 ++--- futures/tests/io_buf_reader.rs | 15 +++++++-------- futures/tests/sink.rs | 4 ++-- futures/tests/stream_peekable.rs | 12 ++++++------ 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/futures-channel/tests/mpsc.rs b/futures-channel/tests/mpsc.rs index 28d476b05a..b88e750489 100644 --- a/futures-channel/tests/mpsc.rs +++ b/futures-channel/tests/mpsc.rs @@ -1,11 +1,11 @@ use futures::channel::{mpsc, oneshot}; use futures::executor::{block_on, block_on_stream}; use futures::future::{poll_fn, FutureExt}; -use futures::pin_mut; use futures::sink::{Sink, SinkExt}; use futures::stream::{Stream, StreamExt}; use futures::task::{Context, Poll}; use futures_test::task::{new_count_waker, noop_context}; +use std::pin::pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::thread; @@ -30,7 +30,8 @@ fn send_recv_no_buffer() { // Run on a task context block_on(poll_fn(move |cx| { let (tx, rx) = mpsc::channel::(0); - pin_mut!(tx, rx); + let mut tx = pin!(tx); + let mut rx = pin!(rx); assert!(tx.as_mut().poll_flush(cx).is_ready()); assert!(tx.as_mut().poll_ready(cx).is_ready()); diff --git a/futures/tests/async_await_macros.rs b/futures/tests/async_await_macros.rs index 0bc79e4ae8..c3e9ae908d 100644 --- a/futures/tests/async_await_macros.rs +++ b/futures/tests/async_await_macros.rs @@ -4,16 +4,15 @@ use futures::future::{self, poll_fn, FutureExt}; use futures::sink::SinkExt; use futures::stream::StreamExt; use futures::task::{Context, Poll}; -use futures::{ - join, pending, pin_mut, poll, select, select_biased, stream, stream_select, try_join, -}; +use futures::{join, pending, poll, select, select_biased, stream, stream_select, try_join}; use std::mem; +use std::pin::pin; #[test] fn poll_and_pending() { let pending_once = async { pending!() }; block_on(async { - pin_mut!(pending_once); + let mut pending_once = pin!(pending_once); assert_eq!(Poll::Pending, poll!(&mut pending_once)); assert_eq!(Poll::Ready(()), poll!(&mut pending_once)); }); @@ -30,7 +29,7 @@ fn join() { }; block_on(async { - pin_mut!(fut); + let mut fut = pin!(fut); assert_eq!(Poll::Pending, poll!(&mut fut)); tx1.send(1).unwrap(); assert_eq!(Poll::Pending, poll!(&mut fut)); diff --git a/futures/tests/future_join_all.rs b/futures/tests/future_join_all.rs index 44486e1ca3..f981b6553a 100644 --- a/futures/tests/future_join_all.rs +++ b/futures/tests/future_join_all.rs @@ -1,15 +1,14 @@ use futures::executor::block_on; use futures::future::{join_all, ready, Future, JoinAll}; -use futures::pin_mut; use std::fmt::Debug; +use std::pin::pin; #[track_caller] fn assert_done(actual_fut: impl Future, expected: T) where T: PartialEq + Debug, { - pin_mut!(actual_fut); - let output = block_on(actual_fut); + let output = block_on(pin!(actual_fut)); assert_eq!(output, expected); } diff --git a/futures/tests/future_try_join_all.rs b/futures/tests/future_try_join_all.rs index 892e775920..52dd117381 100644 --- a/futures/tests/future_try_join_all.rs +++ b/futures/tests/future_try_join_all.rs @@ -1,15 +1,14 @@ use futures::executor::block_on; use futures::future::{err, ok, try_join_all, Future, TryJoinAll}; -use futures::pin_mut; use std::fmt::Debug; +use std::pin::pin; #[track_caller] fn assert_done(actual_fut: impl Future, expected: T) where T: PartialEq + Debug, { - pin_mut!(actual_fut); - let output = block_on(actual_fut); + let output = block_on(pin!(actual_fut)); assert_eq!(output, expected); } diff --git a/futures/tests/io_buf_reader.rs b/futures/tests/io_buf_reader.rs index 717297ccea..7861d6d46e 100644 --- a/futures/tests/io_buf_reader.rs +++ b/futures/tests/io_buf_reader.rs @@ -4,13 +4,12 @@ use futures::io::{ AllowStdIo, AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, BufReader, SeekFrom, }; -use futures::pin_mut; use futures::task::{Context, Poll}; use futures_test::task::noop_context; use pin_project::pin_project; use std::cmp; use std::io; -use std::pin::Pin; +use std::pin::{pin, Pin}; // helper for maybe_pending_* tests fn run(mut f: F) -> F::Output { @@ -157,7 +156,7 @@ fn test_buffered_reader_seek() { block_on(async { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let reader = BufReader::with_capacity(2, Cursor::new(inner)); - pin_mut!(reader); + let mut reader = pin!(reader); assert_eq!(reader.seek(SeekFrom::Start(3)).await.unwrap(), 3); assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1][..]); @@ -175,7 +174,7 @@ fn test_buffered_reader_seek_relative() { block_on(async { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let reader = BufReader::with_capacity(2, Cursor::new(inner)); - pin_mut!(reader); + let mut reader = pin!(reader); assert!(reader.as_mut().seek_relative(3).await.is_ok()); assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1][..]); @@ -195,7 +194,7 @@ fn test_buffered_reader_invalidated_after_read() { block_on(async { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let reader = BufReader::with_capacity(3, Cursor::new(inner)); - pin_mut!(reader); + let mut reader = pin!(reader); assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[5, 6, 7][..]); reader.as_mut().consume(3); @@ -216,7 +215,7 @@ fn test_buffered_reader_invalidated_after_seek() { block_on(async { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let reader = BufReader::with_capacity(3, Cursor::new(inner)); - pin_mut!(reader); + let mut reader = pin!(reader); assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[5, 6, 7][..]); reader.as_mut().consume(3); @@ -265,7 +264,7 @@ fn test_buffered_reader_seek_underflow() { block_on(async { let reader = BufReader::with_capacity(5, AllowStdIo::new(PositionReader { pos: 0 })); - pin_mut!(reader); + let mut reader = pin!(reader); assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1, 2, 3, 4][..]); assert_eq!(reader.seek(SeekFrom::End(-5)).await.unwrap(), u64::MAX - 5); assert_eq!(reader.as_mut().fill_buf().await.unwrap().len(), 5); @@ -419,7 +418,7 @@ fn maybe_pending_seek() { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let reader = BufReader::with_capacity(2, MaybePendingSeek::new(inner)); - pin_mut!(reader); + let mut reader = pin!(reader); assert_eq!(run(reader.seek(SeekFrom::Current(3))).ok(), Some(3)); assert_eq!(run(reader.as_mut().fill_buf()).ok(), Some(&[0, 1][..])); diff --git a/futures/tests/sink.rs b/futures/tests/sink.rs index 5b691e74c6..8898b1a0bd 100644 --- a/futures/tests/sink.rs +++ b/futures/tests/sink.rs @@ -11,7 +11,7 @@ use std::cell::{Cell, RefCell}; use std::collections::VecDeque; use std::fmt; use std::mem; -use std::pin::Pin; +use std::pin::{pin, Pin}; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -509,7 +509,7 @@ fn sink_unfold() { Ok::<_, String>(()) } }); - futures::pin_mut!(unfold); + let mut unfold = pin!(unfold); assert_eq!(unfold.as_mut().start_send(1), Ok(())); assert_eq!(unfold.as_mut().poll_flush(cx), Poll::Ready(Ok(()))); assert_eq!(rx.try_next().unwrap(), Some(1)); diff --git a/futures/tests/stream_peekable.rs b/futures/tests/stream_peekable.rs index 153fcc25b4..06668f444d 100644 --- a/futures/tests/stream_peekable.rs +++ b/futures/tests/stream_peekable.rs @@ -1,17 +1,17 @@ use futures::executor::block_on; -use futures::pin_mut; use futures::stream::{self, Peekable, StreamExt}; +use std::pin::pin; #[test] fn peekable() { block_on(async { let peekable: Peekable<_> = stream::iter(vec![1u8, 2, 3]).peekable(); - pin_mut!(peekable); + let mut peekable = pin!(peekable); assert_eq!(peekable.as_mut().peek().await, Some(&1u8)); assert_eq!(peekable.collect::>().await, vec![1, 2, 3]); let s = stream::once(async { 1 }).peekable(); - pin_mut!(s); + let mut s = pin!(s); assert_eq!(s.as_mut().peek().await, Some(&1u8)); assert_eq!(s.collect::>().await, vec![1]); }); @@ -21,7 +21,7 @@ fn peekable() { fn peekable_mut() { block_on(async { let s = stream::iter(vec![1u8, 2, 3]).peekable(); - pin_mut!(s); + let mut s = pin!(s); if let Some(p) = s.as_mut().peek_mut().await { if *p == 1 { *p = 5; @@ -36,7 +36,7 @@ fn peekable_next_if_eq() { block_on(async { // first, try on references let s = stream::iter(vec!["Heart", "of", "Gold"]).peekable(); - pin_mut!(s); + let mut s = pin!(s); // try before `peek()` assert_eq!(s.as_mut().next_if_eq(&"trillian").await, None); assert_eq!(s.as_mut().next_if_eq(&"Heart").await, Some("Heart")); @@ -49,7 +49,7 @@ fn peekable_next_if_eq() { // make sure comparison works for owned values let s = stream::iter(vec![String::from("Ludicrous"), "speed".into()]).peekable(); - pin_mut!(s); + let mut s = pin!(s); // make sure basic functionality works assert_eq!(s.as_mut().next_if_eq("Ludicrous").await, Some("Ludicrous".into())); assert_eq!(s.as_mut().next_if_eq("speed").await, Some("speed".into())); From 4da80e04870341e1cfe946a827ac3f78085705b5 Mon Sep 17 00:00:00 2001 From: tison Date: Sat, 5 Apr 2025 17:52:26 +0800 Subject: [PATCH 15/33] chore: replace all usage of pin_mut Signed-off-by: tison --- futures-executor/src/local_pool.rs | 6 +++--- futures-util/src/future/future/mod.rs | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/futures-executor/src/local_pool.rs b/futures-executor/src/local_pool.rs index 90c2a41520..fb55343953 100644 --- a/futures-executor/src/local_pool.rs +++ b/futures-executor/src/local_pool.rs @@ -4,11 +4,11 @@ use futures_core::stream::Stream; use futures_core::task::{Context, Poll}; use futures_task::{waker_ref, ArcWake}; use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError}; -use futures_util::pin_mut; use futures_util::stream::FuturesUnordered; use futures_util::stream::StreamExt; use std::cell::RefCell; use std::ops::{Deref, DerefMut}; +use std::pin::pin; use std::rc::{Rc, Weak}; use std::sync::{ atomic::{AtomicBool, Ordering}, @@ -155,7 +155,7 @@ impl LocalPool { /// one of the pool's run or poll methods. While the function is running, /// however, all tasks in the pool will try to make progress. pub fn run_until(&mut self, future: F) -> F::Output { - pin_mut!(future); + let mut future = pin!(future); run_executor(|cx| { { @@ -312,7 +312,7 @@ impl Default for LocalPool { /// /// Use a [`LocalPool`] if you need finer-grained control over spawned tasks. pub fn block_on(f: F) -> F::Output { - pin_mut!(f); + let mut f = pin!(f); run_executor(|cx| f.as_mut().poll(cx)) } diff --git a/futures-util/src/future/future/mod.rs b/futures-util/src/future/future/mod.rs index 815c9c751a..a3237b1a1c 100644 --- a/futures-util/src/future/future/mod.rs +++ b/futures-util/src/future/future/mod.rs @@ -3,16 +3,15 @@ //! This module contains a number of functions for working with `Future`s, //! including the `FutureExt` trait which adds methods to `Future` types. -#[cfg(feature = "alloc")] -use alloc::boxed::Box; -use core::pin::Pin; - use crate::fns::{inspect_fn, into_fn, ok_fn, InspectFn, IntoFn, OkFn}; use crate::future::{assert_future, Either}; use crate::never::Never; -use crate::pin_mut; use crate::stream::assert_stream; #[cfg(feature = "alloc")] +use alloc::boxed::Box; +use core::pin::pin; +use core::pin::Pin; +#[cfg(feature = "alloc")] use futures_core::future::{BoxFuture, LocalBoxFuture}; use futures_core::{ future::Future, @@ -595,8 +594,7 @@ pub trait FutureExt: Future { let noop_waker = crate::task::noop_waker(); let mut cx = Context::from_waker(&noop_waker); - let this = self; - pin_mut!(this); + let this = pin!(self); match this.poll(&mut cx) { Poll::Ready(x) => Some(x), _ => None, From 0cbb31b46cf9cb636f2e1859286996ad3e89843e Mon Sep 17 00:00:00 2001 From: tison Date: Sat, 5 Apr 2025 17:53:01 +0800 Subject: [PATCH 16/33] bump msrv to 1.68 Signed-off-by: tison --- .github/workflows/ci.yml | 2 +- README.md | 2 +- futures-channel/Cargo.toml | 2 +- futures-channel/README.md | 2 +- futures-executor/Cargo.toml | 2 +- futures-executor/README.md | 2 +- futures-macro/Cargo.toml | 2 +- futures-task/Cargo.toml | 2 +- futures-task/README.md | 2 +- futures-test/Cargo.toml | 2 +- futures-test/README.md | 2 +- futures-util/Cargo.toml | 2 +- futures-util/README.md | 2 +- futures/Cargo.toml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15c344452f..8079e21ee8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,7 +102,7 @@ jobs: rust: # This is the minimum Rust version supported by futures, futures-util, futures-task, futures-macro, futures-executor, futures-channel, futures-test. # When updating this, the reminder to update the minimum required version in README.md and Cargo.toml. - - '1.63' + - '1.68' runs-on: ubuntu-latest timeout-minutes: 60 steps: diff --git a/README.md b/README.md index 1ddedca895..a2c622a831 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Add this to your `Cargo.toml`: futures = "0.3" ``` -The current `futures` requires Rust 1.63 or later. +The current `futures` requires Rust 1.68 or later. ### Feature `std` diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml index eab7a0bd2d..ce12dd93b5 100644 --- a/futures-channel/Cargo.toml +++ b/futures-channel/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-channel" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-channel/README.md b/futures-channel/README.md index e465482ac8..f386839289 100644 --- a/futures-channel/README.md +++ b/futures-channel/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-channel = "0.3" ``` -The current `futures-channel` requires Rust 1.63 or later. +The current `futures-channel` requires Rust 1.68 or later. ## License diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index 9bfd2dcb78..53c29d984b 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-executor" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-executor/README.md b/futures-executor/README.md index bc4a3fcb0f..b3906543b0 100644 --- a/futures-executor/README.md +++ b/futures-executor/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-executor = "0.3" ``` -The current `futures-executor` requires Rust 1.63 or later. +The current `futures-executor` requires Rust 1.68 or later. ## License diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml index cc7aaf4a49..cbf4668e12 100644 --- a/futures-macro/Cargo.toml +++ b/futures-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-macro" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml index 130e438fa7..2d1bd72112 100644 --- a/futures-task/Cargo.toml +++ b/futures-task/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-task" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/README.md b/futures-task/README.md index 6a8ca2dd4e..40296f0332 100644 --- a/futures-task/README.md +++ b/futures-task/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-task = "0.3" ``` -The current `futures-task` requires Rust 1.63 or later. +The current `futures-task` requires Rust 1.68 or later. ## License diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml index ab307b3805..07b5eab716 100644 --- a/futures-test/Cargo.toml +++ b/futures-test/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-test" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-test/README.md b/futures-test/README.md index 078457d873..407ec0e291 100644 --- a/futures-test/README.md +++ b/futures-test/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-test = "0.3" ``` -The current `futures-test` requires Rust 1.63 or later. +The current `futures-test` requires Rust 1.68 or later. ## License diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 65b6468472..828c9766a4 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-util" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-util/README.md b/futures-util/README.md index fc1b6d6b0c..d4bcad3406 100644 --- a/futures-util/README.md +++ b/futures-util/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-util = "0.3" ``` -The current `futures-util` requires Rust 1.63 or later. +The current `futures-util` requires Rust 1.68 or later. ## License diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 6511d8951d..e858118bbf 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -2,7 +2,7 @@ name = "futures" version = "0.3.31" edition = "2018" -rust-version = "1.63" +rust-version = "1.68" license = "MIT OR Apache-2.0" readme = "../README.md" keywords = ["futures", "async", "future"] From e0a1d49fcc8552b7ff223a2255163eb30914da91 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Wed, 9 Apr 2025 08:59:27 +0200 Subject: [PATCH 17/33] channel: Add try_recv and deprecate try_next (#2944) --- futures-channel/src/mpsc/mod.rs | 60 ++++++++++++++++++++----- futures-channel/tests/mpsc-close.rs | 33 ++++++++++++++ futures-channel/tests/mpsc-size_hint.rs | 12 ++--- futures-channel/tests/mpsc.rs | 11 ++--- futures/tests/sink.rs | 10 ++--- 5 files changed, 98 insertions(+), 28 deletions(-) diff --git a/futures-channel/src/mpsc/mod.rs b/futures-channel/src/mpsc/mod.rs index 03a8a53898..7e954574c9 100644 --- a/futures-channel/src/mpsc/mod.rs +++ b/futures-channel/src/mpsc/mod.rs @@ -167,9 +167,14 @@ enum SendErrorKind { Disconnected, } -/// The error type returned from [`try_next`](Receiver::try_next). -pub struct TryRecvError { - _priv: (), +/// The error type returned from [`try_recv`](Receiver::try_recv). +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum TryRecvError { + /// The channel is empty but not closed. + Empty, + + /// The channel is empty and closed. + Closed, } impl fmt::Display for SendError { @@ -202,6 +207,18 @@ impl SendError { } } +impl TryRecvError { + /// Returns `true` if the channel is empty but not closed. + pub fn is_empty(&self) -> bool { + matches!(self, TryRecvError::Empty) + } + + /// Returns `true` if the channel is empty and closed. + pub fn is_closed(&self) -> bool { + matches!(self, TryRecvError::Closed) + } +} + impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TrySendError").field("kind", &self.err.kind).finish() @@ -242,15 +259,12 @@ impl TrySendError { } } -impl fmt::Debug for TryRecvError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("TryRecvError").finish() - } -} - impl fmt::Display for TryRecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "receiver channel is empty") + match self { + TryRecvError::Empty => write!(f, "receive failed because channel is empty"), + TryRecvError::Closed => write!(f, "receive failed because channel is closed"), + } } } @@ -997,10 +1011,21 @@ impl Receiver { /// * `Ok(Some(t))` when message is fetched /// * `Ok(None)` when channel is closed and no messages left in the queue /// * `Err(e)` when there are no messages available, but channel is not yet closed + #[deprecated(note = "please use `try_recv` instead")] pub fn try_next(&mut self) -> Result, TryRecvError> { match self.next_message() { Poll::Ready(msg) => Ok(msg), - Poll::Pending => Err(TryRecvError { _priv: () }), + Poll::Pending => Err(TryRecvError::Empty), + } + } + + /// Tries to receive a message from the channel without blocking. + /// If the channel is empty, or empty and closed, this method returns an error. + pub fn try_recv(&mut self) -> Result { + match self.next_message() { + Poll::Ready(Some(msg)) => Ok(msg), + Poll::Ready(None) => Err(TryRecvError::Closed), + Poll::Pending => Err(TryRecvError::Empty), } } @@ -1165,10 +1190,21 @@ impl UnboundedReceiver { /// * `Ok(Some(t))` when message is fetched /// * `Ok(None)` when channel is closed and no messages left in the queue /// * `Err(e)` when there are no messages available, but channel is not yet closed + #[deprecated(note = "please use `try_recv` instead")] pub fn try_next(&mut self) -> Result, TryRecvError> { match self.next_message() { Poll::Ready(msg) => Ok(msg), - Poll::Pending => Err(TryRecvError { _priv: () }), + Poll::Pending => Err(TryRecvError::Empty), + } + } + + /// Tries to receive a message from the channel without blocking. + /// If the channel is empty, or empty and closed, this method returns an error. + pub fn try_recv(&mut self) -> Result { + match self.next_message() { + Poll::Ready(Some(msg)) => Ok(msg), + Poll::Ready(None) => Err(TryRecvError::Closed), + Poll::Pending => Err(TryRecvError::Empty), } } diff --git a/futures-channel/tests/mpsc-close.rs b/futures-channel/tests/mpsc-close.rs index 2d49936fc1..be5d08c322 100644 --- a/futures-channel/tests/mpsc-close.rs +++ b/futures-channel/tests/mpsc-close.rs @@ -4,6 +4,7 @@ use futures::future::Future; use futures::sink::SinkExt; use futures::stream::StreamExt; use futures::task::{Context, Poll}; +use futures_channel::mpsc::TryRecvError; use std::pin::Pin; use std::sync::{Arc, Weak}; use std::thread; @@ -278,6 +279,7 @@ fn stress_try_send_as_receiver_closes() { #[test] fn unbounded_try_next_after_none() { + #![allow(deprecated)] let (tx, mut rx) = mpsc::unbounded::(); // Drop the sender, close the channel. drop(tx); @@ -289,6 +291,7 @@ fn unbounded_try_next_after_none() { #[test] fn bounded_try_next_after_none() { + #![allow(deprecated)] let (tx, mut rx) = mpsc::channel::(17); // Drop the sender, close the channel. drop(tx); @@ -297,3 +300,33 @@ fn bounded_try_next_after_none() { // None received, check we can call `try_next` again. assert_eq!(Ok(None), rx.try_next().map_err(|_| ())); } + +#[test] +fn unbounded_try_recv_after_none() { + let (tx, mut rx) = mpsc::unbounded::(); + + // Channel is empty initially. + assert_eq!(Err(TryRecvError::Empty), rx.try_recv()); + + // Drop the sender, close the channel. + drop(tx); + // Receive the end of channel. + assert_eq!(Err(TryRecvError::Closed), rx.try_recv()); + // Closed received, check we can call `try_next` again. + assert_eq!(Err(TryRecvError::Closed), rx.try_recv()); +} + +#[test] +fn bounded_try_recv_after_none() { + let (tx, mut rx) = mpsc::channel::(17); + + // Channel is empty initially. + assert_eq!(Err(TryRecvError::Empty), rx.try_recv()); + + // Drop the sender, close the channel. + drop(tx); + // Receive the end of channel. + assert_eq!(Err(TryRecvError::Closed), rx.try_recv()); + // Closed received, check we can call `try_next` again. + assert_eq!(Err(TryRecvError::Closed), rx.try_recv()); +} diff --git a/futures-channel/tests/mpsc-size_hint.rs b/futures-channel/tests/mpsc-size_hint.rs index d9cdaa31fa..3c06eec1ab 100644 --- a/futures-channel/tests/mpsc-size_hint.rs +++ b/futures-channel/tests/mpsc-size_hint.rs @@ -7,16 +7,16 @@ fn unbounded_size_hint() { assert_eq!((0, None), rx.size_hint()); tx.unbounded_send(1).unwrap(); assert_eq!((1, None), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((0, None), rx.size_hint()); tx.unbounded_send(2).unwrap(); tx.unbounded_send(3).unwrap(); assert_eq!((2, None), rx.size_hint()); drop(tx); assert_eq!((2, Some(2)), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((1, Some(1)), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((0, Some(0)), rx.size_hint()); } @@ -26,15 +26,15 @@ fn channel_size_hint() { assert_eq!((0, None), rx.size_hint()); tx.try_send(1).unwrap(); assert_eq!((1, None), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((0, None), rx.size_hint()); tx.try_send(2).unwrap(); tx.try_send(3).unwrap(); assert_eq!((2, None), rx.size_hint()); drop(tx); assert_eq!((2, Some(2)), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((1, Some(1)), rx.size_hint()); - rx.try_next().unwrap().unwrap(); + rx.try_recv().unwrap(); assert_eq!((0, Some(0)), rx.size_hint()); } diff --git a/futures-channel/tests/mpsc.rs b/futures-channel/tests/mpsc.rs index b88e750489..5aaff45f3d 100644 --- a/futures-channel/tests/mpsc.rs +++ b/futures-channel/tests/mpsc.rs @@ -4,6 +4,7 @@ use futures::future::{poll_fn, FutureExt}; use futures::sink::{Sink, SinkExt}; use futures::stream::{Stream, StreamExt}; use futures::task::{Context, Poll}; +use futures_channel::mpsc::TryRecvError; use futures_test::task::{new_count_waker, noop_context}; use std::pin::pin; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -505,12 +506,12 @@ fn try_send_recv() { tx.try_send("hello").unwrap(); tx.try_send("hello").unwrap(); tx.try_send("hello").unwrap_err(); // should be full - rx.try_next().unwrap(); - rx.try_next().unwrap(); - rx.try_next().unwrap_err(); // should be empty + rx.try_recv().unwrap(); + rx.try_recv().unwrap(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); tx.try_send("hello").unwrap(); - rx.try_next().unwrap(); - rx.try_next().unwrap_err(); // should be empty + rx.try_recv().unwrap(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); } #[test] diff --git a/futures/tests/sink.rs b/futures/tests/sink.rs index 8898b1a0bd..8fa716f1de 100644 --- a/futures/tests/sink.rs +++ b/futures/tests/sink.rs @@ -512,19 +512,19 @@ fn sink_unfold() { let mut unfold = pin!(unfold); assert_eq!(unfold.as_mut().start_send(1), Ok(())); assert_eq!(unfold.as_mut().poll_flush(cx), Poll::Ready(Ok(()))); - assert_eq!(rx.try_next().unwrap(), Some(1)); + assert_eq!(rx.try_recv().unwrap(), 1); assert_eq!(unfold.as_mut().poll_ready(cx), Poll::Ready(Ok(()))); assert_eq!(unfold.as_mut().start_send(2), Ok(())); assert_eq!(unfold.as_mut().poll_ready(cx), Poll::Ready(Ok(()))); assert_eq!(unfold.as_mut().start_send(3), Ok(())); - assert_eq!(rx.try_next().unwrap(), Some(2)); - assert!(rx.try_next().is_err()); + assert_eq!(rx.try_recv().unwrap(), 2); + assert!(rx.try_recv().is_err()); assert_eq!(unfold.as_mut().poll_ready(cx), Poll::Ready(Ok(()))); assert_eq!(unfold.as_mut().start_send(4), Ok(())); assert_eq!(unfold.as_mut().poll_flush(cx), Poll::Pending); // Channel full - assert_eq!(rx.try_next().unwrap(), Some(3)); - assert_eq!(rx.try_next().unwrap(), Some(4)); + assert_eq!(rx.try_recv().unwrap(), 3); + assert_eq!(rx.try_recv().unwrap(), 4); Poll::Ready(()) })) From bb1f027933d0231d9bb9233f61722c48abd282c6 Mon Sep 17 00:00:00 2001 From: Aatif Syed <38045910+aatifsyed@users.noreply.github.com> Date: Thu, 10 Apr 2025 11:23:22 +0100 Subject: [PATCH 18/33] feat: sink::With: Implement FusedStream (#2948) --- futures-util/src/sink/with.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/futures-util/src/sink/with.rs b/futures-util/src/sink/with.rs index 86d3dcc7b8..5a2c8a089f 100644 --- a/futures-util/src/sink/with.rs +++ b/futures-util/src/sink/with.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::pin::Pin; use futures_core::future::Future; use futures_core::ready; -use futures_core::stream::Stream; +use futures_core::stream::{FusedStream, Stream}; use futures_core::task::{Context, Poll}; use futures_sink::Sink; use pin_project_lite::pin_project; @@ -74,6 +74,17 @@ where delegate_stream!(sink); } +impl FusedStream for With +where + S: FusedStream + Sink, + F: FnMut(U) -> Fut, + Fut: Future, +{ + fn is_terminated(&self) -> bool { + self.sink.is_terminated() + } +} + impl With where Si: Sink, From 16ac1cf3cbf19ae3c186dab60ee2c99bba17c9f3 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Wed, 16 Apr 2025 14:03:16 +0200 Subject: [PATCH 19/33] refactor: remove leftover from `read_initializer` feature (#2949) --- futures-util/src/io/mod.rs | 10 +--------- futures-util/src/io/read_to_end.rs | 11 +++++------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/futures-util/src/io/mod.rs b/futures-util/src/io/mod.rs index c07fe3fe47..923109cce5 100644 --- a/futures-util/src/io/mod.rs +++ b/futures-util/src/io/mod.rs @@ -21,7 +21,7 @@ use crate::compat::Compat; use crate::future::assert_future; use crate::stream::assert_stream; -use std::{pin::Pin, ptr, string::String, vec::Vec}; +use std::{pin::Pin, string::String, vec::Vec}; // 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`. @@ -34,14 +34,6 @@ pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; // https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1 const DEFAULT_BUF_SIZE: usize = 8 * 1024; -/// Initializes a buffer if necessary. -/// -/// A buffer is currently always initialized. -#[inline] -unsafe fn initialize(_reader: &R, buf: &mut [u8]) { - unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) } -} - mod allow_std; pub use self::allow_std::AllowStdIo; diff --git a/futures-util/src/io/read_to_end.rs b/futures-util/src/io/read_to_end.rs index 919d7d13c7..82a36d2164 100644 --- a/futures-util/src/io/read_to_end.rs +++ b/futures-util/src/io/read_to_end.rs @@ -3,6 +3,7 @@ use futures_core::ready; use futures_core::task::{Context, Poll}; use futures_io::AsyncRead; use std::io; +use std::iter; use std::pin::Pin; use std::vec::Vec; @@ -55,12 +56,10 @@ pub(super) fn read_to_end_internal( let mut g = Guard { len: buf.len(), buf }; loop { if g.len == g.buf.len() { - unsafe { - g.buf.reserve(32); - let capacity = g.buf.capacity(); - g.buf.set_len(capacity); - super::initialize(&rd, &mut g.buf[g.len..]); - } + g.buf.reserve(32); + let spare_capacity = g.buf.capacity() - g.buf.len(); + // FIXME: switch to `Vec::resize` once rust-lang/rust#120050 is fixed + g.buf.extend(iter::repeat(0).take(spare_capacity)); } let buf = &mut g.buf[g.len..]; From 3d839541925ee6ae0b7f1dd9945ec5ea2f2d7515 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Wed, 16 Apr 2025 15:24:28 +0200 Subject: [PATCH 20/33] channel: Add recv (#2947) --- futures-channel/src/mpsc/mod.rs | 61 ++++++++++++++++++++++++++++++++- futures-channel/tests/mpsc.rs | 45 +++++++++++++++++++++++- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/futures-channel/src/mpsc/mod.rs b/futures-channel/src/mpsc/mod.rs index 7e954574c9..fd0eace49f 100644 --- a/futures-channel/src/mpsc/mod.rs +++ b/futures-channel/src/mpsc/mod.rs @@ -78,9 +78,11 @@ // happens-before semantics required for the acquire / release semantics used // by the queue structure. +use core::future::Future; use futures_core::stream::{FusedStream, Stream}; use futures_core::task::__internal::AtomicWaker; use futures_core::task::{Context, Poll, Waker}; +use futures_core::FusedFuture; use std::fmt; use std::pin::Pin; use std::sync::atomic::AtomicUsize; @@ -167,7 +169,7 @@ enum SendErrorKind { Disconnected, } -/// The error type returned from [`try_recv`](Receiver::try_recv). +/// Error returned by [`Receiver::try_recv`] or [`UnboundedReceiver::try_recv`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum TryRecvError { /// The channel is empty but not closed. @@ -177,6 +179,18 @@ pub enum TryRecvError { Closed, } +/// Error returned by the future returned by [`Receiver::recv()`] or [`UnboundedReceiver::recv()`]. +/// Received when the channel is empty and closed. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct RecvError; + +/// Future returned by [`Receiver::recv()`] or [`UnboundedReceiver::recv()`]. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Recv<'a, St: ?Sized> { + stream: &'a mut St, +} + impl fmt::Display for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_full() { @@ -189,6 +203,14 @@ impl fmt::Display for SendError { impl std::error::Error for SendError {} +impl fmt::Display for RecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "receive failed because channel is empty and closed") + } +} + +impl std::error::Error for RecvError {} + impl SendError { /// Returns `true` if this error is a result of the channel being full. pub fn is_full(&self) -> bool { @@ -985,6 +1007,12 @@ impl fmt::Debug for UnboundedSender { */ impl Receiver { + /// Waits for a message from the channel. + /// If the channel is empty and closed, returns [`RecvError`]. + pub fn recv(&mut self) -> Recv<'_, Self> { + Recv::new(self) + } + /// Closes the receiving half of a channel, without dropping it. /// /// This prevents any further messages from being sent on the channel while @@ -1127,6 +1155,31 @@ impl Stream for Receiver { } } +impl Unpin for Recv<'_, St> {} +impl<'a, St: ?Sized + Stream + Unpin> Recv<'a, St> { + fn new(stream: &'a mut St) -> Self { + Self { stream } + } +} + +impl FusedFuture for Recv<'_, St> { + fn is_terminated(&self) -> bool { + self.stream.is_terminated() + } +} + +impl Future for Recv<'_, St> { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match Pin::new(&mut self.stream).poll_next(cx) { + Poll::Ready(Some(msg)) => Poll::Ready(Ok(msg)), + Poll::Ready(None) => Poll::Ready(Err(RecvError)), + Poll::Pending => Poll::Pending, + } + } +} + impl Drop for Receiver { fn drop(&mut self) { // Drain the channel of all pending messages @@ -1170,6 +1223,12 @@ impl fmt::Debug for Receiver { } impl UnboundedReceiver { + /// Waits for a message from the channel. + /// If the channel is empty and closed, returns [`RecvError`]. + pub fn recv(&mut self) -> Recv<'_, Self> { + Recv::new(self) + } + /// Closes the receiving half of a channel, without dropping it. /// /// This prevents any further messages from being sent on the channel while diff --git a/futures-channel/tests/mpsc.rs b/futures-channel/tests/mpsc.rs index 5aaff45f3d..08f39eb160 100644 --- a/futures-channel/tests/mpsc.rs +++ b/futures-channel/tests/mpsc.rs @@ -4,7 +4,7 @@ use futures::future::{poll_fn, FutureExt}; use futures::sink::{Sink, SinkExt}; use futures::stream::{Stream, StreamExt}; use futures::task::{Context, Poll}; -use futures_channel::mpsc::TryRecvError; +use futures_channel::mpsc::{RecvError, TryRecvError}; use futures_test::task::{new_count_waker, noop_context}; use std::pin::pin; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -431,6 +431,49 @@ fn stress_poll_ready() { stress(16); } +#[test] +fn test_bounded_recv() { + let (dropped_tx, dropped_rx) = oneshot::channel(); + let (tx, mut rx) = mpsc::channel(1); + thread::spawn(move || { + block_on(async move { + send_one_two_three(tx).await; + dropped_tx.send(()).unwrap(); + }); + }); + + let res = block_on(async move { + let mut res = Vec::new(); + for _ in 0..3 { + res.push(rx.recv().await.unwrap()); + } + dropped_rx.await.unwrap(); + assert_eq!(rx.recv().await, Err(RecvError)); + res + }); + assert_eq!(res, [1, 2, 3]); +} + +#[test] +fn test_unbounded_recv() { + let (mut tx, mut rx) = mpsc::unbounded(); + + let res = block_on(async move { + let mut res = Vec::new(); + for i in 1..=3 { + tx.send(i).await.unwrap(); + } + drop(tx); + + for _ in 0..3 { + res.push(rx.recv().await.unwrap()); + } + assert_eq!(rx.recv().await, Err(RecvError)); + res + }); + assert_eq!(res, [1, 2, 3]); +} + #[test] fn try_send_1() { const N: usize = if cfg!(miri) { 100 } else { 3000 }; From a7156b5ea3ead148a4f5c5d4709fcb299813f5a1 Mon Sep 17 00:00:00 2001 From: Pavel Roskin <1317472+proski@users.noreply.github.com> Date: Fri, 2 May 2025 08:17:17 -0700 Subject: [PATCH 21/33] select: add missing space in panic message (#2952) --- futures-macro/src/select.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-macro/src/select.rs b/futures-macro/src/select.rs index ca83a87e4a..30f7008bc5 100644 --- a/futures-macro/src/select.rs +++ b/futures-macro/src/select.rs @@ -224,7 +224,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { } } else { quote! { - panic!("all futures in select! were completed,\ + panic!("all futures in select! were completed, \ but no `complete =>` handler was provided") } }; From 1b4424499e61c65003409c6282321f7498dd3a27 Mon Sep 17 00:00:00 2001 From: tison Date: Fri, 23 May 2025 22:06:24 +0800 Subject: [PATCH 22/33] chore: replace num_cpus with available_parallelism (#2946) Signed-off-by: tison --- futures-executor/Cargo.toml | 3 +-- futures-executor/src/thread_pool.rs | 12 +++--------- futures-util/Cargo.toml | 7 +++++-- futures-util/src/lock/mutex.rs | 4 ++-- .../stream/futures_unordered/ready_to_run_queue.rs | 2 +- .../src/stream/try_stream/try_for_each_concurrent.rs | 5 ++--- futures/tests/oneshot.rs | 8 ++++---- 7 files changed, 18 insertions(+), 23 deletions(-) diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index 53c29d984b..c41ca25b84 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -13,13 +13,12 @@ Executors for asynchronous tasks based on the futures-rs library. [features] default = ["std"] std = ["futures-core/std", "futures-task/std", "futures-util/std"] -thread-pool = ["std", "num_cpus"] +thread-pool = ["std"] [dependencies] futures-core = { path = "../futures-core", version = "0.3.31", default-features = false } futures-task = { path = "../futures-task", version = "0.3.31", default-features = false } futures-util = { path = "../futures-util", version = "0.3.31", default-features = false } -num_cpus = { version = "1.8.0", optional = true } [dev-dependencies] futures = { path = "../futures", features = ["thread-pool"] } diff --git a/futures-executor/src/thread_pool.rs b/futures-executor/src/thread_pool.rs index c4442e4eeb..774ab53ca2 100644 --- a/futures-executor/src/thread_pool.rs +++ b/futures-executor/src/thread_pool.rs @@ -6,7 +6,6 @@ use futures_task::{waker_ref, ArcWake}; use futures_task::{FutureObj, Spawn, SpawnError}; use futures_util::future::FutureExt; use std::boxed::Box; -use std::cmp; use std::fmt; use std::format; use std::io; @@ -190,13 +189,8 @@ impl ThreadPoolBuilder { /// /// See the other methods on this type for details on the defaults. pub fn new() -> Self { - Self { - pool_size: cmp::max(1, num_cpus::get()), - stack_size: 0, - name_prefix: None, - after_start: None, - before_stop: None, - } + let pool_size = thread::available_parallelism().map_or(1, |p| p.get()); + Self { pool_size, stack_size: 0, name_prefix: None, after_start: None, before_stop: None } } /// Set size of a future ThreadPool @@ -283,7 +277,7 @@ impl ThreadPoolBuilder { let before_stop = self.before_stop.clone(); let mut thread_builder = thread::Builder::new(); if let Some(ref name_prefix) = self.name_prefix { - thread_builder = thread_builder.name(format!("{}{}", name_prefix, counter)); + thread_builder = thread_builder.name(format!("{name_prefix}{counter}")); } if self.stack_size > 0 { thread_builder = thread_builder.stack_size(self.stack_size); diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 828c9766a4..b1a5e21acb 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -16,8 +16,8 @@ std = ["alloc", "futures-core/std", "futures-task/std", "slab/std"] alloc = ["futures-core/alloc", "futures-task/alloc", "slab"] async-await = [] async-await-macro = ["async-await", "futures-macro"] -compat = ["std", "futures_01"] -io-compat = ["io", "compat", "tokio-io"] +compat = ["std", "futures_01", "libc"] +io-compat = ["io", "compat", "tokio-io", "libc"] sink = ["futures-sink"] io = ["std", "futures-io", "memchr"] channel = ["std", "futures-channel"] @@ -48,6 +48,9 @@ tokio-io = { version = "0.1.9", optional = true } pin-project-lite = "0.2.6" spin = { version = "0.10.0", optional = true } +# INDIRECT DEPENDENCYS BUT ONLY FOR SPECIFIC MINIMAL VERSIONS +libc = { version = "0.2.26", optional = true } + [dev-dependencies] futures = { path = "../futures", features = ["async-await", "thread-pool"] } futures-test = { path = "../futures-test" } diff --git a/futures-util/src/lock/mutex.rs b/futures-util/src/lock/mutex.rs index c77048a786..0d31260873 100644 --- a/futures-util/src/lock/mutex.rs +++ b/futures-util/src/lock/mutex.rs @@ -550,8 +550,8 @@ mod tests { fn test_mutex_guard_debug_not_recurse() { let mutex = Mutex::new(42); let guard = mutex.try_lock().unwrap(); - let _ = format!("{:?}", guard); + let _ = format!("{guard:?}"); let guard = MutexGuard::map(guard, |n| n); - let _ = format!("{:?}", guard); + let _ = format!("{guard:?}"); } } diff --git a/futures-util/src/stream/futures_unordered/ready_to_run_queue.rs b/futures-util/src/stream/futures_unordered/ready_to_run_queue.rs index 6ffaf554dd..e35418dfa5 100644 --- a/futures-util/src/stream/futures_unordered/ready_to_run_queue.rs +++ b/futures-util/src/stream/futures_unordered/ready_to_run_queue.rs @@ -69,7 +69,7 @@ impl ReadyToRunQueue { return Dequeue::Data(tail); } - if self.head.load(Acquire) as *const _ != tail { + if !core::ptr::eq(self.head.load(Acquire), tail) { return Dequeue::Inconsistent; } diff --git a/futures-util/src/stream/try_stream/try_for_each_concurrent.rs b/futures-util/src/stream/try_stream/try_for_each_concurrent.rs index 62734c746b..271e03c2ba 100644 --- a/futures-util/src/stream/try_stream/try_for_each_concurrent.rs +++ b/futures-util/src/stream/try_stream/try_for_each_concurrent.rs @@ -1,6 +1,5 @@ use crate::stream::{FuturesUnordered, StreamExt}; use core::fmt; -use core::mem; use core::num::NonZeroUsize; use core::pin::Pin; use futures_core::future::{FusedFuture, Future}; @@ -98,7 +97,7 @@ where // Empty the stream and futures so that we know // the future has completed. this.stream.set(None); - drop(mem::replace(this.futures, FuturesUnordered::new())); + drop(core::mem::take(this.futures)); return Poll::Ready(Err(e)); } }; @@ -120,7 +119,7 @@ where // Empty the stream and futures so that we know // the future has completed. this.stream.set(None); - drop(mem::replace(this.futures, FuturesUnordered::new())); + drop(core::mem::take(this.futures)); return Poll::Ready(Err(e)); } } diff --git a/futures/tests/oneshot.rs b/futures/tests/oneshot.rs index 34b78a33fb..bc005f0688 100644 --- a/futures/tests/oneshot.rs +++ b/futures/tests/oneshot.rs @@ -68,11 +68,11 @@ fn oneshot_drop_rx() { #[test] fn oneshot_debug() { let (tx, rx) = oneshot::channel::(); - assert_eq!(format!("{:?}", tx), "Sender { complete: false }"); - assert_eq!(format!("{:?}", rx), "Receiver { complete: false }"); + assert_eq!(format!("{tx:?}"), "Sender { complete: false }"); + assert_eq!(format!("{rx:?}"), "Receiver { complete: false }"); drop(rx); - assert_eq!(format!("{:?}", tx), "Sender { complete: true }"); + assert_eq!(format!("{tx:?}"), "Sender { complete: true }"); let (tx, rx) = oneshot::channel::(); drop(tx); - assert_eq!(format!("{:?}", rx), "Receiver { complete: true }"); + assert_eq!(format!("{rx:?}"), "Receiver { complete: true }"); } From fe7c535c31f8b98cbd1e34add76cfb07e379ce24 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 19 Jul 2025 17:37:41 +0900 Subject: [PATCH 23/33] Fix unused_parens warning ``` error: unnecessary parentheses around type --> futures-util/src/future/future/remote_handle.rs:72:57 | 72 | type SendMsg = Result<::Output, Box<(dyn Any + Send + 'static)>>; | ^ ^ | = note: `-D unused-parens` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(unused_parens)]` help: remove these parentheses | 72 - type SendMsg = Result<::Output, Box<(dyn Any + Send + 'static)>>; 72 + type SendMsg = Result<::Output, Box>; | ``` --- futures-util/src/future/future/remote_handle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-util/src/future/future/remote_handle.rs b/futures-util/src/future/future/remote_handle.rs index 6c4b7698ae..4aacd2d6be 100644 --- a/futures-util/src/future/future/remote_handle.rs +++ b/futures-util/src/future/future/remote_handle.rs @@ -69,7 +69,7 @@ impl Future for RemoteHandle { } } -type SendMsg = Result<::Output, Box<(dyn Any + Send + 'static)>>; +type SendMsg = Result<::Output, Box>; pin_project! { /// A future which sends its output to the corresponding `RemoteHandle`. From 3b05f3a01f79d1293830b4f71910d5f416370852 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 19 Jul 2025 17:39:01 +0900 Subject: [PATCH 24/33] Ignore dead_code lint on Fn1 trait ``` error: trait `Fn1` is never used --> futures-util/src/fns.rs:34:11 | 34 | pub trait Fn1: FnMut1 { | ^^^ | = note: `-D dead-code` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(dead_code)]` ``` --- futures-util/src/fns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-util/src/fns.rs b/futures-util/src/fns.rs index 37ee03e6df..fc3096a5da 100644 --- a/futures-util/src/fns.rs +++ b/futures-util/src/fns.rs @@ -30,7 +30,7 @@ where } // Not used, but present for completeness -#[allow(unreachable_pub)] +#[allow(dead_code, unreachable_pub)] pub trait Fn1: FnMut1 { fn call(&self, arg: A) -> Self::Output; } From bb315a032a88932d108d3d8e43a2d06faaf0f882 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 19 Jul 2025 17:46:15 +0900 Subject: [PATCH 25/33] ci: Test big-endian target (s390x Linux) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8079e21ee8..4b86625c96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,8 @@ jobs: target: armv5te-unknown-linux-gnueabi - os: ubuntu-latest target: i686-unknown-linux-gnu + - os: ubuntu-latest + target: s390x-unknown-linux-gnu runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: From de3be4f85ed7d46bf664fbc79801be8d8f5c9ee3 Mon Sep 17 00:00:00 2001 From: John Starks Date: Sat, 19 Jul 2025 02:01:30 -0700 Subject: [PATCH 26/33] futures-util: make `Mutex::new()` const (#2956) This builds with the MSRV (1.68) and is convenient for creating `static` mutexes. This does bind the implementation to never allocate in `new` in the future, but that seems like a desirable property anyway. Note that this also requires updating slab to 0.4.7, which is the first version that supports const `Slab::new()`. --- futures-util/Cargo.toml | 2 +- futures-util/src/lock/mutex.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index b1a5e21acb..1a5061ad5d 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -41,7 +41,7 @@ futures-channel = { path = "../futures-channel", version = "0.3.31", default-fea futures-io = { path = "../futures-io", version = "0.3.31", default-features = false, features = ["std"], optional = true } futures-sink = { path = "../futures-sink", version = "0.3.31", default-features = false, optional = true } futures-macro = { path = "../futures-macro", version = "=0.3.31", default-features = false, optional = true } -slab = { version = "0.4.2", default-features = false, optional = true } +slab = { version = "0.4.7", default-features = false, optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } tokio-io = { version = "0.1.9", optional = true } diff --git a/futures-util/src/lock/mutex.rs b/futures-util/src/lock/mutex.rs index 0d31260873..ac0c0ea060 100644 --- a/futures-util/src/lock/mutex.rs +++ b/futures-util/src/lock/mutex.rs @@ -73,7 +73,7 @@ const HAS_WAITERS: usize = 1 << 1; impl Mutex { /// Creates a new futures-aware mutex. - pub fn new(t: T) -> Self { + pub const fn new(t: T) -> Self { Self { state: AtomicUsize::new(0), waiters: StdMutex::new(Slab::new()), From 242e4d8dbd56a5c1d0b203ed71fe11f60bb7bee9 Mon Sep 17 00:00:00 2001 From: Paul-Nicolas Madelaine Date: Tue, 20 Jan 2026 16:09:34 +0100 Subject: [PATCH 27/33] Fix documentation of `BiLock::lock` (#2971) --- futures-util/src/lock/bilock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/futures-util/src/lock/bilock.rs b/futures-util/src/lock/bilock.rs index a89678e05f..7c740f878f 100644 --- a/futures-util/src/lock/bilock.rs +++ b/futures-util/src/lock/bilock.rs @@ -139,7 +139,6 @@ impl BiLock { /// /// This function consumes the `BiLock` and returns a sentinel future, /// `BiLockAcquire`. The returned future will resolve to - /// `BiLockAcquired` which represents a locked lock similarly to /// `BiLockGuard`. /// /// Note that the returned future will never resolve to an error. From c0994f09c3daca89ecfea163fd4295ae9c8aa870 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 20 Jan 2026 23:56:44 +0900 Subject: [PATCH 28/33] Fix rustdoc::broken_intra_doc_links warning ``` error: unresolved link to `Box` --> futures-util/src/future/always_ready.rs:43:83 | 43 | /// This is particularly useful in avoiding a heap allocation when an API needs [`Box>`], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `Box` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `-D rustdoc::broken-intra-doc-links` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(rustdoc::broken_intra_doc_links)]` error: unresolved link to `stream.take` --> futures-util/src/stream/repeat_with.rs:43:7 | 43 | /// [`stream.take()`], in order to make them finite. | ^^^^^^^^^^^^^ no item named `stream.take` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `stream.repeat` --> futures-util/src/stream/repeat_with.rs:47:11 | 47 | /// the [`stream.repeat()`] function. | ^^^^^^^^^^^^^^^ no item named `stream.repeat` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `futures-util::stream::select` --> futures-util/src/stream/select_with_strategy.rs:120:46 | 120 | /// Note: this special case is provided by [`futures-util::stream::select`]. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `futures-util` in scope ``` --- futures-util/src/future/always_ready.rs | 2 +- futures-util/src/stream/repeat_with.rs | 4 ++-- futures-util/src/stream/select_with_strategy.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/futures-util/src/future/always_ready.rs b/futures-util/src/future/always_ready.rs index 28625e7272..422268857a 100644 --- a/futures-util/src/future/always_ready.rs +++ b/futures-util/src/future/always_ready.rs @@ -40,7 +40,7 @@ impl T> Future for AlwaysReady { /// Creates a future that is always immediately ready with a value. /// -/// This is particularly useful in avoiding a heap allocation when an API needs [`Box>`], +/// This is particularly useful in avoiding a heap allocation when an API needs `Box>`, /// as [`AlwaysReady`] does not have to store a boolean for `is_finished`. /// /// # Examples diff --git a/futures-util/src/stream/repeat_with.rs b/futures-util/src/stream/repeat_with.rs index a482510705..2190eb9453 100644 --- a/futures-util/src/stream/repeat_with.rs +++ b/futures-util/src/stream/repeat_with.rs @@ -40,11 +40,11 @@ impl A> FusedStream for RepeatWith { /// The `repeat_with()` function calls the repeater over and over again. /// /// Infinite stream like `repeat_with()` are often used with adapters like -/// [`stream.take()`], in order to make them finite. +/// [`stream.take()`](crate::stream::StreamExt::take), in order to make them finite. /// /// If the element type of the stream you need implements [`Clone`], and /// it is OK to keep the source element in memory, you should instead use -/// the [`stream.repeat()`] function. +/// the [`stream::repeat()`](crate::stream::repeat) function. /// /// # Examples /// diff --git a/futures-util/src/stream/select_with_strategy.rs b/futures-util/src/stream/select_with_strategy.rs index 4e19873af7..d2b49d588f 100644 --- a/futures-util/src/stream/select_with_strategy.rs +++ b/futures-util/src/stream/select_with_strategy.rs @@ -116,7 +116,7 @@ pin_project! { /// /// ### Round Robin /// This example shows how to select from both streams round robin. -/// Note: this special case is provided by [`futures-util::stream::select`]. +/// Note: this special case is provided by [`stream::select`](crate::stream::select). /// /// ```rust /// # futures::executor::block_on(async { From 52d1faf7a6a7e559c64b663d327ff4f509ca3d72 Mon Sep 17 00:00:00 2001 From: Caio Date: Tue, 20 Jan 2026 12:09:58 -0300 Subject: [PATCH 29/33] Add `#[clippy::has_significant_drop]` to guards (#2967) --- futures-util/src/lock/mutex.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/futures-util/src/lock/mutex.rs b/futures-util/src/lock/mutex.rs index ac0c0ea060..24acb0b727 100644 --- a/futures-util/src/lock/mutex.rs +++ b/futures-util/src/lock/mutex.rs @@ -276,6 +276,7 @@ impl Drop for OwnedMutexLockFuture { /// An RAII guard returned by the `lock_owned` and `try_lock_owned` methods. /// When this structure is dropped (falls out of scope), the lock will be /// unlocked. +#[clippy::has_significant_drop] pub struct OwnedMutexGuard { mutex: Arc>, } @@ -385,6 +386,7 @@ impl Drop for MutexLockFuture<'_, T> { /// An RAII guard returned by the `lock` and `try_lock` methods. /// When this structure is dropped (falls out of scope), the lock will be /// unlocked. +#[clippy::has_significant_drop] pub struct MutexGuard<'a, T: ?Sized> { mutex: &'a Mutex, } @@ -446,6 +448,7 @@ impl DerefMut for MutexGuard<'_, T> { /// An RAII guard returned by the `MutexGuard::map` and `MappedMutexGuard::map` methods. /// When this structure is dropped (falls out of scope), the lock will be unlocked. +#[clippy::has_significant_drop] pub struct MappedMutexGuard<'a, T: ?Sized, U: ?Sized> { mutex: &'a Mutex, value: *mut U, From e1c3ea49233d30387008799c136a08ce1c80281f Mon Sep 17 00:00:00 2001 From: Paul IP <52645166+paulip1792@users.noreply.github.com> Date: Wed, 21 Jan 2026 21:58:28 +0800 Subject: [PATCH 30/33] perf: improve AtomicWaker::wake performance (#2983) --- futures-core/src/task/__internal/atomic_waker.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/futures-core/src/task/__internal/atomic_waker.rs b/futures-core/src/task/__internal/atomic_waker.rs index 3b82fb7cc8..e87943be0c 100644 --- a/futures-core/src/task/__internal/atomic_waker.rs +++ b/futures-core/src/task/__internal/atomic_waker.rs @@ -385,7 +385,8 @@ impl AtomicWaker { let waker = unsafe { (*self.waker.get()).take() }; // Release the lock - self.state.fetch_and(!WAKING, Release); + let old_state = self.state.swap(WAITING, Release); + debug_assert!(old_state == WAKING); waker } From 052b51aa1f775166a672e66c57a882ec1932e21e Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 15 Feb 2026 12:38:14 +0900 Subject: [PATCH 31/33] Bump MSRV of utility crates to 1.71 ``` error: package `syn v2.0.115` cannot be built because it requires rustc 1.71 or newer, while the currently active rustc version is 1.68.2 ``` --- .github/workflows/ci.yml | 2 +- README.md | 2 +- futures-channel/Cargo.toml | 2 +- futures-channel/README.md | 2 +- futures-executor/Cargo.toml | 2 +- futures-executor/README.md | 2 +- futures-macro/Cargo.toml | 2 +- futures-task/Cargo.toml | 2 +- futures-task/README.md | 2 +- futures-test/Cargo.toml | 2 +- futures-test/README.md | 2 +- futures-util/Cargo.toml | 2 +- futures-util/README.md | 2 +- futures/Cargo.toml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b86625c96..eacb94a08e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: rust: # This is the minimum Rust version supported by futures, futures-util, futures-task, futures-macro, futures-executor, futures-channel, futures-test. # When updating this, the reminder to update the minimum required version in README.md and Cargo.toml. - - '1.68' + - '1.71' runs-on: ubuntu-latest timeout-minutes: 60 steps: diff --git a/README.md b/README.md index a2c622a831..0a1d5a3565 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Add this to your `Cargo.toml`: futures = "0.3" ``` -The current `futures` requires Rust 1.68 or later. +The current `futures` requires Rust 1.71 or later. ### Feature `std` diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml index ce12dd93b5..5a0c4bac43 100644 --- a/futures-channel/Cargo.toml +++ b/futures-channel/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-channel" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-channel/README.md b/futures-channel/README.md index f386839289..2292652860 100644 --- a/futures-channel/README.md +++ b/futures-channel/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-channel = "0.3" ``` -The current `futures-channel` requires Rust 1.68 or later. +The current `futures-channel` requires Rust 1.71 or later. ## License diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index c41ca25b84..68a9d4cc53 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-executor" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-executor/README.md b/futures-executor/README.md index b3906543b0..b7e1d8bdbf 100644 --- a/futures-executor/README.md +++ b/futures-executor/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-executor = "0.3" ``` -The current `futures-executor` requires Rust 1.68 or later. +The current `futures-executor` requires Rust 1.71 or later. ## License diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml index cbf4668e12..4c2fecedca 100644 --- a/futures-macro/Cargo.toml +++ b/futures-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-macro" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml index 2d1bd72112..14c0dd8837 100644 --- a/futures-task/Cargo.toml +++ b/futures-task/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-task" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-task/README.md b/futures-task/README.md index 40296f0332..64d582a22d 100644 --- a/futures-task/README.md +++ b/futures-task/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-task = "0.3" ``` -The current `futures-task` requires Rust 1.68 or later. +The current `futures-task` requires Rust 1.71 or later. ## License diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml index 07b5eab716..7b19d7e496 100644 --- a/futures-test/Cargo.toml +++ b/futures-test/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-test" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-test/README.md b/futures-test/README.md index 407ec0e291..035010f5e9 100644 --- a/futures-test/README.md +++ b/futures-test/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-test = "0.3" ``` -The current `futures-test` requires Rust 1.68 or later. +The current `futures-test` requires Rust 1.71 or later. ## License diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 1a5061ad5d..e576cb3d9c 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -2,7 +2,7 @@ name = "futures-util" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" diff --git a/futures-util/README.md b/futures-util/README.md index d4bcad3406..91d98c8f89 100644 --- a/futures-util/README.md +++ b/futures-util/README.md @@ -11,7 +11,7 @@ Add this to your `Cargo.toml`: futures-util = "0.3" ``` -The current `futures-util` requires Rust 1.68 or later. +The current `futures-util` requires Rust 1.71 or later. ## License diff --git a/futures/Cargo.toml b/futures/Cargo.toml index e858118bbf..0d5cb4c7de 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -2,7 +2,7 @@ name = "futures" version = "0.3.31" edition = "2018" -rust-version = "1.68" +rust-version = "1.71" license = "MIT OR Apache-2.0" readme = "../README.md" keywords = ["futures", "async", "future"] From 8fc935b1162b0ee026219701beae72e59df389da Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 15 Feb 2026 21:48:28 +0900 Subject: [PATCH 32/33] Add comments on rust-version field in Cargo.toml --- futures-channel/Cargo.toml | 1 + futures-core/Cargo.toml | 1 + futures-executor/Cargo.toml | 1 + futures-io/Cargo.toml | 1 + futures-macro/Cargo.toml | 1 + futures-sink/Cargo.toml | 1 + futures-task/Cargo.toml | 1 + futures-test/Cargo.toml | 1 + futures-util/Cargo.toml | 1 + futures/Cargo.toml | 1 + 10 files changed, 10 insertions(+) diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml index 5a0c4bac43..00e833e665 100644 --- a/futures-channel/Cargo.toml +++ b/futures-channel/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-channel" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-core/Cargo.toml b/futures-core/Cargo.toml index a7d710e6a5..f98d49996d 100644 --- a/futures-core/Cargo.toml +++ b/futures-core/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-core" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index 68a9d4cc53..534cc837e4 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-executor" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-io/Cargo.toml b/futures-io/Cargo.toml index e5320d4281..63922f6b45 100644 --- a/futures-io/Cargo.toml +++ b/futures-io/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-io" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml index 4c2fecedca..c88a86612d 100644 --- a/futures-macro/Cargo.toml +++ b/futures-macro/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-macro" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-sink/Cargo.toml b/futures-sink/Cargo.toml index 21f8259155..2f7a314cba 100644 --- a/futures-sink/Cargo.toml +++ b/futures-sink/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-sink" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml index 14c0dd8837..f98855c296 100644 --- a/futures-task/Cargo.toml +++ b/futures-task/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-task" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml index 7b19d7e496..ea2decda2d 100644 --- a/futures-test/Cargo.toml +++ b/futures-test/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-test" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index e576cb3d9c..c576c2250e 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -2,6 +2,7 @@ name = "futures-util" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 0d5cb4c7de..508e23ba0e 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -2,6 +2,7 @@ name = "futures" version = "0.3.31" edition = "2018" +# NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" license = "MIT OR Apache-2.0" readme = "../README.md" From 1fd09568ac2dae0000c1483f5238f806ce9acec0 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 15 Feb 2026 22:20:54 +0900 Subject: [PATCH 33/33] Release 0.3.32 --- CHANGELOG.md | 17 +++++++++++++++++ futures-channel/Cargo.toml | 6 +++--- futures-core/Cargo.toml | 2 +- futures-executor/Cargo.toml | 8 ++++---- futures-io/Cargo.toml | 2 +- futures-macro/Cargo.toml | 2 +- futures-sink/Cargo.toml | 2 +- futures-task/Cargo.toml | 2 +- futures-test/Cargo.toml | 16 ++++++++-------- futures-util/Cargo.toml | 14 +++++++------- futures/Cargo.toml | 16 ++++++++-------- 11 files changed, 52 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a14e0bb9b7..d0aaef01c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,23 @@ Releases may yanked if there is a security bug, a soundness bug, or a regression Note: In this file, do not use the hard wrap in the middle of a sentence for compatibility with GitHub comment style markdown rendering. --> +# 0.3.32 - 2026-02-15 + +* Bump MSRV of utility crates to 1.71. (#2989) +* Soft-deprecate `ready!` macro in favor of `std::task::ready!` added in Rust 1.64 (#2925) +* Soft-deprecate `pin_mut!` macro in favor of `std::pin::pin!` added in Rust 1.68 (#2929) +* Add `FuturesOrdered::clear` (#2927) +* Add `mpsc::*Receiver::recv` (#2947) +* Add `mpsc::*Receiver::try_recv` and deprecate `mpsc::*Receiver::::try_next` (#2944) +* Implement `FusedStream` for `sink::With` (#2948) +* Add `no_std` support for `shared` (#2868) +* Make `Mutex::new()` const (#2956) +* Add `#[clippy::has_significant_drop]` to guards (#2967) +* Remove dependency to `pin-utils` (#2929) +* Remove dependency on `num_cpus` (#2946) +* Performance improvements (#2983) +* Documentation improvements (#2925, #2926, #2940, #2971) + # 0.3.31 - 2024-10-05 * Fix use after free of task in `FuturesUnordered` when dropped future panics (#2886) diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml index 00e833e665..3d699c8f50 100644 --- a/futures-channel/Cargo.toml +++ b/futures-channel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" @@ -23,8 +23,8 @@ unstable = [] cfg-target-has-atomic = [] [dependencies] -futures-core = { path = "../futures-core", version = "0.3.31", default-features = false } -futures-sink = { path = "../futures-sink", version = "0.3.31", default-features = false, optional = true } +futures-core = { path = "../futures-core", version = "0.3.32", default-features = false } +futures-sink = { path = "../futures-sink", version = "0.3.32", default-features = false, optional = true } [dev-dependencies] futures = { path = "../futures", default-features = true } diff --git a/futures-core/Cargo.toml b/futures-core/Cargo.toml index f98d49996d..273665b637 100644 --- a/futures-core/Cargo.toml +++ b/futures-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-core" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml index 534cc837e4..c4a3921ca7 100644 --- a/futures-executor/Cargo.toml +++ b/futures-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" @@ -17,9 +17,9 @@ std = ["futures-core/std", "futures-task/std", "futures-util/std"] thread-pool = ["std"] [dependencies] -futures-core = { path = "../futures-core", version = "0.3.31", default-features = false } -futures-task = { path = "../futures-task", version = "0.3.31", default-features = false } -futures-util = { path = "../futures-util", version = "0.3.31", default-features = false } +futures-core = { path = "../futures-core", version = "0.3.32", default-features = false } +futures-task = { path = "../futures-task", version = "0.3.32", default-features = false } +futures-util = { path = "../futures-util", version = "0.3.32", default-features = false } [dev-dependencies] futures = { path = "../futures", features = ["thread-pool"] } diff --git a/futures-io/Cargo.toml b/futures-io/Cargo.toml index 63922f6b45..1db5798776 100644 --- a/futures-io/Cargo.toml +++ b/futures-io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-io" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml index c88a86612d..7d9e33e18a 100644 --- a/futures-macro/Cargo.toml +++ b/futures-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" diff --git a/futures-sink/Cargo.toml b/futures-sink/Cargo.toml index 2f7a314cba..3613f0bb67 100644 --- a/futures-sink/Cargo.toml +++ b/futures-sink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and core-msrv job in .github/workflows/ci.yml rust-version = "1.36" diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml index f98855c296..80d963320e 100644 --- a/futures-task/Cargo.toml +++ b/futures-task/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-task" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml index ea2decda2d..dc891fa946 100644 --- a/futures-test/Cargo.toml +++ b/futures-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-test" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" @@ -12,13 +12,13 @@ Common utilities for testing components built off futures-rs. """ [dependencies] -futures-core = { version = "0.3.31", path = "../futures-core", default-features = false } -futures-task = { version = "0.3.31", path = "../futures-task", default-features = false } -futures-io = { version = "0.3.31", path = "../futures-io", default-features = false } -futures-util = { version = "0.3.31", path = "../futures-util", default-features = false } -futures-executor = { version = "0.3.31", path = "../futures-executor", default-features = false } -futures-sink = { version = "0.3.31", path = "../futures-sink", default-features = false } -futures-macro = { version = "=0.3.31", path = "../futures-macro", default-features = false } +futures-core = { version = "0.3.32", path = "../futures-core", default-features = false } +futures-task = { version = "0.3.32", path = "../futures-task", default-features = false } +futures-io = { version = "0.3.32", path = "../futures-io", default-features = false } +futures-util = { version = "0.3.32", path = "../futures-util", default-features = false } +futures-executor = { version = "0.3.32", path = "../futures-executor", default-features = false } +futures-sink = { version = "0.3.32", path = "../futures-sink", default-features = false } +futures-macro = { version = "=0.3.32", path = "../futures-macro", default-features = false } pin-project = "1.0.11" [dev-dependencies] diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index c576c2250e..7915dfa120 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-util" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" @@ -36,12 +36,12 @@ write-all-vectored = ["io"] cfg-target-has-atomic = [] [dependencies] -futures-core = { path = "../futures-core", version = "0.3.31", default-features = false } -futures-task = { path = "../futures-task", version = "0.3.31", default-features = false } -futures-channel = { path = "../futures-channel", version = "0.3.31", default-features = false, features = ["std"], optional = true } -futures-io = { path = "../futures-io", version = "0.3.31", default-features = false, features = ["std"], optional = true } -futures-sink = { path = "../futures-sink", version = "0.3.31", default-features = false, optional = true } -futures-macro = { path = "../futures-macro", version = "=0.3.31", default-features = false, optional = true } +futures-core = { path = "../futures-core", version = "0.3.32", default-features = false } +futures-task = { path = "../futures-task", version = "0.3.32", default-features = false } +futures-channel = { path = "../futures-channel", version = "0.3.32", default-features = false, features = ["std"], optional = true } +futures-io = { path = "../futures-io", version = "0.3.32", default-features = false, features = ["std"], optional = true } +futures-sink = { path = "../futures-sink", version = "0.3.32", default-features = false, optional = true } +futures-macro = { path = "../futures-macro", version = "=0.3.32", default-features = false, optional = true } slab = { version = "0.4.7", default-features = false, optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 508e23ba0e..fcebf0cc76 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures" -version = "0.3.31" +version = "0.3.32" edition = "2018" # NB: Sync with "Usage" section in README.md and util-msrv job in .github/workflows/ci.yml rust-version = "1.71" @@ -16,13 +16,13 @@ composability, and iterator-like interfaces. categories = ["asynchronous"] [dependencies] -futures-core = { path = "../futures-core", version = "0.3.31", default-features = false } -futures-task = { path = "../futures-task", version = "0.3.31", default-features = false } -futures-channel = { path = "../futures-channel", version = "0.3.31", default-features = false, features = ["sink"] } -futures-executor = { path = "../futures-executor", version = "0.3.31", default-features = false, optional = true } -futures-io = { path = "../futures-io", version = "0.3.31", default-features = false } -futures-sink = { path = "../futures-sink", version = "0.3.31", default-features = false } -futures-util = { path = "../futures-util", version = "0.3.31", default-features = false, features = ["sink"] } +futures-core = { path = "../futures-core", version = "0.3.32", default-features = false } +futures-task = { path = "../futures-task", version = "0.3.32", default-features = false } +futures-channel = { path = "../futures-channel", version = "0.3.32", default-features = false, features = ["sink"] } +futures-executor = { path = "../futures-executor", version = "0.3.32", default-features = false, optional = true } +futures-io = { path = "../futures-io", version = "0.3.32", default-features = false } +futures-sink = { path = "../futures-sink", version = "0.3.32", default-features = false } +futures-util = { path = "../futures-util", version = "0.3.32", default-features = false, features = ["sink"] } [dev-dependencies] futures-executor = { path = "../futures-executor", features = ["thread-pool"] }