diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 79a8d7d53f..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.rs] -end_of_line = lf -insert_final_newline = true -charset = utf-8 -indent_style = space -indent_size = 4 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 576e3d671c..0000000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,2 +0,0 @@ -# Cargo fmt all code -dd019055ef5bf4309f15db934407e202caf52e14 diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 996bbcfb2f..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -updates: - - package-ecosystem: cargo - directory: / - schedule: - interval: weekly - commit-message: - prefix: '' - labels: [] - - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - commit-message: - prefix: '' - labels: [] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 9f270cc368..0000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,329 +0,0 @@ -name: CI - -permissions: - contents: read - -on: - pull_request: - push: - branches: - - master - - '[0-9]+.[0-9]+' - schedule: - - cron: '0 2 * * 0' - -env: - CARGO_INCREMENTAL: 0 - CARGO_NET_GIT_FETCH_WITH_CLI: true - CARGO_NET_RETRY: 10 - CARGO_TERM_COLOR: always - RUST_BACKTRACE: 1 - RUSTDOCFLAGS: -D warnings - RUSTFLAGS: -D warnings - RUSTUP_MAX_RETRIES: 10 - -defaults: - run: - shell: bash - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} - cancel-in-progress: true - -jobs: - test: - name: cargo test - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - - os: macos-latest - - os: windows-latest - - os: ubuntu-24.04-arm - - os: ubuntu-24.04-arm - target: armv7-unknown-linux-gnueabihf - - os: ubuntu-latest - 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: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - 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 - - core-msrv: - name: cargo +${{ matrix.rust }} build (futures-{core, io, sink}) - strategy: - matrix: - rust: - # This is the minimum Rust version supported by futures-core, futures-io, futures-sink. - # When updating this, the reminder to update the minimum required version in README.md and Cargo.toml. - - '1.36' - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install 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 - uses: taiki-e/install-action@cargo-hack - # remove dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866 - - run: cargo hack --remove-dev-deps --workspace - # Check no-default-features - - run: | - cargo hack build --workspace --ignore-private --no-default-features \ - --exclude futures --exclude futures-util --exclude futures-task --exclude futures-macro --exclude futures-executor --exclude futures-channel --exclude futures-test - # Check alloc feature - - run: | - cargo hack build --workspace --ignore-private --no-default-features --features alloc --ignore-unknown-features \ - --exclude futures --exclude futures-util --exclude futures-task --exclude futures-macro --exclude futures-executor --exclude futures-channel --exclude futures-test - # Check std feature - - run: | - cargo hack build --workspace --ignore-private --no-default-features --features std \ - --exclude futures --exclude futures-util --exclude futures-task --exclude futures-macro --exclude futures-executor --exclude futures-channel --exclude futures-test - - util-msrv: - name: cargo +${{ matrix.rust }} build - strategy: - matrix: - 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' - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install 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 - - run: cargo hack --remove-dev-deps --workspace - # Check default features - - run: cargo hack build --workspace --ignore-private - # Check no-default-features - - run: cargo hack build --workspace --exclude futures-test --ignore-private --no-default-features - # Check alloc feature - - run: cargo hack build --workspace --exclude futures-test --ignore-private --no-default-features --features alloc --ignore-unknown-features - # Check std feature - - run: cargo hack build --workspace --ignore-private --no-default-features --features std --ignore-unknown-features - # Check compat feature (futures, futures-util) - # Exclude io-compat feature because the MSRV when it is enabled depends on the MSRV of tokio 0.1. - - run: cargo hack build -p futures -p futures-util --no-default-features --features std,compat - # Check thread-pool feature (futures, futures-executor) - - run: cargo hack build -p futures -p futures-executor --no-default-features --features std,thread-pool - - build: - name: cargo +${{ matrix.rust }} build - strategy: - fail-fast: false - matrix: - rust: - - stable - - beta - - nightly - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install 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 - - run: cargo build --tests --features default,thread-pool,io-compat --manifest-path futures/Cargo.toml - - minimal-versions: - name: cargo minimal-versions build - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - uses: taiki-e/github-actions/install-rust@nightly - - name: Install cargo-hack - uses: taiki-e/install-action@cargo-hack - - name: Install cargo-minimal-versions - uses: taiki-e/install-action@cargo-minimal-versions - - run: cargo minimal-versions build --workspace --ignore-private --all-features - - no-std: - name: cargo build --target ${{ matrix.target }} - strategy: - fail-fast: false - matrix: - # thumbv7m-none-eabi supports atomic CAS. - # thumbv6m-none-eabi supports atomic, but not atomic CAS. - target: - - thumbv7m-none-eabi - - thumbv6m-none-eabi - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - 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 - - run: cargo hack --remove-dev-deps --workspace - - run: | - cargo hack build --manifest-path futures/tests/no-std/Cargo.toml \ - --each-feature --optional-deps \ - --target ${{ matrix.target }} - - run: | - cargo hack build --workspace --ignore-private \ - --exclude futures-test --exclude futures-macro \ - --no-default-features \ - --target ${{ matrix.target }} - - run: | - cargo hack build --workspace --ignore-private \ - --exclude futures-test --exclude futures-macro \ - --no-default-features --features alloc --ignore-unknown-features \ - --target ${{ matrix.target }} - - run: | - cargo hack build --workspace --ignore-private \ - --exclude futures-test --exclude futures-macro \ - --no-default-features --features async-await,alloc --ignore-unknown-features \ - --target ${{ matrix.target }} - - bench: - name: cargo bench - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - uses: taiki-e/github-actions/install-rust@nightly - - run: cargo bench --workspace - - run: cargo bench --manifest-path futures-util/Cargo.toml --features=bilock,unstable - - features: - name: cargo hack check --feature-powerset - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - 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 - # * `--feature-powerset` - run for the feature powerset of the package - # * `--depth 2` - limit the max number of simultaneous feature flags of `--feature-powerset` - # * `--no-dev-deps` - build without dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866 - # * `--exclude futures-test` - futures-test cannot be compiled with no-default features - # * `--features unstable` - some features cannot be compiled without this feature - # * `--ignore-unknown-features` - some crates doesn't have 'unstable' feature - - run: | - cargo hack check \ - --feature-powerset --depth 2 --no-dev-deps \ - --workspace --exclude futures-test \ - --features unstable --ignore-unknown-features - - miri: - name: cargo miri test - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - 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 - RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} -Z randomize-layout - RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout - # This test is expected to leak. - - run: cargo miri test --workspace --all-features --test stream_futures_unordered -- panic_on_drop_fut - env: - MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks - RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} -Z randomize-layout - RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout - - san: - name: cargo test -Z sanitizer=${{ matrix.sanitizer }} - strategy: - fail-fast: false - matrix: - sanitizer: - - address - - memory - - thread - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - 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. - - run: cargo -Z build-std test --workspace --all-features --target x86_64-unknown-linux-gnu --lib --tests --exclude futures-macro -- --skip panic_on_drop_fut - env: - # TODO: Once `cfg(sanitize = "..")` is stable, replace - # `cfg(futures_sanitizer)` with `cfg(sanitize = "..")` and remove - # `--cfg futures_sanitizer`. - RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z sanitizer=${{ matrix.sanitizer }} --cfg futures_sanitizer - - clippy: - name: cargo clippy - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - uses: taiki-e/github-actions/install-rust@stable - with: - component: clippy - - run: cargo clippy --workspace --all-features --lib --bins --tests --examples - - fmt: - name: cargo fmt - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - uses: taiki-e/github-actions/install-rust@stable - with: - component: rustfmt - - run: cargo fmt --all -- --check - - docs: - name: cargo doc - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: taiki-e/checkout-action@v1 - - name: Install Rust - uses: taiki-e/github-actions/install-rust@nightly - - run: cargo doc --workspace --no-deps --all-features - env: - RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} --cfg docsrs diff --git a/.gitignore b/.gitignore index de02da3f96..e6fd941844 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -target -**/*.rs.bk -Cargo.lock _site .sass-cache -.idea -.DS_Store +.jekyll-metadata +target +Cargo.lock diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index 2a79d9274a..0000000000 --- a/.rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -use_small_heuristics = "Max" -edition = "2018" diff --git a/404.html b/404.html new file mode 100644 index 0000000000..c472b4ea0a --- /dev/null +++ b/404.html @@ -0,0 +1,24 @@ +--- +layout: default +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index a14e0bb9b7..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,886 +0,0 @@ -# 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) -* Fix soundness bug in `task::waker_ref` (#2830) - This is a breaking change but allowed because it is soundness bug fix. -* Fix bugs in `AsyncBufRead::read_line` and `AsyncBufReadExt::lines` (#2884) -* Fix parsing issue in `select!`/`select_biased!` (#2832) - This is technically a breaking change as it will now reject a very odd undocumented syntax that was previously accidentally accepted. -* Work around issue due to upstream `Waker::will_wake` change (#2865) -* Add `stream::Iter::{get_ref,get_mut,into_inner}` (#2875) -* Add `future::AlwaysReady` (#2825) -* Relax trait bound on non-constructor methods of `io::{BufReader,BufWriter}` (#2848) - -# 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) -* Improve support for targets without atomic CAS (#2811) -* Remove build scripts (#2811) - -# 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) -* Fix `Sync` impl of `FuturesUnordered` (#2788) -* Fix infinite loop caused by invalid UTF-8 bytes (#2785) -* Fix build error with -Z minimal-versions (#2761) - -# 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) -* Make `BiLock` strict-provenance compatible (#2716) - -# 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) -* Implement `FusedStream` for all streams in `ReadyChunks` (#2693) -* Fix bug in `FuturesOrdered::push_front` (#2664) -* Remove `Fut::Output: Clone` bounds from some `Shared` methods (#2662) -* Remove `T: Debug` bounds from `Debug` implementations of `mpsc` and `oneshot` types (#2666, #2667) - -# 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) -* Add `Mutex::lock_owned` and `Mutex::try_lock_owned` (#2571) -* Add `io::copy_buf_abortable` (#2507) -* Remove `Unpin` bound from `TryStreamExt::into_async_read` (#2599) -* Make `run_until_stalled` handle self-waking futures (#2593) -* Use `FuturesOrdered` in `try_join_all` (#2556) -* Fix orderings in `LocalPool` waker (#2608) -* Fix `stream::Chunk` adapters size hints (#2611) -* Add `push_front` and `push_back` to `FuturesOrdered` (#2591) -* Deprecate `FuturesOrdered::push` in favor of `FuturesOrdered::push_back` (#2591) -* Performance improvements (#2583, #2626) -* Documentation improvements (#2579, #2604, #2613) - -# 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. - -* 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) -* Add `StreamExt::{flatten_unordered, flat_map_unordered}` (#2083) - -# 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) -* Add `StreamExt::count` (#2495) - -# 0.3.18 - 2021-11-23 - -**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) -* Add async `LineWriter` (#2477) -* Remove dependency on `proc-macro-hack`. This raises MSRV of utility crates to 1.45. (#2520) - -# 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) -* Implement `Default` for `OptionFuture` (#2471) -* Add `Peekable::{peek_mut, poll_peek_mut}` (#2488) -* Add `BufReader::seek_relative` (#2489) - -# 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) -* Update to new `io_slice_advance` interface (#2454) - -# 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) -* Add `stream::abortable` (#2410) -* Add `FuturesUnordered::clear` (#2415) -* Implement `IntoIterator` for `FuturesUnordered` (#2423) -* Implement `Send` and `Sync` for `FuturesUnordered` iterators (#2416) -* Make `FuturesUnordered::iter_pin_ref` public (#2423) -* Add `SelectAll::clear` (#2430) -* Add `SelectAll::{iter, iter_mut}` (#2428) -* Implement `IntoIterator` for `SelectAll` (#2428) -* Implement `Clone` for `WeakShared` (#2396) - -# 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) -* Add `AsyncSeekExt::stream_position` (#2380) -* Add `stream::Peekable::{next_if, next_if_eq}` (#2379) - -# 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) -* Added `no_std` support for `task::noop_waker_ref` (#2332) -* Implemented `Stream::size_hint` for `Either` (#2325) - -# 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. - -* 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. - -* Significantly improved compile time when `async-await` crate feature is disabled (#2273) -* Added `stream::repeat_with` (#2279) -* Added `StreamExt::unzip` (#2263) -* Added `sink::unfold` (#2268) -* Added `SinkExt::feed` (#2155) -* Implemented `FusedFuture` for `oneshot::Receiver` (#2300) -* Implemented `Clone` for `sink::With` (#2290) -* Re-exported `MapOkOrElse`, `MapInto`, `OkInto`, `TryFlatten`, `WriteAllVectored` (#2275) - -# 0.3.8 - 2020-11-04 - -**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) -* Added `TryStreamExt::try_buffered` (#2245) -* Added `StreamExt::cycle` (#2252) -* Implemented `Clone` for `stream::{Empty, Pending, Repeat, Iter}` (#2248, #2252) -* Fixed panic in some `TryStreamExt` combinators (#2250) - -# 0.3.7 - 2020-10-23 - -**Note:** This release has been yanked. See #2310 for details. - -* Fixed unsoundness in `MappedMutexGuard` (#2240) -* Re-exported `TakeUntil` (#2235) -* futures-test: Prevent double panic in `panic_waker` (#2236) - -# 0.3.6 - 2020-10-06 - -**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) -* Added `TryStreamExt::try_take_while` (#2212) -* Added `is_connected_to` method to `mpsc::{Sender, UnboundedSender}` (#2179) -* Added `is_connected_to` method to `oneshot::Sender` (#2158) -* Implement `FusedStream` for `FuturesOrdered` (#2205) -* Fixed documentation links -* Improved documentation -* futures-test: Added `track_closed` method to `AsyncWriteTestExt` and `SinkTestExt` (#2159) -* futures-test: Implemented more traits for `InterleavePending` (#2208) -* futures-test: Implemented more traits for `AssertUnmoved` (#2208) - -# 0.3.5 - 2020-05-08 - -**Note:** This release has been yanked. See #2310 for details. - -* Added `StreamExt::flat_map`. -* Added `StreamExt::ready_chunks`. -* Added `*_unpin` methods to `SinkExt`. -* Added a `cancellation()` future to `oneshot::Sender`. -* Added `reunite` method to `ReadHalf` and `WriteHalf`. -* Added `Extend` implementations for `Futures(Un)Ordered` and `SelectAll`. -* Added support for reexporting the `join!` and `select!` macros. -* Added `no_std` support for the `pending!` and `poll!` macros. -* Added `Send` and `Sync` support for `AssertUnmoved`. -* Fixed a bug where `Shared` wasn't relinquishing control to the executor. -* Removed the `Send` bound on the output of `RemoteHandle`. -* Relaxed bounds on `FuturesUnordered`. -* Reorganized internal tests to work under different `--feature`s. -* Reorganized the bounds on `StreamExt::forward`. -* Removed and replaced a large amount of internal `unsafe`. - -# 0.3.4 - 2020-02-06 - -**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. - -* Fixed compatibility issue with pinned facade (#2062) - -# 0.3.2 - 2020-02-03 - -**Note:** This release has been yanked. See #2310 for details. - -* Improved buffering performance of `SplitSink` (#1969) -* Added `select_biased!` macro (#1976) -* Added `hash_receiver` method to mpsc channel (#1962) -* Added `stream::try_unfold` (#1977) -* Fixed bug with zero-size buffers in vectored IO (#1998) -* `AtomicWaker::new()` is now `const fn` (#2007) -* Fixed bug between threadpool and user park/unparking (#2010) -* Added `stream::Peekable::peek` (#2021) -* Added `StreamExt::scan` (#2044) -* Added impl of `AsyncRead`/`Write` for `BufReader`/`Writer` (#2033) -* Added impl of `Spawn` and `LocalSpawn` for `Arc` (#2039) -* Fixed `Sync` issues with `FuturesUnordered` (#2054) -* Added `into_inner` method for `future::Ready` (#2055) -* Added `MappedMutexGuard` API (#2056) -* Mitigated starvation issues in `FuturesUnordered` (#2049) -* Added `TryFutureExt::map_ok_or_else` (#2058) - -# 0.3.1 - 2019-11-07 - -**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. - -* Stable release along with stable async/await! -* Added async/await to default features (#1953) -* Changed `Spawn` trait and `FuturesUnordered::push` to take `&self` (#1950) -* Moved `Spawn` and `FutureObj` out of `futures-core` and into `futures-task` (#1925) -* Changed case convention for feature names (#1937) -* Added `executor` feature (#1949) -* Moved `copy_into`/`copy_buf_into` (#1948) -* Changed `SinkExt::send_all` to accept a `TryStream` (#1946) -* Removed `ThreadPool::run` (#1944) -* Changed to use our own definition of `io::Cursor` (#1943) -* Removed `BufReader::poll_seek_relative` (#1938) -* Changed `skip` to take a `usize` rather than `u64` (#1931) -* Removed `Stream` impl for `VecDeque` (#1930) -* Renamed `Peekable::peek` to `poll_peek` (#1928) -* Added immutable iterators for `FuturesUnordered` (#1922) -* Made `ThreadPool` optional (#1910) -* Renamed `oneshot::Sender::poll_cancel` to `poll_canceled` (#1908) -* Added some missing `Clone` implementations -* Documentation fixes - -# 0.3.0-alpha.19 - 2019-09-25 - -* Stabilized the `async-await` feature (#1816) -* Made `async-await` feature no longer require `std` feature (#1815) -* Updated `proc-macro2`, `syn`, and `quote` to 1.0 (#1798) -* Exposed unstable `BiLock` (#1827) -* Renamed "nightly" feature to "unstable" (#1823) -* Moved to our own `io::{Empty, Repeat, Sink}` (#1829) -* Made `AsyncRead::initializer` API unstable (#1845) -* Moved the `Never` type from `futures-core` to `futures-util` (#1836) -* Fixed use-after-free on panic in `ArcWake::wake_by_ref` (#1797) -* Added `AsyncReadExt::chain` (#1810) -* Added `Stream::size_hint` (#1853) -* Added some missing `FusedFuture` (#1868) and `FusedStream` implementations (#1831) -* Added a `From` impl for `Mutex` (#1839) -* Added `Mutex::{get_mut, into_inner}` (#1839) -* Re-exported `TryConcat` and `TryFilter` (#1814) -* Lifted `Unpin` bound and implemented `AsyncBufRead` for `io::Take` (#1821) -* Lifted `Unpin` bounds on `get_pin_mut` (#1820) -* Changed `SendAll` to flush the `Sink` when the source `Stream` is pending (#1877) -* Set default threadpool size to one if `num_cpus::get()` returns zero (#1835) -* Removed dependency on `rand` by using our own PRNG (#1837) -* Removed `futures-core` dependency from `futures-sink` (#1832) - -# 0.3.0-alpha.18 - 2019-08-09 - -* Rewrote `join!` and `try_join!` as procedural macros to allow passing expressions (#1783) -* Banned manual implementation of `TryFuture` and `TryStream` for forward compatibility. See #1776 for more details. (#1777) -* Changed `AsyncReadExt::read_to_end` to return the total number of bytes read (#1721) -* Changed `ArcWake::into_waker` to a free function `waker` (#1676) -* Supported trailing commas in macros (#1733) -* Removed futures-channel dependency from futures-executor (#1735) -* Supported `channel::oneshot` in no_std environment (#1749) -* Added `Future` bounds to `FusedFuture` (#1779) -* Added `Stream` bounds to `FusedStream` (#1779) -* Changed `StreamExt::boxed` to return `BoxStream` (#1780) -* Added `StreamExt::boxed_local` (#1780) -* Added `AsyncReadExt::read_to_string` (#1721) -* Implemented `AsyncWrite` for `IntoAsyncRead` (#1734) -* Added get_ref, get_mut and into_inner methods to `Compat01As03` and `Compat01As03Sink` (#1705) -* Added `ThreadPool::{spawn_ok, spawn_obj_ok}` (#1750) -* Added `TryStreamExt::try_flatten` (#1731) -* Added `FutureExt::now_or_never` (#1747) - -# 0.3.0-alpha.17 - 2019-07-03 - -* Removed `try_ready!` macro in favor of `ready!(..)?`. (#1602) -* Removed `io::Window::{set_start, set_end}` in favor of `io::Window::set`. (#1667) -* Re-exported `pin_utils::pin_mut!` macro. (#1686) -* Made all extension traits unnamed in the prelude. (#1662) -* Allowed `?Sized` types in some methods and structs. (#1647) -* Added `Send + Sync` bounds to `ArcWake` trait to fix unsoundness. (#1654) -* Changed `AsyncReadExt::copy_into` to consume `self`. (#1674) -* Renamed `future::empty` to `pending`. (#1689) -* Added `#[must_use]` to some combinators. (#1600) -* Added `AsyncWriteExt::{write, write_vectored}`. (#1612) -* Added `AsyncReadExt::read_vectored`. (#1612) -* Added `TryFutureExt::try_poll_unpin`. (#1613) -* Added `TryFutureExt::try_flatten_stream`. (#1618) -* Added `io::BufWriter`. (#1608) -* Added `Sender::same_receiver` and `UnboundedSender::same_receiver`. (#1617) -* Added `future::try_select`. (#1622) -* Added `TryFutureExt::{inspect_ok, inspect_err}`. (#1630) -* Added `Compat::get_ref`. (#1648) -* Added `io::Window::set`. (#1667) -* Added `AsyncWriteExt::into_sink`. (#1675) -* Added `AsyncBufReadExt::copy_buf_into`. (#1674) -* Added `stream::pending`. (#1689) -* Implemented `std::error::Error` for `SpawnError`. (#1604) -* Implemented `Stream` for `FlattenSink`. (#1651) -* Implemented `Sink` for `TryFlattenStream`. (#1651) -* Implemented `AsyncRead`, `AsyncWrite`, `AsyncSeek`, `AsyncBufRead`, `FusedFuture` and `FusedStream` for Either. (#1695) -* Replaced empty enums with `Never` type, an alias for `core::convert::Infallible`. -* Removed the `futures-channel` dependency from `futures-sink` and make `futures-sink` - an optional dependency of `futures-channel`. -* Renamed `Sink::SinkError` to `Sink::Error`. -* Made a number of dependencies of `futures-util` optional. - -# 0.3.0-alpha.16 - 2019-05-10 - -* Updated to new nightly `async_await`. -* Changed `AsyncRead::poll_vectored_read` and `AsyncWrite::poll_vectored_write` to use - stabilized `std::io::{IoSlice, IoSliceMut}` instead of `iovec::IoVec`, and renamed to - `AsyncRead::poll_read_vectored` and `AsyncWrite::poll_write_vectored`. -* Added `LocalBoxFuture` and `FutureExt::boxed_local`. -* Added `TryStreamExt::{try_filter, inspect_ok, inspect_err}`. -* Added `try_future::select_ok`. -* Added `AsyncBufReadExt::{read_line, lines}`. -* Added `io::BufReader`. - -# 0.3.0-alpha.15 - 2019-04-26 - -* Updated to stabilized `futures_api`. -* Removed `StreamObj`, cautioned against usage of `FutureObj`. -* Changed `StreamExt::select` to a function. -* Added `AsyncBufRead` and `AsyncSeek` traits. -* Expanded trait impls to include more pinned pointers and ?Sized types. -* Added `future::Fuse::terminated` constructor. -* Added `never_error` combinator. -* Added `StreamExt::enumerate`. -* Re-added `TryStreamExt::{and_then, or_else}`. -* Added functions to partially progress a local pool. -* Changed to use our own `Either` type rather than the one from the `either` crate. - -# 0.3.0-alpha.14 - 2019-04-15 - -* Updated to new nightly `futures_api`. -* Changed `Forward` combinator to drop sink after completion, and allow `!Unpin` `Sink`s. -* Added 0.1 <-> 0.3 compatibility shim for `Sink`s. -* Changed `Sink::Item` to a generic parameter `Sink`, allowing `Sink`s to accept - multiple different types, including types containing references. -* Changed `AsyncRead` and `AsyncWrite` to take `Pin<&mut Self>` rather than `&mut self`. -* Added support for `no_std` + `alloc` use. -* Changed `join` and `try_join` combinators to functions. -* Fixed propagation of `cfg-target-has-atomic` feature. - -# 0.3.0-alpha.13 - 2019-02-20 - -* Updated to new nightly with stabilization candidate API. -* Removed `LocalWaker`. -* Added `#[must_use]` to `Stream` and `Sink` traits. -* Enabled using `!Unpin` futures in `JoinAll`. -* Added the `try_join_all` combinator. -* Stopped closing a whole channel upon closing of one sender. -* Removed `TokioDefaultSpawner` and `tokio-compat`. -* Moved intra-crate dependencies to exact versions. - -# 0.3.0-alpha.12 - 2019-01-14 - -* Updated to new nightly with a modification to `Pin::set`. -* Expose `AssertUnmoved` and `PendingOnce`. -* Prevent double-panic in `AssertUnmoved`. -* Support nested invocations of the `select!` macro. -* Implement `Default` for `Mutex` and `SelectAll`. - -# 0.3.0-alpha.11 - 2018-12-27 - -* Updated to newly stabilized versions of the `pin` and `arbitrary_self_types` features. -* Re-added `select_all` for streams. -* Added `TryStream::into_async_read` for converting from a stream of bytes into - an `AsyncRead`. -* Added `try_poll_next_unpin`. -* Rewrote `select!` as a procedural macro for better error messages -* Exposed `join_all` from the facade - -# 0.3.0-alpha.10 - 2018-11-27 - -* Revamped `select!` macro -* Added `select_next_some` method for getting only the `Some` elements of a stream from `select!` -* Added `futures::lock::Mutex` for async-aware synchronization. -* Fixed bug converting `Pin>` to `StreamObj` -* Improved performance of futures::channel -* Improved performance and documentation of `Shared` -* Add `new` method and more `derive`s to the `Compat` type -* Enabled spawning on a borrowed threadpool -* Re-added `join_all` -* Added `try_concat` - -# 0.3.0-alpha.9 - 2018-10-18 - -* Fixed in response to new nightly handling of 2018 edition + `#![no_std]` - -# 0.3.0-alpha.8 - 2018-10-16 - -* Fixed stack overflow in 0.1 compatibility layer -* Added AsyncRead / AsyncWrite compatibility layer -* Added Spawn -> 0.1 Executor compatibility -* Made 0.1 futures usable on 0.3 executors without an additional global `Task`, accomplished by wrapping 0.1 futures in an 0.1 `Spawn` when using them as 0.3 futures. -* Cleanups and improvements to the `AtomicWaker` implementation. - -# 0.3.0-alpha.7 - 2018-10-01 - -* Update to new nightly which removes `Spawn` from `task::Context` and replaces `Context` with `LocalWaker`. -* Add `Spawn` and `LocalSpawn` traits and `FutureObj` and `LocalFutureObj` types to `futures-core`. - -# 0.3.0-alpha.6 - 2018-09-10 - -* Replace usage of `crate` visibility with `pub(crate)` now that `crate` visibility is no longer included in the 2018 edition -* Remove newly-stabilized "edition" feature in Cargo.toml files - -# 0.3.0-alpha.5 - 2018-09-03 - -* Revert usage of cargo crate renaming feature - -# 0.3.0-alpha.4 - 2018-09-02 - -**Note: This release does not work, use `0.3.0-alpha.5` instead** - -* `future::ok` and `future:err` to create result wrapping futures (similar to `future::ready`) -* `futures-test` crate with testing utilities -* `StreamExt::boxed` combinator -* Unsoundness fix for `FuturesUnordered` -* `StreamObj` (similar to `FutureObj`) -* Code examples for compatibility layer functions -* Use cargo create renaming feature to import `futures@0.1` for compatibility layer -* Import pinning APIs from `core::pin` -* Run Clippy in CI only when it is available - -# 0.3.0-alpha.3 - 2018-08-15 - -* Compatibility with newest nightly -* Futures 0.1 compatibility layer including Tokio compatibility -* Added `spawn!` and `spawn_with_handle!` macros -* Added `SpawnExt` methods `spawn` and `spawn_with_handle` -* Extracted pin macros into `pin_utils` crate -* Added `FutureExt` combinators `boxed` and `unit_error` -* Remove prelude from all doc examples (The prelude is still recommended for usage in playground examples. However, for doc examples we determined that fully expanded imports are more helpful) -* Improvements to `select!` and `join!` macros -* Added `try_join!` macro -* Added `StreamExt` combinator methods `try_join` and `for_each_concurrent` -* Added `TryStreamExt` combinator methods `into_stream`, `try_filter_map`, `try_skip_while`, `try_for_each_concurrent` and `try_buffer_unordered` -* Fix stream termination bug in `StreamExt::buffered` and `StreamExt::buffer_unordered` -* Added docs for `StreamExt::buffered`, `StreamExt::buffer_unordered` -* Added `task::local_waker_ref_from_nonlocal` and `task::local_waker_ref` functions -* CI improvements -* Doc improvements to `StreamExt::select` - -# 0.3.0-alpha.2 - 2018-07-30 - -* The changelog is back! -* Compatibility with futures API in latest nightly -* Code examples and doc improvements - * IO: Methods of traits `AsyncReadExt`, `AsyncWriteExt` - * Future: - * Methods of trait `TryFutureExt` - * Free functions `empty`, `lazy`, `maybe_done`, `poll_fn` and `ready` - * Type `FutureOption` - * Macros `join!`, `select!` and `pending!` - * Stream: Methods of trait `TryStreamExt` -* Added `TryStreamExt` combinators `map_ok`, `map_err`, `err_into`, `try_next` and `try_for_each` -* Added `Drain`, a sink that will discard all items given to it. Can be created using the `drain` function -* Bugfix for the `write_all` combinator -* `AsyncWrite` impl for `Cursor>` -* `FuturesUnordered` optimization: Since the context stores a `&LocalWaker` reference, it was possible to avoid cloning the `Arc` of the waker -* Futures-rs now uses Clippy -* We now use in-band lifetimes -* The `join!` and `select!` macros are now exposed by the `futures` crate -* The project logo was added to the `README.md` -* `sink::MapErr::get_pinned_mut` is now called `get_pin_mut` -* We now use the unstable `use_extern_macros` feature for macro reexports -* CI improvements: Named CI jobs, tests are now run on macOS and Linux, the docs are generated and Clippy needs to pass -* `#[deny(warnings)]` was removed from all crates and is now only enforced in the CI -* We now have a naming convention for type parameters: `Fut` future, `F` function, `St` stream, `Si` sink, `S` sink & stream, `R` reader, `W` writer, `T` value, `E` error -* "Task" is now defined as our term for "lightweight thread". The code of the executors and `FuturesUnordered` was refactored to align with this definition. - -# 0.3.0-alpha.1 - 2018-07-19 - -* Major changes: See [the announcement](https://rust-lang-nursery.github.io/futures-rs/blog/2018/07/19/futures-0.3.0-alpha.1.html) on our new blog for details. The changes are too numerous to be covered in this changelog because nearly every line of code was modified. - -# 0.1.17 - 2017-10-31 - -* Add a `close` method on `sink::Wait` -* Undeprecate `stream::iter` as `stream::iter_result` -* Improve performance of wait-related methods -* Tweak buffered sinks with a 0 capacity to forward directly to the underlying - sink. -* Add `FromIterator` implementation for `FuturesOrdered` and `FuturesUnordered`. - -# 0.1.16 - 2017-09-15 - -* A `prelude` module has been added to glob import from and pick up a whole - bunch of useful types -* `sync::mpsc::Sender::poll_ready` has been added as an API -* `sync::mpsc::Sender::try_send` has been added as an API - -# 0.1.15 - 2017-08-24 - -* Improve performance of `BiLock` methods -* Implement `Clone` for `FutureResult` -* Forward `Stream` trait through `SinkMapErr` -* Add `stream::futures_ordered` next to `futures_unordered` -* Reimplement `Stream::buffered` on top of `stream::futures_ordered` (much more - efficient at scale). -* Add a `with_notify` function for abstractions which previously required - `UnparkEvent`. -* Add `get_ref`/`get_mut`/`into_inner` functions for stream take/skip methods -* Add a `Clone` implementation for `SharedItem` and `SharedError` -* Add a `mpsc::spawn` function to spawn a `Stream` into an `Executor` -* Add a `reunite` function for `BiLock` and the split stream/sink types to - rejoin two halves and reclaim the original item. -* Add `stream::poll_fn` to behave similarly to `future::poll_fn` -* Add `Sink::with_flat_map` like `Iterator::flat_map` -* Bump the minimum Rust version to 1.13.0 -* Expose `AtomicTask` in the public API for managing synchronization around task - notifications. -* Unify the `Canceled` type of the `sync` and `unsync` modules. -* Deprecate the `boxed` methods. These methods have caused more confusion than - they've solved historically, so it's recommended to use a local extension - trait or a local helper instead of the trait-based methods. -* Deprecate the `Stream::merge` method as it's less ergonomic than `select`. -* Add `oneshot::Sender::is_canceled` to test if a oneshot is canceled off a - task. -* Deprecates `UnboundedSender::send` in favor of a method named `unbounded_send` - to avoid a conflict with `Sink::send`. -* Deprecate the `stream::iter` function in favor of an `stream::iter_ok` adaptor - to avoid the need to deal with `Result` manually. -* Add an `inspect` function to the `Future` and `Stream` traits along the lines - of `Iterator::inspect` - -# 0.1.14 - 2017-05-30 - -This is a relatively large release of the `futures` crate, although much of it -is from reworking internals rather than new APIs. The banner feature of this -release is that the `futures::{task, executor}` modules are now available in -`no_std` contexts! A large refactoring of the task system was performed in -PR #436 to accommodate custom memory allocation schemes and otherwise remove -all dependencies on `std` for the task module. More details about this change -can be found on the PR itself. - -Other API additions in this release are: - -* A `FuturesUnordered::push` method was added and the `FuturesUnordered` type - itself was completely rewritten to efficiently track a large number of - futures. -* A `Task::will_notify_current` method was added with a slightly different - implementation than `Task::is_current` but with stronger guarantees and - documentation wording about its purpose. -* Many combinators now have `get_ref`, `get_mut`, and `into_inner` methods for - accessing internal futures and state. -* A `Stream::concat2` method was added which should be considered the "fixed" - version of `concat`, this one doesn't panic on empty streams. -* An `Executor` trait has been added to represent abstracting over the concept - of spawning a new task. Crates which only need the ability to spawn a future - can now be generic over `Executor` rather than requiring a - `tokio_core::reactor::Handle`. - -As with all 0.1.x releases this PR is intended to be 100% backwards compatible. -All code that previously compiled should continue to do so with these changes. -As with other changes, though, there are also some updates to be aware of: - -* The `task::park` function has been renamed to `task::current`. -* The `Task::unpark` function has been renamed to `Task::notify`, and in general - terminology around "unpark" has shifted to terminology around "notify" -* The `Unpark` trait has been deprecated in favor of the `Notify` trait - mentioned above. -* The `UnparkEvent` structure has been deprecated. It currently should perform - the same as it used to, but it's planned that in a future 0.1.x release the - performance will regress for crates that have not transitioned away. The - primary primitive to replace this is the addition of a `push` function on the - `FuturesUnordered` type. If this does not help implement your use case though, - please let us know! -* The `Task::is_current` method is now deprecated, and you likely want to use - `Task::will_notify_current` instead, but let us know if this doesn't suffice! - -# 0.1.13 - 2017-04-05 - -* Add forwarding sink/stream impls for `stream::FromErr` and `sink::SinkFromErr` -* Add `PartialEq` and `Eq` to `mpsc::SendError` -* Reimplement `Shared` with `spawn` instead of `UnparkEvent` - -# 0.1.12 - 2017-04-03 - -* Add `Stream::from_err` and `Sink::from_err` -* Allow `SendError` to be `Clone` when possible - -# 0.1.11 - 2017-03-13 - -The major highlight of this release is the addition of a new "default" method on -the `Sink` trait, `Sink::close`. This method is used to indicate to a sink that -no new values will ever need to get pushed into it. This can be used to -implement graceful shutdown of protocols and otherwise simply indicates to a -sink that it can start freeing up resources. - -Currently this method is **not** a default method to preserve backwards -compatibility, but it's intended to become a default method in the 0.2 series of -the `futures` crate. It's highly recommended to audit implementations of `Sink` -to implement the `close` method as is fit. - -Other changes in this release are: - -* A new select combinator, `Future::select2` was added for a heterogeneous - select. -* A `Shared::peek` method was added to check to see if it's done. -* `Sink::map_err` was implemented -* The `log` dependency was removed -* Implementations of the `Debug` trait are now generally available. -* The `stream::IterStream` type was renamed to `stream::Iter` (with a reexport - for the old name). -* Add a `Sink::wait` method which returns an adapter to use an arbitrary `Sink` - synchronously. -* A `Stream::concat` method was added to concatenate a sequence of lists. -* The `oneshot::Sender::complete` method was renamed to `send` and now returns a - `Result` indicating successful transmission of a message or not. Note that the - `complete` method still exists, it's just deprecated. - -# 0.1.10 - 2017-01-30 - -* Add a new `unsync` module which mirrors `sync` to the extent that it can but - is intended to not perform cross-thread synchronization (only usable within - one thread). -* Tweak `Shared` to work when handles may not get poll'd again. - -# 0.1.9 - 2017-01-18 - -* Fix `Send/Sync` of a few types -* Add `future::tail_fn` for more easily writing loops -* Export SharedItem/SharedError -* Remove an unused type parameter in `from_err` - -# 0.1.8 - 2017-01-11 - -* Fix some race conditions in the `Shared` implementation -* Add `Stream::take_while` -* Fix an unwrap in `stream::futures_unordered` -* Generalize `Stream::for_each` -* Add `Stream::chain` -* Add `stream::repeat` -* Relax `&mut self` to `&self` in `UnboundedSender::send` - -# 0.1.7 - 2016-12-18 - -* Add a `Future::shared` method for creating a future that can be shared - amongst threads by cloning the future itself. All derivative futures - will resolve to the same value once the original future has been - resolved. -* Add a `FutureFrom` trait for future-based conversion -* Fix a wakeup bug in `Receiver::close` -* Add `future::poll_fn` for quickly adapting a `Poll`-based function to - a future. -* Add an `Either` enum with two branches to easily create one future - type based on two different futures created on two branches of control - flow. -* Remove the `'static` bound on `Unpark` -* Optimize `send_all` and `forward` to send as many items as possible - before calling `poll_complete`. -* Unify the return types of the `ok`, `err`, and `result` future to - assist returning different varieties in different branches of a function. -* Add `CpuFuture::forget` to allow the computation to continue running - after a drop. -* Add a `stream::futures_unordered` combinator to turn a list of futures - into a stream representing their order of completion. - -# 0.1.6 - 2016-11-22 - -* Fix `Clone` bound on the type parameter on `UnboundedSender` - -# 0.1.5 - 2016-11-22 - -* Fix `#![no_std]` support - -# 0.1.4 - 2016-11-22 - -This is quite a large release relative to the previous point releases! As -with all 0.1 releases, this release should be fully compatible with the 0.1.3 -release. If any incompatibilities are discovered please file an issue! - -The largest changes in 0.1.4 are the addition of a `Sink` trait coupled with a -reorganization of this crate. Note that all old locations for types/traits -still exist, they're just deprecated and tagged with `#[doc(hidden)]`. - -The new `Sink` trait is used to represent types which can periodically over -time accept items, but may take some time to fully process the item before -another can be accepted. Essentially, a sink is the opposite of a stream. This -trait will then be used in the tokio-core crate to implement simple framing by -modeling I/O streams as both a stream and a sink of frames. - -The organization of this crate is to now have three primary submodules, -`future`, `stream`, and `sink`. The traits as well as all combinator types are -defined in these submodules. The traits and types like `Async` and `Poll` are -then reexported at the top of the crate for convenient usage. It should be a -relatively rare occasion that the modules themselves are reached into. - -Finally, the 0.1.4 release comes with a new module, `sync`, in the futures -crate. This is intended to be the home of a suite of futures-aware -synchronization primitives. Currently this is inhabited with a `oneshot` module -(the old `oneshot` function), a `mpsc` module for a new multi-producer -single-consumer channel, and a `BiLock` type which represents sharing ownership -of one value between two consumers. This module may expand over time with more -types like a mutex, rwlock, spsc channel, etc. - -Notable deprecations in the 0.1.4 release that will be deleted in an eventual -0.2 release: - -* The `TaskRc` type is now deprecated in favor of `BiLock` or otherwise `Arc` - sharing. -* All future combinators should be accessed through the `future` module, not - the top-level of the crate. -* The `Oneshot` and `Complete` types are now replaced with the `sync::oneshot` - module. -* Some old names like `collect` are deprecated in favor of more appropriately - named versions like `join_all` -* The `finished` constructor is now `ok`. -* The `failed` constructor is now `err`. -* The `done` constructor is now `result`. - -As always, please report bugs to https://github.com/rust-lang-nursery/futures-rs and -we always love feedback! If you've got situations we don't cover, combinators -you'd like to see, or slow code, please let us know! - -Full changelog: - -* Improve scalability of `buffer_unordered` combinator -* Fix a memory ordering bug in oneshot -* Add a new trait, `Sink` -* Reorganize the crate into three primary modules -* Add a new `sync` module for synchronization primitives -* Add a `BiLock` sync primitive for two-way sharing -* Deprecate `TaskRc` -* Rename `collect` to `join_all` -* Use a small vec in `Events` for improved clone performance -* Add `Stream::select` for selecting items from two streams like `merge` but - requiring the same types. -* Add `stream::unfold` constructor -* Add a `sync::mpsc` module with a futures-aware multi-producer single-consumer - queue. Both bounded (with backpressure) and unbounded (no backpressure) - variants are provided. -* Renamed `failed`, `finished`, and `done` combinators to `err`, `ok`, and - `result`. -* Add `Stream::forward` to send all items to a sink, like `Sink::send_all` -* Add `Stream::split` for streams which are both sinks and streams to have - separate ownership of the stream/sink halves -* Improve `join_all` with concurrency - -# 0.1.3 - 2016-10-24 - -* Rewrite `oneshot` for efficiency and removing allocations on send/recv -* Errors are passed through in `Stream::take` and `Stream::skip` -* Add a `select_ok` combinator to pick the first of a list that succeeds -* Remove the unnecessary `SelectAllNext` typedef -* Add `Stream::chunks` for receiving chunks of data -* Rewrite `stream::channel` for efficiency, correctness, and removing - allocations -* Remove `Send + 'static` bounds on the `stream::Empty` type - -# 0.1.2 - 2016-10-04 - -* Fixed a bug in drop of `FutureSender` -* Expose the channel `SendError` type -* Add `Future::into_stream` to convert to a single-element stream -* Add `Future::flatten_to_stream` to convert a future of a stream to a stream -* impl Debug for SendError -* Add stream::once for a one element stream -* Accept IntoIterator in stream::iter -* Add `Stream::catch_unwind` - -# 0.1.1 - 2016-09-09 - -Initial release! diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 9f261b44fd..0000000000 --- a/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[workspace] -members = [ - "futures", - "futures-core", - "futures-channel", - "futures-executor", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "futures-util", - "futures-test", - - "futures/tests/macro-tests", - "futures/tests/macro-reexport", - "futures/tests/no-std", - - "examples/functional", - "examples/imperative", -] - -[workspace.lints.rust] -missing_debug_implementations = "warn" -rust_2018_idioms = "warn" -single_use_lifetimes = "warn" -unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(futures_sanitizer)', -] } -unreachable_pub = "warn" -# unsafe_op_in_unsafe_fn = "warn" # Set at crate-level instead since https://github.com/rust-lang/rust/pull/100081 is not available on MSRV -[workspace.lints.clippy] -incompatible_msrv = { level = "allow", priority = 1 } # https://github.com/rust-lang/rust-clippy/issues/12273, https://github.com/rust-lang/rust-clippy/issues/12257 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..3a09b0367f --- /dev/null +++ b/Gemfile @@ -0,0 +1,30 @@ +source "https://rubygems.org" + +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +gem "jekyll", "~> 3.8.3" + +# This is the default theme for new Jekyll sites. You may change this to anything you like. +gem "minima", "~> 2.0" + +# If you want to use GitHub Pages, remove the "gem "jekyll"" above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. +# gem "github-pages", group: :jekyll_plugins + +# If you have any plugins, put them here! +group :jekyll_plugins do + gem "jekyll-feed", "~> 0.6" +end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +# Performance-booster for watching directories on Windows +gem "wdm", "~> 0.1.0" if Gem.win_platform? + diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..e463b4cb91 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,74 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + colorator (1.1.0) + concurrent-ruby (1.0.5) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + eventmachine (1.2.7) + ffi (1.9.25) + forwardable-extended (2.6.0) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jekyll (3.8.3) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-feed (0.10.0) + jekyll (~> 3.3) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.5.0) + jekyll (~> 3.3) + jekyll-watch (2.0.0) + listen (~> 3.0) + kramdown (1.17.0) + liquid (4.0.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + mercenary (0.3.6) + minima (2.5.0) + jekyll (~> 3.5) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + pathutil (0.16.1) + forwardable-extended (~> 2.6) + public_suffix (3.0.2) + rb-fsevent (0.10.3) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + rouge (3.1.1) + ruby_dep (1.5.0) + safe_yaml (1.0.4) + sass (3.5.6) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + +PLATFORMS + ruby + +DEPENDENCIES + jekyll (~> 3.8.3) + jekyll-feed (~> 0.6) + minima (~> 2.0) + tzinfo-data + +BUNDLED WITH + 1.16.3 diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 9eb0b097f5..16fe87b06e 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,8 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright (c) 2016 Alex Crichton -Copyright (c) 2017 The Tokio Authors +Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index a2c622a831..fb004f1ff2 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,8 @@ -

- futures-rs -

+# -

- Zero-cost asynchronous programming in Rust -

+## Developing locally -

- - Build Status - - - - crates.io - -

- -

- - Documentation - | - Website - -

- -`futures-rs` is a library providing the foundations for asynchronous programming in Rust. -It includes key trait definitions like `Stream`, as well as utilities like `join!`, -`select!`, and various futures combinator methods which enable expressive asynchronous -control flow. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures = "0.3" ``` - -The current `futures` requires Rust 1.68 or later. - -### Feature `std` - -Futures-rs works without the standard library, such as in bare metal environments. -However, it has a significantly reduced API surface. To use futures-rs in -a `#[no_std]` environment, use: - -```toml -[dependencies] -futures = { version = "0.3", default-features = false } +> bundle install +> bundle exec jekyll serve ``` - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..11f12e2c8a --- /dev/null +++ b/_config.yml @@ -0,0 +1,32 @@ +title: Futures-rs +baseurl: "/futures-rs" +url: "https://rust-lang-nursery.github.io" + +# Build settings +markdown: kramdown +kramdown: + syntax_highlighter: rouge + syntax_highlighter_opts: + default_lang: rust + css_class: 'highlight' + span: + line_numbers: false + block: + line_numbers: false +theme: minima +plugins: + - jekyll-feed +exclude: + - target # From Rust + +# Exclude from processing. +# The following items will not be processed, by default. Create a custom list +# to override the default setting. +# exclude: +# - Gemfile +# - Gemfile.lock +# - node_modules +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000000..4b1862e9a0 --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,9 @@ + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000000..05d0aa94ce --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,26 @@ + diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000000..f3a6daa32d --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,12 @@ + + + {%- include head.html -%} + + + {%- include header.html -%} + +
{{ content }}
+ + {%- include footer.html -%} + + diff --git a/_layouts/home.html b/_layouts/home.html new file mode 100644 index 0000000000..b811de0589 --- /dev/null +++ b/_layouts/home.html @@ -0,0 +1,43 @@ +--- +layout: default +--- +
+ Futures RS Logo + +
+ Zero-cost asynchronous programming in Rust +
+
+ +
+ {{ content }} + + {%- if site.posts.size > 0 -%} +

Blog Posts

+
    + {%- for post in site.posts -%} +
  • + {%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%} + +

    + + {{ post.title | markdownify }} + +

    +
    {{ post.subtitle | markdownify }}
    +
  • + {%- endfor -%} +
+ + + {%- endif -%} + +
diff --git a/_layouts/page.html b/_layouts/page.html new file mode 100644 index 0000000000..01e4b2a93b --- /dev/null +++ b/_layouts/page.html @@ -0,0 +1,14 @@ +--- +layout: default +--- +
+ +
+

{{ page.title | escape }}

+
+ +
+ {{ content }} +
+ +
diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000000..07f9c0d9af --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,53 @@ +--- +layout: default +--- +
+ +
+

{{ page.title | escape }}

+ +
+ +
+ {{ content }} +
+ + + + + + +
diff --git a/_posts/2018-07-18-new-website.md b/_posts/2018-07-18-new-website.md new file mode 100644 index 0000000000..2bb4022100 --- /dev/null +++ b/_posts/2018-07-18-new-website.md @@ -0,0 +1,17 @@ +--- +layout: post +title: "New Website" +author: "Josef Brandl" +author_github: "MajorBreakfast" +date: 2018-07-19 16:00 +categories: blog +--- + + +## Welcome! + +Futures-rs now has a website and a logo. We hope you like it! This site contains our brand new blog with which we plan to keep you up-to-date about the project. + +Enjoy reading! + +*BTW The logo was inspired by a movie, we'll leave it up to the reader to guess which one :)* diff --git a/_posts/2018-07-19-futures-0.3.0-alpha.1.md b/_posts/2018-07-19-futures-0.3.0-alpha.1.md new file mode 100644 index 0000000000..79f4366412 --- /dev/null +++ b/_posts/2018-07-19-futures-0.3.0-alpha.1.md @@ -0,0 +1,155 @@ +--- +layout: post +title: "Futures 0.3.0-alpha.1" +subtitle: "Our first alpha" +author: "Aaron Turon" +author_github: "aturon" +date: 2018-07-19 17:00 +categories: blog +--- + +Welcome to the inaugural post of the new futures-rs blog! + +After several months of work, we’re happy to announce an *alpha* release of the new edition of futures-rs, version 0.3. The immediate goal of this work is to support async/await notation ([with borrowing](http://aturon.github.io/2018/04/24/async-borrowing/)) in Rust itself, which has entailed significant changes to the futures crate. + +## TL;DR +- The 0.3.0-alpha.1 release is available in the new `futures-preview` family of crates. +- It requires a nightly compiler, and works with rustc’s new support for async/await notation. +- Tokio and Hyper support is not yet available for 0.3.0-alpha.1, but that’s the next area of work. +- Neither the futures crate nor async/await notation will be stabilized for the initial release of the Rust 2018 Edition. +- Futures 0.1 continues to be maintained and is the primary way to write production async code today. We plan to continue maintaining 0.1 for some time after 0.3.0 is released, as well. + +In short, this alpha release sets the stage for kicking off integration and documentation, but is not yet widely usable. + +## The futures-preview crate + +We’re publishing a 0.3.0-alpha.1 release of futures today, but rather than doing it within the existing `futures` crate, we’re publishing within the new `futures-preview` family of crates. This allows us to more clearly signal that this version is a work in progress, and to keep crates.io and docs.rs pages pointing to the 0.1 series. + +In other words: + + +- Futures 0.1 is the production-ready way to use futures today, and is actively maintained. +- Ongoing work for async/await will live in the `futures-preview` crates until it is ready to be promoted to 0.3.0. + +## What is futures 0.3? +### Async/await + +With futures 0.3 alpha, it is possible to use the new `async`/`await` notation that recently landed in nightly: + +```toml +cargo-features = ["edition"] + +[package] +edition = "2018" +``` + +```rust +#![feature(async_await, await_macro)] + +use futures::executor::block_on; +use futures::future::{self, FutureExt}; + +fn main() { + block_on(async { + let fut = future::lazy(|_| vec![0, 1, 2, 3]); + let shared1 = fut.shared(); + let shared2 = shared1.clone(); + + assert_eq!(await!(shared1).len(), 4); + assert_eq!(await!(shared2).len(), 4); + }) +} +``` + +The notation works as described in [the corresponding RFC](https://github.com/rust-lang/rfcs/pull/2394); more documentation for it is forthcoming. There are several open questions on this notation, but these are largely on hold until we have achieved integration with Tokio and Hyper, at which point more serious code can be written against the library. + +While we had originally hoped to ship async/await notation as part of Rust 2018, there’s no chance at this point of having adequate feedback and confidence to do so in time. However, the [Networking WG](https://github.com/rust-lang-nursery/net-wg/) plans to continue pushing hard in this space up to and after the Rust 2018 launch, to provide the strongest story on *nightly* Rust that we can, and to get us on a path for stabilization. + +### Ecosystem integration + +As of this writing, futures 0.3.0-alpha.1 is not integrated in any way with other libraries like Tokio or Hyper. Achieving such integration is a crucial part of getting real experience with the design and ultimately heading toward stabilization. The Futures Team intends to work closely with the Tokio Team to determine the best way forward here — either a shim crate for compatibility with futures 0.1, or direct integration via a feature-flag. + +This integration is our main next area of work, and we’d love to have help! If you’re interested in getting involved, drop by the #wg-net channel on [Discord](https://discord.gg/rust-lang). + +### Crate structure and relation to `std` + +To support the built-in async/await notation, the `Future` trait and associated machinery had to [move into the standard library](https://github.com/rust-lang/rfcs/pull/2418). As such, the futures 0.3.0-alpha.1 release just re-exports those definitions, and then adds a host of useful extras, including streams, sinks, I/O traits, and the various combinators. + +The overall organization of the crate is similar to the 0.2 release: + + +[`futures-core-preview`](https://crates.io/crates/futures-core-preview) +: This crate re-exports the futures-related items from `std`, and defines `Stream`, `TryFuture` and `TryStream`. + +[`futures-executor-preview`](https://crates.io/crates/futures-executor-preview) +: This crate provides basic executors (a thread pool and a thread-local executor). + +[`futures-io-preview`](https://crates.io/crates/futures-io-preview) +: This crate defines core traits for I/O. + +[`futures-sink-preview`](https://crates.io/crates/futures-sink-preview) +: This crate defines the core `Sink` trait. + +[`futures-channel-preview`](https://crates.io/crates/futures-channel-preview) +: This crate defines basic `Sync` channels with end points implementing `Future`, `Stream` or `Sink`. + +[`futures-util-preview`](https://crates.io/crates/futures-util-preview) +: This crate defines a collection of extension traits with useful adapters (aka combinators). + +[`futures-preview`](https://crates.io/crates/futures-preview) +: This crate is a “facade” combining and re-exporting all of the above crates for convenience. + +You can read more about the rationale for the breakdown into multiple crates in the [0.2 notes](http://aturon.github.io/2018/02/27/futures-0-2-RC/). + +### Changes from 0.2 + +*Note: Changes between 0.1 and 0.2 are outlined in the [0.2 notes](http://aturon.github.io/2018/02/27/futures-0-2-RC/).* + +Aside from some minor structural changes, there are two major changes from the 0.2 release: + +- Using pinned types to support borrowing within async blocks. +- Factoring out the `Error` type into separate traits (`TryFuture` and `TryStream`). + +Both of these changes are described and motivated in detail in [the companion RFC](https://github.com/rust-lang/rfcs/pull/2418). + +The RFC, however, covers only the core `Future` trait and executor system. The bulk of the work in 0.3.0-alpha.1 has been pushing through these ideas through the rest of the crates, adapting the combinators and other traits to fit with pinning and the ability to borrow across yield points. For example, the [revised](https://github.com/rust-lang-nursery/futures-rs/blob/0.3/futures-util/src/io/mod.rs#L67-L74) `AsyncReadExt` trait now provides a `read` method that operates on borrowed data, just like in the `Read` trait in `std`: + +```rust +trait AsyncReadExt: AsyncRead { + /// Tries to read some bytes directly into the given `buf` in asynchronous + /// manner, returning a future type. + /// + /// The returned future will resolve to the number of bytes read once the read + /// operation is completed. + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> { + Read::new(self, buf) + } +} +``` + +In contrast, the 0.1-style API must operate on *owned* buffers, which are threaded through the futures code. You can learn more about how this all works in [this blog post on borrowing and async/await](http://aturon.github.io/2018/04/24/async-borrowing/). + +## The road ahead + +While futures 0.3.0-alpha.1 is a major milestone, we still have a *ton* of work to do! The immediate next steps include: + + +- Work out the integration story for Tokio, Hyper, and other important crates. +- Write documentation for async/await notation. +- Flesh out the migration path from futures 0.1 code. +- Generally gain experience and feedback using this new design and async/await notation, so that we can get on track for stabilization. + +More generally, the futures team plans on communicating via this blog much more regularly about progress and ways to get involved. And now that the alpha is at the door, the broader [Networking WG](https://github.com/rust-lang-nursery/net-wg/) is hoping to reboot, bring in a lot more people, and start focusing on ecosystem concerns. + +As always, if you’re interested in getting involved in this space, reach out on #wg-net on [Discord](https://discord.gg/rust-lang). + +## Thank you! + +This alpha release is the result of work by a growing set of people contributing to the futures crate (some of whom have joined the team officially): + +- [@aturon](https://github.com/aturon) +- [@cramertj](https://github.com/cramertj) +- [@MajorBreakfast](https://github.com/MajorBreakfast) +- [@Nemo157](https://github.com/Nemo157) +- [@ngg](https://github.com/ngg) +- [@tinaun](https://github.com/tinaun) diff --git a/_posts/2018-07-30-futures-0.3.0-alpha.2.md b/_posts/2018-07-30-futures-0.3.0-alpha.2.md new file mode 100644 index 0000000000..3b0413bba4 --- /dev/null +++ b/_posts/2018-07-30-futures-0.3.0-alpha.2.md @@ -0,0 +1,66 @@ +--- +layout: post +title: "Futures 0.3.0-alpha.2" +subtitle: "Task definition, `Try` impl for `Poll`" +author: "Josef Brandl" +author_github: "MajorBreakfast" +date: 2018-07-30 +categories: blog +--- + +`0.3.0-alpha.2` requires a recent nightly (2018-07-29 or newer): +```sh +$ rustup update +``` + +## What's new? + +### Refined definition for "task" + +The documentation for the [`Executor`](https://doc.rust-lang.org/nightly/std/task/trait.Executor.html) trait was updated. It now defines a "task executor" like this: + +> Futures are polled until completion by tasks, a kind of lightweight "thread". A *task executor* is responsible for the creation of these tasks and the coordination of their execution on real operating system threads. In particular, whenever a task signals that it can make further progress via a wake-up notification, it is the responsibility of the task executor to put the task into a queue to continue executing it, i.e. polling the future in it, later. + +The notable difference to before is that the term "task" no longer refers to the future that the task runs. Instead, from now on, the term "task" only refers to the concept of a lightweight thread, a kind of thread that doesn't directly correspond to a thread provided by the operating system. This concept is sometimes also referred to as "green thread" - We, however, do not use either of these terms because they tend to cause confusion with real operating system threads. Instead, we call this concept a "task" and the thing that runs them a "task executor" or often just "executor". + +### `Try` impl for `Poll` + +`Poll>` now implements the [`Try`](https://doc.rust-lang.org/std/ops/trait.Try.html) trait. This means you can now do this: + +```rust +fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll> { + let poll: Poll> = self.future().poll(); + let poll: Poll = poll?; // Returns early if there's an error + let ok_value: T = ready!(poll); // Returns early if the value is pending + + // Or short: + let ok_value = ready!(self.future().poll()?); +} +``` + +Additionally `Try` was also implemented for `Poll>>` to make the `?`-operator useful in `Stream::poll` implentations: + +```rust +fn poll_next(mut self: PinMut, cx: &mut task::Context) -> Poll>> { + let poll: Poll>> = self.stream().poll_next(); + let poll: Poll> = poll?; // Returns early if there's an error + let ok_item: Option = ready!(poll); // Returns early if the value is pending + + // Or short: + let ok_item = ready!(self.stream().poll_next()?); +} +``` + +You can find additional details about this change in the [pull request](https://github.com/rust-lang/rust/pull/52721). + +### Changes to futures-rs + +We revived the [changelog](https://github.com/rust-lang-nursery/futures-rs/blob/master/CHANGELOG.md)! + +No major changes happened to the futures crate since the last release. There were, however, numerous little changes. Take a look at the [changelog](https://github.com/rust-lang-nursery/futures-rs/blob/master/CHANGELOG.md) to get an overview. + +## What are we currently working on? + +### Compatiblity layer for futures 0.1 + +We are currently working on an officially supported compatibility layer between `0.1` and `0.3`. This shim will make it possible to mix `0.1` futures with those from the 0.3 branch. The plan is to make it possible to use crates from the existing futures `0.1` ecosystem together with async functions and futures from the `0.3` crate. Additionally, this compatibility layer will also make it possible to gradually migrate exisiting applications and libraries to `0.3`. If you're curious, take a look the [compatibility layer PR](https://github.com/rust-lang-nursery/futures-rs/pull/1119) and the [issue](https://github.com/rust-lang-nursery/net-wg/issues/26) in the net-wg repository. diff --git a/_posts/2018-08-15-futures-0.3.0-alpha.3.md b/_posts/2018-08-15-futures-0.3.0-alpha.3.md new file mode 100644 index 0000000000..41dbb027bd --- /dev/null +++ b/_posts/2018-08-15-futures-0.3.0-alpha.3.md @@ -0,0 +1,127 @@ +--- +layout: post +title: "Futures 0.3.0-alpha.3" +subtitle: "Compatibility layer, spawn improvements and `pin-utils` crate" +author: "Josef Brandl" +author_github: "MajorBreakfast" +date: 2018-08-15 +categories: blog +--- + +`0.3.0-alpha.3` requires a recent nightly (2018-08-13 or newer): +```sh +$ rustup update +``` + +## Compatibility layer + +A compatibility layer between 0.3 and 0.1 was developed. It is now possible to convert an 0.3 future into an 0.1 future and vice versa. Similar conversions for streams and sinks are also supported. Additionally, it is now possible to run 0.3 futures and async functions on Tokio's executor. We have a dedicated blog post coming up that explains this in more detail. + +## Spawning + +### `Spawn` trait + +The `std::task::Executor` trait is now called `std::task::Spawn`. We chose to rename the trait to `Spawn` because the functionality exposed by this trait is not the ability to execute, but the ability to spawn. + +As a consequence of this renaming, some functions on `Context` were adjusted: +```rust +impl<'a> Context<'a> { + pub fn new(local_waker: &'a LocalWaker, spawner: &'a mut dyn Spawn) -> Context<'a> { ... } + + pub fn spawner(&mut self) -> &mut dyn Spawn { ... } + + pub fn with_spawner<'b, Sp: Spawn>(&'b mut self, spawner: &'b mut Sp) -> Context<'b> { ... } + + // ... +} +``` + +### Spawn macros + +This release of futures-rs introduces the `spawn!` and `spawn_with_handle!` macros for use in async functions, closures and blocks. Both macros let you spawn a task that polls the given future to completion. The task is spawned via the current context's spawner. + +`spawn!` lets you spawn futures with `Output = ()`: + +```rust +#![feature(async_await, await_macro, futures_api)] +use futures::spawn; + +spawn!(future).unwrap(); +``` + +`spawn_with_handle!` lets you spawn futures with any `Output: Send` type and returns a future that resolves to the output of the spawned future: + +```rust +use futures::spawn_with_handle; + +let join_handle = spawn_with_handle!(future).unwrap(); +let output = await!(join_handle); +``` + +`spawn!` is slightly cheaper than `spawn_with_handle!` since it doesn't need to provide a way to get the output. + +Should spawning fail, a `SpawnError` error is returned which contains information about why it failed. + +So what futures can be spawned? There are some requirements: The future needs to be `Send` and `'static` and the output needs to be `Send`. Here's why: +- The `'static` lifetime means that the future cannot contain any non-static references. This is required so that the spawned task can be run independently to the task that spawns it. +- The `Send` bounds mean that the future and its output can be sent to other threads. This is required so that multithreaded executors can run the spawned task on any thread they choose. + +Note: You can still execute non-`Send`, non-`'static` futures concurrently via the `join!` macro. + +### Spawn methods + +For use outside of async functions, there's also something new: The `SpawnExt` trait. It provides the methods `spawn` and `spawn_with_handle`: + +```rust +use futures::task::SpawnExt; + +// spawn() +spawner.spawn(future).unwrap(); + +// spawn_with_handle() +let join_handle = spawner.spawn_with_handle(future).unwrap(); +``` + +Inside `poll`, you can use these methods by accessing the context's spawner via `Context::spawner`: + +```rust +fn poll(self: PinMut, cx: &mut task::Context) -> Poll { + cx.spawner().spawn(future).unwrap(); +} +``` + +### The plan: `spawn` with `dyn Future` + +We plan to eventually replace `SpawnExt::spawn` with `Spawn::spawn`. This method will live directly in the `Spawn` trait defined in libcore. It's signature will look like this: + +```rust +fn spawn( + &mut self, + future: dyn Future + Send + 'static, +) -> Result<(), SpawnError> +``` + +This method can't be implemented just yet due to compiler limitations: +- Arbitrary self types are currently not object-safe: `Future::poll` uses `PinMut` as arbitrary self type. This unfortunately makes it impossible to create trait objects for `Future`. Therefore, `Box` and `&dyn Future` are *currently* not supported. +- Unsized rvalues are not yet available: Trait objects (`dyn Trait`) are `!Sized` because the size of a trait object depends on the size of the concrete type behind it and can therefore only be known at runtime. Currently we often use `Box` which stores the trait object on the heap to circumvent that. The unsized rvalues feature will make it possible to store `!Sized` types on the stack. + +To circumvent these limitations, we currently have `FutureObj` and `Spawn::spawn_obj`. These are, however, just a temporary solution until we can introduce the planned `spawn` method. The planned `spawn` method will make it possible to have one fewer heap allocation because the future is kept on the stack for as long as possible. + +## `pin-utils` crate + +The pin macros now live in their own crate, the `pin-utils` crate. The macros are general purpose and can be used in any project that uses the pinning API. + +The crate includes the macros for (un)pin projections `unsafe_pinned!` and `unsafe_unpinned!` and the macro for stack pinning `pin_mut!`: + +```rust +let foo = Foo { ... }; +pin_mut!(foo); // PinMut +``` + +Version `0.1.0-alpha.1` is now available on [crates.io](https://crates.io/crates/pin-utils) and the API docs are available on [docs.rs](https://docs.rs/pin-utils). + +## Further changes + +A complete list of changes can be found in our [changelog](https://github.com/rust-lang-nursery/futures-rs/blob/master/CHANGELOG.md). + +A big thanks goes to every one who contributed to this release! This includes [@tinaun](https://github.com/tinaun), [@Nemo157](https://github.com/Nemo157), [@cramertj](https://github.com/cramertj) and [@MajorBreakfast](https://github.com/MajorBreakfast) and our new contributors [@gbonik](https://github.com/gbonik) and [@dbcfd](https://github.com/dbcfd)! diff --git a/_posts/2018-08-17-toykio.md b/_posts/2018-08-17-toykio.md new file mode 100644 index 0000000000..84587673b4 --- /dev/null +++ b/_posts/2018-08-17-toykio.md @@ -0,0 +1,198 @@ +--- +layout: post +title: "Fahrenheit" +subtitle: "A task executor with event loop for learning purposes" +author: "Alexander Polakov" +author_github: "polachok" +date: 2018-08-17 +categories: blog +--- + +> Note: fahrenheit was previously called "toykio", but it caused [great confusion](https://www.reddit.com/r/rust/comments/97zzig/toykio_and_futures_03/) amongst reddit users. + +In this blog post I'd like to present [fahrenheit](https://github.com/polachok/fahrenheit), a simple futures executor intended for learning about how executors with an event loop work. Fahrenheit only provides a very minimal feature set: An event loop and TCP streams and listeners. However, it turns out that due to the fact that futures are composable, this is enough to build complex clients and servers. + +In the following, I'd like to give you a quick overview of fahrenheit's components. + +## `AsyncTcpStream` + +Fahrenheit defines the `AsyncTcpStream` type, a newtype wrapper around `TcpStream` from the standard library. Just like in std, the `connect` function opens a connection, and sets the socket to non-blocking mode. This means that the `read()` and `write()` methods will return immediately, either with data or an error. If there's not enough data (for reads) or buffer space (for writes) available, a special kind of error - `WouldBlock` - is returned. We'll discuss how to handle it in the next section. + +## `AsyncRead` & `AsyncWrite` +The `AsyncRead` and `AsyncWrite` traits are the foundation of all I/O futures. The `AsyncReadExt` and `AsyncWriteExt` +extension methods (like `read` and `write_all`) are built on top of them. These traits provide a way to connect futures to an event loop while keeping them independent from any particular event loop implementation. + +Let's take a look at the [AsyncRead](https://github.com/polachok/fahrenheit/blob/futures-0.3/src/async_tcp_stream.rs#L42) implementation for `AsyncTcpStream`: + +```rust +impl AsyncRead for AsyncTcpStream { + fn poll_read(&mut self, cx: &mut Context, buf: &mut [u8]) -> Poll> { + match self.0.read(buf) { + Ok(len) => Poll::Ready(Ok(len)), + Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => { + // Get TcpStream file descriptor + let fd = self.0.as_raw_fd(); + let waker = cx.waker(); + + REACTOR.with(|reactor| reactor.add_read_interest(fd, waker.clone())); + + Poll::Pending + } + Err(err) => panic!("error {:?}", err), + } + } +} +``` +It tries to perform a read on the underlying `TcpStream` and if the read succeeds, the slice will be filled with data. If however the read fails with a `WouldBlock` error, then it registers the current task's waker so that it gets awoken when the data becomes available. More about this in the next section. + +The [AsyncWrite](https://github.com/polachok/fahrenheit/blob/futures-0.3/src/async_tcp_stream.rs#L61) implementation does something analogous for writes. + +## Event loop +The [`EventLoop`](https://github.com/polachok/fahrenheit/blob/futures-0.3/src/lib.rs#L101) +(often also called "reactor") is the core of the executor. It is defined like this: + +```rust +struct InnerEventLoop { + read: RefCell>, + write: RefCell>, + counter: Cell, + wait_queue: RefCell>, + run_queue: RefCell>, +} +``` +- `read` and `write` are `BTreeMaps` which map file descriptors to wakers. +- `wait_queue` stores blocked tasks which wait for an event +- and `run_queue` stores wake-up notifications. + +The event loop provides methods to [register](https://github.com/polachok/fahrenheit/blob/futures-0.3/src/lib.rs#L126) (and remove) interest in read and write events. Let's look at what `add_read_interest` does: + +```rust +fn add_read_interest(&self, fd: RawFd, waker: Waker) { + if !self.read.borrow().contains_key(&fd) { + self.read.borrow_mut().insert(fd, waker); + } +} +``` + +But it just inserts `fd` and `waker` into the `read` map! So where does all the magic happen? +In the [main loop](https://github.com/polachok/fahrenheit/blob/futures-0.3/src/lib.rs#L188). +The event loop is called a loop for a reason. Let's take a look: + +```rust +loop { + // Event loop iteration timeout. If no descriptor is ready we continue iterating + let mut tv: timeval = timeval { + tv_sec: 1, + tv_usec: 0, + }; + + // Initialize fd_sets (file descriptor sets) + let mut read_fds: fd_set = unsafe { std::mem::zeroed() }; + let mut write_fds: fd_set = unsafe { std::mem::zeroed() }; + + unsafe { FD_ZERO(&mut read_fds) }; + unsafe { FD_ZERO(&mut write_fds) }; +``` +Woah, woah, a lot of `unsafe` here! Well, don't worry, it's just how C FFI works. We need to initialize some C structures, a timeout and `fd_set`s. They will be passed to the select(2) function later. + +```rust + // Add read interests to read fd_sets + for fd in self.read.borrow().keys() { + unsafe { FD_SET(*fd, &mut read_fds as *mut fd_set) }; + nfds = std::cmp::max(nfds, fd + 1); + } + + // Add write interests to write fd_sets + for fd in self.write.borrow().keys() { + unsafe { FD_SET(*fd, &mut write_fds as *mut fd_set) }; + nfds = std::cmp::max(nfds, fd + 1); + } +``` +Here we add file descriptors from our `read` and `write` maps from before to the `fd_set`s. + +```rust + // `select` will block until some event happens on the fds or the timeout triggers + let rv = unsafe { + select( + nfds, + &mut read_fds, + &mut write_fds, + std::ptr::null_mut(), + &mut tv, + ) + }; + + // Don't care for errors + if rv == -1 { + panic!("select()"); + } else if rv == 0 { + debug!("timeout"); + } else { + debug!("data available on {} fds", rv); + } +``` +Finally we call `select` with arguments we prepared earlier. `select()` accepts 3 fd_sets (we ignore the third for this example) and a timeout and returns something non-zero in case one (or more) of the file descriptors in the sets are ready. We should then go and find which one it was! + +```rust + // Check which fd it was and put appropriate future on run queue + for (fd, waker) in self.read.borrow().iter() { + let is_set = unsafe { FD_ISSET(*fd, &mut read_fds as *mut fd_set) }; + if is_set { + waker.wake(); + } + } + + // Same for write + for (fd, waker) in self.write.borrow().iter() { + let is_set = unsafe { FD_ISSET(*fd, &mut write_fds as *mut fd_set) }; + if is_set { + waker.wake(); + } + } +``` +We go through our maps again and check if they're set (ready) in fd_sets. When they are, we +call `wake` on their associated wakers, which in turn puts `Wakeup` events on the ready-to-run queue. + +```rust + let mut tasks_done = Vec::new(); + + // Now pop tasks from the run queue and poll them + while let Some(wakeup) = self.run_queue.borrow_mut().pop_front() { + let mut handle = self.handle(); + + if let Some(ref mut task) = self.wait_queue.borrow_mut().get_mut(&wakeup.index) { + // If a task returns `Poll::Ready`, we're done with it + if task.poll(wakeup.waker, &mut handle).is_ready() { + tasks_done.push(wakeup.index); + } + } + } + + // Remove completed tasks + for idx in tasks_done { + self.wait_queue.borrow_mut().remove(&idx); + } + + // Stop the loop if there are no more tasks in the `wait_queue` + if self.wait_queue.borrow().is_empty() { + return; + } +``` +We drain the `run_queue`, retrieve the task index on the `wait_queue` and poll the tasks. Ready (done) tasks are removed from the wait_queue. + +## The life of the future + +In this section, I'd like to recap how a future (let's take [`Read`](https://rust-lang-nursery.github.io/futures-doc/0.3.0-alpha.2/futures/io/struct.Read.html) + for example) is executed on the event loop: + + - first it's created using [`read()`](https://rust-lang-nursery.github.io/futures-doc/0.3.0-alpha.2/futures/io/trait.AsyncReadExt.html#method.read) + method on AsyncTcpStream. This method is implemented for all types that implement `AsyncRead` trait. + - then it's spawned on the executor, using either `run()` or `spawn()` method + - the executor calls `poll()` method on the future. `poll` [implementation](https://rust-lang-nursery.github.io/futures-doc/0.3.0-alpha.2/src/futures_util/io/read.rs.html#28) + for `Read` calls `poll_read()` on the `AsyncTcpStream`, which registers its interest in `readable` events + - when an event occurs, future is polled again. This cycle is repeated until future is ready. + +## Thank you +Thanks to all futures team, and specially [@aturon](https://github.com/aturon) for encouragement and [@MajorBreakfast](https://github.com/MajorBreakfast) for edits. + +That's all for today! You can find fahrenheit on [github](https://github.com/polachok/fahrenheit/tree/futures-0.3) and [crates.io](https://crates.io/crates/fahrenheit). Happy hacking! diff --git a/_posts/2018-09-02-futures-0.3.0-alpha.4.md b/_posts/2018-09-02-futures-0.3.0-alpha.4.md new file mode 100644 index 0000000000..d55d2fb01e --- /dev/null +++ b/_posts/2018-09-02-futures-0.3.0-alpha.4.md @@ -0,0 +1,201 @@ +--- +layout: post +title: "Futures 0.3.0-alpha.4" +subtitle: "Testing utilities" +author: "Wim Looman" +author_github: "Nemo157" +date: 2018-09-02 +categories: blog +--- + +`0.3.0-alpha.4` requires a recent nightly (2018-08-31 or newer): +```sh +$ rustup update +``` + +## `futures-test` + +With `futures 0.3.0-alpha.4` we're releasing a new independent crate called +`futures-test` (under the name [`futures-test-preview`][] on crates.io). +The crate contains various testing utilities that were previously only used +internally in the futures crate. We polished them and made them more ergonomic +to use and are now releasing them as a public standalone crate. What's a little +different compared to the other crates that comprise futures-rs is that this +one is meant to be used as a dev dependency when implementing custom futures. +So, unlike the other crates, its content is not reexported from the `futures` +facade. + +### Testing without `futures-test` + +Before getting into the details of `futures-test`, it's useful to go over a +basic technique for testing asynchronous code that may not be known to everyone. + +A lot of the time you don't care about all the details of how some async +operation executes, just that it performs a certain task. In these cases you +can simply use an async block run via [`futures::executor::block_on`][] and +have all your assertions in there. Here's a quick example: + +```rust +async fn some_operation(callback: F) -> io::Result { + await!(async { /* Some IO stuff */ }); + callback(5); + await!(async { /* Some more IO */ }); + callback(6); + await!(async { /* ... */ }); + return 7; +} + +#[test] +fn test_some_operation() { + futures::executor::block_on(async { + let mut values = vec![]; + let result = await!(some_operation(|value| values.push(value))); + assert_eq!(result, Ok(7); + assert_eq!(values, vec![5, 6]); + }) +} +``` + +### Test `Context`s + +While you can get a long way by just defining and running async tests via +`block_on`, sometimes you need to be able to inspect what is happening more +precisely. E.g. when testing [`FutureExt::fuse`][] we want to check that after +it completes, `poll` correctly returns `Poll::Pending` on subsequent calls. +However, to call `poll` we need to somehow acquire a `task::Context`. +`futures-test` makes this easy. It provides you with all sorts of useful contexts +depending on what you are testing. You have two choices to make when you want to +create a context: + + 1. What should happen when a future calls `cx.waker().wake()`? + 2. What should happen when a future calls `cx.spawner().spawn()`? + +For both of these there are two very basic implementations provided: panicking +and noop (short for "no operation"). Sometimes this is all you need. For example +when testing `FutureExt::fuse` we use [`futures_test::task::panic_context`][] +which gives a context that will panic on either operation: + +```rust +#![feature(pin, arbitrary_self_types, futures_api)] + +use futures::future::{self, FutureExt}; +use futures_test::task::panic_context; + +#[test] +fn fuse() { + let mut future = future::ready::(2).fuse(); + let cx = &mut panic_context(); + assert!(future.poll_unpin(cx).is_ready()); + assert!(future.poll_unpin(cx).is_pending()); +} +``` + +#### [`WakeCounter`][] + +One slightly more specialized `Wake` implementation is to count how +many times a task has been woken. This has been used to check that +[`AbortHandle`][] correctly awakens a waiting task when it is aborted. You can +see from this example that setting up a context with this implementation is +slightly more work. We start with a basic `panic_context`, then swap out the +waker with one provided by the `WakeCounter`: + +```rust + +#![feature(pin, arbitrary_self_types, futures_api)] + +use futures::channel::oneshot; +use futures::future::{abortable, Aborted, FutureExt}; +use futures::task::Poll; +use futures_test::task::{panic_context, WakeCounter}; + +#[test] +fn abortable_awakens() { + let (_tx, a_rx) = oneshot::channel::<()>(); + let (mut abortable_rx, abort_handle) = abortable(a_rx); + + let wake_counter = WakeCounter::new(); + let mut cx = panic_context(); + let cx = &mut cx.with_waker(wake_counter.local_waker()); + + assert_eq!(0, wake_counter.count()); + assert_eq!(Poll::Pending, abortable_rx.poll_unpin(cx)); + assert_eq!(0, wake_counter.count()); + abort_handle.abort(); + assert_eq!(1, wake_counter.count()); + assert_eq!(Poll::Ready(Err(Aborted)), abortable_rx.poll_unpin(cx)); +} +``` + +There are some other implementations provided, take a look in the +[`futures_test::task`][] module docs for more info. + +### [`FutureTestExt`][] + +Along with the context utilities there are some more test specific combinators +provided. These come on an additional `FutureTestExt` trait. For now there are +three provided: + +[`assert_unmoved`][] +: When writing custom futures that wrap other futures you want to be sure that + they're not accidentally moved after they were polled because that's not + allowed. This combinator can create a future that can detect such accidental + moves. + +[`pending_once`][] +: When testing, a lot of the time you will be working with instantly ready + futures like `future::ready(5)` or `async { 6 }`. Frequently you need to + have a future that actually acts like a future. This combinator will return + `Poll::Pending` once and instantly wake its task to emulate a real async + operation. + +[`run_in_background`][] +: Sometimes you just want to run some future to completion and not care + about the details. This will spin up a dedicated executor on a background + thread to run it to completion for you. + +### [`assert_stream_*!`][] + +The final testing utility is trio of macros for working with streams. Together, +these macros allow you to poll a stream one poll at a time and ensure it +behaves exactly as you imagined: + +```rust +#![feature(async_await, futures_api, pin)] +use futures::stream; +use futures_test::future::FutureTestExt; +use futures_test::{ + assert_stream_pending, assert_stream_next, assert_stream_done, +}; +use pin_utils::pin_mut; + +let mut stream = stream::once((async { 5 }).pending_once()); +pin_mut!(stream); + +assert_stream_pending!(stream); +assert_stream_next!(stream, 5); +assert_stream_done!(stream); +``` + +### Improvements to come + +The work on this crate is not done. We already have some ideas for other useful +testing utilities. If you have existing utilities that you're using in your +project or ideas about what would be useful to you [please let us know][#1169]. + +## Further changes + +A complete list of changes can be found in our [changelog](https://github.com/rust-lang-nursery/futures-rs/blob/master/CHANGELOG.md). + +[`futures-test-preview`]: https://crates.io/crates/futures-test-preview +[`futures::executor::block_on`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures/executor/fn.block_on.html +[`FutureExt::fuse`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures/future/trait.FutureExt.html#method.fuse +[`futures_test::task::panic_context`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/task/fn.panic_context.html +[`futures_test::task`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/task/index.html +[#1169]: https://github.com/rust-lang-nursery/futures-rs/issues/1169 +[`WakeCounter`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/task/struct.WakeCounter.html +[`FutureTestExt`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/future/trait.FutureTestExt.html +[`AbortHandle`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures/future/struct.AbortHandle.html +[`assert_unmoved`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/future/trait.FutureTestExt.html#method.assert_unmoved +[`pending_once`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/future/trait.FutureTestExt.html#method.pending_once +[`run_in_background`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/future/trait.FutureTestExt.html#method.run_in_background +[`assert_stream_*!`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.4/futures_test/index.html#macros diff --git a/_posts/2019-04-18-compatibility-layer.md b/_posts/2019-04-18-compatibility-layer.md new file mode 100644 index 0000000000..c1bde15906 --- /dev/null +++ b/_posts/2019-04-18-compatibility-layer.md @@ -0,0 +1,179 @@ +--- +layout: post +title: "Compatibility Layer" +subtitle: "0.1 ❤ 0.3" +author: "Josef Brandl" +author_github: "MajorBreakfast" +date: 2019-04-18 +categories: blog +--- + +# Futures 0.1 Compatibility Layer + +Rust's futures ecosystem is currently split in two: On the one hand we have the vibrant ecosystem built around [`futures@0.1`][] with its many libraries working on stable Rust and on the other hand there's the unstable [`std::future`][] ecosystem with support for the ergonomic and powerful `async`/`await` language feature. To bridge the gap between these two worlds we have introduced a compatibility layer as part of the [`futures@0.3`][] extension to `std::future`. This blog post aims to give an overview over how to use it. + +[`futures@0.1`]: https://docs.rs/futures +[`futures@0.3`]: https://rust-lang-nursery.github.io/futures-api-docs/ +[`std::future`]: https://doc.rust-lang.org/nightly/std/future/ + +## `Cargo.toml` + +The compatibility layer can be enabled by setting the `compat` feature in your `Cargo.toml`: + +```toml +futures-preview = { version = "0.3.0-alpha.14", features = ["compat"] } +``` + +To use `futures@0.1` and `futures@0.3` together in a single project, we can make use of the [new cargo feature for renaming dependencies][renaming-dependencies]. Why? Because, even though the `futures@0.3` crate is called `futures-preview` on crates.io, it's lib name is also `futures`. By renaming `futures` version 0.1 to `futures01`, we can avoid a name collision: + +[renaming-dependencies]: https://doc.rust-lang.org/nightly/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml + +```toml +[dependencies] +futures01 = { package = "futures", version = "0.1", optional = true } +``` + +**Note: Renaming the crate is only required if you specify it as a dependency. If your project only depends on Tokio and thus only indirectly on `futures@0.1`, then no renaming is required.** + +## Async functions on 0.1 executors + +The compatibility layer makes it possible to run `std` futures on executors built for `futures@0.1`. This makes it for instance possible to run futures created via `async`/`await!` on Tokio's executor. Here's how this looks like: + +```rust +#![feature(async_await, await_macro, futures_api)] +use futures::future::{FutureExt, TryFutureExt}; + +let future03 = async { + println!("Running on the pool"); +}; + +let future01 = future03 + .unit_error() + .boxed() + .compat(); + +tokio::run(future01); +``` + +Turning a `std` future into a 0.1 future requires three steps: + +- First, the future needs to be a [`TryFuture`][], i.e. a future with `Output = Result`. If your future isn't a `TryFuture` yet, you can quickly make it one using the [`unit_error`][] combinator which wraps the output in a `Result`. + +- Next, the future needs to be [`Unpin`][]. If your future isn't `Unpin` yet, you can use the [`boxed`][] combinator which wraps the future in a `Pin`. + +- The final step is to call the [`compat`][] combinator which wraps the `std` future into a 0.1 future that can run on any 0.1 executor. + +[`TryFuture`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/future/trait.TryFuture.html +[`unit_error`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/future/trait.FutureExt.html#method.unit_error +[`Unpin`]: https://doc.rust-lang.org/nightly/std/marker/trait.Unpin.html +[`boxed`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/future/trait.FutureExt.html#method.boxed +[`compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/future/trait.TryFutureExt.html#method.compat + +## 0.1 futures in async functions + +The conversion from a 0.1 future to a `std` future also works via a [`compat`][Future01CompatExt::compat] combinator method: + +```rust +use futures::compat::Future01CompatExt; + +let future03 = future01.compat(); +``` + +It converts a 0.1 `Future` into a `std` `Future>`. + +[Future01CompatExt::compat]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.Future01CompatExt.html#method.compat + +## Streams and Sinks + +Converting between 0.1 and 0.3 streams and sinks are possible via the [`TryStreamExt::compat`][], [`Stream01CompatExt::compat`][], [`SinkExt::compat`][] and [`Sink01CompatExt::sink_compat`][] methods. These combinators work analogously to their future equivalents. + +[`TryStreamExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/prelude/trait.TryStreamExt.html#method.compat +[`Stream01CompatExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.Stream01CompatExt.html#method.compat +[`SinkExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/prelude/trait.SinkExt.html#method.compat +[`Sink01CompatExt::sink_compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.Sink01CompatExt.html#method.sink_compat + +## Spawning + +Finally from the core `compat` feature, there's also conversions between futures 0.1 [`Executor`][] trait and futures 0.3 [`Spawn`][] trait. Again, these function near identically to the futures compatibility functions with [`SpawnExt::compat`][] and [`Executor01CompatExt::compat`][] providing the conversions in each direction. + +[`Executor`]: https://docs.rs/futures/0.1.25/futures/future/trait.Executor.html +[`Spawn`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/task/trait.Spawn.html +[`SpawnExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/task/trait.SpawnExt.html#method.compat +[`Executor01CompatExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.Executor01CompatExt.html#tymethod.compat + +## Async IO + +With futures 0.1 IO was almost exclusively provided by Tokio, this was reflected in the core IO traits being provided by [`tokio-io`][]. With 0.3 instead the `futures` crate is providing these core abstractions along with generic utilities that work with them. To convert between these traits you can enable the `io-compat` feature in your `Cargo.toml` (this will implicitly enable the base `compat` feature as well): + +```toml +futures-preview = { version = "0.3.0-alpha.14", features = ["io-compat"] } +``` + +This provides the 4 expected conversions: [`AsyncReadExt::compat`][] and [`AsyncRead01CompatExt::compat`][] to convert between [`futures::io::AsyncRead`][] and [`tokio-io::AsyncRead`][]; and [`AsyncWriteExt::compat_write`][] and [`AsyncWrite01CompatExt::compat`][] to convert between [`futures::io::AsyncWrite`][] and [`tokio-io::AsyncWrite`][]. + +[`tokio-io`]: https://docs.rs/tokio-io/ +[`futures::io::AsyncRead`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/io/trait.AsyncRead.html +[`futures::io::AsyncWrite`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/io/trait.AsyncWrite.html +[`tokio-io::AsyncRead`]: https://docs.rs/tokio-io/0.1.10/tokio_io/trait.AsyncRead.html +[`tokio-io::AsyncWrite`]: https://docs.rs/tokio-io/0.1.10/tokio_io/trait.AsyncWrite.html +[`AsyncReadExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/io/trait.AsyncReadExt.html#method.compat +[`AsyncRead01CompatExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.AsyncRead01CompatExt.html#tymethod.compat +[`AsyncWriteExt::compat_write`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/io/trait.AsyncWriteExt.html#method.compat_write +[`AsyncWrite01CompatExt::compat`]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.14/futures/compat/trait.AsyncWrite01CompatExt.html#tymethod.compat + +## Conclusion + +The compatibility layer offers conversions in both directions and thus enables gradual migrations and experiments with `std::future`. With that it manages to bridge the gap between the futures 0.1 and futures 0.3 ecosystems. + +Finally a self contained example that shows using futures 0.1 based `hyper` and `tokio` with a `std` async/await layer in between: + +```toml +[dependencies] +futures-preview = { version = "0.3.0-alpha.14", features = ["io-compat"] } +hyper = "0.12.25" +tokio = "0.1.16" +pin-utils = "0.1.0-alpha.4" +``` + +```rust +#![feature(async_await, await_macro, futures_api)] + +use futures::{ + compat::{Future01CompatExt, Stream01CompatExt, AsyncWrite01CompatExt}, + future::{FutureExt, TryFutureExt}, + io::AsyncWriteExt, + stream::StreamExt, +}; +use pin_utils::pin_mut; +use std::error::Error; + +fn main() { + let future03 = async { + let url = "http://httpbin.org/ip".parse()?; + + let client = hyper::Client::new(); + let res = await!(client.get(url).compat())?; + println!("{}", res.status()); + + let body = res.into_body().compat(); + pin_mut!(body); + + let mut stdout = tokio::io::stdout().compat(); + while let Some(Ok(chunk)) = await!(body.next()) { + await!(stdout.write_all(&chunk))?; + } + + Ok(()) + }; + + tokio::run(future03.map_err(|e: Box| panic!("{}", e)).boxed().compat()) +} +``` + +Special thanks goes to the main authors of the compatibility layer: + + * [@tinaun](https://www.github.com/tinaun) + * [@Nemo157](https://www.github.com/Nemo157) + * [@cramertj](https://www.github.com/cramertj) + * [@LucioFranco](https://www.github.com/LucioFranco) + diff --git a/_sass/_fonts.scss b/_sass/_fonts.scss new file mode 100644 index 0000000000..0e5239ded2 --- /dev/null +++ b/_sass/_fonts.scss @@ -0,0 +1,132 @@ +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-LightItalic.woff2') format('woff2'), + url('fonts/roboto/Roboto-LightItalic.woff') format('woff'); + font-weight: 300; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Thin.woff2') format('woff2'), + url('fonts/roboto/Roboto-Thin.woff') format('woff'); + font-weight: 100; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-BoldItalic.woff2') format('woff2'), + url('fonts/roboto/Roboto-BoldItalic.woff') format('woff'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Light.woff2') format('woff2'), + url('fonts/roboto/Roboto-Light.woff') format('woff'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Regular.woff2') format('woff2'), + url('fonts/roboto/Roboto-Regular.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-ThinItalic.woff2') format('woff2'), + url('fonts/roboto/Roboto-ThinItalic.woff') format('woff'); + font-weight: 100; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Bold.woff2') format('woff2'), + url('fonts/roboto/Roboto-Bold.woff') format('woff'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Medium.woff2') format('woff2'), + url('fonts/roboto/Roboto-Medium.woff') format('woff'); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Italic.woff2') format('woff2'), + url('fonts/roboto/Roboto-Italic.woff') format('woff'); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-Black.woff2') format('woff2'), + url('fonts/roboto/Roboto-Black.woff') format('woff'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-MediumItalic.woff2') format('woff2'), + url('fonts/roboto/Roboto-MediumItalic.woff') format('woff'); + font-weight: 500; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('fonts/roboto/Roboto-BlackItalic.woff2') format('woff2'), + url('fonts/roboto/Roboto-BlackItalic.woff') format('woff'); + font-weight: 900; + font-style: italic; +} + + + + + +@font-face { + font-family: 'Roboto Slab'; + src: url('fonts/roboto-slab/RobotoSlab-Bold.woff2') format('woff2'), + url('fonts/roboto-slab/RobotoSlab-Bold.woff') format('woff'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Roboto Slab'; + src: url('fonts/roboto-slab/RobotoSlab-Light.woff2') format('woff2'), + url('fonts/roboto-slab/RobotoSlab-Light.woff') format('woff'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'Roboto Slab'; + src: url('fonts/roboto-slab/RobotoSlab-Thin.woff2') format('woff2'), + url('fonts/roboto-slab/RobotoSlab-Thin.woff') format('woff'); + font-weight: 100; + font-style: normal; +} + +@font-face { + font-family: 'Roboto Slab'; + src: url('fonts/roboto-slab/RobotoSlab-Regular.woff2') format('woff2'), + url('fonts/roboto-slab/RobotoSlab-Regular.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + diff --git a/_sass/_footer.scss b/_sass/_footer.scss new file mode 100644 index 0000000000..f20c45a9eb --- /dev/null +++ b/_sass/_footer.scss @@ -0,0 +1,16 @@ +footer.site-footer { + border-top: 1px solid #eee; + + .wrapper { + margin: 0 auto; + padding: 30px 15px; + max-width: 800px; + + display: flex; + color: #aaa; + + a { + @include underline-link(#777); + } + } +} diff --git a/_sass/_header.scss b/_sass/_header.scss new file mode 100644 index 0000000000..d7d6d089ce --- /dev/null +++ b/_sass/_header.scss @@ -0,0 +1,39 @@ +header.site-header { + background: linear-gradient(to right, #493c7a, #4b79a1, #493c7a); + + .wrapper { + margin: 0 auto; + padding: 15px 15px; + max-width: 800px; + display: flex; + align-items: center; + + .header-link { + @include underline-link(white); + margin-right: 30px; + } + + .github-link { + border: 2px solid white; + padding: 5px 10px; + color: white; + text-decoration: none; + outline: none; + + display: flex; + align-items: center; + + img { + margin-right: 8px; + } + + &:hover, &:focus { + background: rgba(255, 255, 255, 0.2); + } + + &:active { + background: rgba(255, 255, 255, 0.6); + } + } + } +} diff --git a/_sass/_home.scss b/_sass/_home.scss new file mode 100644 index 0000000000..7d794d1a6f --- /dev/null +++ b/_sass/_home.scss @@ -0,0 +1,56 @@ +#home-futures-logo-box { + background: linear-gradient(to right, #493c7a, #4b79a1, #493c7a); + padding: 30px 15px 50px; + + .slogan { + margin-top: 20px; + } +} + +.page-home { + margin: 0 auto; + padding: 15px; + max-width: 800px; + + h2 { + font-size: 40px; + } + + ul.post-list { + margin: 20px 0 50px; + padding: 0; + + li { + margin: 25px 0; + list-style-type: none; + + h3 { + margin: 2px 0; + + a { + @include underline-link($primary_color); + p { display: inline; margin: 0; } + } + } + + .post-description { + color: #aaa; + font-style: italic; + + p { display: inline; margin: 0; } + + code.highlighter-rouge { + color: #999; + } + } + } + } + + .rss { + margin: 30px 0; + + a { + @include underline-link(black); + } + } +} diff --git a/_sass/_post.scss b/_sass/_post.scss new file mode 100644 index 0000000000..e6e3831e5e --- /dev/null +++ b/_sass/_post.scss @@ -0,0 +1,115 @@ +article.post { + margin: 0 auto; + padding: 15px; + max-width: 800px; + + .post-header { + margin-bottom: 60px; + + h1 { + margin-bottom: 5px; + } + + p { + margin: 0; + } + + .post-meta { + text-align: center; + color: #aaa; + + a.author-github { + @include underline-link(#aaa); + } + } + } + + .post-content { + div.info { + background: rgb(181, 211, 255); + border-left: 4px solid rgb(54, 95, 156); + padding: 15px; + border-radius: 4px; + } + + h1, h2, h3, h4, h5, h6 { + code.highlighter-rouge { + color: $primary-color; + } + } + + a { + @include underline-link($primary-color); + + > code.highlighter-rouge { + position: relative; + box-shadow: 0 3px 0 0px white; // Hide link underline (border) + color: $primary-color; + } + + &:hover > code.highlighter-rouge, + &:focus > code.highlighter-rouge { + color: white; + background: $primary-color; + border-color: $primary-color; + } + } + + dl { + dt { + margin-bottom: 3px; + } + dd { + margin-bottom: 10px; + } + } + + blockquote { + color: #666; + font-style: italic; + margin: 0 0 0 30px; + position: relative; + &::before { + content: ""; + display: block; + position: absolute; top: 0; left: -15px; bottom: 0; width: 3px; + border-radius: 1.5px; + background: $primary-color; + } + } + + ul ul { + margin-bottom: 7px; + } + } + + .edit-link-container { + text-align: right; + margin: 30px 0; + + a { + @include underline-link(#ccc); + } + } + + .navigation-buttons { + display: flex; + margin: 30px 0; + + .next, .previous { + flex: 1 0 0; + + .label { + color: #555; + } + + a { + @include underline-link($primary-color); + } + } + + .next { + text-align: right; + } + } +} diff --git a/_sass/_reset.scss b/_sass/_reset.scss new file mode 100644 index 0000000000..2d3764fb0a --- /dev/null +++ b/_sass/_reset.scss @@ -0,0 +1,5 @@ +html, +body { + margin: 0; + padding: 0; +} diff --git a/_sass/_syntax.scss b/_sass/_syntax.scss new file mode 100644 index 0000000000..fbe5c307f6 --- /dev/null +++ b/_sass/_syntax.scss @@ -0,0 +1,106 @@ +code { + font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace; +} + +div.highlighter-rouge { // Code blocks + padding: 15px; + border: 1px solid #eee; + border-radius: 4px; + margin: 20px 0; + + font-size: 12px; + line-height: 20px; + + overflow: auto; + -webkit-overflow-scrolling: touch; + + .highlight { + margin: 0; + } +} + +code.highlighter-rouge { // Inline code + font-size: 0.8em; + padding: 1px 3px; + border: 1px solid #e4e4e4; + border-radius: 3px; + background: #f7f7f7; + color: #111; +} + +// Based on: https://github.com/richleland/pygments-css/blob/master/colorful.css + +.highlight .nf { color: #6f42c1 } /* `foo` in `bar::foo()` */ + +// .highlight .hll { background-color: #ffffcc } +// .highlight { background: #ffffff; } +.highlight .c { color: #6a737d } /* Comment */ +//.highlight .err {} /* Error */ +.highlight .k { color: #d73a49; } /* Keyword */ +// .highlight .o { color: #d73a49 } /* Operator (Would color `!` in `#![]`) */ +// .highlight .ch { color: #6a737d } /* Comment.Hashbang */ +// .highlight .cm { color: #6a737d } /* Comment.Multiline */ +// .highlight .cp { color: #557799 } /* Comment.Preproc */ +// .highlight .cpf { color: #6a737d } /* Comment.PreprocFile */ +// .highlight .c1 { color: #6a737d } /* Comment.Single */ +// .highlight .cs { color: #cc0000; } /* Comment.Special */ +// .highlight .gd { color: #A00000 } /* Generic.Deleted */ +// .highlight .ge { font-style: italic } /* Generic.Emph */ +// .highlight .gr { color: #FF0000 } /* Generic.Error */ +// .highlight .gh { color: #000080; } /* Generic.Heading */ +// .highlight .gi { color: #00A000 } /* Generic.Inserted */ +// .highlight .go { color: #6a737d } /* Generic.Output */ +// .highlight .gp { color: #c65d09; } /* Generic.Prompt */ +// .highlight .gs { } /* Generic.Strong */ +// .highlight .gu { color: #800080; } /* Generic.Subheading */ +// .highlight .gt { color: #0044DD } /* Generic.Traceback */ +// .highlight .kc { color: #d73a49; } /* Keyword.Constant */ +// .highlight .kd { color: #d73a49; } /* Keyword.Declaration */ +// .highlight .kn { color: #d73a49; } /* Keyword.Namespace */ +// .highlight .kp { color: #003388; } /* Keyword.Pseudo */ +// .highlight .kr { color: #d73a49; } /* Keyword.Reserved */ +// .highlight .kt { color: #333399; } /* Keyword.Type */ +// .highlight .m { color: #6600EE; } /* Literal.Number */ +// .highlight .s {} /* Literal.String */ +// .highlight .na { color: #0000CC } /* Name.Attribute */ +.highlight .nb { color: #d73a49 } /* Name.Builtin */ + +.highlight .n { color: #6f42c1 } /* Name */ +.highlight .nc { color: #6f42c1; } /* Name.Class */ +.highlight .nd { color: #6f42c1; } /* Name.Decorator */ +.highlight .ne { color: #6f42c1; } /* Name.Exception */ +.highlight .nf { color: #6f42c1; } /* Name.Function */ +.highlight .ni { color: #6f42c1; } /* Name.Entity */ +.highlight .nl { color: #6f42c1; } /* Name.Label */ +.highlight .nn { color: #6f42c1; } /* Name.Namespace */ +.highlight .no { color: #6f42c1; } /* Name.Constant */ +.highlight .nt { color: #6f42c1 } /* Name.Tag */ +.highlight .nv { color: #d73a49 } /* Name.Variable */ + +// .highlight .ow { color: #000000; } /* Operator.Word */ +// .highlight .w { color: #bbbbbb } /* Text.Whitespace */ +// .highlight .mb { color: #6600EE; } /* Literal.Number.Bin */ +// .highlight .mf { color: #6600EE; } /* Literal.Number.Float */ +// .highlight .mh { color: #005588; } /* Literal.Number.Hex */ +// .highlight .mi { color: #0000DD; } /* Literal.Number.Integer */ +// .highlight .mo { color: #4400EE; } /* Literal.Number.Oct */ +// .highlight .sa { background-color: #fff0f0 } /* Literal.String.Affix */ +// .highlight .sb { background-color: #fff0f0 } /* Literal.String.Backtick */ +// .highlight .sc { color: #0044DD } /* Literal.String.Char */ +// .highlight .dl { background-color: #fff0f0 } /* Literal.String.Delimiter */ +// .highlight .sd { color: #DD4422 } /* Literal.String.Doc */ +// .highlight .s2 { background-color: #fff0f0 } /* Literal.String.Double */ +// .highlight .se { color: #666666;; background-color: #fff0f0 } /* Literal.String.Escape */ +// .highlight .sh { background-color: #fff0f0 } /* Literal.String.Heredoc */ +// .highlight .si { background-color: #eeeeee } /* Literal.String.Interpol */ +// .highlight .sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */ +// .highlight .sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */ +// .highlight .s1 { background-color: #fff0f0 } /* Literal.String.Single */ +// .highlight .ss { color: #AA6600 } /* Literal.String.Symbol */ +// .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +// .highlight .fm { color: #0066BB; } /* Name.Function.Magic */ +// .highlight .vc { color: #336699 } /* Name.Variable.Class */ +// .highlight .vg { color: #dd7700; } /* Name.Variable.Global */ +// .highlight .vi { color: #3333BB } /* Name.Variable.Instance */ +// .highlight .vm { color: #d73a49 } /* Name.Variable.Magic */ +// .highlight .il { color: #0000DD; } /* Literal.Number.Integer.Long */ diff --git a/_sass/_underline-link-mixin.scss b/_sass/_underline-link-mixin.scss new file mode 100644 index 0000000000..f575bf05f8 --- /dev/null +++ b/_sass/_underline-link-mixin.scss @@ -0,0 +1,22 @@ +@mixin underline-link($color) { + text-decoration: none; + color: $color; + outline: none; + font-weight: bold; + white-space: nowrap; + position: relative; transform: translateX(0); // Force stacking context + + &::after { + z-index: -1; + content: ''; + position: absolute; left: 0; width: 100%; bottom: -2px; height: 2px; + background: $color; + transition: 0.1s ease-out; + transform: scaleX(0); + } + + &:hover::after, + &:focus::after { + transform: scaleX(1); + } +} diff --git a/_sass/futures-theme.scss b/_sass/futures-theme.scss new file mode 100644 index 0000000000..455c8b616b --- /dev/null +++ b/_sass/futures-theme.scss @@ -0,0 +1,28 @@ +$primary-color: #F03E0E; + +@import 'reset'; +@import 'fonts'; +@import 'syntax'; +@import 'underline-link-mixin'; + +@import 'header'; +@import 'footer'; + +@import 'home'; +@import 'post'; + +body { + font-family: Roboto; + line-height: 1.42em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: 'Roboto Slab'; + color: $primary-color; + line-height: 1.5em; +} + +h1 { + font-size: 40px; + text-align: center; +} diff --git a/assets/fonts/roboto-slab/LICENSE.txt b/assets/fonts/roboto-slab/LICENSE.txt new file mode 100755 index 0000000000..75b52484ea --- /dev/null +++ b/assets/fonts/roboto-slab/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/assets/fonts/roboto-slab/RobotoSlab-Bold.woff b/assets/fonts/roboto-slab/RobotoSlab-Bold.woff new file mode 100644 index 0000000000..24c5e3e73c Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Bold.woff differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Bold.woff2 b/assets/fonts/roboto-slab/RobotoSlab-Bold.woff2 new file mode 100644 index 0000000000..39a843e0c0 Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Bold.woff2 differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Light.woff b/assets/fonts/roboto-slab/RobotoSlab-Light.woff new file mode 100644 index 0000000000..28097214f4 Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Light.woff differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Light.woff2 b/assets/fonts/roboto-slab/RobotoSlab-Light.woff2 new file mode 100644 index 0000000000..7f48a58678 Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Light.woff2 differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Regular.woff b/assets/fonts/roboto-slab/RobotoSlab-Regular.woff new file mode 100644 index 0000000000..7f3d91cfe9 Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Regular.woff differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Regular.woff2 b/assets/fonts/roboto-slab/RobotoSlab-Regular.woff2 new file mode 100644 index 0000000000..f1019999fd Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Regular.woff2 differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Thin.woff b/assets/fonts/roboto-slab/RobotoSlab-Thin.woff new file mode 100644 index 0000000000..db7e8ba79e Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Thin.woff differ diff --git a/assets/fonts/roboto-slab/RobotoSlab-Thin.woff2 b/assets/fonts/roboto-slab/RobotoSlab-Thin.woff2 new file mode 100644 index 0000000000..8e2047544a Binary files /dev/null and b/assets/fonts/roboto-slab/RobotoSlab-Thin.woff2 differ diff --git a/assets/fonts/roboto/LICENSE.txt b/assets/fonts/roboto/LICENSE.txt new file mode 100755 index 0000000000..75b52484ea --- /dev/null +++ b/assets/fonts/roboto/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/assets/fonts/roboto/Roboto-Black.woff b/assets/fonts/roboto/Roboto-Black.woff new file mode 100644 index 0000000000..d77f5a1a73 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Black.woff differ diff --git a/assets/fonts/roboto/Roboto-Black.woff2 b/assets/fonts/roboto/Roboto-Black.woff2 new file mode 100644 index 0000000000..8dff3b1b0e Binary files /dev/null and b/assets/fonts/roboto/Roboto-Black.woff2 differ diff --git a/assets/fonts/roboto/Roboto-BlackItalic.woff b/assets/fonts/roboto/Roboto-BlackItalic.woff new file mode 100644 index 0000000000..943e97e625 Binary files /dev/null and b/assets/fonts/roboto/Roboto-BlackItalic.woff differ diff --git a/assets/fonts/roboto/Roboto-BlackItalic.woff2 b/assets/fonts/roboto/Roboto-BlackItalic.woff2 new file mode 100644 index 0000000000..7f511913ec Binary files /dev/null and b/assets/fonts/roboto/Roboto-BlackItalic.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Bold.woff b/assets/fonts/roboto/Roboto-Bold.woff new file mode 100644 index 0000000000..51f1e89d1f Binary files /dev/null and b/assets/fonts/roboto/Roboto-Bold.woff differ diff --git a/assets/fonts/roboto/Roboto-Bold.woff2 b/assets/fonts/roboto/Roboto-Bold.woff2 new file mode 100644 index 0000000000..8d1ec3a769 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Bold.woff2 differ diff --git a/assets/fonts/roboto/Roboto-BoldItalic.woff b/assets/fonts/roboto/Roboto-BoldItalic.woff new file mode 100644 index 0000000000..d916f946ee Binary files /dev/null and b/assets/fonts/roboto/Roboto-BoldItalic.woff differ diff --git a/assets/fonts/roboto/Roboto-BoldItalic.woff2 b/assets/fonts/roboto/Roboto-BoldItalic.woff2 new file mode 100644 index 0000000000..ebca4c79c7 Binary files /dev/null and b/assets/fonts/roboto/Roboto-BoldItalic.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Italic.woff b/assets/fonts/roboto/Roboto-Italic.woff new file mode 100644 index 0000000000..8e72e8d186 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Italic.woff differ diff --git a/assets/fonts/roboto/Roboto-Italic.woff2 b/assets/fonts/roboto/Roboto-Italic.woff2 new file mode 100644 index 0000000000..17140141bf Binary files /dev/null and b/assets/fonts/roboto/Roboto-Italic.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Light.woff b/assets/fonts/roboto/Roboto-Light.woff new file mode 100644 index 0000000000..eec3617f89 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Light.woff differ diff --git a/assets/fonts/roboto/Roboto-Light.woff2 b/assets/fonts/roboto/Roboto-Light.woff2 new file mode 100644 index 0000000000..0e0efd0922 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Light.woff2 differ diff --git a/assets/fonts/roboto/Roboto-LightItalic.woff b/assets/fonts/roboto/Roboto-LightItalic.woff new file mode 100644 index 0000000000..b6b25253be Binary files /dev/null and b/assets/fonts/roboto/Roboto-LightItalic.woff differ diff --git a/assets/fonts/roboto/Roboto-LightItalic.woff2 b/assets/fonts/roboto/Roboto-LightItalic.woff2 new file mode 100644 index 0000000000..b3300d9c4b Binary files /dev/null and b/assets/fonts/roboto/Roboto-LightItalic.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Medium.woff b/assets/fonts/roboto/Roboto-Medium.woff new file mode 100644 index 0000000000..b4f0629a04 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Medium.woff differ diff --git a/assets/fonts/roboto/Roboto-Medium.woff2 b/assets/fonts/roboto/Roboto-Medium.woff2 new file mode 100644 index 0000000000..02bf76456f Binary files /dev/null and b/assets/fonts/roboto/Roboto-Medium.woff2 differ diff --git a/assets/fonts/roboto/Roboto-MediumItalic.woff b/assets/fonts/roboto/Roboto-MediumItalic.woff new file mode 100644 index 0000000000..ca56ca36db Binary files /dev/null and b/assets/fonts/roboto/Roboto-MediumItalic.woff differ diff --git a/assets/fonts/roboto/Roboto-MediumItalic.woff2 b/assets/fonts/roboto/Roboto-MediumItalic.woff2 new file mode 100644 index 0000000000..098ab8adf0 Binary files /dev/null and b/assets/fonts/roboto/Roboto-MediumItalic.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Regular.woff b/assets/fonts/roboto/Roboto-Regular.woff new file mode 100644 index 0000000000..b070d8e0a4 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Regular.woff differ diff --git a/assets/fonts/roboto/Roboto-Regular.woff2 b/assets/fonts/roboto/Roboto-Regular.woff2 new file mode 100644 index 0000000000..30370cf27b Binary files /dev/null and b/assets/fonts/roboto/Roboto-Regular.woff2 differ diff --git a/assets/fonts/roboto/Roboto-Thin.woff b/assets/fonts/roboto/Roboto-Thin.woff new file mode 100644 index 0000000000..bc180321c0 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Thin.woff differ diff --git a/assets/fonts/roboto/Roboto-Thin.woff2 b/assets/fonts/roboto/Roboto-Thin.woff2 new file mode 100644 index 0000000000..c5353095c2 Binary files /dev/null and b/assets/fonts/roboto/Roboto-Thin.woff2 differ diff --git a/assets/fonts/roboto/Roboto-ThinItalic.woff b/assets/fonts/roboto/Roboto-ThinItalic.woff new file mode 100644 index 0000000000..88639462fe Binary files /dev/null and b/assets/fonts/roboto/Roboto-ThinItalic.woff differ diff --git a/assets/fonts/roboto/Roboto-ThinItalic.woff2 b/assets/fonts/roboto/Roboto-ThinItalic.woff2 new file mode 100644 index 0000000000..069ad7b942 Binary files /dev/null and b/assets/fonts/roboto/Roboto-ThinItalic.woff2 differ diff --git a/assets/images/futures-rs-logo-flat.afdesign b/assets/images/futures-rs-logo-flat.afdesign new file mode 100644 index 0000000000..b6165e285d Binary files /dev/null and b/assets/images/futures-rs-logo-flat.afdesign differ diff --git a/assets/images/futures-rs-logo-flat.svg b/assets/images/futures-rs-logo-flat.svg new file mode 100644 index 0000000000..95262f3e1d --- /dev/null +++ b/assets/images/futures-rs-logo-flat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/futures-rs-logo.afdesign b/assets/images/futures-rs-logo.afdesign new file mode 100644 index 0000000000..0f1e52ec13 Binary files /dev/null and b/assets/images/futures-rs-logo.afdesign differ diff --git a/assets/images/futures-rs-logo.svg b/assets/images/futures-rs-logo.svg new file mode 100644 index 0000000000..f3c046d8fb --- /dev/null +++ b/assets/images/futures-rs-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/github.svg b/assets/images/github.svg new file mode 100644 index 0000000000..ef6ea59adc --- /dev/null +++ b/assets/images/github.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/rss.svg b/assets/images/rss.svg new file mode 100644 index 0000000000..0ed25bf6e6 --- /dev/null +++ b/assets/images/rss.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/main.scss b/assets/main.scss new file mode 100644 index 0000000000..5e0e76303c --- /dev/null +++ b/assets/main.scss @@ -0,0 +1,6 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- + +// @import "minima"; +@import "futures-theme"; diff --git a/examples/functional/Cargo.toml b/examples/functional/Cargo.toml deleted file mode 100644 index bb95a6f6a3..0000000000 --- a/examples/functional/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "futures-example-functional" -version = "0.0.0" -edition = "2018" -publish = false - -[dependencies] -futures = { path = "../../futures", features = ["thread-pool"] } - -[lints] -workspace = true diff --git a/examples/functional/src/main.rs b/examples/functional/src/main.rs deleted file mode 100644 index d535a61b45..0000000000 --- a/examples/functional/src/main.rs +++ /dev/null @@ -1,46 +0,0 @@ -use futures::channel::mpsc; -use futures::executor; //standard executors to provide a context for futures and streams -use futures::executor::ThreadPool; -use futures::StreamExt; - -fn main() { - let pool = ThreadPool::new().expect("Failed to build pool"); - let (tx, rx) = mpsc::unbounded::(); - - // Create a future by an async block, where async is responsible for an - // implementation of Future. At this point no executor has been provided - // to this future, so it will not be running. - let fut_values = async { - // Create another async block, again where the Future implementation - // is generated by async. Since this is inside of a parent async block, - // it will be provided with the executor of the parent block when the parent - // block is executed. - // - // This executor chaining is done by Future::poll whose second argument - // is a std::task::Context. This represents our executor, and the Future - // implemented by this async block can be polled using the parent async - // block's executor. - let fut_tx_result = async move { - (0..100).for_each(|v| { - tx.unbounded_send(v).expect("Failed to send"); - }) - }; - - // Use the provided thread pool to spawn the generated future - // responsible for transmission - pool.spawn_ok(fut_tx_result); - - let fut_values = rx.map(|v| v * 2).collect(); - - // Use the executor provided to this async block to wait for the - // future to complete. - fut_values.await - }; - - // Actually execute the above future, which will invoke Future::poll and - // subsequently chain appropriate Future::poll and methods needing executors - // to drive all futures. Eventually fut_values will be driven to completion. - let values: Vec = executor::block_on(fut_values); - - println!("Values={values:?}"); -} diff --git a/examples/imperative/Cargo.toml b/examples/imperative/Cargo.toml deleted file mode 100644 index afd7a20428..0000000000 --- a/examples/imperative/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "futures-example-imperative" -version = "0.0.0" -edition = "2018" -publish = false - -[dependencies] -futures = { path = "../../futures", features = ["thread-pool"] } - -[lints] -workspace = true diff --git a/examples/imperative/src/main.rs b/examples/imperative/src/main.rs deleted file mode 100644 index 1c952537bf..0000000000 --- a/examples/imperative/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -use futures::channel::mpsc; -use futures::executor; //standard executors to provide a context for futures and streams -use futures::executor::ThreadPool; -use futures::StreamExt; - -fn main() { - let pool = ThreadPool::new().expect("Failed to build pool"); - let (tx, mut rx) = mpsc::unbounded::(); - - // Create a future by an async block, where async is responsible for generating - // an implementation of Future. At this point no executor has been provided - // to this future, so it will not be running. - let fut_values = async { - // Create another async block, again where Future is implemented by - // async. Since this is inside of a parent async block, it will be - // provided with the executor of the parent block when the parent - // block is executed. - // - // This executor chaining is done by Future::poll whose second argument - // is a std::task::Context. This represents our executor, and the Future - // implemented by this async block can be polled using the parent async - // block's executor. - let fut_tx_result = async move { - (0..100).for_each(|v| { - tx.unbounded_send(v).expect("Failed to send"); - }) - }; - - // Use the provided thread pool to spawn the transmission - pool.spawn_ok(fut_tx_result); - - let mut pending = vec![]; - // Use the provided executor to wait for the next value - // of the stream to be available. - while let Some(v) = rx.next().await { - pending.push(v * 2); - } - - pending - }; - - // Actually execute the above future, which will invoke Future::poll and - // subsequently chain appropriate Future::poll and methods needing executors - // to drive all futures. Eventually fut_values will be driven to completion. - let values: Vec = executor::block_on(fut_values); - - println!("Values={values:?}"); -} diff --git a/futures-channel/Cargo.toml b/futures-channel/Cargo.toml deleted file mode 100644 index 6443709cb5..0000000000 --- a/futures-channel/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "futures-channel" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -Channels for asynchronous communication using futures-rs. -""" - -[features] -default = ["std"] -std = ["alloc", "futures-core/std"] -alloc = ["futures-core/alloc"] -sink = ["futures-sink"] - -[dependencies] -futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false } -futures-sink = { path = "../futures-sink", version = "=0.4.0-alpha.0", default-features = false, optional = true } - -[dev-dependencies] -futures = { path = "../futures", default-features = true } -futures-test = { path = "../futures-test", default-features = true } - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/futures-channel/LICENSE-APACHE b/futures-channel/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-channel/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-channel/LICENSE-MIT b/futures-channel/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-channel/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-channel/README.md b/futures-channel/README.md deleted file mode 100644 index f386839289..0000000000 --- a/futures-channel/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-channel - -Channels for asynchronous communication using futures-rs. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-channel = "0.3" -``` - -The current `futures-channel` requires Rust 1.68 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-channel/benches/sync_mpsc.rs b/futures-channel/benches/sync_mpsc.rs deleted file mode 100644 index 7c3c3d3a80..0000000000 --- a/futures-channel/benches/sync_mpsc.rs +++ /dev/null @@ -1,135 +0,0 @@ -#![feature(test)] - -extern crate test; -use crate::test::Bencher; - -use { - futures::{ - channel::mpsc::{self, Sender, UnboundedSender}, - ready, - sink::Sink, - stream::{Stream, StreamExt}, - task::{Context, Poll}, - }, - futures_test::task::noop_context, - std::pin::Pin, -}; - -/// Single producer, single consumer -#[bench] -fn unbounded_1_tx(b: &mut Bencher) { - let mut cx = noop_context(); - b.iter(|| { - let (tx, mut rx) = mpsc::unbounded(); - - // 1000 iterations to avoid measuring overhead of initialization - // Result should be divided by 1000 - for i in 0..1000 { - // Poll, not ready, park - assert_eq!(Poll::Pending, rx.poll_next_unpin(&mut cx)); - - UnboundedSender::unbounded_send(&tx, i).unwrap(); - - // Now poll ready - assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx)); - } - }) -} - -/// 100 producers, single consumer -#[bench] -fn unbounded_100_tx(b: &mut Bencher) { - let mut cx = noop_context(); - b.iter(|| { - let (tx, mut rx) = mpsc::unbounded(); - - let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect(); - - // 1000 send/recv operations total, result should be divided by 1000 - for _ in 0..10 { - for (i, x) in tx.iter().enumerate() { - assert_eq!(Poll::Pending, rx.poll_next_unpin(&mut cx)); - - UnboundedSender::unbounded_send(x, i).unwrap(); - - assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx)); - } - } - }) -} - -#[bench] -fn unbounded_uncontended(b: &mut Bencher) { - let mut cx = noop_context(); - b.iter(|| { - let (tx, mut rx) = mpsc::unbounded(); - - for i in 0..1000 { - UnboundedSender::unbounded_send(&tx, i).expect("send"); - // No need to create a task, because poll is not going to park. - assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx)); - } - }) -} - -/// A Stream that continuously sends incrementing number of the queue -struct TestSender { - tx: Sender, - last: u32, // Last number sent -} - -// Could be a Future, it doesn't matter -impl Stream for TestSender { - type Item = u32; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let mut tx = Pin::new(&mut this.tx); - - ready!(tx.as_mut().poll_ready(cx)).unwrap(); - tx.as_mut().start_send(this.last + 1).unwrap(); - this.last += 1; - assert_eq!(Poll::Pending, tx.as_mut().poll_flush(cx)); - Poll::Ready(Some(this.last)) - } -} - -/// Single producers, single consumer -#[bench] -fn bounded_1_tx(b: &mut Bencher) { - let mut cx = noop_context(); - b.iter(|| { - let (tx, mut rx) = mpsc::channel(0); - - let mut tx = TestSender { tx, last: 0 }; - - for i in 0..1000 { - assert_eq!(Poll::Ready(Some(i + 1)), tx.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Pending, tx.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(i + 1)), rx.poll_next_unpin(&mut cx)); - } - }) -} - -/// 100 producers, single consumer -#[bench] -fn bounded_100_tx(b: &mut Bencher) { - let mut cx = noop_context(); - b.iter(|| { - // Each sender can send one item after specified capacity - let (tx, mut rx) = mpsc::channel(0); - - let mut tx: Vec<_> = (0..100).map(|_| TestSender { tx: tx.clone(), last: 0 }).collect(); - - for i in 0..10 { - for x in &mut tx { - // Send an item - assert_eq!(Poll::Ready(Some(i + 1)), x.poll_next_unpin(&mut cx)); - // Then block - assert_eq!(Poll::Pending, x.poll_next_unpin(&mut cx)); - // Recv the item - assert_eq!(Poll::Ready(Some(i + 1)), rx.poll_next_unpin(&mut cx)); - } - } - }) -} diff --git a/futures-channel/src/lib.rs b/futures-channel/src/lib.rs deleted file mode 100644 index 09d6a1e2de..0000000000 --- a/futures-channel/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Asynchronous channels. -//! -//! Like threads, concurrent tasks sometimes need to communicate with each -//! other. This module contains two basic abstractions for doing so: -//! -//! - [oneshot], a way of sending a single value from one task to another. -//! - [mpsc], a multi-producer, single-consumer channel for sending values -//! between tasks, analogous to the similarly-named structure in the standard -//! library. -//! -//! All items are only available when the `std` or `alloc` feature of this -//! library is activated, and it is activated by default. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod lock; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "std")] -pub mod mpsc; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub mod oneshot; diff --git a/futures-channel/src/lock.rs b/futures-channel/src/lock.rs deleted file mode 100644 index b328d0f7dd..0000000000 --- a/futures-channel/src/lock.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! A "mutex" which only supports `try_lock` -//! -//! As a futures library the eventual call to an event loop should be the only -//! thing that ever blocks, so this is assisted with a fast user-space -//! implementation of a lock that can only have a `try_lock` operation. - -use core::cell::UnsafeCell; -use core::ops::{Deref, DerefMut}; -use core::sync::atomic::AtomicBool; -use core::sync::atomic::Ordering::SeqCst; - -/// A "mutex" around a value, similar to `std::sync::Mutex`. -/// -/// This lock only supports the `try_lock` operation, however, and does not -/// implement poisoning. -#[derive(Debug)] -pub(crate) struct Lock { - locked: AtomicBool, - data: UnsafeCell, -} - -/// Sentinel representing an acquired lock through which the data can be -/// accessed. -pub(crate) struct TryLock<'a, T> { - __ptr: &'a Lock, -} - -// The `Lock` structure is basically just a `Mutex`, and these two impls are -// intended to mirror the standard library's corresponding impls for `Mutex`. -// -// If a `T` is sendable across threads, so is the lock, and `T` must be sendable -// across threads to be `Sync` because it allows mutable access from multiple -// threads. -unsafe impl Send for Lock {} -unsafe impl Sync for Lock {} - -impl Lock { - /// Creates a new lock around the given value. - pub(crate) fn new(t: T) -> Self { - Self { locked: AtomicBool::new(false), data: UnsafeCell::new(t) } - } - - /// Attempts to acquire this lock, returning whether the lock was acquired or - /// not. - /// - /// If `Some` is returned then the data this lock protects can be accessed - /// through the sentinel. This sentinel allows both mutable and immutable - /// access. - /// - /// If `None` is returned then the lock is already locked, either elsewhere - /// on this thread or on another thread. - pub(crate) fn try_lock(&self) -> Option> { - if !self.locked.swap(true, SeqCst) { - Some(TryLock { __ptr: self }) - } else { - None - } - } -} - -impl Deref for TryLock<'_, T> { - type Target = T; - fn deref(&self) -> &T { - // The existence of `TryLock` represents that we own the lock, so we - // can safely access the data here. - unsafe { &*self.__ptr.data.get() } - } -} - -impl DerefMut for TryLock<'_, T> { - fn deref_mut(&mut self) -> &mut T { - // The existence of `TryLock` represents that we own the lock, so we - // can safely access the data here. - // - // Additionally, we're the *only* `TryLock` in existence so mutable - // access should be ok. - unsafe { &mut *self.__ptr.data.get() } - } -} - -impl Drop for TryLock<'_, T> { - fn drop(&mut self) { - self.__ptr.locked.store(false, SeqCst); - } -} - -#[cfg(test)] -mod tests { - use super::Lock; - - #[test] - fn smoke() { - let a = Lock::new(1); - let mut a1 = a.try_lock().unwrap(); - assert!(a.try_lock().is_none()); - assert_eq!(*a1, 1); - *a1 = 2; - drop(a1); - assert_eq!(*a.try_lock().unwrap(), 2); - assert_eq!(*a.try_lock().unwrap(), 2); - } -} diff --git a/futures-channel/src/mpsc/mod.rs b/futures-channel/src/mpsc/mod.rs deleted file mode 100644 index 69bb88ffbe..0000000000 --- a/futures-channel/src/mpsc/mod.rs +++ /dev/null @@ -1,1462 +0,0 @@ -//! A multi-producer, single-consumer queue for sending values across -//! asynchronous tasks. -//! -//! Similarly to the `std`, channel creation provides [`Receiver`] and -//! [`Sender`] handles. [`Receiver`] implements [`Stream`] and allows a task to -//! read values out of the channel. If there is no message to read from the -//! channel, the current task will be notified when a new value is sent. -//! [`Sender`] implements the `Sink` trait and allows a task to send messages into -//! the channel. If the channel is at capacity, the send will be rejected and -//! the task will be notified when additional capacity is available. In other -//! words, the channel provides backpressure. -//! -//! Unbounded channels are also available using the `unbounded` constructor. -//! -//! # Disconnection -//! -//! When all [`Sender`] handles have been dropped, it is no longer -//! possible to send values into the channel. This is considered the termination -//! event of the stream. As such, [`Receiver::poll_next`] -//! will return `Ok(Ready(None))`. -//! -//! If the [`Receiver`] handle is dropped, then messages can no longer -//! be read out of the channel. In this case, all further attempts to send will -//! result in an error. -//! -//! # Clean Shutdown -//! -//! If the [`Receiver`] is simply dropped, then it is possible for -//! there to be messages still in the channel that will not be processed. As -//! such, it is usually desirable to perform a "clean" shutdown. To do this, the -//! receiver will first call `close`, which will prevent any further messages to -//! be sent into the channel. Then, the receiver consumes the channel to -//! completion, at which point the receiver can be dropped. -//! -//! [`Sender`]: struct.Sender.html -//! [`Receiver`]: struct.Receiver.html -//! [`Stream`]: ../../futures_core/stream/trait.Stream.html -//! [`Receiver::poll_next`]: -//! ../../futures_core/stream/trait.Stream.html#tymethod.poll_next - -// At the core, the channel uses an atomic FIFO queue for message passing. This -// queue is used as the primary coordination primitive. In order to enforce -// capacity limits and handle back pressure, a secondary FIFO queue is used to -// send parked task handles. -// -// The general idea is that the channel is created with a `buffer` size of `n`. -// The channel capacity is `n + num-senders`. Each sender gets one "guaranteed" -// slot to hold a message. This allows `Sender` to know for a fact that a send -// will succeed *before* starting to do the actual work of sending the value. -// Since most of this work is lock-free, once the work starts, it is impossible -// to safely revert. -// -// If the sender is unable to process a send operation, then the current -// task is parked and the handle is sent on the parked task queue. -// -// Note that the implementation guarantees that the channel capacity will never -// exceed the configured limit, however there is no *strict* guarantee that the -// receiver will wake up a parked task *immediately* when a slot becomes -// available. However, it will almost always unpark a task when a slot becomes -// available and it is *guaranteed* that a sender will be unparked when the -// message that caused the sender to become parked is read out of the channel. -// -// The steps for sending a message are roughly: -// -// 1) Increment the channel message count -// 2) If the channel is at capacity, push the task handle onto the wait queue -// 3) Push the message onto the message queue. -// -// The steps for receiving a message are roughly: -// -// 1) Pop a message from the message queue -// 2) Pop a task handle from the wait queue -// 3) Decrement the channel message count. -// -// It's important for the order of operations on lock-free structures to happen -// in reverse order between the sender and receiver. This makes the message -// queue the primary coordination structure and establishes the necessary -// 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; -use std::sync::atomic::Ordering::SeqCst; -use std::sync::{Arc, Mutex}; -use std::thread; - -use crate::mpsc::queue::Queue; - -mod queue; -#[cfg(feature = "sink")] -mod sink_impl; - -struct UnboundedSenderInner { - // Channel state shared between the sender and receiver. - inner: Arc>, -} - -struct BoundedSenderInner { - // Channel state shared between the sender and receiver. - inner: Arc>, - - // Handle to the task that is blocked on this sender. This handle is sent - // to the receiver half in order to be notified when the sender becomes - // unblocked. - sender_task: Arc>, - - // `true` if the sender might be blocked. This is an optimization to avoid - // having to lock the mutex most of the time. - maybe_parked: bool, -} - -// We never project Pin<&mut SenderInner> to `Pin<&mut T>` -impl Unpin for UnboundedSenderInner {} -impl Unpin for BoundedSenderInner {} - -/// The transmission end of a bounded mpsc channel. -/// -/// This value is created by the [`channel`] function. -pub struct Sender(Option>); - -/// The transmission end of an unbounded mpsc channel. -/// -/// This value is created by the [`unbounded`] function. -pub struct UnboundedSender(Option>); - -#[allow(dead_code)] -trait AssertKinds: Send + Sync + Clone {} -impl AssertKinds for UnboundedSender {} - -/// The receiving end of a bounded mpsc channel. -/// -/// This value is created by the [`channel`] function. -pub struct Receiver { - inner: Option>>, -} - -/// The receiving end of an unbounded mpsc channel. -/// -/// This value is created by the [`unbounded`] function. -pub struct UnboundedReceiver { - inner: Option>>, -} - -// `Pin<&mut UnboundedReceiver>` is never projected to `Pin<&mut T>` -impl Unpin for UnboundedReceiver {} - -/// The error type for [`Sender`s](Sender) used as `Sink`s. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SendError { - kind: SendErrorKind, -} - -/// The error type returned from [`try_send`](Sender::try_send). -#[derive(Clone, PartialEq, Eq)] -pub struct TrySendError { - err: SendError, - val: T, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -enum SendErrorKind { - Full, - Disconnected, -} - -/// 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. - Empty, - - /// The channel is empty and closed. - 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() { - write!(f, "send failed because channel is full") - } else { - write!(f, "send failed because receiver is gone") - } - } -} - -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 { - matches!(self.kind, SendErrorKind::Full) - } - - /// Returns `true` if this error is a result of the receiver being dropped. - pub fn is_disconnected(&self) -> bool { - matches!(self.kind, SendErrorKind::Disconnected) - } -} - -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() - } -} - -impl fmt::Display for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_full() { - write!(f, "send failed because channel is full") - } else { - write!(f, "send failed because receiver is gone") - } - } -} - -impl std::error::Error for TrySendError {} - -impl TrySendError { - /// Returns `true` if this error is a result of the channel being full. - pub fn is_full(&self) -> bool { - self.err.is_full() - } - - /// Returns `true` if this error is a result of the receiver being dropped. - pub fn is_disconnected(&self) -> bool { - self.err.is_disconnected() - } - - /// Returns the message that was attempted to be sent but failed. - pub fn into_inner(self) -> T { - self.val - } - - /// Drops the message and converts into a `SendError`. - pub fn into_send_error(self) -> SendError { - self.err - } -} - -impl fmt::Display for TryRecvError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TryRecvError::Empty => write!(f, "receive failed because channel is empty"), - TryRecvError::Closed => write!(f, "receive failed because channel is closed"), - } - } -} - -impl std::error::Error for TryRecvError {} - -struct UnboundedInner { - // Internal channel state. Consists of the number of messages stored in the - // channel as well as a flag signalling that the channel is closed. - state: AtomicUsize, - - // Atomic, FIFO queue used to send messages to the receiver - message_queue: Queue, - - // Number of senders in existence - num_senders: AtomicUsize, - - // Handle to the receiver's task. - recv_task: AtomicWaker, -} - -struct BoundedInner { - // Max buffer size of the channel. - buffer: usize, - - // Internal channel state. Consists of the number of messages stored in the - // channel as well as a flag signalling that the channel is closed. - state: AtomicUsize, - - // Atomic, FIFO queue used to send messages to the receiver - message_queue: Queue, - - // Atomic, FIFO queue used to send parked task handles to the receiver. - parked_queue: Queue>>, - - // Number of senders in existence - num_senders: AtomicUsize, - - // Handle to the receiver's task. - recv_task: AtomicWaker, -} - -// Struct representation of `Inner::state`. -#[derive(Clone, Copy)] -struct State { - // `true` when the channel is open - is_open: bool, - - // Number of messages in the channel - num_messages: usize, -} - -// The `is_open` flag is stored in the left-most bit of `Inner::state` -const OPEN_MASK: usize = usize::MAX - (usize::MAX >> 1); - -// When a new channel is created, it is created in the open state with no -// pending messages. -const INIT_STATE: usize = OPEN_MASK; - -// The maximum number of messages that a channel can track is `usize::MAX >> 1` -const MAX_CAPACITY: usize = !(OPEN_MASK); - -// The maximum requested buffer size must be less than the maximum capacity of -// a channel. This is because each sender gets a guaranteed slot. -const MAX_BUFFER: usize = MAX_CAPACITY >> 1; - -// Sent to the consumer to wake up blocked producers -struct SenderTask { - task: Option, - is_parked: bool, -} - -impl SenderTask { - fn new() -> Self { - Self { task: None, is_parked: false } - } - - fn notify(&mut self) { - self.is_parked = false; - - if let Some(task) = self.task.take() { - task.wake(); - } - } -} - -/// Creates a bounded mpsc channel for communicating between asynchronous tasks. -/// -/// Being bounded, this channel provides backpressure to ensure that the sender -/// outpaces the receiver by only a limited amount. The channel's capacity is -/// equal to `buffer + num-senders`. In other words, each sender gets a -/// guaranteed slot in the channel capacity, and on top of that there are -/// `buffer` "first come, first serve" slots available to all senders. -/// -/// The [`Receiver`] returned implements the [`Stream`] trait, while [`Sender`] -/// implements `Sink`. -pub fn channel(buffer: usize) -> (Sender, Receiver) { - // Check that the requested buffer size does not exceed the maximum buffer - // size permitted by the system. - assert!(buffer < MAX_BUFFER, "requested buffer size too large"); - - let inner = Arc::new(BoundedInner { - buffer, - state: AtomicUsize::new(INIT_STATE), - message_queue: Queue::new(), - parked_queue: Queue::new(), - num_senders: AtomicUsize::new(1), - recv_task: AtomicWaker::new(), - }); - - let tx = BoundedSenderInner { - inner: inner.clone(), - sender_task: Arc::new(Mutex::new(SenderTask::new())), - maybe_parked: false, - }; - - let rx = Receiver { inner: Some(inner) }; - - (Sender(Some(tx)), rx) -} - -/// Creates an unbounded mpsc channel for communicating between asynchronous -/// tasks. -/// -/// A `send` on this channel will always succeed as long as the receive half has -/// not been closed. If the receiver falls behind, messages will be arbitrarily -/// buffered. -/// -/// **Note** that the amount of available system memory is an implicit bound to -/// the channel. Using an `unbounded` channel has the ability of causing the -/// process to run out of memory. In this case, the process will be aborted. -pub fn unbounded() -> (UnboundedSender, UnboundedReceiver) { - let inner = Arc::new(UnboundedInner { - state: AtomicUsize::new(INIT_STATE), - message_queue: Queue::new(), - num_senders: AtomicUsize::new(1), - recv_task: AtomicWaker::new(), - }); - - let tx = UnboundedSenderInner { inner: inner.clone() }; - - let rx = UnboundedReceiver { inner: Some(inner) }; - - (UnboundedSender(Some(tx)), rx) -} - -/* - * - * ===== impl Sender ===== - * - */ - -impl UnboundedSenderInner { - fn poll_ready_nb(&self) -> Poll> { - let state = decode_state(self.inner.state.load(SeqCst)); - if state.is_open { - Poll::Ready(Ok(())) - } else { - Poll::Ready(Err(SendError { kind: SendErrorKind::Disconnected })) - } - } - - // Push message to the queue and signal to the receiver - fn queue_push_and_signal(&self, msg: T) { - // Push the message onto the message queue - self.inner.message_queue.push(msg); - - // Signal to the receiver that a message has been enqueued. If the - // receiver is parked, this will unpark the task. - self.inner.recv_task.wake(); - } - - // Increment the number of queued messages. Returns the resulting number. - fn inc_num_messages(&self) -> Option { - let mut curr = self.inner.state.load(SeqCst); - - loop { - let mut state = decode_state(curr); - - // The receiver end closed the channel. - if !state.is_open { - return None; - } - - // This probably is never hit? Odds are the process will run out of - // memory first. It may be worth to return something else in this - // case? - assert!( - state.num_messages < MAX_CAPACITY, - "buffer space \ - exhausted; sending this messages would overflow the state" - ); - - state.num_messages += 1; - - let next = encode_state(&state); - match self.inner.state.compare_exchange(curr, next, SeqCst, SeqCst) { - Ok(_) => return Some(state.num_messages), - Err(actual) => curr = actual, - } - } - } - - /// Returns whether the senders send to the same receiver. - fn same_receiver(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.inner, &other.inner) - } - - /// Returns whether the sender send to this receiver. - fn is_connected_to(&self, inner: &Arc>) -> bool { - Arc::ptr_eq(&self.inner, inner) - } - - /// Returns pointer to the Arc containing sender - /// - /// The returned pointer is not referenced and should be only used for hashing! - fn ptr(&self) -> *const UnboundedInner { - &*self.inner - } - - /// Returns whether this channel is closed without needing a context. - fn is_closed(&self) -> bool { - !decode_state(self.inner.state.load(SeqCst)).is_open - } - - /// Closes this channel from the sender side, preventing any new messages. - fn close_channel(&self) { - // There's no need to park this sender, its dropping, - // and we don't want to check for capacity, so skip - // that stuff from `do_send`. - - self.inner.set_closed(); - self.inner.recv_task.wake(); - } -} - -impl BoundedSenderInner { - /// Attempts to send a message on this `Sender`, returning the message - /// if there was an error. - fn try_send(&mut self, msg: T) -> Result<(), TrySendError> { - // If the sender is currently blocked, reject the message - if !self.poll_unparked(None).is_ready() { - return Err(TrySendError { err: SendError { kind: SendErrorKind::Full }, val: msg }); - } - - // The channel has capacity to accept the message, so send it - self.do_send_b(msg) - } - - // Do the send without failing. - // Can be called only by bounded sender. - fn do_send_b(&mut self, msg: T) -> Result<(), TrySendError> { - // Anyone calling do_send *should* make sure there is room first, - // but assert here for tests as a sanity check. - debug_assert!(self.poll_unparked(None).is_ready()); - - // First, increment the number of messages contained by the channel. - // This operation will also atomically determine if the sender task - // should be parked. - // - // `None` is returned in the case that the channel has been closed by the - // receiver. This happens when `Receiver::close` is called or the - // receiver is dropped. - let park_self = match self.inc_num_messages() { - Some(num_messages) => { - // Block if the current number of pending messages has exceeded - // the configured buffer size - num_messages > self.inner.buffer - } - None => { - return Err(TrySendError { - err: SendError { kind: SendErrorKind::Disconnected }, - val: msg, - }) - } - }; - - // If the channel has reached capacity, then the sender task needs to - // be parked. This will send the task handle on the parked task queue. - // - // However, when `do_send` is called while dropping the `Sender`, - // `task::current()` can't be called safely. In this case, in order to - // maintain internal consistency, a blank message is pushed onto the - // parked task queue. - if park_self { - self.park(); - } - - self.queue_push_and_signal(msg); - - Ok(()) - } - - // Push message to the queue and signal to the receiver - fn queue_push_and_signal(&self, msg: T) { - // Push the message onto the message queue - self.inner.message_queue.push(msg); - - // Signal to the receiver that a message has been enqueued. If the - // receiver is parked, this will unpark the task. - self.inner.recv_task.wake(); - } - - // Increment the number of queued messages. Returns the resulting number. - fn inc_num_messages(&self) -> Option { - let mut curr = self.inner.state.load(SeqCst); - - loop { - let mut state = decode_state(curr); - - // The receiver end closed the channel. - if !state.is_open { - return None; - } - - // This probably is never hit? Odds are the process will run out of - // memory first. It may be worth to return something else in this - // case? - assert!( - state.num_messages < MAX_CAPACITY, - "buffer space \ - exhausted; sending this messages would overflow the state" - ); - - state.num_messages += 1; - - let next = encode_state(&state); - match self.inner.state.compare_exchange(curr, next, SeqCst, SeqCst) { - Ok(_) => return Some(state.num_messages), - Err(actual) => curr = actual, - } - } - } - - fn park(&mut self) { - { - let mut sender = self.sender_task.lock().unwrap(); - sender.task = None; - sender.is_parked = true; - } - - // Send handle over queue - let t = self.sender_task.clone(); - self.inner.parked_queue.push(t); - - // Check to make sure we weren't closed after we sent our task on the - // queue - let state = decode_state(self.inner.state.load(SeqCst)); - self.maybe_parked = state.is_open; - } - - /// Polls the channel to determine if there is guaranteed capacity to send - /// at least one item without waiting. - /// - /// # Return value - /// - /// This method returns: - /// - /// - `Poll::Ready(Ok(_))` if there is sufficient capacity; - /// - `Poll::Pending` if the channel may not have - /// capacity, in which case the current task is queued to be notified once - /// capacity is available; - /// - `Poll::Ready(Err(SendError))` if the receiver has been dropped. - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - let state = decode_state(self.inner.state.load(SeqCst)); - if !state.is_open { - return Poll::Ready(Err(SendError { kind: SendErrorKind::Disconnected })); - } - - self.poll_unparked(Some(cx)).map(Ok) - } - - /// Returns whether the senders send to the same receiver. - fn same_receiver(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.inner, &other.inner) - } - - /// Returns whether the sender send to this receiver. - fn is_connected_to(&self, receiver: &Arc>) -> bool { - Arc::ptr_eq(&self.inner, receiver) - } - - /// Returns pointer to the Arc containing sender - /// - /// The returned pointer is not referenced and should be only used for hashing! - fn ptr(&self) -> *const BoundedInner { - &*self.inner - } - - /// Returns whether this channel is closed without needing a context. - fn is_closed(&self) -> bool { - !decode_state(self.inner.state.load(SeqCst)).is_open - } - - /// Closes this channel from the sender side, preventing any new messages. - fn close_channel(&self) { - // There's no need to park this sender, its dropping, - // and we don't want to check for capacity, so skip - // that stuff from `do_send`. - - self.inner.set_closed(); - self.inner.recv_task.wake(); - } - - fn poll_unparked(&mut self, cx: Option<&mut Context<'_>>) -> Poll<()> { - // First check the `maybe_parked` variable. This avoids acquiring the - // lock in most cases - if self.maybe_parked { - // Get a lock on the task handle - let mut task = self.sender_task.lock().unwrap(); - - if !task.is_parked { - self.maybe_parked = false; - return Poll::Ready(()); - } - - // At this point, an unpark request is pending, so there will be an - // unpark sometime in the future. We just need to make sure that - // the correct task will be notified. - // - // Update the task in case the `Sender` has been moved to another - // task - task.task = cx.map(|cx| cx.waker().clone()); - - Poll::Pending - } else { - Poll::Ready(()) - } - } -} - -impl Sender { - /// Attempts to send a message on this `Sender`, returning the message - /// if there was an error. - pub fn try_send(&mut self, msg: T) -> Result<(), TrySendError> { - if let Some(inner) = &mut self.0 { - inner.try_send(msg) - } else { - Err(TrySendError { err: SendError { kind: SendErrorKind::Disconnected }, val: msg }) - } - } - - /// Send a message on the channel. - /// - /// This function should only be called after - /// [`poll_ready`](Sender::poll_ready) has reported that the channel is - /// ready to receive a message. - pub fn start_send(&mut self, msg: T) -> Result<(), SendError> { - self.try_send(msg).map_err(|e| e.err) - } - - /// Polls the channel to determine if there is guaranteed capacity to send - /// at least one item without waiting. - /// - /// # Return value - /// - /// This method returns: - /// - /// - `Poll::Ready(Ok(_))` if there is sufficient capacity; - /// - `Poll::Pending` if the channel may not have - /// capacity, in which case the current task is queued to be notified once - /// capacity is available; - /// - `Poll::Ready(Err(SendError))` if the receiver has been dropped. - pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - let inner = self.0.as_mut().ok_or(SendError { kind: SendErrorKind::Disconnected })?; - inner.poll_ready(cx) - } - - /// Returns whether this channel is closed without needing a context. - pub fn is_closed(&self) -> bool { - self.0.as_ref().map(BoundedSenderInner::is_closed).unwrap_or(true) - } - - /// Closes this channel from the sender side, preventing any new messages. - pub fn close_channel(&mut self) { - if let Some(inner) = &mut self.0 { - inner.close_channel(); - } - } - - /// Disconnects this sender from the channel, closing it if there are no more senders left. - pub fn disconnect(&mut self) { - self.0 = None; - } - - /// Returns whether the senders send to the same receiver. - pub fn same_receiver(&self, other: &Self) -> bool { - match (&self.0, &other.0) { - (Some(inner), Some(other)) => inner.same_receiver(other), - _ => false, - } - } - - /// Returns whether the sender send to this receiver. - pub fn is_connected_to(&self, receiver: &Receiver) -> bool { - match (&self.0, &receiver.inner) { - (Some(inner), Some(receiver)) => inner.is_connected_to(receiver), - _ => false, - } - } - - /// Hashes the receiver into the provided hasher - pub fn hash_receiver(&self, hasher: &mut H) - where - H: std::hash::Hasher, - { - use std::hash::Hash; - - let ptr = self.0.as_ref().map(|inner| inner.ptr()); - ptr.hash(hasher); - } -} - -impl UnboundedSender { - /// Check if the channel is ready to receive a message. - pub fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { - let inner = self.0.as_ref().ok_or(SendError { kind: SendErrorKind::Disconnected })?; - inner.poll_ready_nb() - } - - /// Returns whether this channel is closed without needing a context. - pub fn is_closed(&self) -> bool { - self.0.as_ref().map(UnboundedSenderInner::is_closed).unwrap_or(true) - } - - /// Closes this channel from the sender side, preventing any new messages. - pub fn close_channel(&self) { - if let Some(inner) = &self.0 { - inner.close_channel(); - } - } - - /// Disconnects this sender from the channel, closing it if there are no more senders left. - pub fn disconnect(&mut self) { - self.0 = None; - } - - // Do the send without parking current task. - fn do_send_nb(&self, msg: T) -> Result<(), TrySendError> { - if let Some(inner) = &self.0 { - if inner.inc_num_messages().is_some() { - inner.queue_push_and_signal(msg); - return Ok(()); - } - } - - Err(TrySendError { err: SendError { kind: SendErrorKind::Disconnected }, val: msg }) - } - - /// Send a message on the channel. - /// - /// This method should only be called after `poll_ready` has been used to - /// verify that the channel is ready to receive a message. - pub fn start_send(&mut self, msg: T) -> Result<(), SendError> { - self.do_send_nb(msg).map_err(|e| e.err) - } - - /// Sends a message along this channel. - /// - /// This is an unbounded sender, so this function differs from `Sink::send` - /// by ensuring the return type reflects that the channel is always ready to - /// receive messages. - pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { - self.do_send_nb(msg) - } - - /// Returns whether the senders send to the same receiver. - pub fn same_receiver(&self, other: &Self) -> bool { - match (&self.0, &other.0) { - (Some(inner), Some(other)) => inner.same_receiver(other), - _ => false, - } - } - - /// Returns whether the sender send to this receiver. - pub fn is_connected_to(&self, receiver: &UnboundedReceiver) -> bool { - match (&self.0, &receiver.inner) { - (Some(inner), Some(receiver)) => inner.is_connected_to(receiver), - _ => false, - } - } - - /// Hashes the receiver into the provided hasher - pub fn hash_receiver(&self, hasher: &mut H) - where - H: std::hash::Hasher, - { - use std::hash::Hash; - - let ptr = self.0.as_ref().map(|inner| inner.ptr()); - ptr.hash(hasher); - } - - /// Return the number of messages in the queue or 0 if channel is disconnected. - pub fn len(&self) -> usize { - if let Some(sender) = &self.0 { - decode_state(sender.inner.state.load(SeqCst)).num_messages - } else { - 0 - } - } - - /// Return false is channel has no queued messages, true otherwise. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl Clone for Sender { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl Clone for UnboundedSender { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl Clone for UnboundedSenderInner { - fn clone(&self) -> Self { - // Since this atomic op isn't actually guarding any memory and we don't - // care about any orderings besides the ordering on the single atomic - // variable, a relaxed ordering is acceptable. - let mut curr = self.inner.num_senders.load(SeqCst); - - loop { - // If the maximum number of senders has been reached, then fail - if curr == MAX_BUFFER { - panic!("cannot clone `Sender` -- too many outstanding senders"); - } - - debug_assert!(curr < MAX_BUFFER); - - let next = curr + 1; - match self.inner.num_senders.compare_exchange(curr, next, SeqCst, SeqCst) { - Ok(_) => { - // The ABA problem doesn't matter here. We only care that the - // number of senders never exceeds the maximum. - return Self { inner: self.inner.clone() }; - } - Err(actual) => curr = actual, - } - } - } -} - -impl Clone for BoundedSenderInner { - fn clone(&self) -> Self { - // Since this atomic op isn't actually guarding any memory and we don't - // care about any orderings besides the ordering on the single atomic - // variable, a relaxed ordering is acceptable. - let mut curr = self.inner.num_senders.load(SeqCst); - - loop { - // If the maximum number of senders has been reached, then fail - if curr == self.inner.max_senders() { - panic!("cannot clone `Sender` -- too many outstanding senders"); - } - - debug_assert!(curr < self.inner.max_senders()); - - let next = curr + 1; - match self.inner.num_senders.compare_exchange(curr, next, SeqCst, SeqCst) { - Ok(_) => { - // The ABA problem doesn't matter here. We only care that the - // number of senders never exceeds the maximum. - return Self { - inner: self.inner.clone(), - sender_task: Arc::new(Mutex::new(SenderTask::new())), - maybe_parked: false, - }; - } - Err(actual) => curr = actual, - } - } - } -} - -impl Drop for UnboundedSenderInner { - fn drop(&mut self) { - // Ordering between variables don't matter here - let prev = self.inner.num_senders.fetch_sub(1, SeqCst); - - if prev == 1 { - self.close_channel(); - } - } -} - -impl Drop for BoundedSenderInner { - fn drop(&mut self) { - // Ordering between variables don't matter here - let prev = self.inner.num_senders.fetch_sub(1, SeqCst); - - if prev == 1 { - self.close_channel(); - } - } -} - -impl fmt::Debug for Sender { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Sender").field("closed", &self.is_closed()).finish() - } -} - -impl fmt::Debug for UnboundedSender { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("UnboundedSender").field("closed", &self.is_closed()).finish() - } -} - -/* - * - * ===== impl Receiver ===== - * - */ - -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 - /// still enabling the receiver to drain messages that are buffered. - pub fn close(&mut self) { - if let Some(inner) = &mut self.inner { - inner.set_closed(); - - // Wake up any threads waiting as they'll see that we've closed the - // channel and will continue on their merry way. - while let Some(task) = unsafe { inner.parked_queue.pop_spin() } { - task.lock().unwrap().notify(); - } - } - } - - /// Tries to receive the next message without notifying a context if empty. - /// - /// It is not recommended to call this function from inside of a future, - /// only when you've otherwise arranged to be notified when the channel is - /// no longer empty. - /// - /// This function returns: - /// * `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::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), - } - } - - fn next_message(&mut self) -> Poll> { - let inner = match self.inner.as_mut() { - None => return Poll::Ready(None), - Some(inner) => inner, - }; - // Pop off a message - match unsafe { inner.message_queue.pop_spin() } { - Some(msg) => { - // If there are any parked task handles in the parked queue, - // pop one and unpark it. - self.unpark_one(); - - // Decrement number of messages - self.dec_num_messages(); - - Poll::Ready(Some(msg)) - } - None => { - let state = decode_state(inner.state.load(SeqCst)); - if state.is_closed() { - // If closed flag is set AND there are no pending messages - // it means end of stream - self.inner = None; - Poll::Ready(None) - } else { - // If queue is open, we need to return Pending - // to be woken up when new messages arrive. - // If queue is closed but num_messages is non-zero, - // it means that senders updated the state, - // but didn't put message to queue yet, - // so we need to park until sender unparks the task - // after queueing the message. - Poll::Pending - } - } - } - } - - // Unpark a single task handle if there is one pending in the parked queue - fn unpark_one(&mut self) { - if let Some(inner) = &mut self.inner { - if let Some(task) = unsafe { inner.parked_queue.pop_spin() } { - task.lock().unwrap().notify(); - } - } - } - - fn dec_num_messages(&self) { - if let Some(inner) = &self.inner { - // OPEN_MASK is highest bit, so it's unaffected by subtraction - // unless there's underflow, and we know there's no underflow - // because number of messages at this point is always > 0. - inner.state.fetch_sub(1, SeqCst); - } - } -} - -// The receiver does not ever take a Pin to the inner T -impl Unpin for Receiver {} - -impl FusedStream for Receiver { - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl Stream for Receiver { - type Item = T; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - // Try to read a message off of the message queue. - match self.next_message() { - Poll::Ready(msg) => { - if msg.is_none() { - self.inner = None; - } - Poll::Ready(msg) - } - Poll::Pending => { - // There are no messages to read, in this case, park. - self.inner.as_ref().unwrap().recv_task.register(cx.waker()); - // Check queue again after parking to prevent race condition: - // a message could be added to the queue after previous `next_message` - // before `register` call. - self.next_message() - } - } - } - - fn size_hint(&self) -> (usize, Option) { - if let Some(inner) = &self.inner { - decode_state(inner.state.load(SeqCst)).size_hint() - } else { - (0, Some(0)) - } - } -} - -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 - self.close(); - if self.inner.is_some() { - loop { - match self.next_message() { - Poll::Ready(Some(_)) => {} - Poll::Ready(None) => break, - Poll::Pending => { - let state = decode_state(self.inner.as_ref().unwrap().state.load(SeqCst)); - - // If the channel is closed, then there is no need to park. - if state.is_closed() { - break; - } - - // TODO: Spinning isn't ideal, it might be worth - // investigating using a condvar or some other strategy - // here. That said, if this case is hit, then another thread - // is about to push the value into the queue and this isn't - // the only spinlock in the impl right now. - thread::yield_now(); - } - } - } - } - } -} - -impl fmt::Debug for Receiver { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let closed = if let Some(ref inner) = self.inner { - decode_state(inner.state.load(SeqCst)).is_closed() - } else { - false - }; - - f.debug_struct("Receiver").field("closed", &closed).finish() - } -} - -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 - /// still enabling the receiver to drain messages that are buffered. - pub fn close(&mut self) { - if let Some(inner) = &mut self.inner { - inner.set_closed(); - } - } - - /// Tries to receive the next message without notifying a context if empty. - /// - /// It is not recommended to call this function from inside of a future, - /// only when you've otherwise arranged to be notified when the channel is - /// no longer empty. - /// - /// This function returns: - /// * `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::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), - } - } - - fn next_message(&mut self) -> Poll> { - let inner = match self.inner.as_mut() { - None => return Poll::Ready(None), - Some(inner) => inner, - }; - // Pop off a message - match unsafe { inner.message_queue.pop_spin() } { - Some(msg) => { - // Decrement number of messages - self.dec_num_messages(); - - Poll::Ready(Some(msg)) - } - None => { - let state = decode_state(inner.state.load(SeqCst)); - if state.is_closed() { - // If closed flag is set AND there are no pending messages - // it means end of stream - self.inner = None; - Poll::Ready(None) - } else { - // If queue is open, we need to return Pending - // to be woken up when new messages arrive. - // If queue is closed but num_messages is non-zero, - // it means that senders updated the state, - // but didn't put message to queue yet, - // so we need to park until sender unparks the task - // after queueing the message. - Poll::Pending - } - } - } - } - - fn dec_num_messages(&self) { - if let Some(inner) = &self.inner { - // OPEN_MASK is highest bit, so it's unaffected by subtraction - // unless there's underflow, and we know there's no underflow - // because number of messages at this point is always > 0. - inner.state.fetch_sub(1, SeqCst); - } - } -} - -impl FusedStream for UnboundedReceiver { - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl Stream for UnboundedReceiver { - type Item = T; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - // Try to read a message off of the message queue. - match self.next_message() { - Poll::Ready(msg) => { - if msg.is_none() { - self.inner = None; - } - Poll::Ready(msg) - } - Poll::Pending => { - // There are no messages to read, in this case, park. - self.inner.as_ref().unwrap().recv_task.register(cx.waker()); - // Check queue again after parking to prevent race condition: - // a message could be added to the queue after previous `next_message` - // before `register` call. - self.next_message() - } - } - } - - fn size_hint(&self) -> (usize, Option) { - if let Some(inner) = &self.inner { - decode_state(inner.state.load(SeqCst)).size_hint() - } else { - (0, Some(0)) - } - } -} - -impl Drop for UnboundedReceiver { - fn drop(&mut self) { - // Drain the channel of all pending messages - self.close(); - if self.inner.is_some() { - loop { - match self.next_message() { - Poll::Ready(Some(_)) => {} - Poll::Ready(None) => break, - Poll::Pending => { - let state = decode_state(self.inner.as_ref().unwrap().state.load(SeqCst)); - - // If the channel is closed, then there is no need to park. - if state.is_closed() { - break; - } - - // TODO: Spinning isn't ideal, it might be worth - // investigating using a condvar or some other strategy - // here. That said, if this case is hit, then another thread - // is about to push the value into the queue and this isn't - // the only spinlock in the impl right now. - thread::yield_now(); - } - } - } - } - } -} - -impl fmt::Debug for UnboundedReceiver { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let closed = if let Some(ref inner) = self.inner { - decode_state(inner.state.load(SeqCst)).is_closed() - } else { - false - }; - - f.debug_struct("Receiver").field("closed", &closed).finish() - } -} - -/* - * - * ===== impl Inner ===== - * - */ - -impl UnboundedInner { - // Clear `open` flag in the state, keep `num_messages` intact. - fn set_closed(&self) { - let curr = self.state.load(SeqCst); - if !decode_state(curr).is_open { - return; - } - - self.state.fetch_and(!OPEN_MASK, SeqCst); - } -} - -impl BoundedInner { - // The return value is such that the total number of messages that can be - // enqueued into the channel will never exceed MAX_CAPACITY - fn max_senders(&self) -> usize { - MAX_CAPACITY - self.buffer - } - - // Clear `open` flag in the state, keep `num_messages` intact. - fn set_closed(&self) { - let curr = self.state.load(SeqCst); - if !decode_state(curr).is_open { - return; - } - - self.state.fetch_and(!OPEN_MASK, SeqCst); - } -} - -unsafe impl Send for UnboundedInner {} -unsafe impl Sync for UnboundedInner {} - -unsafe impl Send for BoundedInner {} -unsafe impl Sync for BoundedInner {} - -impl State { - fn is_closed(&self) -> bool { - !self.is_open && self.num_messages == 0 - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_open { - (self.num_messages, None) - } else { - (self.num_messages, Some(self.num_messages)) - } - } -} - -/* - * - * ===== Helpers ===== - * - */ - -fn decode_state(num: usize) -> State { - State { is_open: num & OPEN_MASK == OPEN_MASK, num_messages: num & MAX_CAPACITY } -} - -fn encode_state(state: &State) -> usize { - let mut num = state.num_messages; - - if state.is_open { - num |= OPEN_MASK; - } - - num -} diff --git a/futures-channel/src/mpsc/queue.rs b/futures-channel/src/mpsc/queue.rs deleted file mode 100644 index 78cbdce6ec..0000000000 --- a/futures-channel/src/mpsc/queue.rs +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of Dmitry Vyukov. - */ - -//! A mostly lock-free multi-producer, single consumer queue for sending -//! messages between asynchronous tasks. -//! -//! The queue implementation is essentially the same one used for mpsc channels -//! in the standard library. -//! -//! Note that the current implementation of this queue has a caveat of the `pop` -//! method, and see the method for more information about it. Due to this -//! caveat, this queue may not be appropriate for all use-cases. - -// http://www.1024cores.net/home/lock-free-algorithms -// /queues/non-intrusive-mpsc-node-based-queue - -// NOTE: this implementation is lifted from the standard library and only -// slightly modified - -pub(super) use self::PopResult::*; - -use std::boxed::Box; -use std::cell::UnsafeCell; -use std::ptr; -use std::sync::atomic::{AtomicPtr, Ordering}; -use std::thread; - -/// A result of the `pop` function. -pub(super) enum PopResult { - /// Some data has been popped - Data(T), - /// The queue is empty - Empty, - /// The queue is in an inconsistent state. Popping data should succeed, but - /// some pushers have yet to make enough progress in order allow a pop to - /// succeed. It is recommended that a pop() occur "in the near future" in - /// order to see if the sender has made progress or not - Inconsistent, -} - -struct Node { - next: AtomicPtr, - value: Option, -} - -/// The multi-producer single-consumer structure. This is not cloneable, but it -/// may be safely shared so long as it is guaranteed that there is only one -/// popper at a time (many pushers are allowed). -pub(super) struct Queue { - head: AtomicPtr>, - tail: UnsafeCell<*mut Node>, -} - -unsafe impl Send for Queue {} -unsafe impl Sync for Queue {} - -impl Node { - unsafe fn new(v: Option) -> *mut Self { - Box::into_raw(Box::new(Self { next: AtomicPtr::new(ptr::null_mut()), value: v })) - } -} - -impl Queue { - /// Creates a new queue that is safe to share among multiple producers and - /// one consumer. - pub(super) fn new() -> Self { - let stub = unsafe { Node::new(None) }; - Self { head: AtomicPtr::new(stub), tail: UnsafeCell::new(stub) } - } - - /// Pushes a new value onto this queue. - pub(super) fn push(&self, t: T) { - unsafe { - let n = Node::new(Some(t)); - let prev = self.head.swap(n, Ordering::AcqRel); - (*prev).next.store(n, Ordering::Release); - } - } - - /// Pops some data from this queue. - /// - /// Note that the current implementation means that this function cannot - /// return `Option`. It is possible for this queue to be in an - /// inconsistent state where many pushes have succeeded and completely - /// finished, but pops cannot return `Some(t)`. This inconsistent state - /// happens when a pusher is preempted at an inopportune moment. - /// - /// This inconsistent state means that this queue does indeed have data, but - /// it does not currently have access to it at this time. - /// - /// This function is unsafe because only one thread can call it at a time. - pub(super) unsafe fn pop(&self) -> PopResult { - unsafe { - let tail = *self.tail.get(); - let next = (*tail).next.load(Ordering::Acquire); - - if !next.is_null() { - *self.tail.get() = next; - assert!((*tail).value.is_none()); - assert!((*next).value.is_some()); - let ret = (*next).value.take().unwrap(); - drop(Box::from_raw(tail)); - return Data(ret); - } - - if self.head.load(Ordering::Acquire) == tail { - Empty - } else { - Inconsistent - } - } - } - - /// Pop an element similarly to `pop` function, but spin-wait on inconsistent - /// queue state instead of returning `Inconsistent`. - /// - /// This function is unsafe because only one thread can call it at a time. - pub(super) unsafe fn pop_spin(&self) -> Option { - loop { - match unsafe { self.pop() } { - Empty => return None, - Data(t) => return Some(t), - // Inconsistent means that there will be a message to pop - // in a short time. This branch can only be reached if - // values are being produced from another thread, so there - // are a few ways that we can deal with this: - // - // 1) Spin - // 2) thread::yield_now() - // 3) task::current().unwrap() & return Pending - // - // For now, thread::yield_now() is used, but it would - // probably be better to spin a few times then yield. - Inconsistent => { - thread::yield_now(); - } - } - } - } -} - -impl Drop for Queue { - fn drop(&mut self) { - unsafe { - let mut cur = *self.tail.get(); - while !cur.is_null() { - let next = (*cur).next.load(Ordering::Relaxed); - drop(Box::from_raw(cur)); - cur = next; - } - } - } -} diff --git a/futures-channel/src/mpsc/sink_impl.rs b/futures-channel/src/mpsc/sink_impl.rs deleted file mode 100644 index 1be20162c2..0000000000 --- a/futures-channel/src/mpsc/sink_impl.rs +++ /dev/null @@ -1,73 +0,0 @@ -use super::{SendError, Sender, TrySendError, UnboundedSender}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use std::pin::Pin; - -impl Sink for Sender { - type Error = SendError; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - (*self).poll_ready(cx) - } - - fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> { - (*self).start_send(msg) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match (*self).poll_ready(cx) { - Poll::Ready(Err(ref e)) if e.is_disconnected() => { - // If the receiver disconnected, we consider the sink to be flushed. - Poll::Ready(Ok(())) - } - x => x, - } - } - - fn poll_close(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - self.disconnect(); - Poll::Ready(Ok(())) - } -} - -impl Sink for UnboundedSender { - type Error = SendError; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Self::poll_ready(&*self, cx) - } - - fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> { - Self::start_send(&mut *self, msg) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - self.disconnect(); - Poll::Ready(Ok(())) - } -} - -impl Sink for &UnboundedSender { - type Error = SendError; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - UnboundedSender::poll_ready(*self, cx) - } - - fn start_send(self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> { - self.unbounded_send(msg).map_err(TrySendError::into_send_error) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - self.close_channel(); - Poll::Ready(Ok(())) - } -} diff --git a/futures-channel/src/oneshot.rs b/futures-channel/src/oneshot.rs deleted file mode 100644 index fe5b115a33..0000000000 --- a/futures-channel/src/oneshot.rs +++ /dev/null @@ -1,488 +0,0 @@ -//! A channel for sending a single message between asynchronous tasks. -//! -//! This is a single-producer, single-consumer channel. - -use alloc::sync::Arc; -use core::fmt; -use core::pin::Pin; -use core::sync::atomic::AtomicBool; -use core::sync::atomic::Ordering::SeqCst; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll, Waker}; - -use crate::lock::Lock; - -/// A future for a value that will be provided by another asynchronous task. -/// -/// This is created by the [`channel`] function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Receiver { - inner: Arc>, -} - -/// A means of transmitting a single value to another task. -/// -/// This is created by the [`channel`] function. -pub struct Sender { - inner: Arc>, -} - -// The channels do not ever project Pin to the inner T -impl Unpin for Receiver {} -impl Unpin for Sender {} - -/// Internal state of the `Receiver`/`Sender` pair above. This is all used as -/// the internal synchronization between the two for send/recv operations. -struct Inner { - /// Indicates whether this oneshot is complete yet. This is filled in both - /// by `Sender::drop` and by `Receiver::drop`, and both sides interpret it - /// appropriately. - /// - /// For `Receiver`, if this is `true`, then it's guaranteed that `data` is - /// unlocked and ready to be inspected. - /// - /// For `Sender` if this is `true` then the oneshot has gone away and it - /// can return ready from `poll_canceled`. - complete: AtomicBool, - - /// The actual data being transferred as part of this `Receiver`. This is - /// filled in by `Sender::complete` and read by `Receiver::poll`. - /// - /// Note that this is protected by `Lock`, but it is in theory safe to - /// replace with an `UnsafeCell` as it's actually protected by `complete` - /// above. I wouldn't recommend doing this, however, unless someone is - /// supremely confident in the various atomic orderings here and there. - data: Lock>, - - /// Field to store the task which is blocked in `Receiver::poll`. - /// - /// This is filled in when a oneshot is polled but not ready yet. Note that - /// the `Lock` here, unlike in `data` above, is important to resolve races. - /// Both the `Receiver` and the `Sender` halves understand that if they - /// can't acquire the lock then some important interference is happening. - rx_task: Lock>, - - /// Like `rx_task` above, except for the task blocked in - /// `Sender::poll_canceled`. Additionally, `Lock` cannot be `UnsafeCell`. - tx_task: Lock>, -} - -/// Creates a new one-shot channel for sending a single value across asynchronous tasks. -/// -/// The channel works for a spsc (single-producer, single-consumer) scheme. -/// -/// This function is similar to Rust's channel constructor found in the standard -/// library. Two halves are returned, the first of which is a `Sender` handle, -/// used to signal the end of a computation and provide its value. The second -/// half is a `Receiver` which implements the `Future` trait, resolving to the -/// value that was given to the `Sender` handle. -/// -/// Each half can be separately owned and sent across tasks. -/// -/// # Examples -/// -/// ``` -/// use futures::channel::oneshot; -/// use std::{thread, time::Duration}; -/// -/// let (sender, receiver) = oneshot::channel::(); -/// -/// thread::spawn(|| { -/// println!("THREAD: sleeping zzz..."); -/// thread::sleep(Duration::from_millis(1000)); -/// println!("THREAD: i'm awake! sending."); -/// sender.send(3).unwrap(); -/// }); -/// -/// println!("MAIN: doing some useful stuff"); -/// -/// futures::executor::block_on(async { -/// println!("MAIN: waiting for msg..."); -/// println!("MAIN: got: {:?}", receiver.await) -/// }); -/// ``` -pub fn channel() -> (Sender, Receiver) { - let inner = Arc::new(Inner::new()); - let receiver = Receiver { inner: inner.clone() }; - let sender = Sender { inner }; - (sender, receiver) -} - -impl Inner { - fn new() -> Self { - Self { - complete: AtomicBool::new(false), - data: Lock::new(None), - rx_task: Lock::new(None), - tx_task: Lock::new(None), - } - } - - fn send(&self, t: T) -> Result<(), T> { - if self.complete.load(SeqCst) { - return Err(t); - } - - // Note that this lock acquisition may fail if the receiver - // is closed and sets the `complete` flag to `true`, whereupon - // the receiver may call `poll()`. - if let Some(mut slot) = self.data.try_lock() { - assert!(slot.is_none()); - *slot = Some(t); - drop(slot); - - // If the receiver called `close()` between the check at the - // start of the function, and the lock being released, then - // the receiver may not be around to receive it, so try to - // pull it back out. - if self.complete.load(SeqCst) { - // If lock acquisition fails, then receiver is actually - // receiving it, so we're good. - if let Some(mut slot) = self.data.try_lock() { - if let Some(t) = slot.take() { - return Err(t); - } - } - } - Ok(()) - } else { - // Must have been closed - Err(t) - } - } - - fn poll_canceled(&self, cx: &mut Context<'_>) -> Poll<()> { - // Fast path up first, just read the flag and see if our other half is - // gone. This flag is set both in our destructor and the oneshot - // destructor, but our destructor hasn't run yet so if it's set then the - // oneshot is gone. - if self.complete.load(SeqCst) { - return Poll::Ready(()); - } - - // If our other half is not gone then we need to park our current task - // and move it into the `tx_task` slot to get notified when it's - // actually gone. - // - // If `try_lock` fails, then the `Receiver` is in the process of using - // it, so we can deduce that it's now in the process of going away and - // hence we're canceled. If it succeeds then we just store our handle. - // - // Crucially we then check `complete` *again* before we return. - // While we were storing our handle inside `tx_task` the - // `Receiver` may have been dropped. The first thing it does is set the - // flag, and if it fails to acquire the lock it assumes that we'll see - // the flag later on. So... we then try to see the flag later on! - let handle = cx.waker().clone(); - match self.tx_task.try_lock() { - Some(mut p) => *p = Some(handle), - None => return Poll::Ready(()), - } - if self.complete.load(SeqCst) { - Poll::Ready(()) - } else { - Poll::Pending - } - } - - fn is_canceled(&self) -> bool { - self.complete.load(SeqCst) - } - - fn drop_tx(&self) { - // Flag that we're a completed `Sender` and try to wake up a receiver. - // Whether or not we actually stored any data will get picked up and - // translated to either an item or cancellation. - // - // Note that if we fail to acquire the `rx_task` lock then that means - // we're in one of two situations: - // - // 1. The receiver is trying to block in `poll` - // 2. The receiver is being dropped - // - // In the first case it'll check the `complete` flag after it's done - // blocking to see if it succeeded. In the latter case we don't need to - // wake up anyone anyway. So in both cases it's ok to ignore the `None` - // case of `try_lock` and bail out. - // - // The first case crucially depends on `Lock` using `SeqCst` ordering - // under the hood. If it instead used `Release` / `Acquire` ordering, - // then it would not necessarily synchronize with `inner.complete` - // and deadlock might be possible, as was observed in - // https://github.com/rust-lang/futures-rs/pull/219. - self.complete.store(true, SeqCst); - - if let Some(mut slot) = self.rx_task.try_lock() { - if let Some(task) = slot.take() { - drop(slot); - task.wake(); - } - } - - // If we registered a task for cancel notification drop it to reduce - // spurious wakeups - if let Some(mut slot) = self.tx_task.try_lock() { - drop(slot.take()); - } - } - - fn close_rx(&self) { - // Flag our completion and then attempt to wake up the sender if it's - // blocked. See comments in `drop` below for more info - self.complete.store(true, SeqCst); - if let Some(mut handle) = self.tx_task.try_lock() { - if let Some(task) = handle.take() { - drop(handle); - task.wake() - } - } - } - - fn try_recv(&self) -> Result, Canceled> { - // If we're complete, either `::close_rx` or `::drop_tx` was called. - // We can assume a successful send if data is present. - if self.complete.load(SeqCst) { - if let Some(mut slot) = self.data.try_lock() { - if let Some(data) = slot.take() { - return Ok(Some(data)); - } - } - Err(Canceled) - } else { - Ok(None) - } - } - - fn recv(&self, cx: &mut Context<'_>) -> Poll> { - // Check to see if some data has arrived. If it hasn't then we need to - // block our task. - // - // Note that the acquisition of the `rx_task` lock might fail below, but - // the only situation where this can happen is during `Sender::drop` - // when we are indeed completed already. If that's happening then we - // know we're completed so keep going. - let done = if self.complete.load(SeqCst) { - true - } else { - let task = cx.waker().clone(); - match self.rx_task.try_lock() { - Some(mut slot) => { - *slot = Some(task); - false - } - None => true, - } - }; - - // If we're `done` via one of the paths above, then look at the data and - // figure out what the answer is. If, however, we stored `rx_task` - // successfully above we need to check again if we're completed in case - // a message was sent while `rx_task` was locked and couldn't notify us - // otherwise. - // - // If we're not done, and we're not complete, though, then we've - // successfully blocked our task and we return `Pending`. - if done || self.complete.load(SeqCst) { - // If taking the lock fails, the sender will realise that the we're - // `done` when it checks the `complete` flag on the way out, and - // will treat the send as a failure. - if let Some(mut slot) = self.data.try_lock() { - if let Some(data) = slot.take() { - return Poll::Ready(Ok(data)); - } - } - Poll::Ready(Err(Canceled)) - } else { - Poll::Pending - } - } - - fn drop_rx(&self) { - // Indicate to the `Sender` that we're done, so any future calls to - // `poll_canceled` are weeded out. - self.complete.store(true, SeqCst); - - // If we've blocked a task then there's no need for it to stick around, - // so we need to drop it. If this lock acquisition fails, though, then - // it's just because our `Sender` is trying to take the task, so we - // let them take care of that. - if let Some(mut slot) = self.rx_task.try_lock() { - let task = slot.take(); - drop(slot); - drop(task); - } - - // Finally, if our `Sender` wants to get notified of us going away, it - // would have stored something in `tx_task`. Here we try to peel that - // out and unpark it. - // - // Note that the `try_lock` here may fail, but only if the `Sender` is - // in the process of filling in the task. If that happens then we - // already flagged `complete` and they'll pick that up above. - if let Some(mut handle) = self.tx_task.try_lock() { - if let Some(task) = handle.take() { - drop(handle); - task.wake() - } - } - } -} - -impl Sender { - /// Completes this oneshot with a successful result. - /// - /// This function will consume `self` and indicate to the other end, the - /// [`Receiver`], that the value provided is the result of the computation - /// this represents. - /// - /// If the value is successfully enqueued for the remote end to receive, - /// then `Ok(())` is returned. If the receiving end was dropped before - /// this function was called, however, then `Err(t)` is returned. - pub fn send(self, t: T) -> Result<(), T> { - self.inner.send(t) - } - - /// Polls this `Sender` half to detect whether its associated - /// [`Receiver`] has been dropped. - /// - /// # Return values - /// - /// If `Ready(())` is returned then the associated `Receiver` has been - /// dropped, which means any work required for sending should be canceled. - /// - /// If `Pending` is returned then the associated `Receiver` is still - /// alive and may be able to receive a message if sent. The current task, - /// however, is scheduled to receive a notification if the corresponding - /// `Receiver` goes away. - pub fn poll_canceled(&mut self, cx: &mut Context<'_>) -> Poll<()> { - self.inner.poll_canceled(cx) - } - - /// Creates a future that resolves when this `Sender`'s corresponding - /// [`Receiver`] half has hung up. - /// - /// This is a utility wrapping [`poll_canceled`](Sender::poll_canceled) - /// to expose a [`Future`]. - pub fn cancellation(&mut self) -> Cancellation<'_, T> { - Cancellation { inner: self } - } - - /// Tests to see whether this `Sender`'s corresponding `Receiver` - /// has been dropped. - /// - /// Unlike [`poll_canceled`](Sender::poll_canceled), this function does not - /// enqueue a task for wakeup upon cancellation, but merely reports the - /// current state, which may be subject to concurrent modification. - pub fn is_canceled(&self) -> bool { - self.inner.is_canceled() - } - - /// Tests to see whether this `Sender` is connected to the given `Receiver`. That is, whether - /// they were created by the same call to `channel`. - pub fn is_connected_to(&self, receiver: &Receiver) -> bool { - Arc::ptr_eq(&self.inner, &receiver.inner) - } -} - -impl Drop for Sender { - fn drop(&mut self) { - self.inner.drop_tx() - } -} - -impl fmt::Debug for Sender { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Sender").field("complete", &self.inner.complete).finish() - } -} - -/// A future that resolves when the receiving end of a channel has hung up. -/// -/// This is an `.await`-friendly interface around [`poll_canceled`](Sender::poll_canceled). -#[must_use = "futures do nothing unless you `.await` or poll them"] -#[derive(Debug)] -pub struct Cancellation<'a, T> { - inner: &'a mut Sender, -} - -impl Future for Cancellation<'_, T> { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - self.inner.poll_canceled(cx) - } -} - -/// Error returned from a [`Receiver`] when the corresponding [`Sender`] is -/// dropped. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Canceled; - -impl fmt::Display for Canceled { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "oneshot canceled") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Canceled {} - -impl Receiver { - /// Gracefully close this receiver, preventing any subsequent attempts to - /// send to it. - /// - /// Any `send` operation which happens after this method returns is - /// guaranteed to fail. After calling this method, you can use - /// [`Receiver::poll`](core::future::Future::poll) to determine whether a - /// message had previously been sent. - pub fn close(&mut self) { - self.inner.close_rx() - } - - /// Attempts to receive a message outside of the context of a task. - /// - /// Does not schedule a task wakeup or have any other side effects. - /// - /// A return value of `None` must be considered immediately stale (out of - /// date) unless [`close`](Receiver::close) has been called first. - /// - /// Returns an error if the sender was dropped. - pub fn try_recv(&mut self) -> Result, Canceled> { - self.inner.try_recv() - } -} - -impl Future for Receiver { - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.inner.recv(cx) - } -} - -impl FusedFuture for Receiver { - fn is_terminated(&self) -> bool { - if self.inner.complete.load(SeqCst) { - if let Some(slot) = self.inner.data.try_lock() { - if slot.is_some() { - return false; - } - } - true - } else { - false - } - } -} - -impl Drop for Receiver { - fn drop(&mut self) { - self.inner.drop_rx() - } -} - -impl fmt::Debug for Receiver { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Receiver").field("complete", &self.inner.complete).finish() - } -} diff --git a/futures-channel/tests/channel.rs b/futures-channel/tests/channel.rs deleted file mode 100644 index 5f01a8ef4c..0000000000 --- a/futures-channel/tests/channel.rs +++ /dev/null @@ -1,66 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::block_on; -use futures::future::poll_fn; -use futures::sink::SinkExt; -use futures::stream::StreamExt; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::thread; - -#[test] -fn sequence() { - let (tx, rx) = mpsc::channel(1); - - let amt = 20; - let t = thread::spawn(move || block_on(send_sequence(amt, tx))); - let list: Vec<_> = block_on(rx.collect()); - let mut list = list.into_iter(); - for i in (1..=amt).rev() { - assert_eq!(list.next(), Some(i)); - } - assert_eq!(list.next(), None); - - t.join().unwrap(); -} - -async fn send_sequence(n: u32, mut sender: mpsc::Sender) { - for x in 0..n { - sender.send(n - x).await.unwrap(); - } -} - -#[test] -fn drop_sender() { - let (tx, mut rx) = mpsc::channel::(1); - drop(tx); - let f = poll_fn(|cx| rx.poll_next_unpin(cx)); - assert_eq!(block_on(f), None) -} - -#[test] -fn drop_rx() { - let (mut tx, rx) = mpsc::channel::(1); - block_on(tx.send(1)).unwrap(); - drop(rx); - assert!(block_on(tx.send(1)).is_err()); -} - -#[test] -fn drop_order() { - static DROPS: AtomicUsize = AtomicUsize::new(0); - let (mut tx, rx) = mpsc::channel(1); - - struct A; - - impl Drop for A { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - block_on(tx.send(A)).unwrap(); - assert_eq!(DROPS.load(Ordering::SeqCst), 0); - drop(rx); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); - assert!(block_on(tx.send(A)).is_err()); - assert_eq!(DROPS.load(Ordering::SeqCst), 2); -} diff --git a/futures-channel/tests/mpsc-close.rs b/futures-channel/tests/mpsc-close.rs deleted file mode 100644 index be5d08c322..0000000000 --- a/futures-channel/tests/mpsc-close.rs +++ /dev/null @@ -1,332 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::block_on; -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; -use std::time::{Duration, Instant}; - -#[test] -fn smoke() { - let (mut sender, receiver) = mpsc::channel(1); - - let t = thread::spawn(move || while let Ok(()) = block_on(sender.send(42)) {}); - - // `receiver` needs to be dropped for `sender` to stop sending and therefore before the join. - block_on(receiver.take(3).for_each(|_| futures::future::ready(()))); - - t.join().unwrap() -} - -#[test] -fn multiple_senders_disconnect() { - { - let (mut tx1, mut rx) = mpsc::channel(1); - let (tx2, mut tx3, mut tx4) = (tx1.clone(), tx1.clone(), tx1.clone()); - - // disconnect, dropping and Sink::poll_close should all close this sender but leave the - // channel open for other senders - tx1.disconnect(); - drop(tx2); - block_on(tx3.close()).unwrap(); - - assert!(tx1.is_closed()); - assert!(tx3.is_closed()); - assert!(!tx4.is_closed()); - - block_on(tx4.send(5)).unwrap(); - assert_eq!(block_on(rx.next()), Some(5)); - - // dropping the final sender will close the channel - drop(tx4); - assert_eq!(block_on(rx.next()), None); - } - - { - let (mut tx1, mut rx) = mpsc::unbounded(); - let (tx2, mut tx3, mut tx4) = (tx1.clone(), tx1.clone(), tx1.clone()); - - // disconnect, dropping and Sink::poll_close should all close this sender but leave the - // channel open for other senders - tx1.disconnect(); - drop(tx2); - block_on(tx3.close()).unwrap(); - - assert!(tx1.is_closed()); - assert!(tx3.is_closed()); - assert!(!tx4.is_closed()); - - block_on(tx4.send(5)).unwrap(); - assert_eq!(block_on(rx.next()), Some(5)); - - // dropping the final sender will close the channel - drop(tx4); - assert_eq!(block_on(rx.next()), None); - } -} - -#[test] -fn multiple_senders_close_channel() { - { - let (mut tx1, mut rx) = mpsc::channel(1); - let mut tx2 = tx1.clone(); - - // close_channel should shut down the whole channel - tx1.close_channel(); - - assert!(tx1.is_closed()); - assert!(tx2.is_closed()); - - let err = block_on(tx2.send(5)).unwrap_err(); - assert!(err.is_disconnected()); - - assert_eq!(block_on(rx.next()), None); - } - - { - let (tx1, mut rx) = mpsc::unbounded(); - let mut tx2 = tx1.clone(); - - // close_channel should shut down the whole channel - tx1.close_channel(); - - assert!(tx1.is_closed()); - assert!(tx2.is_closed()); - - let err = block_on(tx2.send(5)).unwrap_err(); - assert!(err.is_disconnected()); - - assert_eq!(block_on(rx.next()), None); - } -} - -#[test] -fn single_receiver_drop_closes_channel_and_drains() { - { - let ref_count = Arc::new(0); - let weak_ref = Arc::downgrade(&ref_count); - - let (sender, receiver) = mpsc::unbounded(); - sender.unbounded_send(ref_count).expect("failed to send"); - - // Verify that the sent message is still live. - assert!(weak_ref.upgrade().is_some()); - - drop(receiver); - - // The sender should know the channel is closed. - assert!(sender.is_closed()); - - // Verify that the sent message has been dropped. - assert!(weak_ref.upgrade().is_none()); - } - - { - let ref_count = Arc::new(0); - let weak_ref = Arc::downgrade(&ref_count); - - let (mut sender, receiver) = mpsc::channel(1); - sender.try_send(ref_count).expect("failed to send"); - - // Verify that the sent message is still live. - assert!(weak_ref.upgrade().is_some()); - - drop(receiver); - - // The sender should know the channel is closed. - assert!(sender.is_closed()); - - // Verify that the sent message has been dropped. - assert!(weak_ref.upgrade().is_none()); - assert!(sender.is_closed()); - } -} - -// Stress test that `try_send()`s occurring concurrently with receiver -// close/drops don't appear as successful sends. -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn stress_try_send_as_receiver_closes() { - const AMT: usize = 10000; - // To provide variable timing characteristics (in the hopes of - // reproducing the collision that leads to a race), we busy-re-poll - // the test MPSC receiver a variable number of times before actually - // stopping. We vary this countdown between 1 and the following - // value. - const MAX_COUNTDOWN: usize = 20; - // When we detect that a successfully sent item is still in the - // queue after a disconnect, we spin for up to 100ms to confirm that - // it is a persistent condition and not a concurrency illusion. - const SPIN_TIMEOUT_S: u64 = 10; - const SPIN_SLEEP_MS: u64 = 10; - struct TestRx { - rx: mpsc::Receiver>, - // The number of times to query `rx` before dropping it. - poll_count: usize, - } - struct TestTask { - command_rx: mpsc::Receiver, - test_rx: Option>>, - countdown: usize, - } - impl TestTask { - /// Create a new TestTask - fn new() -> (Self, mpsc::Sender) { - let (command_tx, command_rx) = mpsc::channel::(0); - ( - Self { - command_rx, - test_rx: None, - countdown: 0, // 0 means no countdown is in progress. - }, - command_tx, - ) - } - } - impl Future for TestTask { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Poll the test channel, if one is present. - if let Some(rx) = &mut self.test_rx { - if let Poll::Ready(v) = rx.poll_next_unpin(cx) { - let _ = v.expect("test finished unexpectedly!"); - } - self.countdown -= 1; - // Busy-poll until the countdown is finished. - cx.waker().wake_by_ref(); - } - // Accept any newly submitted MPSC channels for testing. - match self.command_rx.poll_next_unpin(cx) { - Poll::Ready(Some(TestRx { rx, poll_count })) => { - self.test_rx = Some(rx); - self.countdown = poll_count; - cx.waker().wake_by_ref(); - } - Poll::Ready(None) => return Poll::Ready(()), - Poll::Pending => {} - } - if self.countdown == 0 { - // Countdown complete -- drop the Receiver. - self.test_rx = None; - } - Poll::Pending - } - } - let (f, mut cmd_tx) = TestTask::new(); - let bg = thread::spawn(move || block_on(f)); - for i in 0..AMT { - let (mut test_tx, rx) = mpsc::channel(0); - let poll_count = i % MAX_COUNTDOWN; - cmd_tx.try_send(TestRx { rx, poll_count }).unwrap(); - let mut prev_weak: Option> = None; - let mut attempted_sends = 0; - let mut successful_sends = 0; - loop { - // Create a test item. - let item = Arc::new(()); - let weak = Arc::downgrade(&item); - match test_tx.try_send(item) { - Ok(_) => { - prev_weak = Some(weak); - successful_sends += 1; - } - Err(ref e) if e.is_full() => {} - Err(ref e) if e.is_disconnected() => { - // Test for evidence of the race condition. - if let Some(prev_weak) = prev_weak { - if prev_weak.upgrade().is_some() { - // The previously sent item is still allocated. - // However, there appears to be some aspect of the - // concurrency that can legitimately cause the Arc - // to be momentarily valid. Spin for up to 100ms - // waiting for the previously sent item to be - // dropped. - let t0 = Instant::now(); - let mut spins = 0; - loop { - if prev_weak.upgrade().is_none() { - break; - } - assert!( - t0.elapsed() < Duration::from_secs(SPIN_TIMEOUT_S), - "item not dropped on iteration {} after \ - {} sends ({} successful). spin=({})", - i, - attempted_sends, - successful_sends, - spins - ); - spins += 1; - thread::sleep(Duration::from_millis(SPIN_SLEEP_MS)); - } - } - } - break; - } - Err(ref e) => panic!("unexpected error: {}", e), - } - attempted_sends += 1; - } - } - drop(cmd_tx); - bg.join().expect("background thread join"); -} - -#[test] -fn unbounded_try_next_after_none() { - #![allow(deprecated)] - let (tx, mut rx) = mpsc::unbounded::(); - // Drop the sender, close the channel. - drop(tx); - // Receive the end of channel. - assert_eq!(Ok(None), rx.try_next().map_err(|_| ())); - // None received, check we can call `try_next` again. - assert_eq!(Ok(None), rx.try_next().map_err(|_| ())); -} - -#[test] -fn bounded_try_next_after_none() { - #![allow(deprecated)] - let (tx, mut rx) = mpsc::channel::(17); - // Drop the sender, close the channel. - drop(tx); - // Receive the end of channel. - assert_eq!(Ok(None), rx.try_next().map_err(|_| ())); - // 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 deleted file mode 100644 index 3c06eec1ab..0000000000 --- a/futures-channel/tests/mpsc-size_hint.rs +++ /dev/null @@ -1,40 +0,0 @@ -use futures::channel::mpsc; -use futures::stream::Stream; - -#[test] -fn unbounded_size_hint() { - let (tx, mut rx) = mpsc::unbounded::(); - assert_eq!((0, None), rx.size_hint()); - tx.unbounded_send(1).unwrap(); - assert_eq!((1, None), rx.size_hint()); - 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_recv().unwrap(); - assert_eq!((1, Some(1)), rx.size_hint()); - rx.try_recv().unwrap(); - assert_eq!((0, Some(0)), rx.size_hint()); -} - -#[test] -fn channel_size_hint() { - let (mut tx, mut rx) = mpsc::channel::(10); - assert_eq!((0, None), rx.size_hint()); - tx.try_send(1).unwrap(); - assert_eq!((1, None), rx.size_hint()); - 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_recv().unwrap(); - assert_eq!((1, Some(1)), rx.size_hint()); - 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 deleted file mode 100644 index 847f3a2bd1..0000000000 --- a/futures-channel/tests/mpsc.rs +++ /dev/null @@ -1,701 +0,0 @@ -use futures::channel::{mpsc, oneshot}; -use futures::executor::{block_on, block_on_stream}; -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::{RecvError, TryRecvError}; -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; - -#[allow(dead_code)] -trait AssertSend: Send {} -impl AssertSend for mpsc::Sender {} -impl AssertSend for mpsc::Receiver {} - -#[test] -fn send_recv() { - let (mut tx, rx) = mpsc::channel::(16); - - block_on(tx.send(1)).unwrap(); - drop(tx); - let v: Vec<_> = block_on(rx.collect()); - assert_eq!(v, vec![1]); -} - -#[test] -fn send_recv_no_buffer() { - // Run on a task context - block_on(poll_fn(move |cx| { - let (tx, rx) = mpsc::channel::(0); - 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()); - - // Send first message - assert!(tx.as_mut().start_send(1).is_ok()); - assert!(tx.as_mut().poll_ready(cx).is_pending()); - - // poll_ready said Pending, so no room in buffer, therefore new sends - // should get rejected with is_full. - assert!(tx.as_mut().start_send(0).unwrap_err().is_full()); - assert!(tx.as_mut().poll_ready(cx).is_pending()); - - // Take the value - assert_eq!(rx.as_mut().poll_next(cx), Poll::Ready(Some(1))); - assert!(tx.as_mut().poll_ready(cx).is_ready()); - - // Send second message - assert!(tx.as_mut().poll_ready(cx).is_ready()); - assert!(tx.as_mut().start_send(2).is_ok()); - assert!(tx.as_mut().poll_ready(cx).is_pending()); - - // Take the value - assert_eq!(rx.as_mut().poll_next(cx), Poll::Ready(Some(2))); - assert!(tx.as_mut().poll_ready(cx).is_ready()); - - Poll::Ready(()) - })); -} - -#[test] -fn send_shared_recv() { - let (mut tx1, rx) = mpsc::channel::(16); - let mut rx = block_on_stream(rx); - let mut tx2 = tx1.clone(); - - block_on(tx1.send(1)).unwrap(); - assert_eq!(rx.next(), Some(1)); - - block_on(tx2.send(2)).unwrap(); - assert_eq!(rx.next(), Some(2)); -} - -#[test] -fn send_recv_threads() { - let (mut tx, rx) = mpsc::channel::(16); - - let t = thread::spawn(move || { - block_on(tx.send(1)).unwrap(); - }); - - let v: Vec<_> = block_on(rx.take(1).collect()); - assert_eq!(v, vec![1]); - - t.join().unwrap(); -} - -#[test] -fn send_recv_threads_no_capacity() { - let (mut tx, rx) = mpsc::channel::(0); - - let t = thread::spawn(move || { - block_on(tx.send(1)).unwrap(); - block_on(tx.send(2)).unwrap(); - }); - - let v: Vec<_> = block_on(rx.collect()); - assert_eq!(v, vec![1, 2]); - - t.join().unwrap(); -} - -#[test] -fn recv_close_gets_none() { - let (mut tx, mut rx) = mpsc::channel::(10); - - // Run on a task context - block_on(poll_fn(move |cx| { - rx.close(); - - assert_eq!(rx.poll_next_unpin(cx), Poll::Ready(None)); - match tx.poll_ready(cx) { - Poll::Pending | Poll::Ready(Ok(_)) => panic!(), - Poll::Ready(Err(e)) => assert!(e.is_disconnected()), - }; - - Poll::Ready(()) - })); -} - -#[test] -fn tx_close_gets_none() { - let (_, mut rx) = mpsc::channel::(10); - - // Run on a task context - block_on(poll_fn(move |cx| { - assert_eq!(rx.poll_next_unpin(cx), Poll::Ready(None)); - Poll::Ready(()) - })); -} - -// #[test] -// fn spawn_sends_items() { -// let core = local_executor::Core::new(); -// let stream = unfold(0, |i| Some(ok::<_,u8>((i, i + 1)))); -// let rx = mpsc::spawn(stream, &core, 1); -// assert_eq!(core.run(rx.take(4).collect()).unwrap(), -// [0, 1, 2, 3]); -// } - -// #[test] -// fn spawn_kill_dead_stream() { -// use std::thread; -// use std::time::Duration; -// use futures::future::Either; -// use futures::sync::oneshot; -// -// // a stream which never returns anything (maybe a remote end isn't -// // responding), but dropping it leads to observable side effects -// // (like closing connections, releasing limited resources, ...) -// #[derive(Debug)] -// struct Dead { -// // when dropped you should get Err(oneshot::Canceled) on the -// // receiving end -// done: oneshot::Sender<()>, -// } -// impl Stream for Dead { -// type Item = (); -// type Error = (); -// -// fn poll(&mut self) -> Poll, Self::Error> { -// Ok(Poll::Pending) -// } -// } -// -// // need to implement a timeout for the test, as it would hang -// // forever right now -// let (timeout_tx, timeout_rx) = oneshot::channel(); -// thread::spawn(move || { -// thread::sleep(Duration::from_millis(1000)); -// let _ = timeout_tx.send(()); -// }); -// -// let core = local_executor::Core::new(); -// let (done_tx, done_rx) = oneshot::channel(); -// let stream = Dead{done: done_tx}; -// let rx = mpsc::spawn(stream, &core, 1); -// let res = core.run( -// Ok::<_, ()>(()) -// .into_future() -// .then(move |_| { -// // now drop the spawned stream: maybe some timeout exceeded, -// // or some connection on this end was closed by the remote -// // end. -// drop(rx); -// // and wait for the spawned stream to release its resources -// done_rx -// }) -// .select2(timeout_rx) -// ); -// match res { -// Err(Either::A((oneshot::Canceled, _))) => (), -// _ => { -// panic!("dead stream wasn't canceled"); -// }, -// } -// } - -#[test] -fn stress_shared_unbounded() { - const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; - const NTHREADS: u32 = 8; - let (tx, rx) = mpsc::unbounded::(); - - let t = thread::spawn(move || { - let result: Vec<_> = block_on(rx.collect()); - assert_eq!(result.len(), (AMT * NTHREADS) as usize); - for item in result { - assert_eq!(item, 1); - } - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - - thread::spawn(move || { - for _ in 0..AMT { - tx.unbounded_send(1).unwrap(); - } - }); - } - - drop(tx); - - t.join().ok().unwrap(); -} - -#[test] -fn stress_shared_bounded_hard() { - const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; - const NTHREADS: u32 = 8; - let (tx, rx) = mpsc::channel::(0); - - let t = thread::spawn(move || { - let result: Vec<_> = block_on(rx.collect()); - assert_eq!(result.len(), (AMT * NTHREADS) as usize); - for item in result { - assert_eq!(item, 1); - } - }); - - for _ in 0..NTHREADS { - let mut tx = tx.clone(); - - thread::spawn(move || { - for _ in 0..AMT { - block_on(tx.send(1)).unwrap(); - } - }); - } - - drop(tx); - - t.join().unwrap(); -} - -#[test] -fn stress_receiver_multi_task_bounded_hard() { - const AMT: usize = if cfg!(miri) { 100 } else { 10_000 }; - const NTHREADS: u32 = 2; - - let (mut tx, rx) = mpsc::channel::(0); - let rx = Arc::new(Mutex::new(Some(rx))); - let n = Arc::new(AtomicUsize::new(0)); - - let mut th = vec![]; - - for _ in 0..NTHREADS { - let rx = rx.clone(); - let n = n.clone(); - - let t = thread::spawn(move || { - let mut i = 0; - - loop { - i += 1; - let mut rx_opt = rx.lock().unwrap(); - if let Some(rx) = &mut *rx_opt { - if i % 5 == 0 { - let item = block_on(rx.next()); - - if item.is_none() { - *rx_opt = None; - break; - } - - n.fetch_add(1, Ordering::Relaxed); - } else { - // Just poll - let n = n.clone(); - match rx.poll_next_unpin(&mut noop_context()) { - Poll::Ready(Some(_)) => { - n.fetch_add(1, Ordering::Relaxed); - } - Poll::Ready(None) => { - *rx_opt = None; - break; - } - Poll::Pending => {} - } - } - } else { - break; - } - } - }); - - th.push(t); - } - - for i in 0..AMT { - block_on(tx.send(i)).unwrap(); - } - drop(tx); - - for t in th { - t.join().unwrap(); - } - - assert_eq!(AMT, n.load(Ordering::Relaxed)); -} - -/// Stress test that receiver properly receives all the messages -/// after sender dropped. -#[test] -fn stress_drop_sender() { - const ITER: usize = if cfg!(miri) { 100 } else { 10000 }; - - fn list() -> impl Stream { - let (tx, rx) = mpsc::channel(1); - thread::spawn(move || { - block_on(send_one_two_three(tx)); - }); - rx - } - - for _ in 0..ITER { - let v: Vec<_> = block_on(list().collect()); - assert_eq!(v, vec![1, 2, 3]); - } -} - -async fn send_one_two_three(mut tx: mpsc::Sender) { - for i in 1..=3 { - tx.send(i).await.unwrap(); - } -} - -/// Stress test that after receiver dropped, -/// no messages are lost. -fn stress_close_receiver_iter() { - let (tx, rx) = mpsc::unbounded(); - let mut rx = block_on_stream(rx); - let (unwritten_tx, unwritten_rx) = std::sync::mpsc::channel(); - let th = thread::spawn(move || { - for i in 1.. { - if tx.unbounded_send(i).is_err() { - unwritten_tx.send(i).expect("unwritten_tx"); - return; - } - } - }); - - // Read one message to make sure thread effectively started - assert_eq!(Some(1), rx.next()); - - rx.close(); - - for i in 2.. { - match rx.next() { - Some(r) => assert!(i == r), - None => { - let unwritten = unwritten_rx.recv().expect("unwritten_rx"); - assert_eq!(unwritten, i); - th.join().unwrap(); - return; - } - } - } -} - -#[test] -fn stress_close_receiver() { - const ITER: usize = if cfg!(miri) { 50 } else { 10000 }; - - for _ in 0..ITER { - stress_close_receiver_iter(); - } -} - -async fn stress_poll_ready_sender(mut sender: mpsc::Sender, count: u32) { - for i in (1..=count).rev() { - sender.send(i).await.unwrap(); - } -} - -/// Tests that after `poll_ready` indicates capacity a channel can always send without waiting. -#[test] -fn stress_poll_ready() { - const AMT: u32 = if cfg!(miri) { 100 } else { 1000 }; - const NTHREADS: u32 = 8; - - /// Run a stress test using the specified channel capacity. - fn stress(capacity: usize) { - let (tx, rx) = mpsc::channel(capacity); - let mut threads = Vec::new(); - for _ in 0..NTHREADS { - let sender = tx.clone(); - threads.push(thread::spawn(move || block_on(stress_poll_ready_sender(sender, AMT)))); - } - drop(tx); - - let result: Vec<_> = block_on(rx.collect()); - assert_eq!(result.len() as u32, AMT * NTHREADS); - - for thread in threads { - thread.join().unwrap(); - } - } - - stress(0); - stress(1); - stress(8); - 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 }; - let (mut tx, rx) = mpsc::channel(0); - - let t = thread::spawn(move || { - for i in 0..N { - loop { - if tx.try_send(i).is_ok() { - break; - } - } - } - }); - - let result: Vec<_> = block_on(rx.collect()); - for (i, j) in result.into_iter().enumerate() { - assert_eq!(i, j); - } - - t.join().unwrap(); -} - -#[test] -fn try_send_2() { - let (mut tx, rx) = mpsc::channel(0); - let mut rx = block_on_stream(rx); - - tx.try_send("hello").unwrap(); - - let (readytx, readyrx) = oneshot::channel::<()>(); - - let th = thread::spawn(move || { - block_on(poll_fn(|cx| { - assert!(tx.poll_ready(cx).is_pending()); - Poll::Ready(()) - })); - - drop(readytx); - block_on(tx.send("goodbye")).unwrap(); - }); - - let _ = block_on(readyrx); - assert_eq!(rx.next(), Some("hello")); - assert_eq!(rx.next(), Some("goodbye")); - assert_eq!(rx.next(), None); - - th.join().unwrap(); -} - -#[test] -fn try_send_fail() { - let (mut tx, rx) = mpsc::channel(0); - let mut rx = block_on_stream(rx); - - tx.try_send("hello").unwrap(); - - // This should fail - assert!(tx.try_send("fail").is_err()); - - assert_eq!(rx.next(), Some("hello")); - - tx.try_send("goodbye").unwrap(); - drop(tx); - - assert_eq!(rx.next(), Some("goodbye")); - assert_eq!(rx.next(), None); -} - -#[test] -fn try_send_recv() { - let (mut tx, mut rx) = mpsc::channel(1); - tx.try_send("hello").unwrap(); - tx.try_send("hello").unwrap(); - tx.try_send("hello").unwrap_err(); // should be full - rx.try_recv().unwrap(); - rx.try_recv().unwrap(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.try_send("hello").unwrap(); - rx.try_recv().unwrap(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); -} - -#[test] -fn same_receiver() { - let (mut txa1, _) = mpsc::channel::(1); - let txa2 = txa1.clone(); - - let (mut txb1, _) = mpsc::channel::(1); - let txb2 = txb1.clone(); - - assert!(txa1.same_receiver(&txa2)); - assert!(txb1.same_receiver(&txb2)); - assert!(!txa1.same_receiver(&txb1)); - - txa1.disconnect(); - txb1.close_channel(); - - assert!(!txa1.same_receiver(&txa2)); - assert!(txb1.same_receiver(&txb2)); -} - -#[test] -fn is_connected_to() { - let (txa, rxa) = mpsc::channel::(1); - let (txb, rxb) = mpsc::channel::(1); - - assert!(txa.is_connected_to(&rxa)); - assert!(txb.is_connected_to(&rxb)); - assert!(!txa.is_connected_to(&rxb)); - assert!(!txb.is_connected_to(&rxa)); -} - -#[test] -fn hash_receiver() { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; - - let mut hasher_a1 = DefaultHasher::new(); - let mut hasher_a2 = DefaultHasher::new(); - let mut hasher_b1 = DefaultHasher::new(); - let mut hasher_b2 = DefaultHasher::new(); - let (mut txa1, _) = mpsc::channel::(1); - let txa2 = txa1.clone(); - - let (mut txb1, _) = mpsc::channel::(1); - let txb2 = txb1.clone(); - - txa1.hash_receiver(&mut hasher_a1); - let hash_a1 = hasher_a1.finish(); - txa2.hash_receiver(&mut hasher_a2); - let hash_a2 = hasher_a2.finish(); - txb1.hash_receiver(&mut hasher_b1); - let hash_b1 = hasher_b1.finish(); - txb2.hash_receiver(&mut hasher_b2); - let hash_b2 = hasher_b2.finish(); - - assert_eq!(hash_a1, hash_a2); - assert_eq!(hash_b1, hash_b2); - assert!(hash_a1 != hash_b1); - - txa1.disconnect(); - txb1.close_channel(); - - let mut hasher_a1 = DefaultHasher::new(); - let mut hasher_a2 = DefaultHasher::new(); - let mut hasher_b1 = DefaultHasher::new(); - let mut hasher_b2 = DefaultHasher::new(); - - txa1.hash_receiver(&mut hasher_a1); - let hash_a1 = hasher_a1.finish(); - txa2.hash_receiver(&mut hasher_a2); - let hash_a2 = hasher_a2.finish(); - txb1.hash_receiver(&mut hasher_b1); - let hash_b1 = hasher_b1.finish(); - txb2.hash_receiver(&mut hasher_b2); - let hash_b2 = hasher_b2.finish(); - - assert!(hash_a1 != hash_a2); - assert_eq!(hash_b1, hash_b2); -} - -#[test] -fn send_backpressure() { - let (waker, counter) = new_count_waker(); - let mut cx = Context::from_waker(&waker); - - let (mut tx, mut rx) = mpsc::channel(1); - block_on(tx.send(1)).unwrap(); - - let mut task = tx.send(2); - assert_eq!(task.poll_unpin(&mut cx), Poll::Pending); - assert_eq!(counter, 0); - - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 1); - assert_eq!(counter, 1); - assert_eq!(task.poll_unpin(&mut cx), Poll::Ready(Ok(()))); - - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 2); -} - -#[test] -fn send_backpressure_multi_senders() { - let (waker, counter) = new_count_waker(); - let mut cx = Context::from_waker(&waker); - - let (mut tx1, mut rx) = mpsc::channel(1); - let mut tx2 = tx1.clone(); - block_on(tx1.send(1)).unwrap(); - - let mut task = tx2.send(2); - assert_eq!(task.poll_unpin(&mut cx), Poll::Pending); - assert_eq!(counter, 0); - - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 1); - assert_eq!(counter, 1); - assert_eq!(task.poll_unpin(&mut cx), Poll::Ready(Ok(()))); - - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 2); -} - -/// Test that empty channel has zero length and that non-empty channel has length equal to number -/// of enqueued items -#[test] -fn unbounded_len() { - let (tx, mut rx) = mpsc::unbounded(); - assert_eq!(tx.len(), 0); - assert!(tx.is_empty()); - tx.unbounded_send(1).unwrap(); - assert_eq!(tx.len(), 1); - assert!(!tx.is_empty()); - tx.unbounded_send(2).unwrap(); - assert_eq!(tx.len(), 2); - assert!(!tx.is_empty()); - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 1); - assert_eq!(tx.len(), 1); - assert!(!tx.is_empty()); - let item = block_on(rx.next()).unwrap(); - assert_eq!(item, 2); - assert_eq!(tx.len(), 0); - assert!(tx.is_empty()); -} diff --git a/futures-channel/tests/oneshot.rs b/futures-channel/tests/oneshot.rs deleted file mode 100644 index 6b48376dc0..0000000000 --- a/futures-channel/tests/oneshot.rs +++ /dev/null @@ -1,256 +0,0 @@ -use futures::channel::oneshot::{self, Sender}; -use futures::executor::block_on; -use futures::future::{poll_fn, FutureExt}; -use futures::task::{Context, Poll}; -use futures_test::task::panic_waker_ref; -use std::sync::mpsc; -use std::thread; - -#[test] -fn smoke_poll() { - let (mut tx, rx) = oneshot::channel::(); - let mut rx = Some(rx); - let f = poll_fn(|cx| { - assert!(tx.poll_canceled(cx).is_pending()); - assert!(tx.poll_canceled(cx).is_pending()); - drop(rx.take()); - assert!(tx.poll_canceled(cx).is_ready()); - assert!(tx.poll_canceled(cx).is_ready()); - Poll::Ready(()) - }); - - block_on(f); -} - -#[test] -fn cancel_notifies() { - let (mut tx, rx) = oneshot::channel::(); - - let t = thread::spawn(move || { - block_on(tx.cancellation()); - }); - drop(rx); - t.join().unwrap(); -} - -#[test] -fn cancel_lots() { - const N: usize = if cfg!(miri) { 100 } else { 20000 }; - - let (tx, rx) = mpsc::channel::<(Sender<_>, mpsc::Sender<_>)>(); - let t = thread::spawn(move || { - for (mut tx, tx2) in rx { - block_on(tx.cancellation()); - tx2.send(()).unwrap(); - } - }); - - for _ in 0..N { - let (otx, orx) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - tx.send((otx, tx2)).unwrap(); - drop(orx); - rx2.recv().unwrap(); - } - drop(tx); - - t.join().unwrap(); -} - -#[test] -fn cancel_after_sender_drop_doesnt_notify() { - let (mut tx, rx) = oneshot::channel::(); - let mut cx = Context::from_waker(panic_waker_ref()); - assert_eq!(tx.poll_canceled(&mut cx), Poll::Pending); - drop(tx); - drop(rx); -} - -#[test] -fn close() { - let (mut tx, mut rx) = oneshot::channel::(); - rx.close(); - block_on(poll_fn(|cx| { - match rx.poll_unpin(cx) { - Poll::Ready(Err(_)) => {} - _ => panic!(), - }; - assert!(tx.poll_canceled(cx).is_ready()); - Poll::Ready(()) - })); -} - -#[test] -fn close_wakes() { - let (mut tx, mut rx) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - let t = thread::spawn(move || { - rx.close(); - rx2.recv().unwrap(); - }); - block_on(tx.cancellation()); - tx2.send(()).unwrap(); - t.join().unwrap(); -} - -#[test] -fn is_canceled() { - let (tx, rx) = oneshot::channel::(); - assert!(!tx.is_canceled()); - drop(rx); - assert!(tx.is_canceled()); -} - -#[test] -fn cancel_sends() { - const N: usize = if cfg!(miri) { 100 } else { 20000 }; - - let (tx, rx) = mpsc::channel::>(); - let t = thread::spawn(move || { - for otx in rx { - let _ = otx.send(42); - } - }); - - for _ in 0..N { - let (otx, mut orx) = oneshot::channel::(); - tx.send(otx).unwrap(); - - orx.close(); - let _ = block_on(orx); - } - - drop(tx); - t.join().unwrap(); -} - -// #[test] -// fn spawn_sends_items() { -// let core = local_executor::Core::new(); -// let future = ok::<_, ()>(1); -// let rx = spawn(future, &core); -// assert_eq!(core.run(rx).unwrap(), 1); -// } -// -// #[test] -// fn spawn_kill_dead_stream() { -// use std::thread; -// use std::time::Duration; -// use futures::future::Either; -// use futures::sync::oneshot; -// -// // a future which never returns anything (forever accepting incoming -// // connections), but dropping it leads to observable side effects -// // (like closing listening sockets, releasing limited resources, -// // ...) -// #[derive(Debug)] -// struct Dead { -// // when dropped you should get Err(oneshot::Canceled) on the -// // receiving end -// done: oneshot::Sender<()>, -// } -// impl Future for Dead { -// type Item = (); -// type Error = (); -// -// fn poll(&mut self) -> Poll { -// Ok(Poll::Pending) -// } -// } -// -// // need to implement a timeout for the test, as it would hang -// // forever right now -// let (timeout_tx, timeout_rx) = oneshot::channel(); -// thread::spawn(move || { -// thread::sleep(Duration::from_millis(1000)); -// let _ = timeout_tx.send(()); -// }); -// -// let core = local_executor::Core::new(); -// let (done_tx, done_rx) = oneshot::channel(); -// let future = Dead{done: done_tx}; -// let rx = spawn(future, &core); -// let res = core.run( -// Ok::<_, ()>(()) -// .into_future() -// .then(move |_| { -// // now drop the spawned future: maybe some timeout exceeded, -// // or some connection on this end was closed by the remote -// // end. -// drop(rx); -// // and wait for the spawned future to release its resources -// done_rx -// }) -// .select2(timeout_rx) -// ); -// match res { -// Err(Either::A((oneshot::Canceled, _))) => (), -// Ok(Either::B(((), _))) => { -// panic!("dead future wasn't canceled (timeout)"); -// }, -// _ => { -// panic!("dead future wasn't canceled (unexpected result)"); -// }, -// } -// } -// -// #[test] -// fn spawn_dont_kill_forgot_dead_stream() { -// use std::thread; -// use std::time::Duration; -// use futures::future::Either; -// use futures::sync::oneshot; -// -// // a future which never returns anything (forever accepting incoming -// // connections), but dropping it leads to observable side effects -// // (like closing listening sockets, releasing limited resources, -// // ...) -// #[derive(Debug)] -// struct Dead { -// // when dropped you should get Err(oneshot::Canceled) on the -// // receiving end -// done: oneshot::Sender<()>, -// } -// impl Future for Dead { -// type Item = (); -// type Error = (); -// -// fn poll(&mut self) -> Poll { -// Ok(Poll::Pending) -// } -// } -// -// // need to implement a timeout for the test, as it would hang -// // forever right now -// let (timeout_tx, timeout_rx) = oneshot::channel(); -// thread::spawn(move || { -// thread::sleep(Duration::from_millis(1000)); -// let _ = timeout_tx.send(()); -// }); -// -// let core = local_executor::Core::new(); -// let (done_tx, done_rx) = oneshot::channel(); -// let future = Dead{done: done_tx}; -// let rx = spawn(future, &core); -// let res = core.run( -// Ok::<_, ()>(()) -// .into_future() -// .then(move |_| { -// // forget the spawned future: should keep running, i.e. hit -// // the timeout below. -// rx.forget(); -// // and wait for the spawned future to release its resources -// done_rx -// }) -// .select2(timeout_rx) -// ); -// match res { -// Err(Either::A((oneshot::Canceled, _))) => { -// panic!("forgotten dead future was canceled"); -// }, -// Ok(Either::B(((), _))) => (), // reached timeout -// _ => { -// panic!("forgotten dead future was canceled (unexpected result)"); -// }, -// } -// } diff --git a/futures-core/Cargo.toml b/futures-core/Cargo.toml deleted file mode 100644 index b49dfc31b3..0000000000 --- a/futures-core/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "futures-core" -version = "1.0.0-alpha.0" -edition = "2018" -rust-version = "1.36" -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/futures-rs" -homepage = "https://rust-lang.github.io/futures-rs" -description = """ -The core traits and types in for the `futures` library. -""" - -[features] -default = ["std"] -std = ["alloc"] -alloc = [] - -[dependencies] -portable-atomic = { version = "1.3", optional = true, default-features = false, features = ["require-cas"] } - -[dev-dependencies] -futures = { path = "../futures" } - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/futures-core/LICENSE-APACHE b/futures-core/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-core/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-core/LICENSE-MIT b/futures-core/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-core/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-core/README.md b/futures-core/README.md deleted file mode 100644 index 96e0e064bc..0000000000 --- a/futures-core/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-core - -The core traits and types in for the `futures` library. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-core = "0.3" -``` - -The current `futures-core` requires Rust 1.36 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-core/src/future.rs b/futures-core/src/future.rs deleted file mode 100644 index 30c0323a6b..0000000000 --- a/futures-core/src/future.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Futures. - -use core::ops::DerefMut; -use core::pin::Pin; -use core::task::{Context, Poll}; - -#[doc(no_inline)] -pub use core::future::Future; - -/// An owned dynamically typed [`Future`] for use in cases where you can't -/// statically type your result or need to add some indirection. -/// -/// This type is often created by the [`boxed`] method on [`FutureExt`]. See its documentation for more. -/// -/// [`boxed`]: https://docs.rs/futures/latest/futures/future/trait.FutureExt.html#method.boxed -/// [`FutureExt`]: https://docs.rs/futures/latest/futures/future/trait.FutureExt.html -#[cfg(feature = "alloc")] -pub type BoxFuture<'a, T> = Pin + Send + 'a>>; - -/// `BoxFuture`, but without the `Send` requirement. -/// -/// This type is often created by the [`boxed_local`] method on [`FutureExt`]. See its documentation for more. -/// -/// [`boxed_local`]: https://docs.rs/futures/latest/futures/future/trait.FutureExt.html#method.boxed_local -/// [`FutureExt`]: https://docs.rs/futures/latest/futures/future/trait.FutureExt.html -#[cfg(feature = "alloc")] -pub type LocalBoxFuture<'a, T> = Pin + 'a>>; - -/// A future which tracks whether or not the underlying future -/// should no longer be polled. -/// -/// `is_terminated` will return `true` if a future should no longer be polled. -/// Usually, this state occurs after `poll` (or `try_poll`) returned -/// `Poll::Ready`. However, `is_terminated` may also return `true` if a future -/// has become inactive and can no longer make progress and should be ignored -/// or dropped rather than being `poll`ed again. -pub trait FusedFuture: Future { - /// Returns `true` if the underlying future should no longer be polled. - fn is_terminated(&self) -> bool; -} - -impl FusedFuture for &mut F { - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } -} - -impl

FusedFuture for Pin

-where - P: DerefMut + Unpin, - P::Target: FusedFuture, -{ - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } -} - -mod private_try_future { - use super::Future; - - pub trait Sealed {} - - impl Sealed for F where F: ?Sized + Future> {} -} - -/// A convenience for futures that return `Result` values that includes -/// a variety of adapters tailored to such futures. -pub trait TryFuture: Future + private_try_future::Sealed { - /// The type of successful values yielded by this future - type Ok; - - /// The type of failures yielded by this future - type Error; - - /// Poll this `TryFuture` as if it were a `Future`. - /// - /// This method is a stopgap for a compiler limitation that prevents us from - /// directly inheriting from the `Future` trait; in the future it won't be - /// needed. - fn try_poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; -} - -impl TryFuture for F -where - F: ?Sized + Future>, -{ - type Ok = T; - type Error = E; - - #[inline] - fn try_poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.poll(cx) - } -} - -#[cfg(feature = "alloc")] -mod if_alloc { - use super::*; - use alloc::boxed::Box; - - impl FusedFuture for Box { - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } - } - - #[cfg(feature = "std")] - impl FusedFuture for std::panic::AssertUnwindSafe { - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } - } -} diff --git a/futures-core/src/lib.rs b/futures-core/src/lib.rs deleted file mode 100644 index 6ff6b974b1..0000000000 --- a/futures-core/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Core traits and types for asynchronous operations in Rust. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, /* unsafe_op_in_unsafe_fn */)] // unsafe_op_in_unsafe_fn requires Rust 1.52 - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -pub mod future; -#[doc(no_inline)] -pub use self::future::{FusedFuture, Future, TryFuture}; - -pub mod stream; -#[doc(no_inline)] -pub use self::stream::{FusedStream, Stream, TryStream}; - -#[macro_use] -pub mod task; diff --git a/futures-core/src/stream.rs b/futures-core/src/stream.rs deleted file mode 100644 index dd07d5aa01..0000000000 --- a/futures-core/src/stream.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Asynchronous streams. - -use core::ops::DerefMut; -use core::pin::Pin; -use core::task::{Context, Poll}; - -/// An owned dynamically typed [`Stream`] for use in cases where you can't -/// statically type your result or need to add some indirection. -/// -/// This type is often created by the [`boxed`] method on [`StreamExt`]. See its documentation for more. -/// -/// [`boxed`]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.boxed -/// [`StreamExt`]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html -#[cfg(feature = "alloc")] -pub type BoxStream<'a, T> = Pin + Send + 'a>>; - -/// `BoxStream`, but without the `Send` requirement. -/// -/// This type is often created by the [`boxed_local`] method on [`StreamExt`]. See its documentation for more. -/// -/// [`boxed_local`]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.boxed_local -/// [`StreamExt`]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html -#[cfg(feature = "alloc")] -pub type LocalBoxStream<'a, T> = Pin + 'a>>; - -/// A stream of values produced asynchronously. -/// -/// If `Future` is an asynchronous version of `T`, then `Stream` is an asynchronous version of `Iterator`. A stream -/// represents a sequence of value-producing events that occur asynchronously to -/// the caller. -/// -/// The trait is modeled after `Future`, but allows `poll_next` to be called -/// even after a value has been produced, yielding `None` once the stream has -/// been fully exhausted. -#[must_use = "streams do nothing unless polled"] -pub trait Stream { - /// Values yielded by the stream. - type Item; - - /// Attempt to pull out the next value of this stream, registering the - /// current task for wakeup if the value is not yet available, and returning - /// `None` if the stream is exhausted. - /// - /// # Return value - /// - /// There are several possible return values, each indicating a distinct - /// stream state: - /// - /// - `Poll::Pending` means that this stream's next value is not ready - /// yet. Implementations will ensure that the current task will be notified - /// when the next value may be ready. - /// - /// - `Poll::Ready(Some(val))` means that the stream has successfully - /// produced a value, `val`, and may produce further values on subsequent - /// `poll_next` calls. - /// - /// - `Poll::Ready(None)` means that the stream has terminated, and - /// `poll_next` should not be invoked again. - /// - /// # Panics - /// - /// Once a stream has finished (returned `Ready(None)` from `poll_next`), calling its - /// `poll_next` method again may panic, block forever, or cause other kinds of - /// problems; the `Stream` trait places no requirements on the effects of - /// such a call. However, as the `poll_next` method is not marked `unsafe`, - /// Rust's usual rules apply: calls must never cause undefined behavior - /// (memory corruption, incorrect use of `unsafe` functions, or the like), - /// regardless of the stream's state. - /// - /// If this is difficult to guard against then the [`fuse`] adapter can be used - /// to ensure that `poll_next` always returns `Ready(None)` in subsequent - /// calls. - /// - /// [`fuse`]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html#method.fuse - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Returns the bounds on the remaining length of the stream. - /// - /// Specifically, `size_hint()` returns a tuple where the first element - /// is the lower bound, and the second element is the upper bound. - /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. - /// A [`None`] here means that either there is no known upper bound, or the - /// upper bound is larger than [`usize`]. - /// - /// # Implementation notes - /// - /// It is not enforced that a stream implementation yields the declared - /// number of elements. A buggy stream may yield less than the lower bound - /// or more than the upper bound of elements. - /// - /// `size_hint()` is primarily intended to be used for optimizations such as - /// reserving space for the elements of the stream, but must not be - /// trusted to e.g., omit bounds checks in unsafe code. An incorrect - /// implementation of `size_hint()` should not lead to memory safety - /// violations. - /// - /// That said, the implementation should provide a correct estimation, - /// because otherwise it would be a violation of the trait's protocol. - /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any - /// stream. - #[inline] - fn size_hint(&self) -> (usize, Option) { - (0, None) - } -} - -impl Stream for &mut S { - type Item = S::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - S::poll_next(Pin::new(&mut **self), cx) - } - - fn size_hint(&self) -> (usize, Option) { - (**self).size_hint() - } -} - -impl

Stream for Pin

-where - P: DerefMut + Unpin, - P::Target: Stream, -{ - type Item = ::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - (**self).size_hint() - } -} - -/// A stream which tracks whether or not the underlying stream -/// should no longer be polled. -/// -/// `is_terminated` will return `true` if a future should no longer be polled. -/// Usually, this state occurs after `poll_next` (or `try_poll_next`) returned -/// `Poll::Ready(None)`. However, `is_terminated` may also return `true` if a -/// stream has become inactive and can no longer make progress and should be -/// ignored or dropped rather than being polled again. -pub trait FusedStream: Stream { - /// Returns `true` if the stream should no longer be polled. - fn is_terminated(&self) -> bool; -} - -impl FusedStream for &mut F { - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } -} - -impl

FusedStream for Pin

-where - P: DerefMut + Unpin, - P::Target: FusedStream, -{ - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } -} - -mod private_try_stream { - use super::Stream; - - pub trait Sealed {} - - impl Sealed for S where S: ?Sized + Stream> {} -} - -/// A convenience for streams that return `Result` values that includes -/// a variety of adapters tailored to such futures. -pub trait TryStream: Stream + private_try_stream::Sealed { - /// The type of successful values yielded by this future - type Ok; - - /// The type of failures yielded by this future - type Error; - - /// Poll this `TryStream` as if it were a `Stream`. - /// - /// This method is a stopgap for a compiler limitation that prevents us from - /// directly inheriting from the `Stream` trait; in the future it won't be - /// needed. - fn try_poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>>; -} - -impl TryStream for S -where - S: ?Sized + Stream>, -{ - type Ok = T; - type Error = E; - - fn try_poll_next( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - self.poll_next(cx) - } -} - -#[cfg(feature = "alloc")] -mod if_alloc { - use super::*; - use alloc::boxed::Box; - - impl Stream for Box { - type Item = S::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - (**self).size_hint() - } - } - - #[cfg(feature = "std")] - impl Stream for std::panic::AssertUnwindSafe { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - - impl FusedStream for Box { - fn is_terminated(&self) -> bool { - ::is_terminated(&**self) - } - } -} diff --git a/futures-core/src/task/__internal/atomic_waker.rs b/futures-core/src/task/__internal/atomic_waker.rs deleted file mode 100644 index 3b82fb7cc8..0000000000 --- a/futures-core/src/task/__internal/atomic_waker.rs +++ /dev/null @@ -1,422 +0,0 @@ -use core::cell::UnsafeCell; -use core::fmt; -use core::task::Waker; - -use atomic::AtomicUsize; -use atomic::Ordering::{AcqRel, Acquire, Release}; - -#[cfg(feature = "portable-atomic")] -use portable_atomic as atomic; - -#[cfg(not(feature = "portable-atomic"))] -use core::sync::atomic; - -/// A synchronization primitive for task wakeup. -/// -/// Sometimes the task interested in a given event will change over time. -/// An `AtomicWaker` can coordinate concurrent notifications with the consumer -/// potentially "updating" the underlying task to wake up. This is useful in -/// scenarios where a computation completes in another thread and wants to -/// notify the consumer, but the consumer is in the process of being migrated to -/// a new logical task. -/// -/// Consumers should call `register` before checking the result of a computation -/// and producers should call `wake` after producing the computation (this -/// differs from the usual `thread::park` pattern). It is also permitted for -/// `wake` to be called **before** `register`. This results in a no-op. -/// -/// A single `AtomicWaker` may be reused for any number of calls to `register` or -/// `wake`. -/// -/// # Memory ordering -/// -/// Calling `register` "acquires" all memory "released" by calls to `wake` -/// before the call to `register`. Later calls to `wake` will wake the -/// registered waker (on contention this wake might be triggered in `register`). -/// -/// For concurrent calls to `register` (should be avoided) the ordering is only -/// guaranteed for the winning call. -/// -/// # Examples -/// -/// Here is a simple example providing a `Flag` that can be signalled manually -/// when it is ready. -/// -/// ``` -/// use futures::future::Future; -/// use futures::task::{Context, Poll, AtomicWaker}; -/// use std::sync::Arc; -/// use std::sync::atomic::AtomicBool; -/// use std::sync::atomic::Ordering::Relaxed; -/// use std::pin::Pin; -/// -/// struct Inner { -/// waker: AtomicWaker, -/// set: AtomicBool, -/// } -/// -/// #[derive(Clone)] -/// struct Flag(Arc); -/// -/// impl Flag { -/// pub fn new() -> Self { -/// Self(Arc::new(Inner { -/// waker: AtomicWaker::new(), -/// set: AtomicBool::new(false), -/// })) -/// } -/// -/// pub fn signal(&self) { -/// self.0.set.store(true, Relaxed); -/// self.0.waker.wake(); -/// } -/// } -/// -/// impl Future for Flag { -/// type Output = (); -/// -/// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { -/// // quick check to avoid registration if already done. -/// if self.0.set.load(Relaxed) { -/// return Poll::Ready(()); -/// } -/// -/// self.0.waker.register(cx.waker()); -/// -/// // Need to check condition **after** `register` to avoid a race -/// // condition that would result in lost notifications. -/// if self.0.set.load(Relaxed) { -/// Poll::Ready(()) -/// } else { -/// Poll::Pending -/// } -/// } -/// } -/// ``` -pub struct AtomicWaker { - state: AtomicUsize, - waker: UnsafeCell>, -} - -// `AtomicWaker` is a multi-consumer, single-producer transfer cell. The cell -// stores a `Waker` value produced by calls to `register` and many threads can -// race to take the waker (to wake it) by calling `wake`. -// -// If a new `Waker` instance is produced by calling `register` before an -// existing one is consumed, then the existing one is overwritten. -// -// While `AtomicWaker` is single-producer, the implementation ensures memory -// safety. In the event of concurrent calls to `register`, there will be a -// single winner whose waker will get stored in the cell. The losers will not -// have their tasks woken. As such, callers should ensure to add synchronization -// to calls to `register`. -// -// The implementation uses a single `AtomicUsize` value to coordinate access to -// the `Waker` cell. There are two bits that are operated on independently. -// These are represented by `REGISTERING` and `WAKING`. -// -// The `REGISTERING` bit is set when a producer enters the critical section. The -// `WAKING` bit is set when a consumer enters the critical section. Neither bit -// being set is represented by `WAITING`. -// -// A thread obtains an exclusive lock on the waker cell by transitioning the -// state from `WAITING` to `REGISTERING` or `WAKING`, depending on the operation -// the thread wishes to perform. When this transition is made, it is guaranteed -// that no other thread will access the waker cell. -// -// # Registering -// -// On a call to `register`, an attempt to transition the state from WAITING to -// REGISTERING is made. On success, the caller obtains a lock on the waker cell. -// -// If the lock is obtained, then the thread sets the waker cell to the waker -// provided as an argument. Then it attempts to transition the state back from -// `REGISTERING` -> `WAITING`. -// -// If this transition is successful, then the registering process is complete -// and the next call to `wake` will observe the waker. -// -// If the transition fails, then there was a concurrent call to `wake` that was -// unable to access the waker cell (due to the registering thread holding the -// lock). To handle this, the registering thread removes the waker it just set -// from the cell and calls `wake` on it. This call to wake represents the -// attempt to wake by the other thread (that set the `WAKING` bit). The state is -// then transitioned from `REGISTERING | WAKING` back to `WAITING`. This -// transition must succeed because, at this point, the state cannot be -// transitioned by another thread. -// -// # Waking -// -// On a call to `wake`, an attempt to transition the state from `WAITING` to -// `WAKING` is made. On success, the caller obtains a lock on the waker cell. -// -// If the lock is obtained, then the thread takes ownership of the current value -// in the waker cell, and calls `wake` on it. The state is then transitioned -// back to `WAITING`. This transition must succeed as, at this point, the state -// cannot be transitioned by another thread. -// -// If the thread is unable to obtain the lock, the `WAKING` bit is still. This -// is because it has either been set by the current thread but the previous -// value included the `REGISTERING` bit **or** a concurrent thread is in the -// `WAKING` critical section. Either way, no action must be taken. -// -// If the current thread is the only concurrent call to `wake` and another -// thread is in the `register` critical section, when the other thread **exits** -// the `register` critical section, it will observe the `WAKING` bit and handle -// the wake itself. -// -// If another thread is in the `wake` critical section, then it will handle -// waking the task. -// -// # A potential race (is safely handled). -// -// Imagine the following situation: -// -// * Thread A obtains the `wake` lock and wakes a task. -// -// * Before thread A releases the `wake` lock, the woken task is scheduled. -// -// * Thread B attempts to wake the task. In theory this should result in the -// task being woken, but it cannot because thread A still holds the wake lock. -// -// This case is handled by requiring users of `AtomicWaker` to call `register` -// **before** attempting to observe the application state change that resulted -// in the task being awoken. The wakers also change the application state before -// calling wake. -// -// Because of this, the waker will do one of two things. -// -// 1) Observe the application state change that Thread B is woken for. In this -// case, it is OK for Thread B's wake to be lost. -// -// 2) Call register before attempting to observe the application state. Since -// Thread A still holds the `wake` lock, the call to `register` will result -// in the task waking itself and get scheduled again. - -/// Idle state -const WAITING: usize = 0; - -/// A new waker value is being registered with the `AtomicWaker` cell. -const REGISTERING: usize = 0b01; - -/// The waker currently registered with the `AtomicWaker` cell is being woken. -const WAKING: usize = 0b10; - -impl AtomicWaker { - /// Create an `AtomicWaker`. - pub const fn new() -> Self { - // Make sure that task is Sync - #[allow(dead_code)] - trait AssertSync: Sync {} - impl AssertSync for Waker {} - - Self { state: AtomicUsize::new(WAITING), waker: UnsafeCell::new(None) } - } - - /// Registers the waker to be notified on calls to `wake`. - /// - /// The new task will take place of any previous tasks that were registered - /// by previous calls to `register`. Any calls to `wake` that happen after - /// a call to `register` (as defined by the memory ordering rules), will - /// notify the `register` caller's task and deregister the waker from future - /// notifications. Because of this, callers should ensure `register` gets - /// invoked with a new `Waker` **each** time they require a wakeup. - /// - /// It is safe to call `register` with multiple other threads concurrently - /// calling `wake`. This will result in the `register` caller's current - /// task being notified once. - /// - /// This function is safe to call concurrently, but this is generally a bad - /// idea. Concurrent calls to `register` will attempt to register different - /// tasks to be notified. One of the callers will win and have its task set, - /// but there is no guarantee as to which caller will succeed. - /// - /// # Examples - /// - /// Here is how `register` is used when implementing a flag. - /// - /// ``` - /// use futures::future::Future; - /// use futures::task::{Context, Poll, AtomicWaker}; - /// use std::sync::atomic::AtomicBool; - /// use std::sync::atomic::Ordering::Relaxed; - /// use std::pin::Pin; - /// - /// struct Flag { - /// waker: AtomicWaker, - /// set: AtomicBool, - /// } - /// - /// impl Future for Flag { - /// type Output = (); - /// - /// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - /// // Register **before** checking `set` to avoid a race condition - /// // that would result in lost notifications. - /// self.waker.register(cx.waker()); - /// - /// if self.set.load(Relaxed) { - /// Poll::Ready(()) - /// } else { - /// Poll::Pending - /// } - /// } - /// } - /// ``` - pub fn register(&self, waker: &Waker) { - match self - .state - .compare_exchange(WAITING, REGISTERING, Acquire, Acquire) - .unwrap_or_else(|x| x) - { - WAITING => { - unsafe { - // Locked acquired, update the waker cell - - // Avoid cloning the waker if the old waker will awaken the same task. - match &*self.waker.get() { - Some(old_waker) if old_waker.will_wake(waker) => (), - _ => *self.waker.get() = Some(waker.clone()), - } - - // Release the lock. If the state transitioned to include - // the `WAKING` bit, this means that at least one wake has - // been called concurrently. - // - // Start by assuming that the state is `REGISTERING` as this - // is what we just set it to. If this holds, we know that no - // other writes were performed in the meantime, so there is - // nothing to acquire, only release. In case of concurrent - // wakers, we need to acquire their releases, so success needs - // to do both. - let res = self.state.compare_exchange(REGISTERING, WAITING, AcqRel, Acquire); - - match res { - Ok(_) => { - // memory ordering: acquired self.state during CAS - // - if previous wakes went through it syncs with - // their final release (`fetch_and`) - // - if there was no previous wake the next wake - // will wake us, no sync needed. - } - Err(actual) => { - // This branch can only be reached if at least one - // concurrent thread called `wake`. In this - // case, `actual` **must** be `REGISTERING | - // `WAKING`. - debug_assert_eq!(actual, REGISTERING | WAKING); - - // Take the waker to wake once the atomic operation has - // completed. - let waker = (*self.waker.get()).take().unwrap(); - - // We need to return to WAITING state (clear our lock and - // concurrent WAKING flag). This needs to acquire all - // WAKING fetch_or releases and it needs to release our - // update to self.waker, so we need a `swap` operation. - self.state.swap(WAITING, AcqRel); - - // memory ordering: we acquired the state for all - // concurrent wakes, but future wakes might still - // need to wake us in case we can't make progress - // from the pending wakes. - // - // So we simply schedule to come back later (we could - // also simply leave the registration in place above). - waker.wake(); - } - } - } - } - WAKING => { - // Currently in the process of waking the task, i.e., - // `wake` is currently being called on the old task handle. - // - // memory ordering: we acquired the state for all - // concurrent wakes, but future wakes might still - // need to wake us in case we can't make progress - // from the pending wakes. - // - // So we simply schedule to come back later (we - // could also spin here trying to acquire the lock - // to register). - waker.wake_by_ref(); - } - state => { - // In this case, a concurrent thread is holding the - // "registering" lock. This probably indicates a bug in the - // caller's code as racing to call `register` doesn't make much - // sense. - // - // memory ordering: don't care. a concurrent register() is going - // to succeed and provide proper memory ordering. - // - // We just want to maintain memory safety. It is ok to drop the - // call to `register`. - debug_assert!(state == REGISTERING || state == REGISTERING | WAKING); - } - } - } - - /// Calls `wake` on the last `Waker` passed to `register`. - /// - /// If `register` has not been called yet, then this does nothing. - pub fn wake(&self) { - if let Some(waker) = self.take() { - waker.wake(); - } - } - - /// Returns the last `Waker` passed to `register`, so that the user can wake it. - /// - /// - /// Sometimes, just waking the AtomicWaker is not fine grained enough. This allows the user - /// to take the waker and then wake it separately, rather than performing both steps in one - /// atomic action. - /// - /// If a waker has not been registered, this returns `None`. - pub fn take(&self) -> Option { - // AcqRel ordering is used in order to acquire the value of the `task` - // cell as well as to establish a `release` ordering with whatever - // memory the `AtomicWaker` is associated with. - match self.state.fetch_or(WAKING, AcqRel) { - WAITING => { - // The waking lock has been acquired. - let waker = unsafe { (*self.waker.get()).take() }; - - // Release the lock - self.state.fetch_and(!WAKING, Release); - - waker - } - state => { - // There is a concurrent thread currently updating the - // associated task. - // - // Nothing more to do as the `WAKING` bit has been set. It - // doesn't matter if there are concurrent registering threads or - // not. - // - debug_assert!( - state == REGISTERING || state == REGISTERING | WAKING || state == WAKING - ); - None - } - } - } -} - -impl Default for AtomicWaker { - fn default() -> Self { - Self::new() - } -} - -impl fmt::Debug for AtomicWaker { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "AtomicWaker") - } -} - -unsafe impl Send for AtomicWaker {} -unsafe impl Sync for AtomicWaker {} diff --git a/futures-core/src/task/__internal/mod.rs b/futures-core/src/task/__internal/mod.rs deleted file mode 100644 index c248742280..0000000000 --- a/futures-core/src/task/__internal/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg_attr(target_os = "none", cfg(any(target_has_atomic = "ptr", feature = "portable-atomic")))] -mod atomic_waker; -#[cfg_attr( - target_os = "none", - cfg(any(target_has_atomic = "ptr", feature = "portable-atomic")) -)] -pub use self::atomic_waker::AtomicWaker; diff --git a/futures-core/src/task/mod.rs b/futures-core/src/task/mod.rs deleted file mode 100644 index 19e4eaecdd..0000000000 --- a/futures-core/src/task/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Task notification. - -#[macro_use] -mod poll; - -#[doc(hidden)] -pub mod __internal; - -#[doc(no_inline)] -pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; diff --git a/futures-core/src/task/poll.rs b/futures-core/src/task/poll.rs deleted file mode 100644 index bde0f8a5fe..0000000000 --- a/futures-core/src/task/poll.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// 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 $(,)?) => { - match $e { - $crate::task::Poll::Ready(t) => t, - $crate::task::Poll::Pending => return $crate::task::Poll::Pending, - } - }; -} diff --git a/futures-executor/Cargo.toml b/futures-executor/Cargo.toml deleted file mode 100644 index 72625d16d2..0000000000 --- a/futures-executor/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "futures-executor" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -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"] - -[dependencies] -futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false } -futures-task = { path = "../futures-task", version = "=0.4.0-alpha.0", default-features = false } -futures-util = { path = "../futures-util", version = "=0.4.0-alpha.0", default-features = false } - -[dev-dependencies] -futures = { path = "../futures", features = ["thread-pool"] } - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/futures-executor/LICENSE-APACHE b/futures-executor/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-executor/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-executor/LICENSE-MIT b/futures-executor/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-executor/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-executor/README.md b/futures-executor/README.md deleted file mode 100644 index b3906543b0..0000000000 --- a/futures-executor/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-executor - -Executors for asynchronous tasks based on the futures-rs library. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-executor = "0.3" -``` - -The current `futures-executor` requires Rust 1.68 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-executor/benches/thread_notify.rs b/futures-executor/benches/thread_notify.rs deleted file mode 100644 index 88d0447cf6..0000000000 --- a/futures-executor/benches/thread_notify.rs +++ /dev/null @@ -1,109 +0,0 @@ -#![feature(test)] - -extern crate test; -use crate::test::Bencher; - -use futures::executor::block_on; -use futures::future::Future; -use futures::task::{Context, Poll, Waker}; -use std::pin::Pin; - -#[bench] -fn thread_yield_single_thread_one_wait(b: &mut Bencher) { - const NUM: usize = 10_000; - - struct Yield { - rem: usize, - } - - impl Future for Yield { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.rem == 0 { - Poll::Ready(()) - } else { - self.rem -= 1; - cx.waker().wake_by_ref(); - Poll::Pending - } - } - } - - b.iter(|| { - let y = Yield { rem: NUM }; - block_on(y); - }); -} - -#[bench] -fn thread_yield_single_thread_many_wait(b: &mut Bencher) { - const NUM: usize = 10_000; - - struct Yield { - rem: usize, - } - - impl Future for Yield { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.rem == 0 { - Poll::Ready(()) - } else { - self.rem -= 1; - cx.waker().wake_by_ref(); - Poll::Pending - } - } - } - - b.iter(|| { - for _ in 0..NUM { - let y = Yield { rem: 1 }; - block_on(y); - } - }); -} - -#[bench] -fn thread_yield_multi_thread(b: &mut Bencher) { - use std::sync::mpsc; - use std::thread; - - const NUM: usize = 1_000; - - let (tx, rx) = mpsc::sync_channel::(10_000); - - struct Yield { - rem: usize, - tx: mpsc::SyncSender, - } - impl Unpin for Yield {} - - impl Future for Yield { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.rem == 0 { - Poll::Ready(()) - } else { - self.rem -= 1; - self.tx.send(cx.waker().clone()).unwrap(); - Poll::Pending - } - } - } - - thread::spawn(move || { - while let Ok(task) = rx.recv() { - task.wake(); - } - }); - - b.iter(move || { - let y = Yield { rem: NUM, tx: tx.clone() }; - - block_on(y); - }); -} diff --git a/futures-executor/src/enter.rs b/futures-executor/src/enter.rs deleted file mode 100644 index 46e1bd147e..0000000000 --- a/futures-executor/src/enter.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::cell::Cell; -use std::fmt; - -std::thread_local!(static ENTERED: Cell = const { Cell::new(false) }); - -/// Represents an executor context. -/// -/// For more details, see [`enter` documentation](enter()). -pub struct Enter { - _priv: (), -} - -/// An error returned by `enter` if an execution scope has already been -/// entered. -pub struct EnterError { - _priv: (), -} - -impl fmt::Debug for EnterError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EnterError").finish() - } -} - -impl fmt::Display for EnterError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "an execution scope has already been entered") - } -} - -impl std::error::Error for EnterError {} - -/// Marks the current thread as being within the dynamic extent of an -/// executor. -/// -/// Executor implementations should call this function before beginning to -/// execute a task, and drop the returned [`Enter`](Enter) value after -/// completing task execution: -/// -/// ``` -/// use futures::executor::enter; -/// -/// let enter = enter().expect("..."); -/// /* run task */ -/// drop(enter); -/// ``` -/// -/// Doing so ensures that executors aren't -/// accidentally invoked in a nested fashion. -/// -/// # Error -/// -/// Returns an error if the current thread is already marked, in which case the -/// caller should panic with a tailored error message. -pub fn enter() -> Result { - ENTERED.with(|c| { - if c.get() { - Err(EnterError { _priv: () }) - } else { - c.set(true); - - Ok(Enter { _priv: () }) - } - }) -} - -impl fmt::Debug for Enter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Enter").finish() - } -} - -impl Drop for Enter { - fn drop(&mut self) { - ENTERED.with(|c| { - assert!(c.get()); - c.set(false); - }); - } -} diff --git a/futures-executor/src/lib.rs b/futures-executor/src/lib.rs deleted file mode 100644 index a0dc49d7ba..0000000000 --- a/futures-executor/src/lib.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Built-in executors and related tools. -//! -//! All asynchronous computation occurs within an executor, which is -//! capable of spawning futures as tasks. This module provides several -//! built-in executors, as well as tools for building your own. -//! -//! All items are only available when the `std` feature of this -//! library is activated, and it is activated by default. -//! -//! # Using a thread pool (M:N task scheduling) -//! -//! Most of the time tasks should be executed on a [thread pool](ThreadPool). -//! A small set of worker threads can handle a very large set of spawned tasks -//! (which are much lighter weight than threads). Tasks spawned onto the pool -//! with the [`spawn_ok`](ThreadPool::spawn_ok) function will run ambiently on -//! the created threads. -//! -//! # Spawning additional tasks -//! -//! Tasks can be spawned onto a spawner by calling its [`spawn_obj`] method -//! directly. In the case of `!Send` futures, [`spawn_local_obj`] can be used -//! instead. -//! -//! # Single-threaded execution -//! -//! In addition to thread pools, it's possible to run a task (and the tasks -//! it spawns) entirely within a single thread via the [`LocalPool`] executor. -//! Aside from cutting down on synchronization costs, this executor also makes -//! it possible to spawn non-`Send` tasks, via [`spawn_local_obj`]. The -//! [`LocalPool`] is best suited for running I/O-bound tasks that do relatively -//! little work between I/O operations. -//! -//! There is also a convenience function [`block_on`] for simply running a -//! future to completion on the current thread. -//! -//! [`spawn_obj`]: https://docs.rs/futures/0.3/futures/task/trait.Spawn.html#tymethod.spawn_obj -//! [`spawn_local_obj`]: https://docs.rs/futures/0.3/futures/task/trait.LocalSpawn.html#tymethod.spawn_local_obj - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] -#![cfg_attr(docsrs, feature(doc_cfg))] - -#[cfg(feature = "std")] -extern crate std; - -#[cfg(feature = "std")] -mod local_pool; -#[cfg(feature = "std")] -pub use crate::local_pool::{block_on, block_on_stream, BlockingStream, LocalPool, LocalSpawner}; - -#[cfg(feature = "thread-pool")] -#[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] -#[cfg(feature = "std")] -mod thread_pool; -#[cfg(feature = "thread-pool")] -#[cfg(feature = "std")] -mod unpark_mutex; -#[cfg(feature = "thread-pool")] -#[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] -#[cfg(feature = "std")] -pub use crate::thread_pool::{ThreadPool, ThreadPoolBuilder}; - -#[cfg(feature = "std")] -mod enter; -#[cfg(feature = "std")] -pub use crate::enter::{enter, Enter, EnterError}; diff --git a/futures-executor/src/local_pool.rs b/futures-executor/src/local_pool.rs deleted file mode 100644 index fb55343953..0000000000 --- a/futures-executor/src/local_pool.rs +++ /dev/null @@ -1,401 +0,0 @@ -use crate::enter; -use futures_core::future::Future; -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::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}, - Arc, -}; -use std::thread::{self, Thread}; -use std::vec::Vec; - -/// A single-threaded task pool for polling futures to completion. -/// -/// This executor allows you to multiplex any number of tasks onto a single -/// thread. It's appropriate to poll strictly I/O-bound futures that do very -/// little work in between I/O actions. -/// -/// To get a handle to the pool that implements -/// [`Spawn`](futures_task::Spawn), use the -/// [`spawner()`](LocalPool::spawner) method. Because the executor is -/// single-threaded, it supports a special form of task spawning for non-`Send` -/// futures, via [`spawn_local_obj`](futures_task::LocalSpawn::spawn_local_obj). -#[derive(Debug)] -pub struct LocalPool { - pool: FuturesUnordered>, - incoming: Rc, -} - -/// A handle to a [`LocalPool`] that implements [`Spawn`](futures_task::Spawn). -#[derive(Clone, Debug)] -pub struct LocalSpawner { - incoming: Weak, -} - -type Incoming = RefCell>>; - -pub(crate) struct ThreadNotify { - /// The (single) executor thread. - thread: Thread, - /// A flag to ensure a wakeup (i.e. `unpark()`) is not "forgotten" - /// before the next `park()`, which may otherwise happen if the code - /// being executed as part of the future(s) being polled makes use of - /// park / unpark calls of its own, i.e. we cannot assume that no other - /// code uses park / unpark on the executing `thread`. - unparked: AtomicBool, -} - -std::thread_local! { - static CURRENT_THREAD_NOTIFY: Arc = Arc::new(ThreadNotify { - thread: thread::current(), - unparked: AtomicBool::new(false), - }); -} - -impl ArcWake for ThreadNotify { - fn wake_by_ref(arc_self: &Arc) { - // Make sure the wakeup is remembered until the next `park()`. - let unparked = arc_self.unparked.swap(true, Ordering::Release); - if !unparked { - // If the thread has not been unparked yet, it must be done - // now. If it was actually parked, it will run again, - // otherwise the token made available by `unpark` - // may be consumed before reaching `park()`, but `unparked` - // ensures it is not forgotten. - arc_self.thread.unpark(); - } - } -} - -// Set up and run a basic single-threaded spawner loop, invoking `f` on each -// turn. -fn run_executor) -> Poll>(mut f: F) -> T { - let _enter = enter().expect( - "cannot execute `LocalPool` executor from within \ - another executor", - ); - - CURRENT_THREAD_NOTIFY.with(|thread_notify| { - let waker = waker_ref(thread_notify); - let mut cx = Context::from_waker(&waker); - loop { - if let Poll::Ready(t) = f(&mut cx) { - return t; - } - - // Wait for a wakeup. - while !thread_notify.unparked.swap(false, Ordering::Acquire) { - // No wakeup occurred. It may occur now, right before parking, - // but in that case the token made available by `unpark()` - // is guaranteed to still be available and `park()` is a no-op. - thread::park(); - } - } - }) -} - -/// Check for a wakeup, but don't consume it. -fn woken() -> bool { - CURRENT_THREAD_NOTIFY.with(|thread_notify| thread_notify.unparked.load(Ordering::Acquire)) -} - -impl LocalPool { - /// Create a new, empty pool of tasks. - pub fn new() -> Self { - Self { pool: FuturesUnordered::new(), incoming: Default::default() } - } - - /// Get a clonable handle to the pool as a [`Spawn`]. - pub fn spawner(&self) -> LocalSpawner { - LocalSpawner { incoming: Rc::downgrade(&self.incoming) } - } - - /// Run all tasks in the pool to completion. - /// - /// ``` - /// use futures::executor::LocalPool; - /// - /// let mut pool = LocalPool::new(); - /// - /// // ... spawn some initial tasks using `spawn.spawn()` or `spawn.spawn_local()` - /// - /// // run *all* tasks in the pool to completion, including any newly-spawned ones. - /// pool.run(); - /// ``` - /// - /// The function will block the calling thread until *all* tasks in the pool - /// are complete, including any spawned while running existing tasks. - pub fn run(&mut self) { - run_executor(|cx| self.poll_pool(cx)) - } - - /// Runs all the tasks in the pool until the given future completes. - /// - /// ``` - /// use futures::executor::LocalPool; - /// - /// let mut pool = LocalPool::new(); - /// # let my_app = async {}; - /// - /// // run tasks in the pool until `my_app` completes - /// pool.run_until(my_app); - /// ``` - /// - /// The function will block the calling thread *only* until the future `f` - /// completes; there may still be incomplete tasks in the pool, which will - /// be inert after the call completes, but can continue with further use of - /// 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 { - let mut future = pin!(future); - - run_executor(|cx| { - { - // if our main task is done, so are we - let result = future.as_mut().poll(cx); - if let Poll::Ready(output) = result { - return Poll::Ready(output); - } - } - - let _ = self.poll_pool(cx); - Poll::Pending - }) - } - - /// Runs all tasks and returns after completing one future or until no more progress - /// can be made. Returns `true` if one future was completed, `false` otherwise. - /// - /// ``` - /// use futures::executor::LocalPool; - /// use futures::task::LocalSpawnExt; - /// use futures::future::{ready, pending}; - /// - /// let mut pool = LocalPool::new(); - /// let spawner = pool.spawner(); - /// - /// spawner.spawn_local(ready(())).unwrap(); - /// spawner.spawn_local(ready(())).unwrap(); - /// spawner.spawn_local(pending()).unwrap(); - /// - /// // Run the two ready tasks and return true for them. - /// pool.try_run_one(); // returns true after completing one of the ready futures - /// pool.try_run_one(); // returns true after completing the other ready future - /// - /// // the remaining task can not be completed - /// assert!(!pool.try_run_one()); // returns false - /// ``` - /// - /// This function will not block the calling thread and will return the moment - /// that there are no tasks left for which progress can be made or after exactly one - /// task was completed; Remaining incomplete tasks in the pool can continue with - /// further use of one of the pool's run or poll methods. - /// Though only one task will be completed, progress may be made on multiple tasks. - pub fn try_run_one(&mut self) -> bool { - run_executor(|cx| { - loop { - self.drain_incoming(); - - match self.pool.poll_next_unpin(cx) { - // Success! - Poll::Ready(Some(())) => return Poll::Ready(true), - // The pool was empty. - Poll::Ready(None) => return Poll::Ready(false), - Poll::Pending => (), - } - - if !self.incoming.borrow().is_empty() { - // New tasks were spawned; try again. - continue; - } else if woken() { - // The pool yielded to us, but there's more progress to be made. - return Poll::Pending; - } else { - return Poll::Ready(false); - } - } - }) - } - - /// Runs all tasks in the pool and returns if no more progress can be made - /// on any task. - /// - /// ``` - /// use futures::executor::LocalPool; - /// use futures::task::LocalSpawnExt; - /// use futures::future::{ready, pending}; - /// - /// let mut pool = LocalPool::new(); - /// let spawner = pool.spawner(); - /// - /// spawner.spawn_local(ready(())).unwrap(); - /// spawner.spawn_local(ready(())).unwrap(); - /// spawner.spawn_local(pending()).unwrap(); - /// - /// // Runs the two ready task and returns. - /// // The empty task remains in the pool. - /// pool.run_until_stalled(); - /// ``` - /// - /// This function will not block the calling thread and will return the moment - /// that there are no tasks left for which progress can be made; - /// remaining incomplete tasks in the pool can continue with further use of one - /// of the pool's run or poll methods. While the function is running, all tasks - /// in the pool will try to make progress. - pub fn run_until_stalled(&mut self) { - run_executor(|cx| match self.poll_pool(cx) { - // The pool is empty. - Poll::Ready(()) => Poll::Ready(()), - Poll::Pending => { - if woken() { - Poll::Pending - } else { - // We're stalled for now. - Poll::Ready(()) - } - } - }); - } - - /// Poll `self.pool`, re-filling it with any newly-spawned tasks. - /// Repeat until either the pool is empty, or it returns `Pending`. - /// - /// Returns `Ready` if the pool was empty, and `Pending` otherwise. - /// - /// NOTE: the pool may call `wake`, so `Pending` doesn't necessarily - /// mean that the pool can't make progress. - fn poll_pool(&mut self, cx: &mut Context<'_>) -> Poll<()> { - loop { - self.drain_incoming(); - - let pool_ret = self.pool.poll_next_unpin(cx); - - // We queued up some new tasks; add them and poll again. - if !self.incoming.borrow().is_empty() { - continue; - } - - match pool_ret { - Poll::Ready(Some(())) => continue, - Poll::Ready(None) => return Poll::Ready(()), - Poll::Pending => return Poll::Pending, - } - } - } - - /// Empty the incoming queue of newly-spawned tasks. - fn drain_incoming(&mut self) { - let mut incoming = self.incoming.borrow_mut(); - for task in incoming.drain(..) { - self.pool.push(task) - } - } -} - -impl Default for LocalPool { - fn default() -> Self { - Self::new() - } -} - -/// Run a future to completion on the current thread. -/// -/// This function will block the caller until the given future has completed. -/// -/// Use a [`LocalPool`] if you need finer-grained control over spawned tasks. -pub fn block_on(f: F) -> F::Output { - let mut f = pin!(f); - run_executor(|cx| f.as_mut().poll(cx)) -} - -/// Turn a stream into a blocking iterator. -/// -/// When `next` is called on the resulting `BlockingStream`, the caller -/// will be blocked until the next element of the `Stream` becomes available. -pub fn block_on_stream(stream: S) -> BlockingStream { - BlockingStream { stream } -} - -/// An iterator which blocks on values from a stream until they become available. -#[derive(Debug)] -pub struct BlockingStream { - stream: S, -} - -impl Deref for BlockingStream { - type Target = S; - fn deref(&self) -> &Self::Target { - &self.stream - } -} - -impl DerefMut for BlockingStream { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.stream - } -} - -impl BlockingStream { - /// Convert this `BlockingStream` into the inner `Stream` type. - pub fn into_inner(self) -> S { - self.stream - } -} - -impl Iterator for BlockingStream { - type Item = S::Item; - - fn next(&mut self) -> Option { - LocalPool::new().run_until(self.stream.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.stream.size_hint() - } -} - -impl Spawn for LocalSpawner { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - if let Some(incoming) = self.incoming.upgrade() { - incoming.borrow_mut().push(future.into()); - Ok(()) - } else { - Err(SpawnError::shutdown()) - } - } - - fn status(&self) -> Result<(), SpawnError> { - if self.incoming.upgrade().is_some() { - Ok(()) - } else { - Err(SpawnError::shutdown()) - } - } -} - -impl LocalSpawn for LocalSpawner { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - if let Some(incoming) = self.incoming.upgrade() { - incoming.borrow_mut().push(future); - Ok(()) - } else { - Err(SpawnError::shutdown()) - } - } - - fn status_local(&self) -> Result<(), SpawnError> { - if self.incoming.upgrade().is_some() { - Ok(()) - } else { - Err(SpawnError::shutdown()) - } - } -} diff --git a/futures-executor/src/thread_pool.rs b/futures-executor/src/thread_pool.rs deleted file mode 100644 index 774ab53ca2..0000000000 --- a/futures-executor/src/thread_pool.rs +++ /dev/null @@ -1,377 +0,0 @@ -use crate::enter; -use crate::unpark_mutex::UnparkMutex; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_task::{waker_ref, ArcWake}; -use futures_task::{FutureObj, Spawn, SpawnError}; -use futures_util::future::FutureExt; -use std::boxed::Box; -use std::fmt; -use std::format; -use std::io; -use std::string::String; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc; -use std::sync::{Arc, Mutex}; -use std::thread; - -/// A general-purpose thread pool for scheduling tasks that poll futures to -/// completion. -/// -/// The thread pool multiplexes any number of tasks onto a fixed number of -/// worker threads. -/// -/// This type is a clonable handle to the threadpool itself. -/// Cloning it will only create a new reference, not a new threadpool. -/// -/// This type is only available when the `thread-pool` feature of this -/// library is activated. -#[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] -pub struct ThreadPool { - state: Arc, -} - -/// Thread pool configuration object. -/// -/// This type is only available when the `thread-pool` feature of this -/// library is activated. -#[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] -pub struct ThreadPoolBuilder { - pool_size: usize, - stack_size: usize, - name_prefix: Option, - after_start: Option>, - before_stop: Option>, -} - -#[allow(dead_code)] -trait AssertSendSync: Send + Sync {} -impl AssertSendSync for ThreadPool {} - -struct PoolState { - tx: Mutex>, - rx: Mutex>, - cnt: AtomicUsize, - size: usize, -} - -impl fmt::Debug for ThreadPool { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ThreadPool").field("size", &self.state.size).finish() - } -} - -impl fmt::Debug for ThreadPoolBuilder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ThreadPoolBuilder") - .field("pool_size", &self.pool_size) - .field("name_prefix", &self.name_prefix) - .finish() - } -} - -enum Message { - Run(Task), - Close, -} - -impl ThreadPool { - /// Creates a new thread pool with the default configuration. - /// - /// See documentation for the methods in - /// [`ThreadPoolBuilder`](ThreadPoolBuilder) for details on the default - /// configuration. - pub fn new() -> Result { - ThreadPoolBuilder::new().create() - } - - /// Create a default thread pool configuration, which can then be customized. - /// - /// See documentation for the methods in - /// [`ThreadPoolBuilder`](ThreadPoolBuilder) for details on the default - /// configuration. - pub fn builder() -> ThreadPoolBuilder { - ThreadPoolBuilder::new() - } - - /// Spawns a future that will be run to completion. - /// - /// > **Note**: This method is similar to `Spawn::spawn_obj`, except that - /// > it is guaranteed to always succeed. - pub fn spawn_obj_ok(&self, future: FutureObj<'static, ()>) { - let task = Task { - future, - wake_handle: Arc::new(WakeHandle { exec: self.clone(), mutex: UnparkMutex::new() }), - exec: self.clone(), - }; - self.state.send(Message::Run(task)); - } - - /// Spawns a task that polls the given future with output `()` to - /// completion. - /// - /// ``` - /// # { - /// use futures::executor::ThreadPool; - /// - /// let pool = ThreadPool::new().unwrap(); - /// - /// let future = async { /* ... */ }; - /// pool.spawn_ok(future); - /// # } - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - /// - /// > **Note**: This method is similar to `SpawnExt::spawn`, except that - /// > it is guaranteed to always succeed. - pub fn spawn_ok(&self, future: Fut) - where - Fut: Future + Send + 'static, - { - self.spawn_obj_ok(FutureObj::new(Box::new(future))) - } -} - -impl Spawn for ThreadPool { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - self.spawn_obj_ok(future); - Ok(()) - } -} - -impl PoolState { - fn send(&self, msg: Message) { - self.tx.lock().unwrap().send(msg).unwrap(); - } - - fn work( - &self, - idx: usize, - after_start: Option>, - before_stop: Option>, - ) { - let _scope = enter().unwrap(); - if let Some(after_start) = after_start { - after_start(idx); - } - loop { - let msg = self.rx.lock().unwrap().recv().unwrap(); - match msg { - Message::Run(task) => task.run(), - Message::Close => break, - } - } - if let Some(before_stop) = before_stop { - before_stop(idx); - } - } -} - -impl Clone for ThreadPool { - fn clone(&self) -> Self { - self.state.cnt.fetch_add(1, Ordering::Relaxed); - Self { state: self.state.clone() } - } -} - -impl Drop for ThreadPool { - fn drop(&mut self) { - if self.state.cnt.fetch_sub(1, Ordering::Relaxed) == 1 { - for _ in 0..self.state.size { - self.state.send(Message::Close); - } - } - } -} - -impl ThreadPoolBuilder { - /// Create a default thread pool configuration. - /// - /// See the other methods on this type for details on the defaults. - pub fn new() -> Self { - 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 - /// - /// The size of a thread pool is the number of worker threads spawned. By - /// default, this is equal to the number of CPU cores. - /// - /// # Panics - /// - /// Panics if `pool_size == 0`. - pub fn pool_size(&mut self, size: usize) -> &mut Self { - assert!(size > 0); - self.pool_size = size; - self - } - - /// Set stack size of threads in the pool, in bytes. - /// - /// By default, worker threads use Rust's standard stack size. - pub fn stack_size(&mut self, stack_size: usize) -> &mut Self { - self.stack_size = stack_size; - self - } - - /// Set thread name prefix of a future ThreadPool. - /// - /// Thread name prefix is used for generating thread names. For example, if prefix is - /// `my-pool-`, then threads in the pool will get names like `my-pool-1` etc. - /// - /// By default, worker threads are assigned Rust's standard thread name. - pub fn name_prefix>(&mut self, name_prefix: S) -> &mut Self { - self.name_prefix = Some(name_prefix.into()); - self - } - - /// Execute the closure `f` immediately after each worker thread is started, - /// but before running any tasks on it. - /// - /// This hook is intended for bookkeeping and monitoring. - /// The closure `f` will be dropped after the `builder` is dropped - /// and all worker threads in the pool have executed it. - /// - /// The closure provided will receive an index corresponding to the worker - /// thread it's running on. - pub fn after_start(&mut self, f: F) -> &mut Self - where - F: Fn(usize) + Send + Sync + 'static, - { - self.after_start = Some(Arc::new(f)); - self - } - - /// Execute closure `f` just prior to shutting down each worker thread. - /// - /// This hook is intended for bookkeeping and monitoring. - /// The closure `f` will be dropped after the `builder` is dropped - /// and all threads in the pool have executed it. - /// - /// The closure provided will receive an index corresponding to the worker - /// thread it's running on. - pub fn before_stop(&mut self, f: F) -> &mut Self - where - F: Fn(usize) + Send + Sync + 'static, - { - self.before_stop = Some(Arc::new(f)); - self - } - - /// Create a [`ThreadPool`](ThreadPool) with the given configuration. - pub fn create(&mut self) -> Result { - let (tx, rx) = mpsc::channel(); - let pool = ThreadPool { - state: Arc::new(PoolState { - tx: Mutex::new(tx), - rx: Mutex::new(rx), - cnt: AtomicUsize::new(1), - size: self.pool_size, - }), - }; - - for counter in 0..self.pool_size { - let state = pool.state.clone(); - let after_start = self.after_start.clone(); - 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}")); - } - if self.stack_size > 0 { - thread_builder = thread_builder.stack_size(self.stack_size); - } - thread_builder.spawn(move || state.work(counter, after_start, before_stop))?; - } - Ok(pool) - } -} - -impl Default for ThreadPoolBuilder { - fn default() -> Self { - Self::new() - } -} - -/// A task responsible for polling a future to completion. -struct Task { - future: FutureObj<'static, ()>, - exec: ThreadPool, - wake_handle: Arc, -} - -struct WakeHandle { - mutex: UnparkMutex, - exec: ThreadPool, -} - -impl Task { - /// Actually run the task (invoking `poll` on the future) on the current - /// thread. - fn run(self) { - let Self { mut future, wake_handle, mut exec } = self; - let waker = waker_ref(&wake_handle); - let mut cx = Context::from_waker(&waker); - - // Safety: The ownership of this `Task` object is evidence that - // we are in the `POLLING`/`REPOLL` state for the mutex. - unsafe { - wake_handle.mutex.start_poll(); - - loop { - let res = future.poll_unpin(&mut cx); - match res { - Poll::Pending => {} - Poll::Ready(()) => return wake_handle.mutex.complete(), - } - let task = Self { future, wake_handle: wake_handle.clone(), exec }; - match wake_handle.mutex.wait(task) { - Ok(()) => return, // we've waited - Err(task) => { - // someone's notified us - future = task.future; - exec = task.exec; - } - } - } - } - } -} - -impl fmt::Debug for Task { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Task").field("contents", &"...").finish() - } -} - -impl ArcWake for WakeHandle { - fn wake_by_ref(arc_self: &Arc) { - if let Ok(task) = arc_self.mutex.notify() { - arc_self.exec.state.send(Message::Run(task)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_drop_after_start() { - { - let (tx, rx) = mpsc::sync_channel(2); - let _cpu_pool = ThreadPoolBuilder::new() - .pool_size(2) - .after_start(move |_| tx.send(1).unwrap()) - .create() - .unwrap(); - - // After ThreadPoolBuilder is deconstructed, the tx should be dropped - // so that we can use rx as an iterator. - let count = rx.into_iter().count(); - assert_eq!(count, 2); - } - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - } -} diff --git a/futures-executor/src/unpark_mutex.rs b/futures-executor/src/unpark_mutex.rs deleted file mode 100644 index f45164be9d..0000000000 --- a/futures-executor/src/unpark_mutex.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::cell::UnsafeCell; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -/// A "lock" around data `D`, which employs a *helping* strategy. -/// -/// Used to ensure that concurrent `unpark` invocations lead to (1) `poll` being -/// invoked on only a single thread at a time (2) `poll` being invoked at least -/// once after each `unpark` (unless the future has completed). -pub(crate) struct UnparkMutex { - // The state of task execution (state machine described below) - status: AtomicUsize, - - // The actual task data, accessible only in the POLLING state - inner: UnsafeCell>, -} - -// `UnparkMutex` functions in many ways like a `Mutex`, except that on -// acquisition failure, the current lock holder performs the desired work -- -// re-polling. -// -// As such, these impls mirror those for `Mutex`. In particular, a reference -// to `UnparkMutex` can be used to gain `&mut` access to the inner data, which -// must therefore be `Send`. -unsafe impl Send for UnparkMutex {} -unsafe impl Sync for UnparkMutex {} - -// There are four possible task states, listed below with their possible -// transitions: - -// The task is blocked, waiting on an event -const WAITING: usize = 0; // --> POLLING - -// The task is actively being polled by a thread; arrival of additional events -// of interest should move it to the REPOLL state -const POLLING: usize = 1; // --> WAITING, REPOLL, or COMPLETE - -// The task is actively being polled, but will need to be re-polled upon -// completion to ensure that all events were observed. -const REPOLL: usize = 2; // --> POLLING - -// The task has finished executing (either successfully or with an error/panic) -const COMPLETE: usize = 3; // No transitions out - -impl UnparkMutex { - pub(crate) fn new() -> Self { - Self { status: AtomicUsize::new(WAITING), inner: UnsafeCell::new(None) } - } - - /// Attempt to "notify" the mutex that a poll should occur. - /// - /// An `Ok` result indicates that the `POLLING` state has been entered, and - /// the caller can proceed to poll the future. An `Err` result indicates - /// that polling is not necessary (because the task is finished or the - /// polling has been delegated). - pub(crate) fn notify(&self) -> Result { - let mut status = self.status.load(SeqCst); - loop { - match status { - // The task is idle, so try to run it immediately. - WAITING => { - match self.status.compare_exchange(WAITING, POLLING, SeqCst, SeqCst) { - Ok(_) => { - let data = unsafe { - // SAFETY: we've ensured mutual exclusion via - // the status protocol; we are the only thread - // that has transitioned to the POLLING state, - // and we won't transition back to QUEUED until - // the lock is "released" by this thread. See - // the protocol diagram above. - (*self.inner.get()).take().unwrap() - }; - return Ok(data); - } - Err(cur) => status = cur, - } - } - - // The task is being polled, so we need to record that it should - // be *repolled* when complete. - POLLING => match self.status.compare_exchange(POLLING, REPOLL, SeqCst, SeqCst) { - Ok(_) => return Err(()), - Err(cur) => status = cur, - }, - - // The task is already scheduled for polling, or is complete, so - // we've got nothing to do. - _ => return Err(()), - } - } - } - - /// Alert the mutex that polling is about to begin, clearing any accumulated - /// re-poll requests. - /// - /// # Safety - /// - /// Callable only from the `POLLING`/`REPOLL` states, i.e. between - /// successful calls to `notify` and `wait`/`complete`. - pub(crate) unsafe fn start_poll(&self) { - self.status.store(POLLING, SeqCst); - } - - /// Alert the mutex that polling completed with `Pending`. - /// - /// # Safety - /// - /// Callable only from the `POLLING`/`REPOLL` states, i.e. between - /// successful calls to `notify` and `wait`/`complete`. - pub(crate) unsafe fn wait(&self, data: D) -> Result<(), D> { - unsafe { *self.inner.get() = Some(data) } - - match self.status.compare_exchange(POLLING, WAITING, SeqCst, SeqCst) { - // no unparks came in while we were running - Ok(_) => Ok(()), - - // guaranteed to be in REPOLL state; just clobber the - // state and run again. - Err(status) => { - assert_eq!(status, REPOLL); - self.status.store(POLLING, SeqCst); - Err(unsafe { (*self.inner.get()).take().unwrap() }) - } - } - } - - /// Alert the mutex that the task has completed execution and should not be - /// notified again. - /// - /// # Safety - /// - /// Callable only from the `POLLING`/`REPOLL` states, i.e. between - /// successful calls to `notify` and `wait`/`complete`. - pub(crate) unsafe fn complete(&self) { - self.status.store(COMPLETE, SeqCst); - } -} diff --git a/futures-executor/tests/local_pool.rs b/futures-executor/tests/local_pool.rs deleted file mode 100644 index 131f37934b..0000000000 --- a/futures-executor/tests/local_pool.rs +++ /dev/null @@ -1,497 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::LocalPool; -use futures::future::{self, lazy, poll_fn, Future}; -use futures::task::{Context, LocalSpawn, LocalSpawnExt, Poll, Spawn, SpawnExt, Waker}; -use std::cell::{Cell, RefCell}; -use std::marker::PhantomData; -use std::pin::Pin; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time::Duration; - -struct Pending(PhantomData>); - -impl Future for Pending { - type Output = (); - - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { - Poll::Pending - } -} - -fn pending() -> Pending { - Pending(PhantomData) -} - -#[test] -fn run_until_single_future() { - let mut cnt = 0; - - { - let mut pool = LocalPool::new(); - let fut = lazy(|_| { - cnt += 1; - }); - pool.run_until(fut); - } - - assert_eq!(cnt, 1); -} - -#[test] -fn run_until_ignores_spawned() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - spawn.spawn_local_obj(Box::pin(pending()).into()).unwrap(); - pool.run_until(lazy(|_| ())); -} - -#[test] -fn run_until_executes_spawned() { - let (tx, rx) = oneshot::channel(); - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - spawn - .spawn_local_obj( - Box::pin(lazy(move |_| { - tx.send(()).unwrap(); - })) - .into(), - ) - .unwrap(); - pool.run_until(rx).unwrap(); -} - -#[test] -fn run_returns_if_empty() { - let mut pool = LocalPool::new(); - pool.run(); - pool.run(); -} - -#[test] -fn run_executes_spawned() { - let cnt = Rc::new(Cell::new(0)); - let cnt2 = cnt.clone(); - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - let spawn2 = pool.spawner(); - - spawn - .spawn_local_obj( - Box::pin(lazy(move |_| { - spawn2 - .spawn_local_obj( - Box::pin(lazy(move |_| { - cnt2.set(cnt2.get() + 1); - })) - .into(), - ) - .unwrap(); - })) - .into(), - ) - .unwrap(); - - pool.run(); - - assert_eq!(cnt.get(), 1); -} - -#[test] -fn run_spawn_many() { - const ITER: usize = 200; - - let cnt = Rc::new(Cell::new(0)); - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - for _ in 0..ITER { - let cnt = cnt.clone(); - spawn - .spawn_local_obj( - Box::pin(lazy(move |_| { - cnt.set(cnt.get() + 1); - })) - .into(), - ) - .unwrap(); - } - - pool.run(); - - assert_eq!(cnt.get(), ITER); -} - -#[test] -fn try_run_one_returns_if_empty() { - let mut pool = LocalPool::new(); - assert!(!pool.try_run_one()); -} - -#[test] -fn try_run_one_executes_one_ready() { - const ITER: usize = 200; - - let cnt = Rc::new(Cell::new(0)); - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - for _ in 0..ITER { - spawn.spawn_local_obj(Box::pin(pending()).into()).unwrap(); - - let cnt = cnt.clone(); - spawn - .spawn_local_obj( - Box::pin(lazy(move |_| { - cnt.set(cnt.get() + 1); - })) - .into(), - ) - .unwrap(); - - spawn.spawn_local_obj(Box::pin(pending()).into()).unwrap(); - } - - for i in 0..ITER { - assert_eq!(cnt.get(), i); - assert!(pool.try_run_one()); - assert_eq!(cnt.get(), i + 1); - } - assert!(!pool.try_run_one()); -} - -#[test] -fn try_run_one_returns_on_no_progress() { - const ITER: usize = 10; - - let cnt = Rc::new(Cell::new(0)); - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - let waker: Rc>> = Rc::new(Cell::new(None)); - { - let cnt = cnt.clone(); - let waker = waker.clone(); - spawn - .spawn_local_obj( - Box::pin(poll_fn(move |ctx| { - cnt.set(cnt.get() + 1); - waker.set(Some(ctx.waker().clone())); - if cnt.get() == ITER { - Poll::Ready(()) - } else { - Poll::Pending - } - })) - .into(), - ) - .unwrap(); - } - - for i in 0..ITER - 1 { - assert_eq!(cnt.get(), i); - assert!(!pool.try_run_one()); - assert_eq!(cnt.get(), i + 1); - let w = waker.take(); - assert!(w.is_some()); - w.unwrap().wake(); - } - assert!(pool.try_run_one()); - assert_eq!(cnt.get(), ITER); -} - -#[test] -fn try_run_one_runs_sub_futures() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - let cnt = Rc::new(Cell::new(0)); - - let inner_spawner = spawn.clone(); - let cnt1 = cnt.clone(); - spawn - .spawn_local_obj( - Box::pin(poll_fn(move |_| { - cnt1.set(cnt1.get() + 1); - - let cnt2 = cnt1.clone(); - inner_spawner - .spawn_local_obj(Box::pin(lazy(move |_| cnt2.set(cnt2.get() + 1))).into()) - .unwrap(); - - Poll::Pending - })) - .into(), - ) - .unwrap(); - - pool.try_run_one(); - assert_eq!(cnt.get(), 2); -} - -#[test] -fn run_until_stalled_returns_if_empty() { - let mut pool = LocalPool::new(); - pool.run_until_stalled(); - pool.run_until_stalled(); -} - -#[test] -fn run_until_stalled_returns_multiple_times() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - let cnt = Rc::new(Cell::new(0)); - - let cnt1 = cnt.clone(); - spawn.spawn_local_obj(Box::pin(lazy(move |_| cnt1.set(cnt1.get() + 1))).into()).unwrap(); - pool.run_until_stalled(); - assert_eq!(cnt.get(), 1); - - let cnt2 = cnt.clone(); - spawn.spawn_local_obj(Box::pin(lazy(move |_| cnt2.set(cnt2.get() + 1))).into()).unwrap(); - pool.run_until_stalled(); - assert_eq!(cnt.get(), 2); -} - -#[test] -fn run_until_stalled_runs_spawned_sub_futures() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - let cnt = Rc::new(Cell::new(0)); - - let inner_spawner = spawn.clone(); - let cnt1 = cnt.clone(); - spawn - .spawn_local_obj( - Box::pin(poll_fn(move |_| { - cnt1.set(cnt1.get() + 1); - - let cnt2 = cnt1.clone(); - inner_spawner - .spawn_local_obj(Box::pin(lazy(move |_| cnt2.set(cnt2.get() + 1))).into()) - .unwrap(); - - Poll::Pending - })) - .into(), - ) - .unwrap(); - - pool.run_until_stalled(); - assert_eq!(cnt.get(), 2); -} - -#[test] -fn run_until_stalled_executes_all_ready() { - const ITER: usize = if cfg!(miri) { 50 } else { 200 }; - const PER_ITER: usize = 3; - - let cnt = Rc::new(Cell::new(0)); - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - for i in 0..ITER { - for _ in 0..PER_ITER { - spawn.spawn_local_obj(Box::pin(pending()).into()).unwrap(); - - let cnt = cnt.clone(); - spawn - .spawn_local_obj( - Box::pin(lazy(move |_| { - cnt.set(cnt.get() + 1); - })) - .into(), - ) - .unwrap(); - - // also add some pending tasks to test if they are ignored - spawn.spawn_local_obj(Box::pin(pending()).into()).unwrap(); - } - assert_eq!(cnt.get(), i * PER_ITER); - pool.run_until_stalled(); - assert_eq!(cnt.get(), (i + 1) * PER_ITER); - } -} - -#[test] -#[should_panic] -fn nesting_run() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - spawn - .spawn_obj( - Box::pin(lazy(|_| { - let mut pool = LocalPool::new(); - pool.run(); - })) - .into(), - ) - .unwrap(); - - pool.run(); -} - -#[test] -#[should_panic] -fn nesting_run_run_until_stalled() { - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - spawn - .spawn_obj( - Box::pin(lazy(|_| { - let mut pool = LocalPool::new(); - pool.run_until_stalled(); - })) - .into(), - ) - .unwrap(); - - pool.run(); -} - -#[test] -fn tasks_are_scheduled_fairly() { - let state = Rc::new(RefCell::new([0, 0])); - - struct Spin { - state: Rc>, - idx: usize, - } - - impl Future for Spin { - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let mut state = self.state.borrow_mut(); - - if self.idx == 0 { - let diff = state[0] - state[1]; - - assert!(diff.abs() <= 1); - - if state[0] >= 50 { - return Poll::Ready(()); - } - } - - state[self.idx] += 1; - - if state[self.idx] >= 100 { - return Poll::Ready(()); - } - - cx.waker().wake_by_ref(); - Poll::Pending - } - } - - let mut pool = LocalPool::new(); - let spawn = pool.spawner(); - - spawn.spawn_local_obj(Box::pin(Spin { state: state.clone(), idx: 0 }).into()).unwrap(); - - spawn.spawn_local_obj(Box::pin(Spin { state, idx: 1 }).into()).unwrap(); - - pool.run(); -} - -// Tests that the use of park/unpark in user-code has no -// effect on the expected behavior of the executor. -#[test] -fn park_unpark_independence() { - let mut done = false; - - let future = future::poll_fn(move |cx| { - if done { - return Poll::Ready(()); - } - done = true; - cx.waker().wake_by_ref(); // (*) - // some user-code that temporarily parks the thread - let test = thread::current(); - let latch = Arc::new(AtomicBool::new(false)); - let signal = latch.clone(); - thread::spawn(move || { - thread::sleep(Duration::from_millis(10)); - signal.store(true, Ordering::SeqCst); - test.unpark() - }); - while !latch.load(Ordering::Relaxed) { - thread::park(); - } - Poll::Pending // Expect to be called again due to (*). - }); - - futures::executor::block_on(future) -} - -struct SelfWaking { - wakeups_remaining: Rc>, -} - -impl Future for SelfWaking { - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if *self.wakeups_remaining.borrow() != 0 { - *self.wakeups_remaining.borrow_mut() -= 1; - cx.waker().wake_by_ref(); - } - - Poll::Pending - } -} - -/// Regression test for https://github.com/rust-lang/futures-rs/pull/2593 -/// -/// The issue was that self-waking futures could cause `run_until_stalled` -/// to exit early, even when progress could still be made. -#[test] -fn self_waking_run_until_stalled() { - let wakeups_remaining = Rc::new(RefCell::new(10)); - - let mut pool = LocalPool::new(); - let spawner = pool.spawner(); - for _ in 0..3 { - let wakeups_remaining = Rc::clone(&wakeups_remaining); - spawner.spawn_local(SelfWaking { wakeups_remaining }).unwrap(); - } - - // This should keep polling until there are no more wakeups. - pool.run_until_stalled(); - - assert_eq!(*wakeups_remaining.borrow(), 0); -} - -/// Regression test for https://github.com/rust-lang/futures-rs/pull/2593 -/// -/// The issue was that self-waking futures could cause `try_run_one` -/// to exit early, even when progress could still be made. -#[test] -fn self_waking_try_run_one() { - let wakeups_remaining = Rc::new(RefCell::new(10)); - - let mut pool = LocalPool::new(); - let spawner = pool.spawner(); - for _ in 0..3 { - let wakeups_remaining = Rc::clone(&wakeups_remaining); - spawner.spawn_local(SelfWaking { wakeups_remaining }).unwrap(); - } - - spawner.spawn(future::ready(())).unwrap(); - - // The `ready` future should complete. - assert!(pool.try_run_one()); - - // The self-waking futures are each polled once. - assert_eq!(*wakeups_remaining.borrow(), 7); -} diff --git a/futures-io/Cargo.toml b/futures-io/Cargo.toml deleted file mode 100644 index e5320d4281..0000000000 --- a/futures-io/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "futures-io" -version = "0.3.31" -edition = "2018" -rust-version = "1.36" -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/futures-rs" -homepage = "https://rust-lang.github.io/futures-rs" -description = """ -The `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and `AsyncBufRead` traits for the futures-rs library. -""" - -[features] -default = ["std"] -std = [] - -# Unstable features -# These features are outside of the normal semver guarantees and require the -# `unstable` feature as an explicit opt-in to unstable API. -unstable = [] - -[dependencies] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/futures-io/LICENSE-APACHE b/futures-io/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-io/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-io/LICENSE-MIT b/futures-io/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-io/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-io/README.md b/futures-io/README.md deleted file mode 100644 index da6eec28ba..0000000000 --- a/futures-io/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-io - -The `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and `AsyncBufRead` traits for the futures-rs library. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-io = "0.3" -``` - -The current `futures-io` requires Rust 1.36 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-io/src/lib.rs b/futures-io/src/lib.rs deleted file mode 100644 index 4e2e03a028..0000000000 --- a/futures-io/src/lib.rs +++ /dev/null @@ -1,560 +0,0 @@ -//! Asynchronous I/O -//! -//! This crate contains the `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and -//! `AsyncBufRead` traits, the asynchronous analogs to -//! `std::io::{Read, Write, Seek, BufRead}`. The primary difference is -//! that these traits integrate with the asynchronous task system. -//! -//! All items of this library are only available when the `std` feature of this -//! library is activated, and it is activated by default. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, /* unsafe_op_in_unsafe_fn */)] // unsafe_op_in_unsafe_fn requires Rust 1.52 -#![cfg_attr(docsrs, feature(doc_cfg))] - -#[cfg(feature = "std")] -extern crate std; - -#[cfg(feature = "std")] -mod if_std { - use std::boxed::Box; - use std::io; - use std::ops::DerefMut; - use std::pin::Pin; - use std::task::{Context, Poll}; - use std::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`. - #[doc(no_inline)] - pub use io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom}; - - /// Read bytes asynchronously. - /// - /// This trait is analogous to the `std::io::Read` trait, but integrates - /// with the asynchronous task system. In particular, the `poll_read` - /// method, unlike `Read::read`, will automatically queue the current task - /// for wakeup and return if data is not yet available, rather than blocking - /// the calling thread. - pub trait AsyncRead { - /// Attempt to read from the `AsyncRead` into `buf`. - /// - /// On success, returns `Poll::Ready(Ok(num_bytes_read))`. - /// - /// If no data is available for reading, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// readable or is closed. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll>; - - /// Attempt to read from the `AsyncRead` into `bufs` using vectored - /// IO operations. - /// - /// This method is similar to `poll_read`, but allows data to be read - /// into multiple buffers using a single operation. - /// - /// On success, returns `Poll::Ready(Ok(num_bytes_read))`. - /// - /// If no data is available for reading, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// readable or is closed. - /// By default, this method delegates to using `poll_read` on the first - /// nonempty buffer in `bufs`, or an empty one if none exists. Objects which - /// support vectored IO should override this method. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - for b in bufs { - if !b.is_empty() { - return self.poll_read(cx, b); - } - } - - self.poll_read(cx, &mut []) - } - } - - /// Write bytes asynchronously. - /// - /// This trait is analogous to the `std::io::Write` trait, but integrates - /// with the asynchronous task system. In particular, the `poll_write` - /// method, unlike `Write::write`, will automatically queue the current task - /// for wakeup and return if the writer cannot take more data, rather than blocking - /// the calling thread. - pub trait AsyncWrite { - /// Attempt to write bytes from `buf` into the object. - /// - /// On success, returns `Poll::Ready(Ok(num_bytes_written))`. - /// - /// If the object is not ready for writing, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// writable or is closed. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - /// - /// `poll_write` must try to make progress by flushing the underlying object if - /// that is the only way the underlying object can become writable again. - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll>; - - /// Attempt to write bytes from `bufs` into the object using vectored - /// IO operations. - /// - /// This method is similar to `poll_write`, but allows data from multiple buffers to be written - /// using a single operation. - /// - /// On success, returns `Poll::Ready(Ok(num_bytes_written))`. - /// - /// If the object is not ready for writing, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// writable or is closed. - /// - /// By default, this method delegates to using `poll_write` on the first - /// nonempty buffer in `bufs`, or an empty one if none exists. Objects which - /// support vectored IO should override this method. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - for b in bufs { - if !b.is_empty() { - return self.poll_write(cx, b); - } - } - - self.poll_write(cx, &[]) - } - - /// Attempt to flush the object, ensuring that any buffered data reach - /// their destination. - /// - /// On success, returns `Poll::Ready(Ok(()))`. - /// - /// If flushing cannot immediately complete, this method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object can make - /// progress towards flushing. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - /// - /// It only makes sense to do anything here if you actually buffer data. - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Attempt to close the object. - /// - /// On success, returns `Poll::Ready(Ok(()))`. - /// - /// If closing cannot immediately complete, this function returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object can make - /// progress towards closing. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - } - - /// Seek bytes asynchronously. - /// - /// This trait is analogous to the `std::io::Seek` trait, but integrates - /// with the asynchronous task system. In particular, the `poll_seek` - /// method, unlike `Seek::seek`, will automatically queue the current task - /// for wakeup and return if data is not yet available, rather than blocking - /// the calling thread. - pub trait AsyncSeek { - /// Attempt to seek to an offset, in bytes, in a stream. - /// - /// A seek beyond the end of a stream is allowed, but behavior is defined - /// by the implementation. - /// - /// If the seek operation completed successfully, - /// this method returns the new position from the start of the stream. - /// That position can be used later with [`SeekFrom::Start`]. - /// - /// # Errors - /// - /// Seeking to a negative offset is considered an error. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll>; - } - - /// Read bytes asynchronously. - /// - /// This trait is analogous to the `std::io::BufRead` trait, but integrates - /// with the asynchronous task system. In particular, the `poll_fill_buf` - /// method, unlike `BufRead::fill_buf`, will automatically queue the current task - /// for wakeup and return if data is not yet available, rather than blocking - /// the calling thread. - pub trait AsyncBufRead: AsyncRead { - /// Attempt to return the contents of the internal buffer, filling it with more data - /// from the inner reader if it is empty. - /// - /// On success, returns `Poll::Ready(Ok(buf))`. - /// - /// If no data is available for reading, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// readable or is closed. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`consume`] method to function properly. When calling this - /// method, none of the contents will be "read" in the sense that later - /// calling [`poll_read`] may return the same contents. As such, [`consume`] must - /// be called with the number of bytes that are consumed from this buffer to - /// ensure that the bytes are never returned twice. - /// - /// [`poll_read`]: AsyncRead::poll_read - /// [`consume`]: AsyncBufRead::consume - /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to [`poll_read`]. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`poll_fill_buf`] method to function properly. This function does - /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`poll_fill_buf`], has been consumed and should - /// no longer be returned. As such, this function may do odd things if - /// [`poll_fill_buf`] isn't called before calling it. - /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`poll_fill_buf`]. - /// - /// [`poll_read`]: AsyncRead::poll_read - /// [`poll_fill_buf`]: AsyncBufRead::poll_fill_buf - fn consume(self: Pin<&mut Self>, amt: usize); - } - - macro_rules! deref_async_read { - () => { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - Pin::new(&mut **self).poll_read(cx, buf) - } - - fn poll_read_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - Pin::new(&mut **self).poll_read_vectored(cx, bufs) - } - }; - } - - impl AsyncRead for Box { - deref_async_read!(); - } - - impl AsyncRead for &mut T { - deref_async_read!(); - } - - impl

AsyncRead for Pin

- where - P: DerefMut + Unpin, - P::Target: AsyncRead, - { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.get_mut().as_mut().poll_read(cx, buf) - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - self.get_mut().as_mut().poll_read_vectored(cx, bufs) - } - } - - macro_rules! delegate_async_read_to_stdio { - () => { - fn poll_read( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - Poll::Ready(io::Read::read(&mut *self, buf)) - } - - fn poll_read_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - Poll::Ready(io::Read::read_vectored(&mut *self, bufs)) - } - }; - } - - impl AsyncRead for &[u8] { - delegate_async_read_to_stdio!(); - } - - macro_rules! deref_async_write { - () => { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut **self).poll_write(cx, buf) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - Pin::new(&mut **self).poll_write_vectored(cx, bufs) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_close(cx) - } - }; - } - - impl AsyncWrite for Box { - deref_async_write!(); - } - - impl AsyncWrite for &mut T { - deref_async_write!(); - } - - impl

AsyncWrite for Pin

- where - P: DerefMut + Unpin, - P::Target: AsyncWrite, - { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.get_mut().as_mut().poll_write(cx, buf) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - self.get_mut().as_mut().poll_write_vectored(cx, bufs) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_close(cx) - } - } - - macro_rules! delegate_async_write_to_stdio { - () => { - fn poll_write( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Poll::Ready(io::Write::write(&mut *self, buf)) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - Poll::Ready(io::Write::write_vectored(&mut *self, bufs)) - } - - fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(io::Write::flush(&mut *self)) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } - }; - } - - impl AsyncWrite for Vec { - delegate_async_write_to_stdio!(); - } - - macro_rules! deref_async_seek { - () => { - fn poll_seek( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - Pin::new(&mut **self).poll_seek(cx, pos) - } - }; - } - - impl AsyncSeek for Box { - deref_async_seek!(); - } - - impl AsyncSeek for &mut T { - deref_async_seek!(); - } - - impl

AsyncSeek for Pin

- where - P: DerefMut + Unpin, - P::Target: AsyncSeek, - { - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - self.get_mut().as_mut().poll_seek(cx, pos) - } - } - - macro_rules! deref_async_buf_read { - () => { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self.get_mut()).poll_fill_buf(cx) - } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - Pin::new(&mut **self).consume(amt) - } - }; - } - - impl AsyncBufRead for Box { - deref_async_buf_read!(); - } - - impl AsyncBufRead for &mut T { - deref_async_buf_read!(); - } - - impl

AsyncBufRead for Pin

- where - P: DerefMut + Unpin, - P::Target: AsyncBufRead, - { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.get_mut().as_mut().consume(amt) - } - } - - macro_rules! delegate_async_buf_read_to_stdio { - () => { - fn poll_fill_buf(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(io::BufRead::fill_buf(self.get_mut())) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - io::BufRead::consume(self.get_mut(), amt) - } - }; - } - - impl AsyncBufRead for &[u8] { - delegate_async_buf_read_to_stdio!(); - } -} - -#[cfg(feature = "std")] -pub use self::if_std::*; diff --git a/futures-macro/Cargo.toml b/futures-macro/Cargo.toml deleted file mode 100644 index 25ee040fee..0000000000 --- a/futures-macro/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "futures-macro" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -The futures-rs procedural macro implementations. -""" - -[lib] -proc-macro = true - -[features] - -[dependencies] -proc-macro2 = "1.0.60" -quote = "1.0" -syn = { version = "2.0.52", features = ["full"] } - -[lints] -workspace = true diff --git a/futures-macro/LICENSE-APACHE b/futures-macro/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-macro/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-macro/LICENSE-MIT b/futures-macro/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-macro/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-macro/src/executor.rs b/futures-macro/src/executor.rs deleted file mode 100644 index 7f1d0a93f4..0000000000 --- a/futures-macro/src/executor.rs +++ /dev/null @@ -1,56 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{quote, quote_spanned, ToTokens}; - -pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream { - if !args.is_empty() { - return syn::Error::new_spanned(proc_macro2::TokenStream::from(args), "invalid argument") - .to_compile_error() - .into(); - } - - let mut input = syn::parse_macro_input!(item as syn::ItemFn); - - if input.sig.asyncness.take().is_none() { - return syn::Error::new_spanned(input.sig.fn_token, "Only async functions are supported") - .to_compile_error() - .into(); - } - - // If type mismatch occurs, the current rustc points to the last statement. - let (last_stmt_start_span, last_stmt_end_span) = { - let mut last_stmt = input - .block - .stmts - .last() - .map(ToTokens::into_token_stream) - .unwrap_or_default() - .into_iter(); - // `Span` on stable Rust has a limitation that only points to the first - // token, not the whole tokens. We can work around this limitation by - // using the first/last span of the tokens like - // `syn::Error::new_spanned` does. - let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span()); - let end = last_stmt.last().map_or(start, |t| t.span()); - (start, end) - }; - - let path = quote_spanned! {last_stmt_start_span=> - ::futures_test::__private - }; - let body = &input.block; - input.block.stmts = vec![syn::Stmt::Expr( - syn::parse2(quote_spanned! {last_stmt_end_span=> - #path::block_on(async #body) - }) - .unwrap(), - None, - )]; - - let gen = quote! { - #[::core::prelude::v1::test] - #input - }; - - gen.into() -} diff --git a/futures-macro/src/join.rs b/futures-macro/src/join.rs deleted file mode 100644 index 0e891b3aad..0000000000 --- a/futures-macro/src/join.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! The futures-rs `join!` macro implementation. - -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{format_ident, quote}; -use syn::parse::{Parse, ParseStream}; -use syn::{Expr, Ident, Token}; - -#[derive(Default)] -struct Join { - fut_exprs: Vec, -} - -impl Parse for Join { - fn parse(input: ParseStream<'_>) -> syn::Result { - let mut join = Self::default(); - - while !input.is_empty() { - join.fut_exprs.push(input.parse::()?); - - if !input.is_empty() { - input.parse::()?; - } - } - - Ok(join) - } -} - -fn bind_futures(fut_exprs: Vec, span: Span) -> (Vec, Vec) { - let mut future_let_bindings = Vec::with_capacity(fut_exprs.len()); - let future_names: Vec<_> = fut_exprs - .into_iter() - .enumerate() - .map(|(i, expr)| { - let name = format_ident!("_fut{}", i, span = span); - future_let_bindings.push(quote! { - // Move future into a local so that it is pinned in one place and - // is no longer accessible by the end user. - let mut #name = __futures_crate::future::maybe_done(#expr); - let mut #name = unsafe { __futures_crate::Pin::new_unchecked(&mut #name) }; - }); - name - }) - .collect(); - - (future_let_bindings, future_names) -} - -/// The `join!` macro. -pub(crate) fn join(input: TokenStream) -> TokenStream { - let parsed = syn::parse_macro_input!(input as Join); - - // should be def_site, but that's unstable - let span = Span::call_site(); - - let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span); - - let poll_futures = future_names.iter().map(|fut| { - quote! { - __all_done &= __futures_crate::future::Future::poll( - #fut.as_mut(), __cx).is_ready(); - } - }); - let take_outputs = future_names.iter().map(|fut| { - quote! { - #fut.as_mut().take_output().unwrap(), - } - }); - - TokenStream::from(quote! { { - #( #future_let_bindings )* - - __futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| { - let mut __all_done = true; - #( #poll_futures )* - if __all_done { - __futures_crate::task::Poll::Ready(( - #( #take_outputs )* - )) - } else { - __futures_crate::task::Poll::Pending - } - }).await - } }) -} - -/// The `try_join!` macro. -pub(crate) fn try_join(input: TokenStream) -> TokenStream { - let parsed = syn::parse_macro_input!(input as Join); - - // should be def_site, but that's unstable - let span = Span::call_site(); - - let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span); - - let poll_futures = future_names.iter().map(|fut| { - quote! { - if __futures_crate::future::Future::poll( - #fut.as_mut(), __cx).is_pending() - { - __all_done = false; - } else if #fut.as_mut().output_mut().unwrap().is_err() { - // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce - // a `T: Debug` bound. - // Also, for an error type of ! any code after `err().unwrap()` is unreachable. - #[allow(unreachable_code)] - return __futures_crate::task::Poll::Ready( - __futures_crate::Err( - #fut.as_mut().take_output().unwrap().err().unwrap() - ) - ); - } - } - }); - let take_outputs = future_names.iter().map(|fut| { - quote! { - // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce - // an `E: Debug` bound. - // Also, for an ok type of ! any code after `ok().unwrap()` is unreachable. - #[allow(unreachable_code)] - #fut.as_mut().take_output().unwrap().ok().unwrap(), - } - }); - - TokenStream::from(quote! { { - #( #future_let_bindings )* - - #[allow(clippy::diverging_sub_expression)] - __futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| { - let mut __all_done = true; - #( #poll_futures )* - if __all_done { - __futures_crate::task::Poll::Ready( - __futures_crate::Ok(( - #( #take_outputs )* - )) - ) - } else { - __futures_crate::task::Poll::Pending - } - }).await - } }) -} diff --git a/futures-macro/src/lib.rs b/futures-macro/src/lib.rs deleted file mode 100644 index c1b94785e8..0000000000 --- a/futures-macro/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! The futures-rs procedural macro implementations. - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] - -use proc_macro::TokenStream; - -mod executor; -mod join; -mod select; -mod stream_select; - -/// The `join!` macro. -#[proc_macro] -pub fn join_internal(input: TokenStream) -> TokenStream { - crate::join::join(input) -} - -/// The `try_join!` macro. -#[proc_macro] -pub fn try_join_internal(input: TokenStream) -> TokenStream { - crate::join::try_join(input) -} - -/// The `select!` macro. -#[proc_macro] -pub fn select_internal(input: TokenStream) -> TokenStream { - crate::select::select(input) -} - -/// The `select_biased!` macro. -#[proc_macro] -pub fn select_biased_internal(input: TokenStream) -> TokenStream { - crate::select::select_biased(input) -} - -// TODO: Change this to doc comment once rustdoc bug fixed: https://github.com/rust-lang/futures-rs/pull/2435 -// The `test` attribute. -#[proc_macro_attribute] -pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream { - crate::executor::test(input, item) -} - -/// The `stream_select!` macro. -#[proc_macro] -pub fn stream_select_internal(input: TokenStream) -> TokenStream { - crate::stream_select::stream_select(input.into()) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} diff --git a/futures-macro/src/select.rs b/futures-macro/src/select.rs deleted file mode 100644 index bddcb4b0ed..0000000000 --- a/futures-macro/src/select.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! The futures-rs `select!` macro implementation. - -use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{format_ident, quote}; -use syn::parse::{Parse, ParseStream}; -use syn::{parse_quote, Expr, Ident, Pat, Token}; - -mod kw { - syn::custom_keyword!(complete); -} - -struct Select { - // span of `complete`, then expression after `=> ...` - complete: Option, - default: Option, - normal_fut_exprs: Vec, - normal_fut_handlers: Vec<(Pat, Expr)>, -} - -#[allow(clippy::large_enum_variant)] -enum CaseKind { - Complete, - Default, - Normal(Pat, Expr), -} - -impl Parse for Select { - fn parse(input: ParseStream<'_>) -> syn::Result { - let mut select = Self { - complete: None, - default: None, - normal_fut_exprs: vec![], - normal_fut_handlers: vec![], - }; - - while !input.is_empty() { - let case_kind = if input.peek(kw::complete) { - // `complete` - if select.complete.is_some() { - return Err(input.error("multiple `complete` cases found, only one allowed")); - } - input.parse::()?; - CaseKind::Complete - } else if input.peek(Token![default]) { - // `default` - if select.default.is_some() { - return Err(input.error("multiple `default` cases found, only one allowed")); - } - input.parse::()?; - CaseKind::Default - } else { - // ` = ` - let pat = Pat::parse_multi_with_leading_vert(input)?; - input.parse::()?; - let expr = input.parse()?; - CaseKind::Normal(pat, expr) - }; - - // `=> ` - input.parse::]>()?; - let expr = Expr::parse_with_earlier_boundary_rule(input)?; - - // Commas after the expression are only optional if it's a `Block` - // or it is the last branch in the `match`. - let is_block = matches!(expr, Expr::Block(_)); - if is_block || input.is_empty() { - input.parse::>()?; - } else { - input.parse::()?; - } - - match case_kind { - CaseKind::Complete => select.complete = Some(expr), - CaseKind::Default => select.default = Some(expr), - CaseKind::Normal(pat, fut_expr) => { - select.normal_fut_exprs.push(fut_expr); - select.normal_fut_handlers.push((pat, expr)); - } - } - } - - Ok(select) - } -} - -// Enum over all the cases in which the `select!` waiting has completed and the result -// can be processed. -// -// `enum __PrivResult<_1, _2, ...> { _1(_1), _2(_2), ..., Complete }` -fn declare_result_enum( - result_ident: Ident, - variants: usize, - complete: bool, - span: Span, -) -> (Vec, syn::ItemEnum) { - // "_0", "_1", "_2" - let variant_names: Vec = - (0..variants).map(|num| format_ident!("_{}", num, span = span)).collect(); - - let type_parameters = &variant_names; - let variants = &variant_names; - - let complete_variant = if complete { Some(quote!(Complete)) } else { None }; - - let enum_item = parse_quote! { - enum #result_ident<#(#type_parameters,)*> { - #( - #variants(#type_parameters), - )* - #complete_variant - } - }; - - (variant_names, enum_item) -} - -/// The `select!` macro. -pub(crate) fn select(input: TokenStream) -> TokenStream { - select_inner(input, true) -} - -/// The `select_biased!` macro. -pub(crate) fn select_biased(input: TokenStream) -> TokenStream { - select_inner(input, false) -} - -fn select_inner(input: TokenStream, random: bool) -> TokenStream { - let parsed = syn::parse_macro_input!(input as Select); - - // should be def_site, but that's unstable - let span = Span::call_site(); - - let enum_ident = Ident::new("__PrivResult", span); - - let (variant_names, enum_item) = declare_result_enum( - enum_ident.clone(), - parsed.normal_fut_exprs.len(), - parsed.complete.is_some(), - span, - ); - - // bind non-`Ident` future exprs w/ `let` - let mut future_let_bindings = Vec::with_capacity(parsed.normal_fut_exprs.len()); - let bound_future_names: Vec<_> = parsed - .normal_fut_exprs - .into_iter() - .zip(variant_names.iter()) - .map(|(expr, variant_name)| { - match expr { - syn::Expr::Path(path) => { - // Don't bind futures that are already a path. - // This prevents creating redundant stack space - // for them. - // Passing Futures by path requires those Futures to implement Unpin. - // We check for this condition here in order to be able to - // safely use Pin::new_unchecked(&mut #path) later on. - future_let_bindings.push(quote! { - __futures_crate::async_await::assert_fused_future(&#path); - __futures_crate::async_await::assert_unpin(&#path); - }); - path - } - _ => { - // Bind and pin the resulting Future on the stack. This is - // necessary to support direct select! calls on !Unpin - // Futures. The Future is not explicitly pinned here with - // a Pin call, but assumed as pinned. The actual Pin is - // created inside the poll() function below to defer the - // creation of the temporary pointer, which would otherwise - // increase the size of the generated Future. - // Safety: This is safe since the lifetime of the Future - // is totally constraint to the lifetime of the select! - // expression, and the Future can't get moved inside it - // (it is shadowed). - future_let_bindings.push(quote! { - let mut #variant_name = #expr; - }); - parse_quote! { #variant_name } - } - } - }) - .collect(); - - // For each future, make an `&mut dyn FnMut(&mut Context<'_>) -> Option>` - // to use for polling that individual future. These will then be put in an array. - let poll_functions = bound_future_names.iter().zip(variant_names.iter()).map( - |(bound_future_name, variant_name)| { - // Below we lazily create the Pin on the Future below. - // This is done in order to avoid allocating memory in the generator - // for the Pin variable. - // Safety: This is safe because one of the following condition applies: - // 1. The Future is passed by the caller by name, and we assert that - // it implements Unpin. - // 2. The Future is created in scope of the select! function and will - // not be moved for the duration of it. It is thereby stack-pinned - quote! { - let mut #variant_name = |__cx: &mut __futures_crate::task::Context<'_>| { - let mut #bound_future_name = unsafe { - __futures_crate::Pin::new_unchecked(&mut #bound_future_name) - }; - if __futures_crate::future::FusedFuture::is_terminated(&#bound_future_name) { - __futures_crate::None - } else { - __futures_crate::Some(__futures_crate::future::FutureExt::poll_unpin( - &mut #bound_future_name, - __cx, - ).map(#enum_ident::#variant_name)) - } - }; - let #variant_name: &mut dyn FnMut( - &mut __futures_crate::task::Context<'_> - ) -> __futures_crate::Option<__futures_crate::task::Poll<_>> = &mut #variant_name; - } - }, - ); - - let none_polled = if parsed.complete.is_some() { - quote! { - __futures_crate::task::Poll::Ready(#enum_ident::Complete) - } - } else { - quote! { - panic!("all futures in select! were completed, \ - but no `complete =>` handler was provided") - } - }; - - let branches = parsed.normal_fut_handlers.into_iter().zip(variant_names.iter()).map( - |((pat, expr), variant_name)| { - quote! { - #enum_ident::#variant_name(#pat) => #expr, - } - }, - ); - let branches = quote! { #( #branches )* }; - - let complete_branch = parsed.complete.map(|complete_expr| { - quote! { - #enum_ident::Complete => { #complete_expr }, - } - }); - - let branches = quote! { - #branches - #complete_branch - }; - - let await_select_fut = if parsed.default.is_some() { - // For select! with default this returns the Poll result - quote! { - __poll_fn(&mut __futures_crate::task::Context::from_waker( - __futures_crate::task::noop_waker_ref() - )) - } - } else { - quote! { - __futures_crate::future::poll_fn(__poll_fn).await - } - }; - - let execute_result_expr = if let Some(default_expr) = &parsed.default { - // For select! with default __select_result is a Poll, otherwise not - quote! { - match __select_result { - __futures_crate::task::Poll::Ready(result) => match result { - #branches - }, - _ => #default_expr - } - } - } else { - quote! { - match __select_result { - #branches - } - } - }; - - let shuffle = if random { - quote! { - __futures_crate::async_await::shuffle(&mut __select_arr); - } - } else { - quote!() - }; - - TokenStream::from(quote! { { - #enum_item - - let __select_result = { - #( #future_let_bindings )* - - let mut __poll_fn = |__cx: &mut __futures_crate::task::Context<'_>| { - let mut __any_polled = false; - - #( #poll_functions )* - - let mut __select_arr = [#( #variant_names ),*]; - #shuffle - for poller in &mut __select_arr { - let poller: &mut &mut dyn FnMut( - &mut __futures_crate::task::Context<'_> - ) -> __futures_crate::Option<__futures_crate::task::Poll<_>> = poller; - match poller(__cx) { - __futures_crate::Some(x @ __futures_crate::task::Poll::Ready(_)) => - return x, - __futures_crate::Some(__futures_crate::task::Poll::Pending) => { - __any_polled = true; - } - __futures_crate::None => {} - } - } - - if !__any_polled { - #none_polled - } else { - __futures_crate::task::Poll::Pending - } - }; - - #await_select_fut - }; - - #execute_result_expr - } }) -} diff --git a/futures-macro/src/stream_select.rs b/futures-macro/src/stream_select.rs deleted file mode 100644 index 9927b53073..0000000000 --- a/futures-macro/src/stream_select.rs +++ /dev/null @@ -1,113 +0,0 @@ -use proc_macro2::TokenStream; -use quote::{format_ident, quote, ToTokens}; -use syn::{parse::Parser, punctuated::Punctuated, Expr, Index, Token}; - -/// The `stream_select!` macro. -pub(crate) fn stream_select(input: TokenStream) -> Result { - let args = Punctuated::::parse_terminated.parse2(input)?; - if args.len() < 2 { - return Ok(quote! { - compile_error!("stream select macro needs at least two arguments.") - }); - } - let generic_idents = (0..args.len()).map(|i| format_ident!("_{}", i)).collect::>(); - let field_idents = (0..args.len()).map(|i| format_ident!("__{}", i)).collect::>(); - let field_idents_2 = (0..args.len()).map(|i| format_ident!("___{}", i)).collect::>(); - let field_indices = (0..args.len()).map(Index::from).collect::>(); - let args = args.iter().map(|e| e.to_token_stream()); - - Ok(quote! { - { - #[derive(Debug)] - struct StreamSelect<#(#generic_idents),*> (#(Option<#generic_idents>),*); - - enum StreamEnum<#(#generic_idents),*> { - #( - #generic_idents(#generic_idents) - ),*, - None, - } - - impl __futures_crate::stream::Stream for StreamEnum<#(#generic_idents),*> - where #(#generic_idents: __futures_crate::stream::Stream + ::std::marker::Unpin,)* - { - type Item = ITEM; - - fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll> { - match self.get_mut() { - #( - Self::#generic_idents(#generic_idents) => ::std::pin::Pin::new(#generic_idents).poll_next(cx) - ),*, - Self::None => panic!("StreamEnum::None should never be polled!"), - } - } - } - - impl __futures_crate::stream::Stream for StreamSelect<#(#generic_idents),*> - where #(#generic_idents: __futures_crate::stream::Stream + ::std::marker::Unpin,)* - { - type Item = ITEM; - - fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll> { - let Self(#(ref mut #field_idents),*) = self.get_mut(); - #( - let mut #field_idents_2 = false; - )* - let mut any_pending = false; - { - let mut stream_array = [#(#field_idents.as_mut().map(|f| StreamEnum::#generic_idents(f)).unwrap_or(StreamEnum::None)),*]; - __futures_crate::async_await::shuffle(&mut stream_array); - - for mut s in stream_array { - if let StreamEnum::None = s { - continue; - } else { - match __futures_crate::stream::Stream::poll_next(::std::pin::Pin::new(&mut s), cx) { - r @ __futures_crate::task::Poll::Ready(Some(_)) => { - return r; - }, - __futures_crate::task::Poll::Pending => { - any_pending = true; - }, - __futures_crate::task::Poll::Ready(None) => { - match s { - #( - StreamEnum::#generic_idents(_) => { #field_idents_2 = true; } - ),*, - StreamEnum::None => panic!("StreamEnum::None should never be polled!"), - } - }, - } - } - } - } - #( - if #field_idents_2 { - *#field_idents = None; - } - )* - if any_pending { - __futures_crate::task::Poll::Pending - } else { - __futures_crate::task::Poll::Ready(None) - } - } - - fn size_hint(&self) -> (usize, Option) { - let mut s = (0, Some(0)); - #( - if let Some(new_hint) = self.#field_indices.as_ref().map(|s| s.size_hint()) { - s.0 += new_hint.0; - // We can change this out for `.zip` when the MSRV is 1.46.0 or higher. - s.1 = s.1.and_then(|a| new_hint.1.map(|b| a + b)); - } - )* - s - } - } - - StreamSelect(#(Some(#args)),*) - - } - }) -} diff --git a/futures-sink/Cargo.toml b/futures-sink/Cargo.toml deleted file mode 100644 index 7e0200194f..0000000000 --- a/futures-sink/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "futures-sink" -version = "0.4.0-alpha.0" -edition = "2018" -rust-version = "1.36" -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/futures-rs" -homepage = "https://rust-lang.github.io/futures-rs" -description = """ -The asynchronous `Sink` trait for the futures-rs library. -""" - -[features] -default = ["std"] -std = ["alloc"] -alloc = [] - -[dependencies] - -[package.metadata.docs.rs] -all-features = true - -[lints] -workspace = true diff --git a/futures-sink/LICENSE-APACHE b/futures-sink/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-sink/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-sink/LICENSE-MIT b/futures-sink/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-sink/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-sink/README.md b/futures-sink/README.md deleted file mode 100644 index 1d683e95b5..0000000000 --- a/futures-sink/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-sink - -The asynchronous `Sink` trait for the futures-rs library. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-sink = "0.3" -``` - -The current `futures-sink` requires Rust 1.36 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-sink/src/lib.rs b/futures-sink/src/lib.rs deleted file mode 100644 index 60a95621f1..0000000000 --- a/futures-sink/src/lib.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! Asynchronous sinks -//! -//! This crate contains the `Sink` trait which allows values to be sent -//! asynchronously. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, /* unsafe_op_in_unsafe_fn */)] // unsafe_op_in_unsafe_fn requires Rust 1.52 - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -use core::ops::DerefMut; -use core::pin::Pin; -use core::task::{Context, Poll}; - -/// A `Sink` is a value into which other values can be sent, asynchronously. -/// -/// Basic examples of sinks include the sending side of: -/// -/// - Channels -/// - Sockets -/// - Pipes -/// -/// In addition to such "primitive" sinks, it's typical to layer additional -/// functionality, such as buffering, on top of an existing sink. -/// -/// Sending to a sink is "asynchronous" in the sense that the value may not be -/// sent in its entirety immediately. Instead, values are sent in a two-phase -/// way: first by initiating a send, and then by polling for completion. This -/// two-phase setup is analogous to buffered writing in synchronous code, where -/// writes often succeed immediately, but internally are buffered and are -/// *actually* written only upon flushing. -/// -/// In addition, the `Sink` may be *full*, in which case it is not even possible -/// to start the sending process. -/// -/// As with `Future` and `Stream`, the `Sink` trait is built from a few core -/// required methods, and a host of default methods for working in a -/// higher-level way. The `Sink::send_all` combinator is of particular -/// importance: you can use it to send an entire stream to a sink, which is -/// the simplest way to ultimately consume a stream. -#[must_use = "sinks do nothing unless polled"] -pub trait Sink { - /// The type of value produced by the sink when an error occurs. - type Error; - - /// Attempts to prepare the `Sink` to receive a value. - /// - /// This method must be called and return `Poll::Ready(Ok(()))` prior to - /// each call to `start_send`. - /// - /// This method returns `Poll::Ready` once the underlying sink is ready to - /// receive data. If this method returns `Poll::Pending`, the current task - /// is registered to be notified (via `cx.waker().wake_by_ref()`) when `poll_ready` - /// should be called again. - /// - /// In most cases, if the sink encounters an error, the sink will - /// permanently be unable to receive items. - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Begin the process of sending a value to the sink. - /// Each call to this function must be preceded by a successful call to - /// `poll_ready` which returned `Poll::Ready(Ok(()))`. - /// - /// As the name suggests, this method only *begins* the process of sending - /// the item. If the sink employs buffering, the item isn't fully processed - /// until the buffer is fully flushed. Since sinks are designed to work with - /// asynchronous I/O, the process of actually writing out the data to an - /// underlying object takes place asynchronously. **You *must* use - /// `poll_flush` or `poll_close` in order to guarantee completion of a - /// send**. - /// - /// Implementations of `poll_ready` and `start_send` will usually involve - /// flushing behind the scenes in order to make room for new messages. - /// It is only necessary to call `poll_flush` if you need to guarantee that - /// *all* of the items placed into the `Sink` have been sent. - /// - /// In most cases, if the sink encounters an error, the sink will - /// permanently be unable to receive items. - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error>; - - /// Flush any remaining output from this sink. - /// - /// Returns `Poll::Ready(Ok(()))` when no buffered items remain. If this - /// value is returned then it is guaranteed that all previous values sent - /// via `start_send` have been flushed. - /// - /// Returns `Poll::Pending` if there is more work left to do, in which - /// case the current task is scheduled (via `cx.waker().wake_by_ref()`) to wake up when - /// `poll_flush` should be called again. - /// - /// In most cases, if the sink encounters an error, the sink will - /// permanently be unable to receive items. - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Flush any remaining output and close this sink, if necessary. - /// - /// Returns `Poll::Ready(Ok(()))` when no buffered items remain and the sink - /// has been successfully closed. - /// - /// Returns `Poll::Pending` if there is more work left to do, in which - /// case the current task is scheduled (via `cx.waker().wake_by_ref()`) to wake up when - /// `poll_close` should be called again. - /// - /// If this function encounters an error, the sink should be considered to - /// have failed permanently, and no more `Sink` methods should be called. - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; -} - -impl + Unpin, Item> Sink for &mut S { - type Error = S::Error; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_ready(cx) - } - - fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - Pin::new(&mut **self).start_send(item) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_close(cx) - } -} - -impl Sink for Pin

-where - P: DerefMut + Unpin, - P::Target: Sink, -{ - type Error = >::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_ready(cx) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - self.get_mut().as_mut().start_send(item) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_close(cx) - } -} - -#[cfg(feature = "alloc")] -mod if_alloc { - use super::*; - use core::convert::Infallible; - - impl Sink for alloc::vec::Vec { - type Error = Infallible; - - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { - // TODO: impl Unpin for Vec {} - unsafe { self.get_unchecked_mut() }.push(item); - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - } - - impl Sink for alloc::collections::VecDeque { - type Error = Infallible; - - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { - // TODO: impl Unpin for Vec {} - unsafe { self.get_unchecked_mut() }.push_back(item); - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - } - - impl + Unpin, Item> Sink for alloc::boxed::Box { - type Error = S::Error; - - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - Pin::new(&mut **self).poll_ready(cx) - } - - fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - Pin::new(&mut **self).start_send(item) - } - - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - Pin::new(&mut **self).poll_flush(cx) - } - - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - Pin::new(&mut **self).poll_close(cx) - } - } -} diff --git a/futures-task/Cargo.toml b/futures-task/Cargo.toml deleted file mode 100644 index be1a6c6c03..0000000000 --- a/futures-task/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "futures-task" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -Tools for working with tasks. -""" - -[features] -default = ["std"] -std = ["alloc"] -alloc = [] - -[dependencies] - -[dev-dependencies] -futures = { path = "../futures" } - -[package.metadata.docs.rs] -all-features = true - -[lints] -workspace = true diff --git a/futures-task/LICENSE-APACHE b/futures-task/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-task/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-task/LICENSE-MIT b/futures-task/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-task/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-task/README.md b/futures-task/README.md deleted file mode 100644 index 40296f0332..0000000000 --- a/futures-task/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-task - -Tools for working with tasks. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-task = "0.3" -``` - -The current `futures-task` requires Rust 1.68 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-task/src/arc_wake.rs b/futures-task/src/arc_wake.rs deleted file mode 100644 index aa6de0fc43..0000000000 --- a/futures-task/src/arc_wake.rs +++ /dev/null @@ -1,49 +0,0 @@ -use alloc::sync::Arc; - -/// A way of waking up a specific task. -/// -/// By implementing this trait, types that are expected to be wrapped in an `Arc` -/// can be converted into [`Waker`] objects. -/// Those Wakers can be used to signal executors that a task it owns -/// is ready to be `poll`ed again. -/// -/// Currently, there are two ways to convert `ArcWake` into [`Waker`]: -/// -/// * [`waker`](super::waker()) converts `Arc` into [`Waker`]. -/// * [`waker_ref`](super::waker_ref()) converts `&Arc` into [`WakerRef`] that -/// provides access to a [`&Waker`][`Waker`]. -/// -/// [`Waker`]: std::task::Waker -/// [`WakerRef`]: super::WakerRef -// Note: Send + Sync required because `Arc` doesn't automatically imply -// those bounds, but `Waker` implements them. -pub trait ArcWake: Send + Sync { - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// This function can be called from an arbitrary thread, including threads which - /// did not create the `ArcWake` based [`Waker`]. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - /// - /// [`Waker`]: std::task::Waker - fn wake(self: Arc) { - Self::wake_by_ref(&self) - } - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// This function can be called from an arbitrary thread, including threads which - /// did not create the `ArcWake` based [`Waker`]. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake_by_ref` should place - /// the associated task onto this queue. - /// - /// This function is similar to [`wake`](ArcWake::wake), but must not consume the provided data - /// pointer. - /// - /// [`Waker`]: std::task::Waker - fn wake_by_ref(arc_self: &Arc); -} diff --git a/futures-task/src/future_obj.rs b/futures-task/src/future_obj.rs deleted file mode 100644 index 93bf7ccec0..0000000000 --- a/futures-task/src/future_obj.rs +++ /dev/null @@ -1,333 +0,0 @@ -use core::{ - fmt, - future::Future, - marker::PhantomData, - mem, - pin::Pin, - task::{Context, Poll}, -}; - -/// A custom trait object for polling futures, roughly akin to -/// `Box + 'a>`. -/// -/// This custom trait object was introduced as currently it is not possible to -/// take `dyn Trait` by value and `Box` is not available in no_std -/// contexts. -pub struct LocalFutureObj<'a, T> { - future: *mut (dyn Future + 'static), - drop_fn: unsafe fn(*mut (dyn Future + 'static)), - _marker: PhantomData<&'a ()>, -} - -// As LocalFutureObj only holds pointers, even if we move it, the pointed to values won't move, -// so this is safe as long as we don't provide any way for a user to directly access the pointers -// and move their values. -impl Unpin for LocalFutureObj<'_, T> {} - -#[allow(single_use_lifetimes)] -unsafe fn remove_future_lifetime<'a, T>( - ptr: *mut (dyn Future + 'a), -) -> *mut (dyn Future + 'static) { - unsafe { mem::transmute(ptr) } -} - -#[allow(single_use_lifetimes)] -unsafe fn remove_drop_lifetime<'a, T>( - ptr: unsafe fn(*mut (dyn Future + 'a)), -) -> unsafe fn(*mut (dyn Future + 'static)) { - unsafe { mem::transmute(ptr) } -} - -impl<'a, T> LocalFutureObj<'a, T> { - /// Create a `LocalFutureObj` from a custom trait object representation. - #[inline] - pub fn new + 'a>(f: F) -> Self { - Self { - future: unsafe { remove_future_lifetime(f.into_raw()) }, - drop_fn: unsafe { remove_drop_lifetime(F::drop) }, - _marker: PhantomData, - } - } - - /// Converts the `LocalFutureObj` into a `FutureObj`. - /// - /// # Safety - /// - /// To make this operation safe one has to ensure that the `UnsafeFutureObj` - /// instance from which this `LocalFutureObj` was created actually - /// implements `Send`. - #[inline] - pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> { - FutureObj(self) - } -} - -impl fmt::Debug for LocalFutureObj<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("LocalFutureObj").finish() - } -} - -impl<'a, T> From> for LocalFutureObj<'a, T> { - #[inline] - fn from(f: FutureObj<'a, T>) -> Self { - f.0 - } -} - -impl Future for LocalFutureObj<'_, T> { - type Output = T; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unsafe { Pin::new_unchecked(&mut *self.future).poll(cx) } - } -} - -impl Drop for LocalFutureObj<'_, T> { - fn drop(&mut self) { - unsafe { (self.drop_fn)(self.future) } - } -} - -/// A custom trait object for polling futures, roughly akin to -/// `Box + Send + 'a>`. -/// -/// This custom trait object was introduced as currently it is not possible to -/// take `dyn Trait` by value and `Box` is not available in no_std -/// contexts. -/// -/// You should generally not need to use this type outside of `no_std` or when -/// implementing `Spawn`, consider using `BoxFuture` instead. -pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); - -impl Unpin for FutureObj<'_, T> {} -unsafe impl Send for FutureObj<'_, T> {} - -impl<'a, T> FutureObj<'a, T> { - /// Create a `FutureObj` from a custom trait object representation. - #[inline] - pub fn new + Send>(f: F) -> Self { - Self(LocalFutureObj::new(f)) - } -} - -impl fmt::Debug for FutureObj<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FutureObj").finish() - } -} - -impl Future for FutureObj<'_, T> { - type Output = T; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) - } -} - -/// A custom implementation of a future trait object for `FutureObj`, providing -/// a vtable with drop support. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// # Safety -/// -/// See the safety notes on individual methods for what guarantees an -/// implementor must provide. -pub unsafe trait UnsafeFutureObj<'a, T>: 'a { - /// Convert an owned instance into a (conceptually owned) fat pointer. - /// - /// # Safety - /// - /// ## Implementor - /// - /// The trait implementor must guarantee that it is safe to convert the - /// provided `*mut (dyn Future + 'a)` into a `Pin<&mut (dyn - /// Future + 'a)>` and call methods on it, non-reentrantly, - /// until `UnsafeFutureObj::drop` is called with it. - fn into_raw(self) -> *mut (dyn Future + 'a); - - /// Drops the future represented by the given fat pointer. - /// - /// # Safety - /// - /// ## Implementor - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation. - /// - /// ## Caller - /// - /// The caller must ensure: - /// - /// * the pointer passed was obtained from an `into_raw` invocation from - /// this same trait object - /// * the pointer is not currently in use as a `Pin<&mut (dyn Future + 'a)>` - /// * the pointer must not be used again after this function is called - unsafe fn drop(ptr: *mut (dyn Future + 'a)); -} - -unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F -where - F: Future + Unpin + 'a, -{ - fn into_raw(self) -> *mut (dyn Future + 'a) { - self as *mut dyn Future - } - - unsafe fn drop(_ptr: *mut (dyn Future + 'a)) {} -} - -unsafe impl<'a, T> UnsafeFutureObj<'a, T> for &'a mut (dyn Future + Unpin + 'a) { - fn into_raw(self) -> *mut (dyn Future + 'a) { - self as *mut dyn Future - } - - unsafe fn drop(_ptr: *mut (dyn Future + 'a)) {} -} - -unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin<&'a mut F> -where - F: Future + 'a, -{ - fn into_raw(self) -> *mut (dyn Future + 'a) { - unsafe { self.get_unchecked_mut() as *mut dyn Future } - } - - unsafe fn drop(_ptr: *mut (dyn Future + 'a)) {} -} - -unsafe impl<'a, T> UnsafeFutureObj<'a, T> for Pin<&'a mut (dyn Future + 'a)> { - fn into_raw(self) -> *mut (dyn Future + 'a) { - unsafe { self.get_unchecked_mut() as *mut dyn Future } - } - - unsafe fn drop(_ptr: *mut (dyn Future + 'a)) {} -} - -#[cfg(feature = "alloc")] -mod if_alloc { - use super::*; - use alloc::boxed::Box; - - unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box - where - F: Future + 'a, - { - fn into_raw(self) -> *mut (dyn Future + 'a) { - Box::into_raw(self) - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(unsafe { Box::from_raw(ptr.cast::()) }) - } - } - - unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box + 'a> { - fn into_raw(self) -> *mut (dyn Future + 'a) { - Box::into_raw(self) - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(unsafe { Box::from_raw(ptr) }) - } - } - - unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box + Send + 'a> { - fn into_raw(self) -> *mut (dyn Future + 'a) { - Box::into_raw(self) - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(unsafe { Box::from_raw(ptr) }) - } - } - - unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin> - where - F: Future + 'a, - { - fn into_raw(self) -> *mut (dyn Future + 'a) { - let mut this = mem::ManuallyDrop::new(self); - unsafe { this.as_mut().get_unchecked_mut() as *mut _ } - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(Pin::from(unsafe { Box::from_raw(ptr) })) - } - } - - unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin + 'a>> { - fn into_raw(self) -> *mut (dyn Future + 'a) { - let mut this = mem::ManuallyDrop::new(self); - unsafe { this.as_mut().get_unchecked_mut() as *mut _ } - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(Pin::from(unsafe { Box::from_raw(ptr) })) - } - } - - unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin + Send + 'a>> { - fn into_raw(self) -> *mut (dyn Future + 'a) { - let mut this = mem::ManuallyDrop::new(self); - unsafe { this.as_mut().get_unchecked_mut() as *mut _ } - } - - unsafe fn drop(ptr: *mut (dyn Future + 'a)) { - drop(Pin::from(unsafe { Box::from_raw(ptr) })) - } - } - - impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { - fn from(boxed: Box) -> Self { - Self::new(boxed) - } - } - - impl<'a> From + Send + 'a>> for FutureObj<'a, ()> { - fn from(boxed: Box + Send + 'a>) -> Self { - Self::new(boxed) - } - } - - impl<'a, F: Future + Send + 'a> From>> for FutureObj<'a, ()> { - fn from(boxed: Pin>) -> Self { - Self::new(boxed) - } - } - - impl<'a> From + Send + 'a>>> for FutureObj<'a, ()> { - fn from(boxed: Pin + Send + 'a>>) -> Self { - Self::new(boxed) - } - } - - impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { - fn from(boxed: Box) -> Self { - Self::new(boxed) - } - } - - impl<'a> From + 'a>> for LocalFutureObj<'a, ()> { - fn from(boxed: Box + 'a>) -> Self { - Self::new(boxed) - } - } - - impl<'a, F: Future + 'a> From>> for LocalFutureObj<'a, ()> { - fn from(boxed: Pin>) -> Self { - Self::new(boxed) - } - } - - impl<'a> From + 'a>>> for LocalFutureObj<'a, ()> { - fn from(boxed: Pin + 'a>>) -> Self { - Self::new(boxed) - } - } -} diff --git a/futures-task/src/lib.rs b/futures-task/src/lib.rs deleted file mode 100644 index c119b6b1e4..0000000000 --- a/futures-task/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Tools for working with tasks. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -mod spawn; -pub use crate::spawn::{LocalSpawn, Spawn, SpawnError}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod arc_wake; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use crate::arc_wake::ArcWake; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod waker; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use crate::waker::waker; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod waker_ref; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use crate::waker_ref::{waker_ref, WakerRef}; - -mod future_obj; -pub use crate::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; - -mod noop_waker; -pub use crate::noop_waker::noop_waker; -pub use crate::noop_waker::noop_waker_ref; - -#[doc(no_inline)] -pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; diff --git a/futures-task/src/noop_waker.rs b/futures-task/src/noop_waker.rs deleted file mode 100644 index f76a8a2e95..0000000000 --- a/futures-task/src/noop_waker.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! Utilities for creating zero-cost wakers that don't do anything. - -use core::ptr::null; -use core::task::{RawWaker, RawWakerVTable, Waker}; - -unsafe fn noop_clone(_data: *const ()) -> RawWaker { - noop_raw_waker() -} - -unsafe fn noop(_data: *const ()) {} - -const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop); - -const fn noop_raw_waker() -> RawWaker { - RawWaker::new(null(), &NOOP_WAKER_VTABLE) -} - -/// Create a new [`Waker`] which does -/// nothing when `wake()` is called on it. -/// -/// # Examples -/// -/// ``` -/// use futures::task::noop_waker; -/// let waker = noop_waker(); -/// waker.wake(); -/// ``` -#[inline] -pub fn noop_waker() -> Waker { - // FIXME: Since 1.46.0 we can use transmute in consts, allowing this function to be const. - unsafe { Waker::from_raw(noop_raw_waker()) } -} - -/// Get a static reference to a [`Waker`] which -/// does nothing when `wake()` is called on it. -/// -/// # Examples -/// -/// ``` -/// use futures::task::noop_waker_ref; -/// let waker = noop_waker_ref(); -/// waker.wake_by_ref(); -/// ``` -#[inline] -pub fn noop_waker_ref() -> &'static Waker { - struct SyncRawWaker(RawWaker); - unsafe impl Sync for SyncRawWaker {} - - static NOOP_WAKER_INSTANCE: SyncRawWaker = SyncRawWaker(noop_raw_waker()); - - // SAFETY: `Waker` is #[repr(transparent)] over its `RawWaker`. - unsafe { &*(&NOOP_WAKER_INSTANCE.0 as *const RawWaker as *const Waker) } -} - -#[cfg(test)] -mod tests { - #[test] - #[cfg(feature = "std")] - fn issue_2091_cross_thread_segfault() { - let waker = std::thread::spawn(super::noop_waker_ref).join().unwrap(); - waker.wake_by_ref(); - } -} diff --git a/futures-task/src/spawn.rs b/futures-task/src/spawn.rs deleted file mode 100644 index 4a9a45a446..0000000000 --- a/futures-task/src/spawn.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::{FutureObj, LocalFutureObj}; -use core::fmt; - -/// The `Spawn` trait allows for pushing futures onto an executor that will -/// run them to completion. -pub trait Spawn { - /// Spawns a future that will be run to completion. - /// - /// # Errors - /// - /// The executor may be unable to spawn tasks. Spawn errors should - /// represent relatively rare scenarios, such as the executor - /// having been shut down so that it is no longer able to accept - /// tasks. - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>; - - /// Determines whether the executor is able to spawn new tasks. - /// - /// This method will return `Ok` when the executor is *likely* - /// (but not guaranteed) to accept a subsequent spawn attempt. - /// Likewise, an `Err` return means that `spawn` is likely, but - /// not guaranteed, to yield an error. - #[inline] - fn status(&self) -> Result<(), SpawnError> { - Ok(()) - } -} - -/// The `LocalSpawn` is similar to [`Spawn`], but allows spawning futures -/// that don't implement `Send`. -pub trait LocalSpawn { - /// Spawns a future that will be run to completion. - /// - /// # Errors - /// - /// The executor may be unable to spawn tasks. Spawn errors should - /// represent relatively rare scenarios, such as the executor - /// having been shut down so that it is no longer able to accept - /// tasks. - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>; - - /// Determines whether the executor is able to spawn new tasks. - /// - /// This method will return `Ok` when the executor is *likely* - /// (but not guaranteed) to accept a subsequent spawn attempt. - /// Likewise, an `Err` return means that `spawn` is likely, but - /// not guaranteed, to yield an error. - #[inline] - fn status_local(&self) -> Result<(), SpawnError> { - Ok(()) - } -} - -/// An error that occurred during spawning. -pub struct SpawnError { - _priv: (), -} - -impl fmt::Debug for SpawnError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("SpawnError").field(&"shutdown").finish() - } -} - -impl fmt::Display for SpawnError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Executor is shutdown") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for SpawnError {} - -impl SpawnError { - /// Spawning failed because the executor has been shut down. - pub fn shutdown() -> Self { - Self { _priv: () } - } - - /// Check whether spawning failed to the executor being shut down. - pub fn is_shutdown(&self) -> bool { - true - } -} - -impl Spawn for &Sp { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - Sp::spawn_obj(self, future) - } - - fn status(&self) -> Result<(), SpawnError> { - Sp::status(self) - } -} - -impl Spawn for &mut Sp { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - Sp::spawn_obj(self, future) - } - - fn status(&self) -> Result<(), SpawnError> { - Sp::status(self) - } -} - -impl LocalSpawn for &Sp { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - Sp::spawn_local_obj(self, future) - } - - fn status_local(&self) -> Result<(), SpawnError> { - Sp::status_local(self) - } -} - -impl LocalSpawn for &mut Sp { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - Sp::spawn_local_obj(self, future) - } - - fn status_local(&self) -> Result<(), SpawnError> { - Sp::status_local(self) - } -} - -#[cfg(feature = "alloc")] -mod if_alloc { - use super::*; - use alloc::{boxed::Box, rc::Rc}; - - impl Spawn for Box { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_obj(future) - } - - fn status(&self) -> Result<(), SpawnError> { - (**self).status() - } - } - - impl LocalSpawn for Box { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_local_obj(future) - } - - fn status_local(&self) -> Result<(), SpawnError> { - (**self).status_local() - } - } - - impl Spawn for Rc { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_obj(future) - } - - fn status(&self) -> Result<(), SpawnError> { - (**self).status() - } - } - - impl LocalSpawn for Rc { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_local_obj(future) - } - - fn status_local(&self) -> Result<(), SpawnError> { - (**self).status_local() - } - } - - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - impl Spawn for alloc::sync::Arc { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_obj(future) - } - - fn status(&self) -> Result<(), SpawnError> { - (**self).status() - } - } - - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - impl LocalSpawn for alloc::sync::Arc { - fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - (**self).spawn_local_obj(future) - } - - fn status_local(&self) -> Result<(), SpawnError> { - (**self).status_local() - } - } -} diff --git a/futures-task/src/waker.rs b/futures-task/src/waker.rs deleted file mode 100644 index 747457a521..0000000000 --- a/futures-task/src/waker.rs +++ /dev/null @@ -1,59 +0,0 @@ -use super::arc_wake::ArcWake; -use alloc::sync::Arc; -use core::mem; -use core::task::{RawWaker, RawWakerVTable, Waker}; - -pub(super) fn waker_vtable() -> &'static RawWakerVTable { - &RawWakerVTable::new( - clone_arc_raw::, - wake_arc_raw::, - wake_by_ref_arc_raw::, - drop_arc_raw::, - ) -} - -/// Creates a [`Waker`] from an `Arc`. -/// -/// The returned [`Waker`] will call -/// [`ArcWake.wake()`](ArcWake::wake) if awoken. -pub fn waker(wake: Arc) -> Waker -where - W: ArcWake + 'static, -{ - let ptr = Arc::into_raw(wake).cast::<()>(); - - unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::())) } -} - -// FIXME: panics on Arc::clone / refcount changes could wreak havoc on the -// code here. We should guard against this by aborting. - -unsafe fn increase_refcount(data: *const ()) { - // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); - // Now increase refcount, but don't drop new refcount either - let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); -} - -// used by `waker_ref` -#[inline(always)] -unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { - unsafe { increase_refcount::(data) } - RawWaker::new(data, waker_vtable::()) -} - -unsafe fn wake_arc_raw(data: *const ()) { - let arc: Arc = unsafe { Arc::from_raw(data.cast::()) }; - ArcWake::wake(arc); -} - -// used by `waker_ref` -unsafe fn wake_by_ref_arc_raw(data: *const ()) { - // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); - ArcWake::wake_by_ref(&arc); -} - -unsafe fn drop_arc_raw(data: *const ()) { - drop(unsafe { Arc::::from_raw(data.cast::()) }) -} diff --git a/futures-task/src/waker_ref.rs b/futures-task/src/waker_ref.rs deleted file mode 100644 index 5957b4d46a..0000000000 --- a/futures-task/src/waker_ref.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::arc_wake::ArcWake; -use super::waker::waker_vtable; -use alloc::sync::Arc; -use core::marker::PhantomData; -use core::mem::ManuallyDrop; -use core::ops::Deref; -use core::task::{RawWaker, Waker}; - -/// A [`Waker`] that is only valid for a given lifetime. -/// -/// Note: this type implements [`Deref`](std::ops::Deref), -/// so it can be used to get a `&Waker`. -#[derive(Debug)] -pub struct WakerRef<'a> { - waker: ManuallyDrop, - _marker: PhantomData<&'a ()>, -} - -impl<'a> WakerRef<'a> { - /// Create a new [`WakerRef`] from a [`Waker`] reference. - #[inline] - pub fn new(waker: &'a Waker) -> Self { - // copy the underlying (raw) waker without calling a clone, - // as we won't call Waker::drop either. - let waker = ManuallyDrop::new(unsafe { core::ptr::read(waker) }); - Self { waker, _marker: PhantomData } - } - - /// Create a new [`WakerRef`] from a [`Waker`] that must not be dropped. - /// - /// Note: this if for rare cases where the caller created a [`Waker`] in - /// an unsafe way (that will be valid only for a lifetime to be determined - /// by the caller), and the [`Waker`] doesn't need to or must not be - /// destroyed. - #[inline] - pub fn new_unowned(waker: ManuallyDrop) -> Self { - Self { waker, _marker: PhantomData } - } -} - -impl Deref for WakerRef<'_> { - type Target = Waker; - - #[inline] - fn deref(&self) -> &Waker { - &self.waker - } -} - -/// Creates a reference to a [`Waker`] from a reference to `Arc`. -/// -/// The resulting [`Waker`] will call -/// [`ArcWake.wake()`](ArcWake::wake) if awoken. -#[inline] -pub fn waker_ref(wake: &Arc) -> WakerRef<'_> -where - W: ArcWake + 'static, -{ - // simply copy the pointer instead of using Arc::into_raw, - // as we don't actually keep a refcount by using ManuallyDrop.< - let ptr = Arc::as_ptr(wake).cast::<()>(); - - let waker = - ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::())) }); - WakerRef::new_unowned(waker) -} diff --git a/futures-test/Cargo.toml b/futures-test/Cargo.toml deleted file mode 100644 index 245df3039b..0000000000 --- a/futures-test/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "futures-test" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -Common utilities for testing components built off futures-rs. -""" - -[dependencies] -futures-core = { version = "=1.0.0-alpha.0", path = "../futures-core", default-features = false } -futures-task = { version = "=0.4.0-alpha.0", path = "../futures-task", default-features = false } -futures-io = { version = "0.3.31", path = "../futures-io", default-features = false } -futures-util = { version = "=0.4.0-alpha.0", path = "../futures-util", default-features = false } -futures-executor = { version = "=0.4.0-alpha.0", path = "../futures-executor", default-features = false } -futures-sink = { version = "=0.4.0-alpha.0", path = "../futures-sink", default-features = false } -futures-macro = { version = "=0.4.0-alpha.0", path = "../futures-macro", default-features = false } -pin-project = "1.0.11" - -[dev-dependencies] -futures = { path = "../futures", default-features = false, features = ["std", "executor"] } - -[features] -default = ["std"] -std = ["futures-core/std", "futures-task/std", "futures-io/std", "futures-util/std", "futures-util/io", "futures-executor/std"] - -[package.metadata.docs.rs] -all-features = true - -[lints] -workspace = true diff --git a/futures-test/LICENSE-APACHE b/futures-test/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-test/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-test/LICENSE-MIT b/futures-test/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-test/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-test/README.md b/futures-test/README.md deleted file mode 100644 index 407ec0e291..0000000000 --- a/futures-test/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-test - -Common utilities for testing components built off futures-rs. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-test = "0.3" -``` - -The current `futures-test` requires Rust 1.68 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-test/src/assert.rs b/futures-test/src/assert.rs deleted file mode 100644 index f1310356c7..0000000000 --- a/futures-test/src/assert.rs +++ /dev/null @@ -1,127 +0,0 @@ -use futures_core::stream::Stream; - -#[doc(hidden)] -pub fn assert_is_unpin_stream(_: &mut S) {} - -/// Assert that the next poll to the provided stream will return -/// [`Poll::Pending`](futures_core::task::Poll::Pending). -/// -/// # Examples -/// -/// ``` -/// use core::pin::pin; -/// -/// use futures::stream; -/// use futures_test::future::FutureTestExt; -/// 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()); -/// let mut stream = pin!(stream); -/// -/// assert_stream_pending!(stream); -/// assert_stream_next!(stream, 5); -/// assert_stream_done!(stream); -/// ``` -#[macro_export] -macro_rules! assert_stream_pending { - ($stream:expr) => { - #[allow(clippy::if_then_panic)] - { - let mut stream = &mut $stream; - $crate::__private::assert::assert_is_unpin_stream(stream); - let stream = $crate::__private::Pin::new(stream); - let mut cx = $crate::task::noop_context(); - let poll = $crate::__private::stream::Stream::poll_next(stream, &mut cx); - if poll.is_ready() { - panic!("assertion failed: stream is not pending"); - } - } - }; -} - -/// Assert that the next poll to the provided stream will return -/// [`Poll::Ready`](futures_core::task::Poll::Ready) with the provided item. -/// -/// # Examples -/// -/// ``` -/// use core::pin::pin; -/// -/// use futures::stream; -/// use futures_test::future::FutureTestExt; -/// 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()); -/// let mut stream = pin!(stream); -/// -/// assert_stream_pending!(stream); -/// assert_stream_next!(stream, 5); -/// assert_stream_done!(stream); -/// ``` -#[macro_export] -macro_rules! assert_stream_next { - ($stream:expr, $item:expr) => {{ - let mut stream = &mut $stream; - $crate::__private::assert::assert_is_unpin_stream(stream); - let stream = $crate::__private::Pin::new(stream); - let mut cx = $crate::task::noop_context(); - match $crate::__private::stream::Stream::poll_next(stream, &mut cx) { - $crate::__private::task::Poll::Ready($crate::__private::Some(x)) => { - assert_eq!(x, $item); - } - $crate::__private::task::Poll::Ready($crate::__private::None) => { - panic!( - "assertion failed: expected stream to provide item but stream is at its end" - ); - } - $crate::__private::task::Poll::Pending => { - panic!("assertion failed: expected stream to provide item but stream wasn't ready"); - } - } - }}; -} - -/// Assert that the next poll to the provided stream will return an empty -/// [`Poll::Ready`](futures_core::task::Poll::Ready) signalling the -/// completion of the stream. -/// -/// # Examples -/// -/// ``` -/// use core::pin::pin; -/// -/// use futures::stream; -/// use futures_test::future::FutureTestExt; -/// 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()); -/// let mut stream = pin!(stream); -/// -/// assert_stream_pending!(stream); -/// assert_stream_next!(stream, 5); -/// assert_stream_done!(stream); -/// ``` -#[macro_export] -macro_rules! assert_stream_done { - ($stream:expr) => {{ - let mut stream = &mut $stream; - $crate::__private::assert::assert_is_unpin_stream(stream); - let stream = $crate::__private::Pin::new(stream); - let mut cx = $crate::task::noop_context(); - match $crate::__private::stream::Stream::poll_next(stream, &mut cx) { - $crate::__private::task::Poll::Ready($crate::__private::Some(_)) => { - panic!("assertion failed: expected stream to be done but had more elements"); - } - $crate::__private::task::Poll::Ready($crate::__private::None) => {} - $crate::__private::task::Poll::Pending => { - panic!("assertion failed: expected stream to be done but was pending"); - } - } - }}; -} diff --git a/futures-test/src/assert_unmoved.rs b/futures-test/src/assert_unmoved.rs deleted file mode 100644 index 3b604cc1d3..0000000000 --- a/futures-test/src/assert_unmoved.rs +++ /dev/null @@ -1,213 +0,0 @@ -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_io::{ - self as io, AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, SeekFrom, -}; -use futures_sink::Sink; -use pin_project::{pin_project, pinned_drop}; -use std::pin::Pin; -use std::thread::panicking; - -/// Combinator that asserts that the underlying type is not moved after being polled. -/// -/// See the `assert_unmoved` methods on: -/// * [`FutureTestExt`](crate::future::FutureTestExt::assert_unmoved) -/// * [`StreamTestExt`](crate::stream::StreamTestExt::assert_unmoved) -/// * [`SinkTestExt`](crate::sink::SinkTestExt::assert_unmoved_sink) -/// * [`AsyncReadTestExt`](crate::io::AsyncReadTestExt::assert_unmoved) -/// * [`AsyncWriteTestExt`](crate::io::AsyncWriteTestExt::assert_unmoved_write) -#[pin_project(PinnedDrop, !Unpin)] -#[derive(Debug, Clone)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct AssertUnmoved { - #[pin] - inner: T, - this_addr: usize, -} - -impl AssertUnmoved { - pub(crate) fn new(inner: T) -> Self { - Self { inner, this_addr: 0 } - } - - fn poll_with<'a, U>(mut self: Pin<&'a mut Self>, f: impl FnOnce(Pin<&'a mut T>) -> U) -> U { - let cur_this = &*self as *const Self as usize; - if self.this_addr == 0 { - // First time being polled - *self.as_mut().project().this_addr = cur_this; - } else { - assert_eq!(self.this_addr, cur_this, "AssertUnmoved moved between poll calls"); - } - f(self.project().inner) - } -} - -impl Future for AssertUnmoved { - type Output = Fut::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.poll_with(|f| f.poll(cx)) - } -} - -impl FusedFuture for AssertUnmoved { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl Stream for AssertUnmoved { - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|s| s.poll_next(cx)) - } -} - -impl FusedStream for AssertUnmoved { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl, Item> Sink for AssertUnmoved { - type Error = Si::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|s| s.poll_ready(cx)) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - self.poll_with(|s| s.start_send(item)) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|s| s.poll_flush(cx)) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|s| s.poll_close(cx)) - } -} - -impl AsyncRead for AssertUnmoved { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.poll_with(|r| r.poll_read(cx, buf)) - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - self.poll_with(|r| r.poll_read_vectored(cx, bufs)) - } -} - -impl AsyncWrite for AssertUnmoved { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.poll_with(|w| w.poll_write(cx, buf)) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - self.poll_with(|w| w.poll_write_vectored(cx, bufs)) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|w| w.poll_flush(cx)) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|w| w.poll_close(cx)) - } -} - -impl AsyncSeek for AssertUnmoved { - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - self.poll_with(|s| s.poll_seek(cx, pos)) - } -} - -impl AsyncBufRead for AssertUnmoved { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(|r| r.poll_fill_buf(cx)) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.poll_with(|r| r.consume(amt)) - } -} - -#[pinned_drop] -impl PinnedDrop for AssertUnmoved { - fn drop(self: Pin<&mut Self>) { - // If the thread is panicking then we can't panic again as that will - // cause the process to be aborted. - if !panicking() && self.this_addr != 0 { - let cur_this = &*self as *const Self as usize; - assert_eq!(self.this_addr, cur_this, "AssertUnmoved moved before drop"); - } - } -} - -#[cfg(test)] -mod tests { - use futures_core::future::Future; - use futures_core::task::{Context, Poll}; - use futures_util::future::pending; - use futures_util::task::noop_waker; - use std::pin::Pin; - - use super::AssertUnmoved; - - // TODO: move this to futures/tests/auto_traits.rs - #[test] - fn assert_send_sync() { - fn assert() {} - assert::>(); - } - - #[test] - fn dont_panic_when_not_polled() { - // This shouldn't panic. - let future = AssertUnmoved::new(pending::<()>()); - drop(future); - } - - #[test] - #[should_panic(expected = "AssertUnmoved moved between poll calls")] - fn dont_double_panic() { - // This test should only panic, not abort the process. - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - - // First we allocate the future on the stack and poll it. - let mut future = AssertUnmoved::new(pending::<()>()); - let pinned_future = unsafe { Pin::new_unchecked(&mut future) }; - assert_eq!(pinned_future.poll(&mut cx), Poll::Pending); - - // Next we move it back to the heap and poll it again. This second call - // should panic (as the future is moved), but we shouldn't panic again - // whilst dropping `AssertUnmoved`. - let mut future = Box::new(future); - let pinned_boxed_future = unsafe { Pin::new_unchecked(&mut *future) }; - assert_eq!(pinned_boxed_future.poll(&mut cx), Poll::Pending); - } -} diff --git a/futures-test/src/future/mod.rs b/futures-test/src/future/mod.rs deleted file mode 100644 index b066443ae4..0000000000 --- a/futures-test/src/future/mod.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Additional combinators for testing futures. - -mod pending_once; -pub use self::pending_once::PendingOnce; - -use futures_core::future::Future; -use std::thread; - -pub use crate::assert_unmoved::AssertUnmoved; -pub use crate::interleave_pending::InterleavePending; - -/// Additional combinators for testing futures. -pub trait FutureTestExt: Future { - /// Asserts that the given is not moved after being polled. - /// - /// A check for movement is performed each time the future is polled - /// and when `Drop` is called. - /// - /// Aside from keeping track of the location at which the future was first - /// polled and providing assertions, this future adds no runtime behavior - /// and simply delegates to the child future. - fn assert_unmoved(self) -> AssertUnmoved - where - Self: Sized, - { - AssertUnmoved::new(self) - } - - /// Introduces one [`Poll::Pending`](futures_core::task::Poll::Pending) - /// before polling the given 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; - /// - /// let future = (async { 5 }).pending_once(); - /// let mut future = pin!(future); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(future.poll_unpin(&mut cx), Poll::Pending); - /// assert_eq!(future.poll_unpin(&mut cx), Poll::Ready(5)); - /// ``` - fn pending_once(self) -> PendingOnce - where - Self: Sized, - { - PendingOnce::new(self) - } - - /// Runs this future on a dedicated executor running in a background thread. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures_test::future::FutureTestExt; - /// - /// let (tx, rx) = oneshot::channel::(); - /// - /// (async { tx.send(5).unwrap() }).run_in_background(); - /// - /// assert_eq!(rx.await, Ok(5)); - /// # }); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - fn run_in_background(self) - where - Self: Sized + Send + 'static, - Self::Output: Send, - { - thread::spawn(|| futures_executor::block_on(self)); - } - - /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending) - /// in between each call to poll. - /// - /// # 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; - /// - /// let future = future::ready(1).interleave_pending(); - /// let mut future = pin!(future); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Pending); - /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(1)); - /// ``` - fn interleave_pending(self) -> InterleavePending - where - Self: Sized, - { - InterleavePending::new(self) - } -} - -impl FutureTestExt for Fut where Fut: Future {} diff --git a/futures-test/src/future/pending_once.rs b/futures-test/src/future/pending_once.rs deleted file mode 100644 index 0fc3ef0b34..0000000000 --- a/futures-test/src/future/pending_once.rs +++ /dev/null @@ -1,46 +0,0 @@ -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; -use pin_project::pin_project; -use std::pin::Pin; - -/// Combinator that guarantees one [`Poll::Pending`] before polling its inner -/// future. -/// -/// This is created by the -/// [`FutureTestExt::pending_once`](super::FutureTestExt::pending_once) -/// method. -#[pin_project] -#[derive(Debug, Clone)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct PendingOnce { - #[pin] - future: Fut, - polled_before: bool, -} - -impl PendingOnce { - pub(super) fn new(future: Fut) -> Self { - Self { future, polled_before: false } - } -} - -impl Future for PendingOnce { - type Output = Fut::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.project(); - if *this.polled_before { - this.future.poll(cx) - } else { - *this.polled_before = true; - cx.waker().wake_by_ref(); - Poll::Pending - } - } -} - -impl FusedFuture for PendingOnce { - fn is_terminated(&self) -> bool { - self.polled_before && self.future.is_terminated() - } -} diff --git a/futures-test/src/interleave_pending.rs b/futures-test/src/interleave_pending.rs deleted file mode 100644 index 91640778b2..0000000000 --- a/futures-test/src/interleave_pending.rs +++ /dev/null @@ -1,191 +0,0 @@ -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, Stream}; -use futures_io::{ - self as io, AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, SeekFrom, -}; -use futures_sink::Sink; -use pin_project::pin_project; -use std::{ - pin::Pin, - task::{Context, Poll}, -}; - -/// Wrapper that interleaves [`Poll::Pending`] in calls to poll. -/// -/// See the `interleave_pending` methods on: -/// * [`FutureTestExt`](crate::future::FutureTestExt::interleave_pending) -/// * [`StreamTestExt`](crate::stream::StreamTestExt::interleave_pending) -/// * [`SinkTestExt`](crate::sink::SinkTestExt::interleave_pending_sink) -/// * [`AsyncReadTestExt`](crate::io::AsyncReadTestExt::interleave_pending) -/// * [`AsyncWriteTestExt`](crate::io::AsyncWriteTestExt::interleave_pending_write) -#[pin_project] -#[derive(Debug)] -pub struct InterleavePending { - #[pin] - inner: T, - pended: bool, -} - -impl InterleavePending { - pub(crate) fn new(inner: T) -> Self { - Self { inner, pended: false } - } - - /// Acquires a reference to the underlying I/O object that this adaptor is - /// wrapping. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Acquires a mutable reference to the underlying I/O object that this - /// adaptor is wrapping. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Acquires a pinned mutable reference to the underlying I/O object that - /// this adaptor is wrapping. - pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { - self.project().inner - } - - /// Consumes this adaptor returning the underlying I/O object. - pub fn into_inner(self) -> T { - self.inner - } - - fn poll_with<'a, U>( - self: Pin<&'a mut Self>, - cx: &mut Context<'_>, - f: impl FnOnce(Pin<&'a mut T>, &mut Context<'_>) -> Poll, - ) -> Poll { - let this = self.project(); - if *this.pended { - let next = f(this.inner, cx); - if next.is_ready() { - *this.pended = false; - } - next - } else { - cx.waker().wake_by_ref(); - *this.pended = true; - Poll::Pending - } - } -} - -impl Future for InterleavePending { - type Output = Fut::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.poll_with(cx, Fut::poll) - } -} - -impl FusedFuture for InterleavePending { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl Stream for InterleavePending { - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, St::poll_next) - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl FusedStream for InterleavePending { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl, Item> Sink for InterleavePending { - type Error = Si::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, Si::poll_ready) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - self.project().inner.start_send(item) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, Si::poll_flush) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, Si::poll_close) - } -} - -impl AsyncRead for InterleavePending { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.poll_with(cx, |r, cx| r.poll_read(cx, buf)) - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - self.poll_with(cx, |r, cx| r.poll_read_vectored(cx, bufs)) - } -} - -impl AsyncWrite for InterleavePending { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.poll_with(cx, |w, cx| w.poll_write(cx, buf)) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - self.poll_with(cx, |w, cx| w.poll_write_vectored(cx, bufs)) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, W::poll_flush) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, W::poll_close) - } -} - -impl AsyncSeek for InterleavePending { - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - self.poll_with(cx, |s, cx| s.poll_seek(cx, pos)) - } -} - -impl AsyncBufRead for InterleavePending { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_with(cx, R::poll_fill_buf) - } - - fn consume(self: Pin<&mut Self>, amount: usize) { - self.project().inner.consume(amount) - } -} diff --git a/futures-test/src/io/limited.rs b/futures-test/src/io/limited.rs deleted file mode 100644 index 34b72a530e..0000000000 --- a/futures-test/src/io/limited.rs +++ /dev/null @@ -1,91 +0,0 @@ -use futures_io::{self as io, AsyncBufRead, AsyncRead, AsyncWrite}; -use pin_project::pin_project; -use std::{ - cmp, - pin::Pin, - task::{Context, Poll}, -}; - -/// I/O wrapper that limits the number of bytes written or read on each call. -/// -/// See the [`limited`] and [`limited_write`] methods. -/// -/// [`limited`]: super::AsyncReadTestExt::limited -/// [`limited_write`]: super::AsyncWriteTestExt::limited_write -#[pin_project] -#[derive(Debug)] -pub struct Limited { - #[pin] - io: Io, - limit: usize, -} - -impl Limited { - pub(crate) fn new(io: Io, limit: usize) -> Self { - Self { io, limit } - } - - /// Acquires a reference to the underlying I/O object that this adaptor is - /// wrapping. - pub fn get_ref(&self) -> &Io { - &self.io - } - - /// Acquires a mutable reference to the underlying I/O object that this - /// adaptor is wrapping. - pub fn get_mut(&mut self) -> &mut Io { - &mut self.io - } - - /// Acquires a pinned mutable reference to the underlying I/O object that - /// this adaptor is wrapping. - pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Io> { - self.project().io - } - - /// Consumes this adaptor returning the underlying I/O object. - pub fn into_inner(self) -> Io { - self.io - } -} - -impl AsyncWrite for Limited { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.project(); - this.io.poll_write(cx, &buf[..cmp::min(*this.limit, buf.len())]) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().io.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().io.poll_close(cx) - } -} - -impl AsyncRead for Limited { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let this = self.project(); - let limit = cmp::min(*this.limit, buf.len()); - this.io.poll_read(cx, &mut buf[..limit]) - } -} - -impl AsyncBufRead for Limited { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().io.poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amount: usize) { - self.project().io.consume(amount) - } -} diff --git a/futures-test/src/io/mod.rs b/futures-test/src/io/mod.rs deleted file mode 100644 index 03827845e4..0000000000 --- a/futures-test/src/io/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Additional combinators for testing async IO. - -mod limited; - -pub mod read; -pub use read::AsyncReadTestExt; - -pub mod write; -pub use write::AsyncWriteTestExt; diff --git a/futures-test/src/io/read/mod.rs b/futures-test/src/io/read/mod.rs deleted file mode 100644 index 28a25f5a9f..0000000000 --- a/futures-test/src/io/read/mod.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Additional combinators for testing async readers. - -use futures_io::AsyncRead; - -pub use super::limited::Limited; -pub use crate::assert_unmoved::AssertUnmoved; -pub use crate::interleave_pending::InterleavePending; - -/// Additional combinators for testing async readers. -pub trait AsyncReadTestExt: AsyncRead { - /// Asserts that the given is not moved after being polled. - /// - /// A check for movement is performed each time the reader is polled - /// and when `Drop` is called. - /// - /// Aside from keeping track of the location at which the reader was first - /// polled and providing assertions, this reader adds no runtime behavior - /// and simply delegates to the child reader. - fn assert_unmoved(self) -> AssertUnmoved - where - Self: Sized, - { - AssertUnmoved::new(self) - } - - /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending) - /// in between each read of the reader. - /// - /// # 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; - /// - /// let reader = Cursor::new(&[1, 2, 3]).interleave_pending(); - /// let mut reader = pin!(reader); - /// - /// let mut cx = noop_context(); - /// - /// let mut buf = [0, 0]; - /// - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Ready(2)); - /// assert_eq!(buf, [1, 2]); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Ready(1)); - /// assert_eq!(buf, [3, 2]); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf[..])?, Poll::Ready(0)); - /// - /// # Ok::<(), std::io::Error>(()) - /// ``` - /// - /// ## `AsyncBufRead` - /// - /// 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; - /// - /// let reader = Cursor::new(&[1, 2, 3]).interleave_pending(); - /// let mut reader = pin!(reader); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[1, 2, 3][..])); - /// reader.as_mut().consume(2); - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[3][..])); - /// reader.as_mut().consume(1); - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Pending); - /// assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[][..])); - /// - /// # Ok::<(), std::io::Error>(()) - /// ``` - fn interleave_pending(self) -> InterleavePending - where - Self: Sized, - { - InterleavePending::new(self) - } - - /// Limit the number of bytes allowed to be read on each call to `poll_read`. - /// - /// # 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; - /// - /// let reader = Cursor::new(&[1, 2, 3, 4, 5]).limited(2); - /// let mut reader = pin!(reader); - /// - /// let mut cx = noop_context(); - /// - /// let mut buf = [0; 10]; - /// - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf)?, Poll::Ready(2)); - /// assert_eq!(&buf[..2], &[1, 2]); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf)?, Poll::Ready(2)); - /// assert_eq!(&buf[..2], &[3, 4]); - /// assert_eq!(reader.as_mut().poll_read(&mut cx, &mut buf)?, Poll::Ready(1)); - /// assert_eq!(&buf[..1], &[5]); - /// - /// # Ok::<(), std::io::Error>(()) - /// ``` - fn limited(self, limit: usize) -> Limited - where - Self: Sized, - { - Limited::new(self, limit) - } -} - -impl AsyncReadTestExt for R where R: AsyncRead {} diff --git a/futures-test/src/io/write/mod.rs b/futures-test/src/io/write/mod.rs deleted file mode 100644 index 3c1b96eb8a..0000000000 --- a/futures-test/src/io/write/mod.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Additional combinators for testing async writers. - -use futures_io::AsyncWrite; - -pub use super::limited::Limited; -pub use crate::assert_unmoved::AssertUnmoved; -pub use crate::interleave_pending::InterleavePending; -pub use crate::track_closed::TrackClosed; - -/// Additional combinators for testing async writers. -pub trait AsyncWriteTestExt: AsyncWrite { - /// Asserts that the given is not moved after being polled. - /// - /// A check for movement is performed each time the writer is polled - /// and when `Drop` is called. - /// - /// Aside from keeping track of the location at which the writer was first - /// polled and providing assertions, this writer adds no runtime behavior - /// and simply delegates to the child writer. - fn assert_unmoved_write(self) -> AssertUnmoved - where - Self: Sized, - { - AssertUnmoved::new(self) - } - - /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending) - /// in between each operation on the writer. - /// - /// # 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; - /// - /// let writer = Cursor::new(vec![0u8; 4].into_boxed_slice()).interleave_pending_write(); - /// let mut writer = pin!(writer); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[1, 2])?, Poll::Pending); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[1, 2])?, Poll::Ready(2)); - /// assert_eq!(&writer.get_ref().get_ref()[..], [1, 2, 0, 0]); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[3, 4])?, Poll::Pending); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[3, 4])?, Poll::Ready(2)); - /// assert_eq!(&writer.get_ref().get_ref()[..], [1, 2, 3, 4]); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[5, 6])?, Poll::Pending); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[5, 6])?, Poll::Ready(0)); - /// - /// assert_eq!(writer.as_mut().poll_flush(&mut cx)?, Poll::Pending); - /// assert_eq!(writer.as_mut().poll_flush(&mut cx)?, Poll::Ready(())); - /// - /// assert_eq!(writer.as_mut().poll_close(&mut cx)?, Poll::Pending); - /// assert_eq!(writer.as_mut().poll_close(&mut cx)?, Poll::Ready(())); - /// - /// # Ok::<(), std::io::Error>(()) - /// ``` - fn interleave_pending_write(self) -> InterleavePending - where - Self: Sized, - { - InterleavePending::new(self) - } - - /// Limit the number of bytes allowed to be written on each call to `poll_write`. - /// - /// # 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; - /// - /// let writer = Cursor::new(vec![0u8; 4].into_boxed_slice()).limited_write(2); - /// let mut writer = pin!(writer); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[1, 2])?, Poll::Ready(2)); - /// assert_eq!(&writer.get_ref().get_ref()[..], [1, 2, 0, 0]); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[3])?, Poll::Ready(1)); - /// assert_eq!(&writer.get_ref().get_ref()[..], [1, 2, 3, 0]); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[4, 5])?, Poll::Ready(1)); - /// assert_eq!(&writer.get_ref().get_ref()[..], [1, 2, 3, 4]); - /// assert_eq!(writer.as_mut().poll_write(&mut cx, &[5])?, Poll::Ready(0)); - /// - /// # Ok::<(), std::io::Error>(()) - /// ``` - fn limited_write(self, limit: usize) -> Limited - where - Self: Sized, - { - Limited::new(self, limit) - } - - /// Track whether this stream has been closed and errors if it is used after closing. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncWriteExt, Cursor}; - /// use futures_test::io::AsyncWriteTestExt; - /// - /// let mut writer = Cursor::new(vec![0u8; 4]).track_closed(); - /// - /// writer.write_all(&[1, 2]).await?; - /// assert!(!writer.is_closed()); - /// writer.close().await?; - /// assert!(writer.is_closed()); - /// - /// # Ok::<(), std::io::Error>(()) })?; - /// # Ok::<(), std::io::Error>(()) - /// ``` - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncWriteExt, Cursor}; - /// use futures_test::io::AsyncWriteTestExt; - /// - /// let mut writer = Cursor::new(vec![0u8; 4]).track_closed(); - /// - /// writer.close().await?; - /// assert!(writer.write_all(&[1, 2]).await.is_err()); - /// # Ok::<(), std::io::Error>(()) })?; - /// # Ok::<(), std::io::Error>(()) - /// ``` - fn track_closed(self) -> TrackClosed - where - Self: Sized, - { - TrackClosed::new(self) - } -} - -impl AsyncWriteTestExt for W where W: AsyncWrite {} diff --git a/futures-test/src/lib.rs b/futures-test/src/lib.rs deleted file mode 100644 index 4e420eac88..0000000000 --- a/futures-test/src/lib.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Utilities to make testing [`Future`s](futures_core::future::Future) easier - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] -#![allow(clippy::test_attr_in_doctest)] - -#[cfg(not(feature = "std"))] -compile_error!( - "`futures-test` must have the `std` feature activated, this is a default-active feature" -); - -// Not public API. -#[doc(hidden)] -#[cfg(feature = "std")] -pub mod __private { - pub use futures_core::{future, stream, task}; - pub use futures_executor::block_on; - pub use std::{ - option::Option::{None, Some}, - pin::Pin, - result::Result::{Err, Ok}, - }; - - pub mod assert { - pub use crate::assert::*; - } -} - -#[macro_use] -#[cfg(feature = "std")] -mod assert; - -#[cfg(feature = "std")] -pub mod task; - -#[cfg(feature = "std")] -pub mod future; - -#[cfg(feature = "std")] -pub mod stream; - -#[cfg(feature = "std")] -pub mod sink; - -#[cfg(feature = "std")] -pub mod io; - -mod assert_unmoved; -mod interleave_pending; -mod track_closed; - -/// Enables an `async` test function. The generated future will be run to completion with -/// [`futures_executor::block_on`]. -/// -/// ``` -/// #[futures_test::test] -/// async fn my_test() { -/// let fut = async { true }; -/// assert!(fut.await); -/// } -/// ``` -/// -/// This is equivalent to the following code: -/// -/// ``` -/// #[test] -/// fn my_test() { -/// futures::executor::block_on(async move { -/// let fut = async { true }; -/// assert!(fut.await); -/// }) -/// } -/// ``` -#[cfg(feature = "std")] -pub use futures_macro::test_internal as test; diff --git a/futures-test/src/sink/mod.rs b/futures-test/src/sink/mod.rs deleted file mode 100644 index eb5a6efa84..0000000000 --- a/futures-test/src/sink/mod.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Additional combinators for testing sinks. - -use futures_sink::Sink; - -pub use crate::assert_unmoved::AssertUnmoved; -pub use crate::interleave_pending::InterleavePending; -pub use crate::track_closed::TrackClosed; - -/// Additional combinators for testing sinks. -pub trait SinkTestExt: Sink { - /// Asserts that the given is not moved after being polled. - /// - /// A check for movement is performed each time the sink is polled - /// and when `Drop` is called. - /// - /// Aside from keeping track of the location at which the sink was first - /// polled and providing assertions, this sink adds no runtime behavior - /// and simply delegates to the child sink. - fn assert_unmoved_sink(self) -> AssertUnmoved - where - Self: Sized, - { - AssertUnmoved::new(self) - } - - /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending) - /// in between each operation on the sink. - fn interleave_pending_sink(self) -> InterleavePending - where - Self: Sized, - { - InterleavePending::new(self) - } - - /// Track whether this sink has been closed and panics if it is used after closing. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::sink::{SinkExt, drain}; - /// use futures_test::sink::SinkTestExt; - /// - /// let mut sink = drain::().track_closed(); - /// - /// sink.send(1).await?; - /// assert!(!sink.is_closed()); - /// sink.close().await?; - /// assert!(sink.is_closed()); - /// - /// # Ok::<(), std::convert::Infallible>(()) })?; - /// # Ok::<(), std::convert::Infallible>(()) - /// ``` - /// - /// Note: Unlike [`AsyncWriteTestExt::track_closed`] when - /// used as a sink the adaptor will panic if closed too early as there's no easy way to - /// integrate as an error. - /// - /// [`AsyncWriteTestExt::track_closed`]: crate::io::AsyncWriteTestExt::track_closed - /// - /// ``` - /// # futures::executor::block_on(async { - /// use std::panic::AssertUnwindSafe; - /// use futures::{sink::{SinkExt, drain}, future::FutureExt}; - /// use futures_test::sink::SinkTestExt; - /// - /// let mut sink = drain::().track_closed(); - /// - /// sink.close().await?; - /// assert!(AssertUnwindSafe(sink.send(1)).catch_unwind().await.is_err()); - /// # Ok::<(), std::convert::Infallible>(()) })?; - /// # Ok::<(), std::convert::Infallible>(()) - /// ``` - fn track_closed(self) -> TrackClosed - where - Self: Sized, - { - TrackClosed::new(self) - } -} - -impl SinkTestExt for W where W: Sink {} diff --git a/futures-test/src/stream/mod.rs b/futures-test/src/stream/mod.rs deleted file mode 100644 index 904f802875..0000000000 --- a/futures-test/src/stream/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Additional combinators for testing streams. - -use futures_core::stream::Stream; - -pub use crate::assert_unmoved::AssertUnmoved; -pub use crate::interleave_pending::InterleavePending; - -/// Additional combinators for testing streams. -pub trait StreamTestExt: Stream { - /// Asserts that the given is not moved after being polled. - /// - /// A check for movement is performed each time the stream is polled - /// and when `Drop` is called. - /// - /// Aside from keeping track of the location at which the stream was first - /// polled and providing assertions, this stream adds no runtime behavior - /// and simply delegates to the child stream. - fn assert_unmoved(self) -> AssertUnmoved - where - Self: Sized, - { - AssertUnmoved::new(self) - } - - /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending) - /// in between each item of the 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; - /// - /// let stream = stream::iter(vec![1, 2]).interleave_pending(); - /// let mut stream = pin!(stream); - /// - /// let mut cx = noop_context(); - /// - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending); - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending); - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(2))); - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Pending); - /// assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(None)); - /// ``` - fn interleave_pending(self) -> InterleavePending - where - Self: Sized, - { - InterleavePending::new(self) - } -} - -impl StreamTestExt for St where St: Stream {} diff --git a/futures-test/src/task/context.rs b/futures-test/src/task/context.rs deleted file mode 100644 index 408dfdfef7..0000000000 --- a/futures-test/src/task/context.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::task::{noop_waker_ref, panic_waker_ref}; -use futures_core::task::Context; - -/// Create a new [`Context`](core::task::Context) where the -/// [waker](core::task::Context::waker) will panic if used. -/// -/// # Examples -/// -/// ```should_panic -/// use futures_test::task::panic_context; -/// -/// let cx = panic_context(); -/// cx.waker().wake_by_ref(); // Will panic -/// ``` -pub fn panic_context() -> Context<'static> { - Context::from_waker(panic_waker_ref()) -} - -/// Create a new [`Context`](core::task::Context) where the -/// [waker](core::task::Context::waker) will ignore any uses. -/// -/// # Examples -/// -/// ``` -/// use core::pin::pin; -/// -/// use futures::future::Future; -/// use futures::task::Poll; -/// use futures_test::task::noop_context; -/// -/// let future = async { 5 }; -/// let future = pin!(future); -/// -/// assert_eq!(future.poll(&mut noop_context()), Poll::Ready(5)); -/// ``` -pub fn noop_context() -> Context<'static> { - Context::from_waker(noop_waker_ref()) -} diff --git a/futures-test/src/task/mod.rs b/futures-test/src/task/mod.rs deleted file mode 100644 index e10ecbb875..0000000000 --- a/futures-test/src/task/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -// TODO: note that paths like futures_core::task::Context actually get redirected to core::task::Context -// in the rendered docs. Is this desirable? If so, should we change the paths here? -// -// Also, there is cross crate links in here. They are not going to work anytime soon. Do we put https links -// in here? to here: https://rust-lang.github.io/futures-api-docs? The problem is these have a -// version hardcoded in the url: 0.3.0-alpha.16 We could link to docs.rs, but currently that says: -// docs.rs failed to build futures-0.3.0-alpha.16 -> ok the reason seems to be that they are on -// 2019-04-17 which does still have futures-api unstable feature, so that should get solved. -// -//! Task related testing utilities. -//! -//! This module provides utilities for creating test -//! [`Context`](futures_core::task::Context)s, -//! [`Waker`](futures_core::task::Waker)s and -//! [`Spawn`](futures_task::Spawn) implementations. -//! -//! Test contexts: -//! - [`noop_context`] creates a context that ignores calls to -//! [`cx.waker().wake_by_ref()`](futures_core::task::Waker). -//! - [`panic_context`] creates a context that panics when -//! [`cx.waker().wake_by_ref()`](futures_core::task::Waker) is called. -//! -//! Test wakers: -//! - [`noop_waker`] creates a waker that ignores calls to -//! [`wake`](futures_core::task::Waker). -//! - [`panic_waker`](panic_waker()) creates a waker that panics when -//! [`wake`](futures_core::task::Waker) is called. -//! - [`new_count_waker`] creates a waker that increments a counter whenever -//! [`wake`](futures_core::task::Waker) is called. -//! -//! Test spawners: -//! - [`NoopSpawner`] ignores calls to -//! [`spawn`](futures_util::task::SpawnExt::spawn) -//! - [`PanicSpawner`] panics if [`spawn`](futures_util::task::SpawnExt::spawn) is -//! called. -//! - [`RecordSpawner`] records the spawned futures. -//! -//! For convenience there additionally exist various functions that directly -//! return waker/spawner references: [`noop_waker_ref`], [`panic_waker_ref`], -//! [`noop_spawner_mut`] and [`panic_spawner_mut`]. - -mod context; -pub use self::context::{noop_context, panic_context}; - -mod noop_spawner; -pub use self::noop_spawner::{noop_spawner_mut, NoopSpawner}; - -pub use futures_util::task::{noop_waker, noop_waker_ref}; - -mod panic_spawner; -pub use self::panic_spawner::{panic_spawner_mut, PanicSpawner}; - -mod panic_waker; -pub use self::panic_waker::{panic_waker, panic_waker_ref}; - -mod record_spawner; -pub use self::record_spawner::RecordSpawner; - -mod wake_counter; -pub use self::wake_counter::{new_count_waker, AwokenCount}; diff --git a/futures-test/src/task/noop_spawner.rs b/futures-test/src/task/noop_spawner.rs deleted file mode 100644 index 8967f91ec4..0000000000 --- a/futures-test/src/task/noop_spawner.rs +++ /dev/null @@ -1,52 +0,0 @@ -use futures_task::{FutureObj, Spawn, SpawnError}; - -/// An implementation of [`Spawn`](futures_task::Spawn) that -/// discards spawned futures when used. -/// -/// # Examples -/// -/// ``` -/// use futures::task::SpawnExt; -/// use futures_test::task::NoopSpawner; -/// -/// let spawner = NoopSpawner::new(); -/// spawner.spawn(async { }).unwrap(); -/// ``` -#[derive(Debug)] -pub struct NoopSpawner { - _reserved: (), -} - -impl NoopSpawner { - /// Create a new instance - pub fn new() -> Self { - Self { _reserved: () } - } -} - -impl Spawn for NoopSpawner { - fn spawn_obj(&self, _future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - Ok(()) - } -} - -impl Default for NoopSpawner { - fn default() -> Self { - Self::new() - } -} - -/// Get a reference to a singleton instance of [`NoopSpawner`]. -/// -/// # Examples -/// -/// ``` -/// use futures::task::SpawnExt; -/// use futures_test::task::noop_spawner_mut; -/// -/// let spawner = noop_spawner_mut(); -/// spawner.spawn(async { }).unwrap(); -/// ``` -pub fn noop_spawner_mut() -> &'static mut NoopSpawner { - Box::leak(Box::new(NoopSpawner::new())) -} diff --git a/futures-test/src/task/panic_spawner.rs b/futures-test/src/task/panic_spawner.rs deleted file mode 100644 index e29463df6d..0000000000 --- a/futures-test/src/task/panic_spawner.rs +++ /dev/null @@ -1,54 +0,0 @@ -use futures_task::{FutureObj, Spawn, SpawnError}; - -/// An implementation of [`Spawn`](futures_task::Spawn) that panics -/// when used. -/// -/// # Examples -/// -/// ```should_panic -/// use futures::task::SpawnExt; -/// use futures_test::task::PanicSpawner; -/// -/// let spawn = PanicSpawner::new(); -/// spawn.spawn(async { })?; // Will panic -/// # Ok::<(), Box>(()) -/// ``` -#[derive(Debug)] -pub struct PanicSpawner { - _reserved: (), -} - -impl PanicSpawner { - /// Create a new instance - pub fn new() -> Self { - Self { _reserved: () } - } -} - -impl Spawn for PanicSpawner { - fn spawn_obj(&self, _future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - panic!("should not spawn") - } -} - -impl Default for PanicSpawner { - fn default() -> Self { - Self::new() - } -} - -/// Get a reference to a singleton instance of [`PanicSpawner`]. -/// -/// # Examples -/// -/// ```should_panic -/// use futures::task::SpawnExt; -/// use futures_test::task::panic_spawner_mut; -/// -/// let spawner = panic_spawner_mut(); -/// spawner.spawn(async { })?; // Will panic -/// # Ok::<(), Box>(()) -/// ``` -pub fn panic_spawner_mut() -> &'static mut PanicSpawner { - Box::leak(Box::new(PanicSpawner::new())) -} diff --git a/futures-test/src/task/panic_waker.rs b/futures-test/src/task/panic_waker.rs deleted file mode 100644 index 38e2443156..0000000000 --- a/futures-test/src/task/panic_waker.rs +++ /dev/null @@ -1,70 +0,0 @@ -use core::ptr::null; -use futures_core::task::{RawWaker, RawWakerVTable, Waker}; - -unsafe fn clone_panic_waker(_data: *const ()) -> RawWaker { - raw_panic_waker() -} - -unsafe fn noop(_data: *const ()) {} - -unsafe fn wake_panic(_data: *const ()) { - if !std::thread::panicking() { - panic!("should not be woken"); - } -} - -const PANIC_WAKER_VTABLE: RawWakerVTable = - RawWakerVTable::new(clone_panic_waker, wake_panic, wake_panic, noop); - -const fn raw_panic_waker() -> RawWaker { - RawWaker::new(null(), &PANIC_WAKER_VTABLE) -} - -/// Create a new [`Waker`](futures_core::task::Waker) which will -/// panic when `wake()` is called on it. The [`Waker`] can be converted -/// into a [`Waker`] which will behave the same way. -/// -/// # Examples -/// -/// ```should_panic -/// use futures_test::task::panic_waker; -/// -/// let waker = panic_waker(); -/// waker.wake(); // Will panic -/// ``` -pub fn panic_waker() -> Waker { - // FIXME: Since 1.46.0 we can use transmute in consts, allowing this function to be const. - unsafe { Waker::from_raw(raw_panic_waker()) } -} - -/// Get a global reference to a -/// [`Waker`](futures_core::task::Waker) referencing a singleton -/// instance of a [`Waker`] which panics when woken. -/// -/// # Examples -/// -/// ```should_panic -/// use futures_test::task::panic_waker_ref; -/// -/// let waker = panic_waker_ref(); -/// waker.wake_by_ref(); // Will panic -/// ``` -pub fn panic_waker_ref() -> &'static Waker { - struct SyncRawWaker(RawWaker); - unsafe impl Sync for SyncRawWaker {} - - static PANIC_WAKER_INSTANCE: SyncRawWaker = SyncRawWaker(raw_panic_waker()); - - // SAFETY: `Waker` is #[repr(transparent)] over its `RawWaker`. - unsafe { &*(&PANIC_WAKER_INSTANCE.0 as *const RawWaker as *const Waker) } -} - -#[cfg(test)] -mod tests { - #[test] - #[should_panic(expected = "should not be woken")] - fn issue_2091_cross_thread_segfault() { - let waker = std::thread::spawn(super::panic_waker_ref).join().unwrap(); - waker.wake_by_ref(); - } -} diff --git a/futures-test/src/task/record_spawner.rs b/futures-test/src/task/record_spawner.rs deleted file mode 100644 index 59539fa217..0000000000 --- a/futures-test/src/task/record_spawner.rs +++ /dev/null @@ -1,39 +0,0 @@ -use futures_task::{FutureObj, Spawn, SpawnError}; -use std::cell::{Ref, RefCell}; - -/// An implementation of [`Spawn`](futures_task::Spawn) that records -/// any [`Future`](futures_core::future::Future)s spawned on it. -/// -/// # Examples -/// -/// ``` -/// use futures::task::SpawnExt; -/// use futures_test::task::RecordSpawner; -/// -/// let recorder = RecordSpawner::new(); -/// recorder.spawn(async { }).unwrap(); -/// assert_eq!(recorder.spawned().len(), 1); -/// ``` -#[derive(Debug, Default)] -pub struct RecordSpawner { - spawned: RefCell>>, -} - -impl RecordSpawner { - /// Create a new instance - pub fn new() -> Self { - Default::default() - } - - /// Inspect any futures that were spawned onto this [`Spawn`]. - pub fn spawned(&self) -> Ref<'_, Vec>> { - self.spawned.borrow() - } -} - -impl Spawn for RecordSpawner { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - self.spawned.borrow_mut().push(future); - Ok(()) - } -} diff --git a/futures-test/src/task/wake_counter.rs b/futures-test/src/task/wake_counter.rs deleted file mode 100644 index 52c63e1cc9..0000000000 --- a/futures-test/src/task/wake_counter.rs +++ /dev/null @@ -1,59 +0,0 @@ -use futures_core::task::Waker; -use futures_util::task::{self, ArcWake}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; - -/// Number of times the waker was awoken. -/// -/// See [`new_count_waker`] for usage. -#[derive(Debug)] -pub struct AwokenCount { - inner: Arc, -} - -impl AwokenCount { - /// Get the current count. - pub fn get(&self) -> usize { - self.inner.count.load(Ordering::SeqCst) - } -} - -impl PartialEq for AwokenCount { - fn eq(&self, other: &usize) -> bool { - self.get() == *other - } -} - -#[derive(Debug)] -struct WakerInner { - count: AtomicUsize, -} - -impl ArcWake for WakerInner { - fn wake_by_ref(arc_self: &Arc) { - let _ = arc_self.count.fetch_add(1, Ordering::SeqCst); - } -} - -/// Create a new [`Waker`] that counts the number of times it's awoken. -/// -/// [`Waker`]: futures_core::task::Waker -/// -/// # Examples -/// -/// ``` -/// use futures_test::task::new_count_waker; -/// -/// let (waker, count) = new_count_waker(); -/// -/// assert_eq!(count, 0); -/// -/// waker.wake_by_ref(); -/// waker.wake(); -/// -/// assert_eq!(count, 2); -/// ``` -pub fn new_count_waker() -> (Waker, AwokenCount) { - let inner = Arc::new(WakerInner { count: AtomicUsize::new(0) }); - (task::waker(inner.clone()), AwokenCount { inner }) -} diff --git a/futures-test/src/track_closed.rs b/futures-test/src/track_closed.rs deleted file mode 100644 index be883b1491..0000000000 --- a/futures-test/src/track_closed.rs +++ /dev/null @@ -1,143 +0,0 @@ -use futures_io::AsyncWrite; -use futures_sink::Sink; -use std::{ - io::{self, IoSlice}, - pin::Pin, - task::{Context, Poll}, -}; - -/// Async wrapper that tracks whether it has been closed. -/// -/// See the `track_closed` methods on: -/// * [`SinkTestExt`](crate::sink::SinkTestExt::track_closed) -/// * [`AsyncWriteTestExt`](crate::io::AsyncWriteTestExt::track_closed) -#[pin_project::pin_project] -#[derive(Debug)] -pub struct TrackClosed { - #[pin] - inner: T, - closed: bool, -} - -impl TrackClosed { - pub(crate) fn new(inner: T) -> Self { - Self { inner, closed: false } - } - - /// Check whether this object has been closed. - pub fn is_closed(&self) -> bool { - self.closed - } - - /// Acquires a reference to the underlying object that this adaptor is - /// wrapping. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Acquires a mutable reference to the underlying object that this - /// adaptor is wrapping. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Acquires a pinned mutable reference to the underlying object that - /// this adaptor is wrapping. - pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { - self.project().inner - } - - /// Consumes this adaptor returning the underlying object. - pub fn into_inner(self) -> T { - self.inner - } -} - -impl AsyncWrite for TrackClosed { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - if self.is_closed() { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - "Attempted to write after stream was closed", - ))); - } - self.project().inner.poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.is_closed() { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - "Attempted to flush after stream was closed", - ))); - } - assert!(!self.is_closed()); - self.project().inner.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.is_closed() { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - "Attempted to close after stream was closed", - ))); - } - let this = self.project(); - match this.inner.poll_close(cx) { - Poll::Ready(Ok(())) => { - *this.closed = true; - Poll::Ready(Ok(())) - } - other => other, - } - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - if self.is_closed() { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - "Attempted to write after stream was closed", - ))); - } - self.project().inner.poll_write_vectored(cx, bufs) - } -} - -impl> Sink for TrackClosed { - type Error = T::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - assert!(!self.is_closed()); - self.project().inner.poll_ready(cx) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - assert!(!self.is_closed()); - self.project().inner.start_send(item) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - assert!(!self.is_closed()); - self.project().inner.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - assert!(!self.is_closed()); - let this = self.project(); - match this.inner.poll_close(cx) { - Poll::Ready(Ok(())) => { - *this.closed = true; - Poll::Ready(Ok(())) - } - other => other, - } - } -} diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml deleted file mode 100644 index e0c4148be7..0000000000 --- a/futures-util/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "futures-util" -version = "0.4.0-alpha.0" -edition = "2018" -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" -description = """ -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/std"] -alloc = ["futures-core/alloc", "futures-task/alloc", "slab"] -async-await = [] -async-await-macro = ["async-await", "futures-macro"] -compat = ["std", "futures_01", "libc"] -io-compat = ["io", "compat", "tokio-io", "libc"] -sink = ["futures-sink"] -io = ["std", "futures-io", "memchr"] -channel = ["std", "futures-channel"] -portable-atomic = ["futures-core/portable-atomic"] - -# Unstable features -# These features are outside of the normal semver guarantees and require the -# `unstable` feature as an explicit opt-in to unstable API. -unstable = [] -bilock = [] -write-all-vectored = ["io"] - -[dependencies] -futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false } -futures-task = { path = "../futures-task", version = "=0.4.0-alpha.0", default-features = false } -futures-channel = { path = "../futures-channel", version = "=0.4.0-alpha.0", 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.4.0-alpha.0", default-features = false, optional = true } -futures-macro = { path = "../futures-macro", version = "=0.4.0-alpha.0", 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 } -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" } -tokio = "0.1.11" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/futures-util/LICENSE-APACHE b/futures-util/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures-util/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures-util/LICENSE-MIT b/futures-util/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures-util/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures-util/README.md b/futures-util/README.md deleted file mode 100644 index d4bcad3406..0000000000 --- a/futures-util/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# futures-util - -Common utilities and extension traits for the futures-rs library. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -futures-util = "0.3" -``` - -The current `futures-util` requires Rust 1.68 or later. - -## License - -Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or -[MIT license](LICENSE-MIT) at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/futures-util/benches/bilock.rs b/futures-util/benches/bilock.rs deleted file mode 100644 index 013f3351e4..0000000000 --- a/futures-util/benches/bilock.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![feature(test)] -#![cfg(feature = "bilock")] - -extern crate test; - -use futures::task::Poll; -use futures_test::task::noop_context; -use futures_util::lock::BiLock; - -use crate::test::Bencher; - -#[bench] -fn contended(b: &mut Bencher) { - let mut context = noop_context(); - - b.iter(|| { - let (x, y) = BiLock::new(1); - - for _ in 0..1000 { - let x_guard = match x.poll_lock(&mut context) { - Poll::Ready(guard) => guard, - _ => panic!(), - }; - - // Try poll second lock while first lock still holds the lock - match y.poll_lock(&mut context) { - Poll::Pending => (), - _ => panic!(), - }; - - drop(x_guard); - - let y_guard = match y.poll_lock(&mut context) { - Poll::Ready(guard) => guard, - _ => panic!(), - }; - - drop(y_guard); - } - (x, y) - }); -} - -#[bench] -fn lock_unlock(b: &mut Bencher) { - let mut context = noop_context(); - - b.iter(|| { - let (x, y) = BiLock::new(1); - - for _ in 0..1000 { - let x_guard = match x.poll_lock(&mut context) { - Poll::Ready(guard) => guard, - _ => panic!(), - }; - - drop(x_guard); - - let y_guard = match y.poll_lock(&mut context) { - Poll::Ready(guard) => guard, - _ => panic!(), - }; - - drop(y_guard); - } - (x, y) - }) -} diff --git a/futures-util/benches/flatten_unordered.rs b/futures-util/benches/flatten_unordered.rs deleted file mode 100644 index 517b2816c3..0000000000 --- a/futures-util/benches/flatten_unordered.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![feature(test)] - -extern crate test; -use crate::test::Bencher; - -use futures::channel::oneshot; -use futures::executor::block_on; -use futures::future; -use futures::stream::{self, StreamExt}; -use futures::task::Poll; -use futures_util::FutureExt; -use std::collections::VecDeque; -use std::thread; - -#[bench] -fn oneshot_streams(b: &mut Bencher) { - const STREAM_COUNT: usize = 10_000; - const STREAM_ITEM_COUNT: usize = 1; - - b.iter(|| { - let mut txs = VecDeque::with_capacity(STREAM_COUNT); - let mut rxs = Vec::new(); - - for _ in 0..STREAM_COUNT { - let (tx, rx) = oneshot::channel(); - txs.push_back(tx); - rxs.push(rx); - } - - thread::spawn(move || { - let mut last = 1; - while let Some(tx) = txs.pop_front() { - let _ = tx.send(stream::iter(last..last + STREAM_ITEM_COUNT)); - last += STREAM_ITEM_COUNT; - } - }); - - let mut flatten = stream::iter(rxs) - .map(|recv| recv.into_stream().map(|val| val.unwrap()).flatten()) - .flatten_unordered(None); - - block_on(future::poll_fn(move |cx| { - let mut count = 0; - loop { - match flatten.poll_next_unpin(cx) { - Poll::Ready(None) => break, - Poll::Ready(Some(_)) => { - count += 1; - } - _ => {} - } - } - assert_eq!(count, STREAM_COUNT * STREAM_ITEM_COUNT); - - Poll::Ready(()) - })) - }); -} diff --git a/futures-util/benches/futures_unordered.rs b/futures-util/benches/futures_unordered.rs deleted file mode 100644 index d5fe7a59de..0000000000 --- a/futures-util/benches/futures_unordered.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![feature(test)] - -extern crate test; -use crate::test::Bencher; - -use futures::channel::oneshot; -use futures::executor::block_on; -use futures::future; -use futures::stream::{FuturesUnordered, StreamExt}; -use futures::task::Poll; -use std::collections::VecDeque; -use std::thread; - -#[bench] -fn oneshots(b: &mut Bencher) { - const NUM: usize = 10_000; - - b.iter(|| { - let mut txs = VecDeque::with_capacity(NUM); - let mut rxs = FuturesUnordered::new(); - - for _ in 0..NUM { - let (tx, rx) = oneshot::channel(); - txs.push_back(tx); - rxs.push(rx); - } - - thread::spawn(move || { - while let Some(tx) = txs.pop_front() { - let _ = tx.send("hello"); - } - }); - - block_on(future::poll_fn(move |cx| { - loop { - if let Poll::Ready(None) = rxs.poll_next_unpin(cx) { - break; - } - } - Poll::Ready(()) - })) - }); -} diff --git a/futures-util/benches/select.rs b/futures-util/benches/select.rs deleted file mode 100644 index 6609d916eb..0000000000 --- a/futures-util/benches/select.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![feature(test)] - -extern crate test; -use crate::test::Bencher; - -use futures::executor::block_on; -use futures::stream::{repeat, select, StreamExt}; - -#[bench] -fn select_streams(b: &mut Bencher) { - const STREAM_COUNT: usize = 10_000; - - b.iter(|| { - let stream1 = repeat(1).take(STREAM_COUNT); - let stream2 = repeat(2).take(STREAM_COUNT); - let stream3 = repeat(3).take(STREAM_COUNT); - let stream4 = repeat(4).take(STREAM_COUNT); - let stream5 = repeat(5).take(STREAM_COUNT); - let stream6 = repeat(6).take(STREAM_COUNT); - let stream7 = repeat(7).take(STREAM_COUNT); - let count = block_on( - select( - stream1, - select( - stream2, - select(stream3, select(stream4, select(stream5, select(stream6, stream7)))), - ), - ) - .count(), - ); - assert_eq!(count, STREAM_COUNT * 7); - }); -} diff --git a/futures-util/src/abortable.rs b/futures-util/src/abortable.rs deleted file mode 100644 index e1e79e371d..0000000000 --- a/futures-util/src/abortable.rs +++ /dev/null @@ -1,209 +0,0 @@ -use crate::task::AtomicWaker; -use alloc::sync::Arc; -use core::fmt; -use core::pin::Pin; -use core::sync::atomic::{AtomicBool, Ordering}; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_core::Stream; -use pin_project_lite::pin_project; - -pin_project! { - /// A future/stream which can be remotely short-circuited using an `AbortHandle`. - #[derive(Debug, Clone)] - #[must_use = "futures/streams do nothing unless you poll them"] - pub struct Abortable { - #[pin] - task: T, - inner: Arc, - } -} - -impl Abortable { - /// Creates a new `Abortable` future/stream using an existing `AbortRegistration`. - /// `AbortRegistration`s can be acquired through `AbortHandle::new`. - /// - /// When `abort` is called on the handle tied to `reg` or if `abort` has - /// already been called, the future/stream will complete immediately without making - /// any further progress. - /// - /// # Examples: - /// - /// Usage with futures: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::{Abortable, AbortHandle, Aborted}; - /// - /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); - /// let future = Abortable::new(async { 2 }, abort_registration); - /// abort_handle.abort(); - /// assert_eq!(future.await, Err(Aborted)); - /// # }); - /// ``` - /// - /// Usage with streams: - /// - /// ``` - /// # futures::executor::block_on(async { - /// # use futures::future::{Abortable, AbortHandle}; - /// # use futures::stream::{self, StreamExt}; - /// - /// let (abort_handle, abort_registration) = AbortHandle::new_pair(); - /// let mut stream = Abortable::new(stream::iter(vec![1, 2, 3]), abort_registration); - /// abort_handle.abort(); - /// assert_eq!(stream.next().await, None); - /// # }); - /// ``` - pub fn new(task: T, reg: AbortRegistration) -> Self { - Self { task, inner: reg.inner } - } - - /// Checks whether the task has been aborted. Note that all this - /// method indicates is whether [`AbortHandle::abort`] was *called*. - /// This means that it will return `true` even if: - /// * `abort` was called after the task had completed. - /// * `abort` was called while the task was being polled - the task may still be running and - /// will not be stopped until `poll` returns. - pub fn is_aborted(&self) -> bool { - self.inner.aborted.load(Ordering::Relaxed) - } -} - -/// A registration handle for an `Abortable` task. -/// Values of this type can be acquired from `AbortHandle::new` and are used -/// in calls to `Abortable::new`. -#[derive(Debug)] -pub struct AbortRegistration { - pub(crate) inner: Arc, -} - -impl AbortRegistration { - /// Create an [`AbortHandle`] from the given [`AbortRegistration`]. - /// - /// The created [`AbortHandle`] is functionally the same as any other - /// [`AbortHandle`]s that are associated with the same [`AbortRegistration`], - /// such as the one created by [`AbortHandle::new_pair`]. - pub fn handle(&self) -> AbortHandle { - AbortHandle { inner: self.inner.clone() } - } -} - -/// A handle to an `Abortable` task. -#[derive(Debug, Clone)] -pub struct AbortHandle { - inner: Arc, -} - -impl AbortHandle { - /// Creates an (`AbortHandle`, `AbortRegistration`) pair which can be used - /// to abort a running future or stream. - /// - /// This function is usually paired with a call to [`Abortable::new`]. - pub fn new_pair() -> (Self, AbortRegistration) { - let inner = - Arc::new(AbortInner { waker: AtomicWaker::new(), aborted: AtomicBool::new(false) }); - - (Self { inner: inner.clone() }, AbortRegistration { inner }) - } -} - -// Inner type storing the waker to awaken and a bool indicating that it -// should be aborted. -#[derive(Debug)] -pub(crate) struct AbortInner { - pub(crate) waker: AtomicWaker, - pub(crate) aborted: AtomicBool, -} - -/// Indicator that the `Abortable` task was aborted. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Aborted; - -impl fmt::Display for Aborted { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "`Abortable` future has been aborted") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Aborted {} - -impl Abortable { - fn try_poll( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - poll: impl Fn(Pin<&mut T>, &mut Context<'_>) -> Poll, - ) -> Poll> { - // Check if the task has been aborted - if self.is_aborted() { - return Poll::Ready(Err(Aborted)); - } - - // attempt to complete the task - if let Poll::Ready(x) = poll(self.as_mut().project().task, cx) { - return Poll::Ready(Ok(x)); - } - - // Register to receive a wakeup if the task is aborted in the future - self.inner.waker.register(cx.waker()); - - // Check to see if the task was aborted between the first check and - // registration. - // Checking with `is_aborted` which uses `Relaxed` is sufficient because - // `register` introduces an `AcqRel` barrier. - if self.is_aborted() { - return Poll::Ready(Err(Aborted)); - } - - Poll::Pending - } -} - -impl Future for Abortable -where - Fut: Future, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.try_poll(cx, |fut, cx| fut.poll(cx)) - } -} - -impl Stream for Abortable -where - St: Stream, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.try_poll(cx, |stream, cx| stream.poll_next(cx)).map(Result::ok).map(Option::flatten) - } -} - -impl AbortHandle { - /// Abort the `Abortable` stream/future associated with this handle. - /// - /// Notifies the Abortable task associated with this handle that it - /// should abort. Note that if the task is currently being polled on - /// another thread, it will not immediately stop running. Instead, it will - /// continue to run until its poll method returns. - pub fn abort(&self) { - self.inner.aborted.store(true, Ordering::Relaxed); - self.inner.waker.wake(); - } - - /// Checks whether [`AbortHandle::abort`] was *called* on any associated - /// [`AbortHandle`]s, which includes all the [`AbortHandle`]s linked with - /// the same [`AbortRegistration`]. This means that it will return `true` - /// even if: - /// * `abort` was called after the task had completed. - /// * `abort` was called while the task was being polled - the task may still be running and - /// will not be stopped until `poll` returns. - /// - /// This operation has a Relaxed ordering. - pub fn is_aborted(&self) -> bool { - self.inner.aborted.load(Ordering::Relaxed) - } -} diff --git a/futures-util/src/async_await/join_mod.rs b/futures-util/src/async_await/join_mod.rs deleted file mode 100644 index 21bb2ebdee..0000000000 --- a/futures-util/src/async_await/join_mod.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! The `join` macro. - -macro_rules! document_join_macro { - ($join:item $try_join:item) => { - /// Polls multiple futures simultaneously, returning a tuple - /// of all results once complete. - /// - /// While `join!(a, b)` is similar to `(a.await, b.await)`, - /// `join!` polls both futures concurrently and therefore is more efficient. - /// - /// This macro is only usable inside of async functions, closures, and blocks. - /// It is also gated behind the `async-await` feature of this library, which is - /// activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::join; - /// - /// let a = async { 1 }; - /// let b = async { 2 }; - /// assert_eq!(join!(a, b), (1, 2)); - /// - /// // `join!` is variadic, so you can pass any number of futures - /// let c = async { 3 }; - /// let d = async { 4 }; - /// let e = async { 5 }; - /// assert_eq!(join!(c, d, e), (3, 4, 5)); - /// # }); - /// ``` - $join - - /// Polls multiple futures simultaneously, resolving to a [`Result`] containing - /// either a tuple of the successful outputs or an error. - /// - /// `try_join!` is similar to [`join!`], but completes immediately if any of - /// the futures return an error. - /// - /// This macro is only usable inside of async functions, closures, and blocks. - /// It is also gated behind the `async-await` feature of this library, which is - /// activated by default. - /// - /// # Examples - /// - /// When used on multiple futures that return `Ok`, `try_join!` will return - /// `Ok` of a tuple of the values: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::try_join; - /// - /// let a = async { Ok::(1) }; - /// let b = async { Ok::(2) }; - /// assert_eq!(try_join!(a, b), Ok((1, 2))); - /// - /// // `try_join!` is variadic, so you can pass any number of futures - /// let c = async { Ok::(3) }; - /// let d = async { Ok::(4) }; - /// let e = async { Ok::(5) }; - /// assert_eq!(try_join!(c, d, e), Ok((3, 4, 5))); - /// # }); - /// ``` - /// - /// If one of the futures resolves to an error, `try_join!` will return - /// that error: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::try_join; - /// - /// let a = async { Ok::(1) }; - /// let b = async { Err::(2) }; - /// - /// assert_eq!(try_join!(a, b), Err(2)); - /// # }); - /// ``` - $try_join - } -} - -#[doc(hidden)] -pub use futures_macro::join_internal; - -#[doc(hidden)] -pub use futures_macro::try_join_internal; - -document_join_macro! { - #[macro_export] - macro_rules! join { - ($($tokens:tt)*) => {{ - use $crate::__private as __futures_crate; - $crate::join_internal! { - $( $tokens )* - } - }} - } - - #[macro_export] - macro_rules! try_join { - ($($tokens:tt)*) => {{ - use $crate::__private as __futures_crate; - $crate::try_join_internal! { - $( $tokens )* - } - }} - } -} diff --git a/futures-util/src/async_await/mod.rs b/futures-util/src/async_await/mod.rs deleted file mode 100644 index 09152f94c5..0000000000 --- a/futures-util/src/async_await/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Await -//! -//! This module contains a number of functions and combinators for working -//! with `async`/`await` code. - -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, Stream}; - -#[macro_use] -mod poll; -pub use self::poll::*; - -#[macro_use] -mod pending; -pub use self::pending::*; - -// Primary export is a macro -#[cfg(feature = "async-await-macro")] -mod join_mod; -#[cfg(feature = "async-await-macro")] -pub use self::join_mod::*; - -// Primary export is a macro -#[cfg(feature = "async-await-macro")] -mod select_mod; -#[cfg(feature = "async-await-macro")] -pub use self::select_mod::*; - -// Primary export is a macro -#[cfg(feature = "std")] -#[cfg(feature = "async-await-macro")] -mod stream_select_mod; -#[cfg(feature = "std")] -#[cfg(feature = "async-await-macro")] -pub use self::stream_select_mod::*; - -#[cfg(feature = "std")] -#[cfg(feature = "async-await-macro")] -mod random; -#[cfg(feature = "std")] -#[cfg(feature = "async-await-macro")] -pub use self::random::*; - -#[doc(hidden)] -#[inline(always)] -pub fn assert_unpin(_: &T) {} - -#[doc(hidden)] -#[inline(always)] -pub fn assert_fused_future(_: &T) {} - -#[doc(hidden)] -#[inline(always)] -pub fn assert_fused_stream(_: &T) {} diff --git a/futures-util/src/async_await/pending.rs b/futures-util/src/async_await/pending.rs deleted file mode 100644 index 5d7a431811..0000000000 --- a/futures-util/src/async_await/pending.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; - -/// A macro which yields to the event loop once. -/// -/// This is equivalent to returning [`Poll::Pending`](futures_core::task::Poll) -/// from a [`Future::poll`](futures_core::future::Future::poll) implementation. -/// Similarly, when using this macro, it must be ensured that [`wake`](std::task::Waker::wake) -/// is called somewhere when further progress can be made. -/// -/// This macro is only usable inside of async functions, closures, and blocks. -/// It is also gated behind the `async-await` feature of this library, which is -/// activated by default. -#[macro_export] -macro_rules! pending { - () => { - $crate::__private::async_await::pending_once().await - }; -} - -#[doc(hidden)] -pub fn pending_once() -> PendingOnce { - PendingOnce { is_ready: false } -} - -#[allow(missing_debug_implementations)] -#[doc(hidden)] -pub struct PendingOnce { - is_ready: bool, -} - -impl Future for PendingOnce { - type Output = (); - fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { - if self.is_ready { - Poll::Ready(()) - } else { - self.is_ready = true; - Poll::Pending - } - } -} diff --git a/futures-util/src/async_await/poll.rs b/futures-util/src/async_await/poll.rs deleted file mode 100644 index b62f45a943..0000000000 --- a/futures-util/src/async_await/poll.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::future::FutureExt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; - -/// A macro which returns the result of polling a future once within the -/// current `async` context. -/// -/// This macro is only usable inside of `async` functions, closures, and blocks. -/// It is also gated behind the `async-await` feature of this library, which is -/// activated by default. -/// -/// If you need the result of polling a [`Stream`](crate::stream::Stream), -/// you can use this macro with the [`next`](crate::stream::StreamExt::next) method: -/// `poll!(stream.next())`. -#[macro_export] -macro_rules! poll { - ($x:expr $(,)?) => { - $crate::__private::async_await::poll($x).await - }; -} - -#[doc(hidden)] -pub fn poll(future: F) -> PollOnce { - PollOnce { future } -} - -#[allow(missing_debug_implementations)] -#[doc(hidden)] -pub struct PollOnce { - future: F, -} - -impl Future for PollOnce { - type Output = Poll; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready(self.future.poll_unpin(cx)) - } -} diff --git a/futures-util/src/async_await/random.rs b/futures-util/src/async_await/random.rs deleted file mode 100644 index 2ac2f78a87..0000000000 --- a/futures-util/src/async_await/random.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{ - cell::Cell, - collections::hash_map::DefaultHasher, - hash::Hasher, - num::Wrapping, - sync::atomic::{AtomicUsize, Ordering}, -}; - -// Based on [Fisher–Yates shuffle]. -// -// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle -#[doc(hidden)] -pub fn shuffle(slice: &mut [T]) { - for i in (1..slice.len()).rev() { - slice.swap(i, gen_index(i + 1)); - } -} - -/// Return a value from `0..n`. -fn gen_index(n: usize) -> usize { - (random() % n as u64) as usize -} - -/// Pseudorandom number generator based on [xorshift*]. -/// -/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* -fn random() -> u64 { - std::thread_local! { - static RNG: Cell> = Cell::new(Wrapping(prng_seed())); - } - - fn prng_seed() -> u64 { - static COUNTER: AtomicUsize = AtomicUsize::new(0); - - // Any non-zero seed will do - let mut seed = 0; - while seed == 0 { - let mut hasher = DefaultHasher::new(); - hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed)); - seed = hasher.finish(); - } - seed - } - - RNG.with(|rng| { - let mut x = rng.get(); - debug_assert_ne!(x.0, 0); - x ^= x >> 12; - x ^= x << 25; - x ^= x >> 27; - rng.set(x); - x.0.wrapping_mul(0x2545_f491_4f6c_dd1d) - }) -} diff --git a/futures-util/src/async_await/select_mod.rs b/futures-util/src/async_await/select_mod.rs deleted file mode 100644 index 882f125158..0000000000 --- a/futures-util/src/async_await/select_mod.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! The `select` macro. - -macro_rules! document_select_macro { - // This branch is required for `futures 0.3.1`, from before select_biased was introduced - ($select:item) => { - #[allow(clippy::too_long_first_doc_paragraph)] - /// Polls multiple futures and streams simultaneously, executing the branch - /// for the future that finishes first. If multiple futures are ready, - /// one will be pseudo-randomly selected at runtime. Futures directly - /// passed to `select!` must be `Unpin` and implement `FusedFuture`. - /// - /// If an expression which yields a `Future` is passed to `select!` - /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin` - /// requirement is relaxed, since the macro will pin the resulting `Future` - /// on the stack. However the `Future` returned by the expression must - /// still implement `FusedFuture`. - /// - /// Futures and streams which are not already fused can be fused using the - /// `.fuse()` method. Note, though, that fusing a future or stream directly - /// in the call to `select!` will not be enough to prevent it from being - /// polled after completion if the `select!` call is in a loop, so when - /// `select!`ing in a loop, users should take care to `fuse()` outside of - /// the loop. - /// - /// `select!` can be used as an expression and will return the return - /// value of the selected branch. For this reason the return type of every - /// branch in a `select!` must be the same. - /// - /// This macro is only usable inside of async functions, closures, and blocks. - /// It is also gated behind the `async-await` feature of this library, which is - /// activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::select; - /// let mut a = future::ready(4); - /// let mut b = future::pending::<()>(); - /// - /// let res = select! { - /// a_res = a => a_res + 1, - /// _ = b => 0, - /// }; - /// assert_eq!(res, 5); - /// # }); - /// ``` - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// use futures::select; - /// let mut st = stream::iter(vec![2]).fuse(); - /// let mut fut = future::pending::<()>(); - /// - /// select! { - /// x = st.next() => assert_eq!(Some(2), x), - /// _ = fut => panic!(), - /// } - /// # }); - /// ``` - /// - /// As described earlier, `select` can directly select on expressions - /// which return `Future`s - even if those do not implement `Unpin`: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// use futures::select; - /// - /// // Calling the following async fn returns a Future which does not - /// // implement Unpin - /// async fn async_identity_fn(arg: usize) -> usize { - /// arg - /// } - /// - /// let res = select! { - /// a_res = async_identity_fn(62).fuse() => a_res + 1, - /// b_res = async_identity_fn(13).fuse() => b_res, - /// }; - /// assert!(res == 63 || res == 13); - /// # }); - /// ``` - /// - /// 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!` macro for pinning a `Future` - /// on the stack. - /// - /// ``` - /// # futures::executor::block_on(async { - /// use core::pin::pin; - /// - /// use futures::future::FutureExt; - /// use futures::select; - /// - /// // Calling the following async fn returns a Future which does not - /// // implement Unpin - /// async fn async_identity_fn(arg: usize) -> usize { - /// arg - /// } - /// - /// 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 - /// let mut fut_2 = pin!(fut_2); // Pins the Future on the stack - /// - /// let res = select! { - /// a_res = fut_1 => a_res, - /// b_res = fut_2 => b_res, - /// }; - /// assert!(res == 1 || res == 2); - /// # }); - /// ``` - /// - /// `select` also accepts a `complete` branch and a `default` branch. - /// `complete` will run if all futures and streams have already been - /// exhausted. `default` will run if no futures or streams are - /// immediately ready. `complete` takes priority over `default` in - /// the case where all futures have completed. - /// A motivating use-case for passing `Future`s by name as well as for - /// `complete` blocks is to call `select!` in a loop, which is - /// demonstrated in the following example: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::select; - /// let mut a_fut = future::ready(4); - /// let mut b_fut = future::ready(6); - /// let mut total = 0; - /// - /// loop { - /// select! { - /// a = a_fut => total += a, - /// b = b_fut => total += b, - /// complete => break, - /// default => panic!(), // never runs (futures run first, then complete) - /// } - /// } - /// assert_eq!(total, 10); - /// # }); - /// ``` - /// - /// Note that the futures that have been matched over can still be mutated - /// from inside the `select!` block's branches. This can be used to implement - /// more complex behavior such as timer resets or writing into the head of - /// a stream. - $select - }; - - ($select:item $select_biased:item) => { - document_select_macro!($select); - - #[allow(clippy::too_long_first_doc_paragraph)] - /// Polls multiple futures and streams simultaneously, executing the branch - /// for the future that finishes first. Unlike [`select!`], if multiple futures are ready, - /// one will be selected in order of declaration. Futures directly - /// passed to `select_biased!` must be `Unpin` and implement `FusedFuture`. - /// - /// If an expression which yields a `Future` is passed to `select_biased!` - /// (e.g. an `async fn` call) instead of a `Future` by name the `Unpin` - /// requirement is relaxed, since the macro will pin the resulting `Future` - /// on the stack. However the `Future` returned by the expression must - /// still implement `FusedFuture`. - /// - /// Futures and streams which are not already fused can be fused using the - /// `.fuse()` method. Note, though, that fusing a future or stream directly - /// in the call to `select_biased!` will not be enough to prevent it from being - /// polled after completion if the `select_biased!` call is in a loop, so when - /// `select_biased!`ing in a loop, users should take care to `fuse()` outside of - /// the loop. - /// - /// `select_biased!` can be used as an expression and will return the return - /// value of the selected branch. For this reason the return type of every - /// branch in a `select_biased!` must be the same. - /// - /// This macro is only usable inside of async functions, closures, and blocks. - /// It is also gated behind the `async-await` feature of this library, which is - /// activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::select_biased; - /// let mut a = future::ready(4); - /// let mut b = future::pending::<()>(); - /// - /// let res = select_biased! { - /// a_res = a => a_res + 1, - /// _ = b => 0, - /// }; - /// assert_eq!(res, 5); - /// # }); - /// ``` - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// use futures::select_biased; - /// let mut st = stream::iter(vec![2]).fuse(); - /// let mut fut = future::pending::<()>(); - /// - /// select_biased! { - /// x = st.next() => assert_eq!(Some(2), x), - /// _ = fut => panic!(), - /// } - /// # }); - /// ``` - /// - /// As described earlier, `select_biased` can directly select on expressions - /// which return `Future`s - even if those do not implement `Unpin`: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// use futures::select_biased; - /// - /// // Calling the following async fn returns a Future which does not - /// // implement Unpin - /// async fn async_identity_fn(arg: usize) -> usize { - /// arg - /// } - /// - /// let res = select_biased! { - /// a_res = async_identity_fn(62).fuse() => a_res + 1, - /// b_res = async_identity_fn(13).fuse() => b_res, - /// }; - /// assert_eq!(res, 63); - /// # }); - /// ``` - /// - /// 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!` 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; - /// - /// // Calling the following async fn returns a Future which does not - /// // implement Unpin - /// async fn async_identity_fn(arg: usize) -> usize { - /// arg - /// } - /// - /// 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 - /// let mut fut_2 = pin!(fut_2); // Pins the Future on the stack - /// - /// let res = select_biased! { - /// a_res = fut_1 => a_res, - /// b_res = fut_2 => b_res, - /// }; - /// assert!(res == 1 || res == 2); - /// # }); - /// ``` - /// - /// `select_biased` also accepts a `complete` branch and a `default` branch. - /// `complete` will run if all futures and streams have already been - /// exhausted. `default` will run if no futures or streams are - /// immediately ready. `complete` takes priority over `default` in - /// the case where all futures have completed. - /// A motivating use-case for passing `Future`s by name as well as for - /// `complete` blocks is to call `select_biased!` in a loop, which is - /// demonstrated in the following example: - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::select_biased; - /// let mut a_fut = future::ready(4); - /// let mut b_fut = future::ready(6); - /// let mut total = 0; - /// - /// loop { - /// select_biased! { - /// a = a_fut => total += a, - /// b = b_fut => total += b, - /// complete => break, - /// default => panic!(), // never runs (futures run first, then complete) - /// } - /// } - /// assert_eq!(total, 10); - /// # }); - /// ``` - /// - /// Note that the futures that have been matched over can still be mutated - /// from inside the `select_biased!` block's branches. This can be used to implement - /// more complex behavior such as timer resets or writing into the head of - /// a stream. - /// - /// [`select!`]: macro.select.html - $select_biased - }; -} - -#[cfg(feature = "std")] -#[doc(hidden)] -pub use futures_macro::select_internal; - -#[doc(hidden)] -pub use futures_macro::select_biased_internal; - -document_select_macro! { - #[cfg(feature = "std")] - #[macro_export] - macro_rules! select { - ($($tokens:tt)*) => {{ - use $crate::__private as __futures_crate; - $crate::select_internal! { - $( $tokens )* - } - }} - } - - #[macro_export] - macro_rules! select_biased { - ($($tokens:tt)*) => {{ - use $crate::__private as __futures_crate; - $crate::select_biased_internal! { - $( $tokens )* - } - }} - } -} diff --git a/futures-util/src/async_await/stream_select_mod.rs b/futures-util/src/async_await/stream_select_mod.rs deleted file mode 100644 index 039e65a658..0000000000 --- a/futures-util/src/async_await/stream_select_mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! The `stream_select` macro. - -#[doc(hidden)] -pub use futures_macro::stream_select_internal; - -#[allow(clippy::too_long_first_doc_paragraph)] -/// Combines several streams, all producing the same `Item` type, into one stream. -/// This is similar to `select_all` but does not require the streams to all be the same type. -/// It also keeps the streams inline, and does not require `Box`s to be allocated. -/// Streams passed to this macro must be `Unpin`. -/// -/// If multiple streams are ready, one will be pseudo randomly selected at runtime. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::{stream, StreamExt, stream_select}; -/// let endless_ints = |i| stream::iter(vec![i].into_iter().cycle()).fuse(); -/// -/// let mut endless_numbers = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3)); -/// match endless_numbers.next().await { -/// Some(1) => println!("Got a 1"), -/// Some(2) => println!("Got a 2"), -/// Some(3) => println!("Got a 3"), -/// _ => unreachable!(), -/// } -/// # }); -/// ``` -#[macro_export] -macro_rules! stream_select { - ($($tokens:tt)*) => {{ - use $crate::__private as __futures_crate; - $crate::stream_select_internal! { - $( $tokens )* - } - }} -} diff --git a/futures-util/src/compat/compat01as03.rs b/futures-util/src/compat/compat01as03.rs deleted file mode 100644 index d63d73c7dc..0000000000 --- a/futures-util/src/compat/compat01as03.rs +++ /dev/null @@ -1,453 +0,0 @@ -use futures_01::executor::{ - spawn as spawn01, Notify as Notify01, NotifyHandle as NotifyHandle01, Spawn as Spawn01, - UnsafeNotify as UnsafeNotify01, -}; -use futures_01::{Async as Async01, Future as Future01, Stream as Stream01}; -#[cfg(feature = "sink")] -use futures_01::{AsyncSink as AsyncSink01, Sink as Sink01}; -use futures_core::{future::Future as Future03, stream::Stream as Stream03, task as task03}; -#[cfg(feature = "sink")] -use futures_sink::Sink as Sink03; -use std::boxed::Box; -use std::pin::Pin; -use std::task::Context; - -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -pub use io::{AsyncRead01CompatExt, AsyncWrite01CompatExt}; - -/// Converts a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite -/// object to a futures 0.3-compatible version, -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Compat01As03 { - pub(crate) inner: Spawn01, -} - -impl Unpin for Compat01As03 {} - -impl Compat01As03 { - /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite - /// object in a futures 0.3-compatible wrapper. - pub fn new(object: T) -> Self { - Self { inner: spawn01(object) } - } - - fn in_notify(&mut self, cx: &mut Context<'_>, f: impl FnOnce(&mut T) -> R) -> R { - let notify = &WakerToHandle(cx.waker()); - self.inner.poll_fn_notify(notify, 0, f) - } - - /// Get a reference to 0.1 Future, Stream, AsyncRead, or AsyncWrite object contained within. - pub fn get_ref(&self) -> &T { - self.inner.get_ref() - } - - /// Get a mutable reference to 0.1 Future, Stream, AsyncRead or AsyncWrite object contained - /// within. - pub fn get_mut(&mut self) -> &mut T { - self.inner.get_mut() - } - - /// Consume this wrapper to return the underlying 0.1 Future, Stream, AsyncRead, or - /// AsyncWrite object. - pub fn into_inner(self) -> T { - self.inner.into_inner() - } -} - -/// Extension trait for futures 0.1 [`Future`](futures_01::future::Future) -pub trait Future01CompatExt: Future01 { - /// Converts a futures 0.1 - /// [`Future`](futures_01::future::Future) - /// into a futures 0.3 - /// [`Future>`](futures_core::future::Future). - /// - /// ``` - /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 - /// # futures::executor::block_on(async { - /// # // TODO: These should be all using `futures::compat`, but that runs up against Cargo - /// # // feature issues - /// use futures_util::compat::Future01CompatExt; - /// - /// let future = futures_01::future::ok::(1); - /// assert_eq!(future.compat().await, Ok(1)); - /// # }); - /// ``` - fn compat(self) -> Compat01As03 - where - Self: Sized, - { - Compat01As03::new(self) - } -} -impl Future01CompatExt for Fut {} - -/// Extension trait for futures 0.1 [`Stream`](futures_01::stream::Stream) -pub trait Stream01CompatExt: Stream01 { - /// Converts a futures 0.1 - /// [`Stream`](futures_01::stream::Stream) - /// into a futures 0.3 - /// [`Stream>`](futures_core::stream::Stream). - /// - /// ``` - /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 - /// # futures::executor::block_on(async { - /// use futures::stream::StreamExt; - /// use futures_util::compat::Stream01CompatExt; - /// - /// let stream = futures_01::stream::once::(Ok(1)); - /// let mut stream = stream.compat(); - /// assert_eq!(stream.next().await, Some(Ok(1))); - /// assert_eq!(stream.next().await, None); - /// # }); - /// ``` - fn compat(self) -> Compat01As03 - where - Self: Sized, - { - Compat01As03::new(self) - } -} -impl Stream01CompatExt for St {} - -/// Extension trait for futures 0.1 [`Sink`](futures_01::sink::Sink) -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub trait Sink01CompatExt: Sink01 { - /// Converts a futures 0.1 - /// [`Sink`](futures_01::sink::Sink) - /// into a futures 0.3 - /// [`Sink`](futures_sink::Sink). - /// - /// ``` - /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 - /// # futures::executor::block_on(async { - /// use futures::{sink::SinkExt, stream::StreamExt}; - /// use futures_util::compat::{Stream01CompatExt, Sink01CompatExt}; - /// - /// let (tx, rx) = futures_01::unsync::mpsc::channel(1); - /// let (mut tx, mut rx) = (tx.sink_compat(), rx.compat()); - /// - /// tx.send(1).await.unwrap(); - /// drop(tx); - /// assert_eq!(rx.next().await, Some(Ok(1))); - /// assert_eq!(rx.next().await, None); - /// # }); - /// ``` - fn sink_compat(self) -> Compat01As03Sink - where - Self: Sized, - { - Compat01As03Sink::new(self) - } -} -#[cfg(feature = "sink")] -impl Sink01CompatExt for Si {} - -fn poll_01_to_03(x: Result, E>) -> task03::Poll> { - match x? { - Async01::Ready(t) => task03::Poll::Ready(Ok(t)), - Async01::NotReady => task03::Poll::Pending, - } -} - -impl Future03 for Compat01As03 { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> task03::Poll { - poll_01_to_03(self.in_notify(cx, Future01::poll)) - } -} - -impl Stream03 for Compat01As03 { - type Item = Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - match self.in_notify(cx, Stream01::poll)? { - Async01::Ready(Some(t)) => task03::Poll::Ready(Some(Ok(t))), - Async01::Ready(None) => task03::Poll::Ready(None), - Async01::NotReady => task03::Poll::Pending, - } - } -} - -/// Converts a futures 0.1 Sink object to a futures 0.3-compatible version -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -#[derive(Debug)] -#[must_use = "sinks do nothing unless polled"] -pub struct Compat01As03Sink { - pub(crate) inner: Spawn01, - pub(crate) buffer: Option, - pub(crate) close_started: bool, -} - -#[cfg(feature = "sink")] -impl Unpin for Compat01As03Sink {} - -#[cfg(feature = "sink")] -impl Compat01As03Sink { - /// Wraps a futures 0.1 Sink object in a futures 0.3-compatible wrapper. - pub fn new(inner: S) -> Self { - Self { inner: spawn01(inner), buffer: None, close_started: false } - } - - fn in_notify(&mut self, cx: &mut Context<'_>, f: impl FnOnce(&mut S) -> R) -> R { - let notify = &WakerToHandle(cx.waker()); - self.inner.poll_fn_notify(notify, 0, f) - } - - /// Get a reference to 0.1 Sink object contained within. - pub fn get_ref(&self) -> &S { - self.inner.get_ref() - } - - /// Get a mutable reference to 0.1 Sink contained within. - pub fn get_mut(&mut self) -> &mut S { - self.inner.get_mut() - } - - /// Consume this wrapper to return the underlying 0.1 Sink. - pub fn into_inner(self) -> S { - self.inner.into_inner() - } -} - -#[cfg(feature = "sink")] -impl Stream03 for Compat01As03Sink -where - S: Stream01, -{ - type Item = Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - match self.in_notify(cx, Stream01::poll)? { - Async01::Ready(Some(t)) => task03::Poll::Ready(Some(Ok(t))), - Async01::Ready(None) => task03::Poll::Ready(None), - Async01::NotReady => task03::Poll::Pending, - } - } -} - -#[cfg(feature = "sink")] -impl Sink03 for Compat01As03Sink -where - S: Sink01, -{ - type Error = S::SinkError; - - fn start_send(mut self: Pin<&mut Self>, item: SinkItem) -> Result<(), Self::Error> { - debug_assert!(self.buffer.is_none()); - self.buffer = Some(item); - Ok(()) - } - - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - match self.buffer.take() { - Some(item) => match self.in_notify(cx, |f| f.start_send(item))? { - AsyncSink01::Ready => task03::Poll::Ready(Ok(())), - AsyncSink01::NotReady(i) => { - self.buffer = Some(i); - task03::Poll::Pending - } - }, - None => task03::Poll::Ready(Ok(())), - } - } - - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - let item = self.buffer.take(); - match self.in_notify(cx, |f| match item { - Some(i) => match f.start_send(i)? { - AsyncSink01::Ready => f.poll_complete().map(|i| (i, None)), - AsyncSink01::NotReady(t) => Ok((Async01::NotReady, Some(t))), - }, - None => f.poll_complete().map(|i| (i, None)), - })? { - (Async01::Ready(_), _) => task03::Poll::Ready(Ok(())), - (Async01::NotReady, item) => { - self.buffer = item; - task03::Poll::Pending - } - } - } - - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - let item = self.buffer.take(); - let close_started = self.close_started; - - let result = self.in_notify(cx, |f| { - if !close_started { - if let Some(item) = item { - if let AsyncSink01::NotReady(item) = f.start_send(item)? { - return Ok((Async01::NotReady, Some(item), false)); - } - } - - if let Async01::NotReady = f.poll_complete()? { - return Ok((Async01::NotReady, None, false)); - } - } - - Ok((::close(f)?, None, true)) - }); - - match result? { - (Async01::Ready(_), _, _) => task03::Poll::Ready(Ok(())), - (Async01::NotReady, item, close_started) => { - self.buffer = item; - self.close_started = close_started; - task03::Poll::Pending - } - } - } -} - -struct NotifyWaker(task03::Waker); - -#[derive(Clone)] -struct WakerToHandle<'a>(&'a task03::Waker); - -impl From> for NotifyHandle01 { - fn from(handle: WakerToHandle<'_>) -> Self { - let ptr = Box::new(NotifyWaker(handle.0.clone())); - - unsafe { Self::new(Box::into_raw(ptr)) } - } -} - -impl Notify01 for NotifyWaker { - fn notify(&self, _: usize) { - self.0.wake_by_ref(); - } -} - -unsafe impl UnsafeNotify01 for NotifyWaker { - unsafe fn clone_raw(&self) -> NotifyHandle01 { - WakerToHandle(&self.0).into() - } - - unsafe fn drop_raw(&self) { - let ptr: *const dyn UnsafeNotify01 = self; - drop(unsafe { Box::from_raw(ptr as *mut dyn UnsafeNotify01) }); - } -} - -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -mod io { - use super::*; - use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03}; - use std::io::Error; - use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01}; - - /// Extension trait for tokio-io [`AsyncRead`](tokio_io::AsyncRead) - #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] - pub trait AsyncRead01CompatExt: AsyncRead01 { - /// Converts a tokio-io [`AsyncRead`](tokio_io::AsyncRead) into a futures-io 0.3 - /// [`AsyncRead`](futures_io::AsyncRead). - /// - /// ``` - /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 - /// # futures::executor::block_on(async { - /// use futures::io::AsyncReadExt; - /// use futures_util::compat::AsyncRead01CompatExt; - /// - /// let input = b"Hello World!"; - /// let reader /* : impl tokio_io::AsyncRead */ = std::io::Cursor::new(input); - /// let mut reader /* : impl futures::io::AsyncRead + Unpin */ = reader.compat(); - /// - /// let mut output = Vec::with_capacity(12); - /// reader.read_to_end(&mut output).await.unwrap(); - /// assert_eq!(output, input); - /// # }); - /// ``` - fn compat(self) -> Compat01As03 - where - Self: Sized, - { - Compat01As03::new(self) - } - } - impl AsyncRead01CompatExt for R {} - - /// Extension trait for tokio-io [`AsyncWrite`](tokio_io::AsyncWrite) - #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] - pub trait AsyncWrite01CompatExt: AsyncWrite01 { - /// Converts a tokio-io [`AsyncWrite`](tokio_io::AsyncWrite) into a futures-io 0.3 - /// [`AsyncWrite`](futures_io::AsyncWrite). - /// - /// ``` - /// # if cfg!(miri) { return; } // https://github.com/rust-lang/futures-rs/issues/2514 - /// # futures::executor::block_on(async { - /// use futures::io::AsyncWriteExt; - /// use futures_util::compat::AsyncWrite01CompatExt; - /// - /// let input = b"Hello World!"; - /// let mut cursor = std::io::Cursor::new(Vec::with_capacity(12)); - /// - /// let mut writer = (&mut cursor).compat(); - /// writer.write_all(input).await.unwrap(); - /// - /// assert_eq!(cursor.into_inner(), input); - /// # }); - /// ``` - fn compat(self) -> Compat01As03 - where - Self: Sized, - { - Compat01As03::new(self) - } - } - impl AsyncWrite01CompatExt for W {} - - impl AsyncRead03 for Compat01As03 { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> task03::Poll> { - poll_01_to_03(self.in_notify(cx, |x| x.poll_read(buf))) - } - } - - impl AsyncWrite03 for Compat01As03 { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> task03::Poll> { - poll_01_to_03(self.in_notify(cx, |x| x.poll_write(buf))) - } - - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - poll_01_to_03(self.in_notify(cx, AsyncWrite01::poll_flush)) - } - - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> task03::Poll> { - poll_01_to_03(self.in_notify(cx, AsyncWrite01::shutdown)) - } - } -} diff --git a/futures-util/src/compat/compat03as01.rs b/futures-util/src/compat/compat03as01.rs deleted file mode 100644 index 3c5bb77b49..0000000000 --- a/futures-util/src/compat/compat03as01.rs +++ /dev/null @@ -1,268 +0,0 @@ -use crate::task::{self as task03, ArcWake as ArcWake03, WakerRef}; -use futures_01::{ - task as task01, Async as Async01, Future as Future01, Poll as Poll01, Stream as Stream01, -}; -#[cfg(feature = "sink")] -use futures_01::{AsyncSink as AsyncSink01, Sink as Sink01, StartSend as StartSend01}; -use futures_core::{ - future::TryFuture as TryFuture03, - stream::TryStream as TryStream03, - task::{RawWaker, RawWakerVTable}, -}; -#[cfg(feature = "sink")] -use futures_sink::Sink as Sink03; -#[cfg(feature = "sink")] -use std::marker::PhantomData; -use std::{mem, pin::Pin, sync::Arc, task::Context}; - -#[allow(clippy::too_long_first_doc_paragraph)] // clippy bug, see https://github.com/rust-lang/rust-clippy/issues/13315 -/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture) or -/// [`TryStream`](futures_core::stream::TryStream) into a futures 0.1 -/// [`Future`](futures_01::future::Future) or -/// [`Stream`](futures_01::stream::Stream). -#[derive(Debug, Clone, Copy)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Compat { - pub(crate) inner: T, -} - -/// Converts a futures 0.3 [`Sink`](futures_sink::Sink) into a futures 0.1 -/// [`Sink`](futures_01::sink::Sink). -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -#[derive(Debug)] -#[must_use = "sinks do nothing unless polled"] -pub struct CompatSink { - inner: T, - _phantom: PhantomData, -} - -impl Compat { - /// Creates a new [`Compat`]. - /// - /// For types which implement appropriate futures `0.3` - /// traits, the result will be a type which implements - /// the corresponding futures 0.1 type. - pub fn new(inner: T) -> Self { - Self { inner } - } - - /// Get a reference to 0.3 Future, Stream, AsyncRead, or AsyncWrite object - /// contained within. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Get a mutable reference to 0.3 Future, Stream, AsyncRead, or AsyncWrite object - /// contained within. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Returns the inner item. - pub fn into_inner(self) -> T { - self.inner - } -} - -#[cfg(feature = "sink")] -impl CompatSink { - /// Creates a new [`CompatSink`]. - pub fn new(inner: T) -> Self { - Self { inner, _phantom: PhantomData } - } - - /// Get a reference to 0.3 Sink contained within. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Get a mutable reference to 0.3 Sink contained within. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Returns the inner item. - pub fn into_inner(self) -> T { - self.inner - } -} - -fn poll_03_to_01(x: task03::Poll>) -> Result, E> { - match x? { - task03::Poll::Ready(t) => Ok(Async01::Ready(t)), - task03::Poll::Pending => Ok(Async01::NotReady), - } -} - -impl Future01 for Compat -where - Fut: TryFuture03 + Unpin, -{ - type Item = Fut::Ok; - type Error = Fut::Error; - - fn poll(&mut self) -> Poll01 { - with_context(self, |inner, cx| poll_03_to_01(inner.try_poll(cx))) - } -} - -impl Stream01 for Compat -where - St: TryStream03 + Unpin, -{ - type Item = St::Ok; - type Error = St::Error; - - fn poll(&mut self) -> Poll01, Self::Error> { - with_context(self, |inner, cx| match inner.try_poll_next(cx)? { - task03::Poll::Ready(None) => Ok(Async01::Ready(None)), - task03::Poll::Ready(Some(t)) => Ok(Async01::Ready(Some(t))), - task03::Poll::Pending => Ok(Async01::NotReady), - }) - } -} - -#[cfg(feature = "sink")] -impl Sink01 for CompatSink -where - T: Sink03 + Unpin, -{ - type SinkItem = Item; - type SinkError = T::Error; - - fn start_send(&mut self, item: Self::SinkItem) -> StartSend01 { - with_sink_context(self, |mut inner, cx| match inner.as_mut().poll_ready(cx)? { - task03::Poll::Ready(()) => inner.start_send(item).map(|()| AsyncSink01::Ready), - task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)), - }) - } - - fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> { - with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_flush(cx))) - } - - fn close(&mut self) -> Poll01<(), Self::SinkError> { - with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_close(cx))) - } -} - -#[derive(Clone)] -struct Current(task01::Task); - -impl Current { - fn new() -> Self { - Self(task01::current()) - } - - fn as_waker(&self) -> WakerRef<'_> { - unsafe fn ptr_to_current<'a>(ptr: *const ()) -> &'a Current { - unsafe { &*(ptr as *const Current) } - } - fn current_to_ptr(current: &Current) -> *const () { - current as *const Current as *const () - } - - unsafe fn clone(ptr: *const ()) -> RawWaker { - // Lazily create the `Arc` only when the waker is actually cloned. - // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion - // function is landed in `core`. - unsafe { - mem::transmute::(task03::waker(Arc::new( - ptr_to_current(ptr).clone(), - ))) - } - } - unsafe fn drop(_: *const ()) {} - unsafe fn wake(ptr: *const ()) { - unsafe { ptr_to_current(ptr).0.notify() } - } - - let ptr = current_to_ptr(self); - let vtable = &RawWakerVTable::new(clone, wake, wake, drop); - WakerRef::new_unowned(std::mem::ManuallyDrop::new(unsafe { - task03::Waker::from_raw(RawWaker::new(ptr, vtable)) - })) - } -} - -impl ArcWake03 for Current { - fn wake_by_ref(arc_self: &Arc) { - arc_self.0.notify(); - } -} - -fn with_context(compat: &mut Compat, f: F) -> R -where - T: Unpin, - F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R, -{ - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - f(Pin::new(&mut compat.inner), &mut cx) -} - -#[cfg(feature = "sink")] -fn with_sink_context(compat: &mut CompatSink, f: F) -> R -where - T: Unpin, - F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R, -{ - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - f(Pin::new(&mut compat.inner), &mut cx) -} - -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -mod io { - use super::*; - use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03}; - use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01}; - - fn poll_03_to_io(x: task03::Poll>) -> Result { - match x { - task03::Poll::Ready(Ok(t)) => Ok(t), - task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), - task03::Poll::Ready(Err(e)) => Err(e), - } - } - - impl std::io::Read for Compat { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - poll_03_to_io(Pin::new(&mut self.inner).poll_read(&mut cx, buf)) - } - } - - impl AsyncRead01 for Compat {} - - impl std::io::Write for Compat { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - poll_03_to_io(Pin::new(&mut self.inner).poll_write(&mut cx, buf)) - } - - fn flush(&mut self) -> std::io::Result<()> { - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - poll_03_to_io(Pin::new(&mut self.inner).poll_flush(&mut cx)) - } - } - - impl AsyncWrite01 for Compat { - fn shutdown(&mut self) -> std::io::Result> { - let current = Current::new(); - let waker = current.as_waker(); - let mut cx = Context::from_waker(&waker); - poll_03_to_01(Pin::new(&mut self.inner).poll_close(&mut cx)) - } - } -} diff --git a/futures-util/src/compat/executor.rs b/futures-util/src/compat/executor.rs deleted file mode 100644 index f798eabf8a..0000000000 --- a/futures-util/src/compat/executor.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::{Compat, Future01CompatExt}; -use crate::{ - future::{FutureExt, TryFutureExt, UnitError}, - task::SpawnExt, -}; -use futures_01::future::{ExecuteError as ExecuteError01, Executor as Executor01}; -use futures_01::Future as Future01; -use futures_task::{FutureObj, Spawn as Spawn03, SpawnError as SpawnError03}; - -/// A future that can run on a futures 0.1 -/// [`Executor`](futures_01::future::Executor). -pub type Executor01Future = Compat>>; - -/// Extension trait for futures 0.1 [`Executor`](futures_01::future::Executor). -pub trait Executor01CompatExt: Executor01 + Clone + Send + 'static { - /// Converts a futures 0.1 [`Executor`](futures_01::future::Executor) into a - /// futures 0.3 [`Spawn`](futures_task::Spawn). - /// - /// ``` - /// # if cfg!(miri) { return; } // Miri does not support epoll - /// use futures::task::SpawnExt; - /// use futures::future::{FutureExt, TryFutureExt}; - /// use futures_util::compat::Executor01CompatExt; - /// use tokio::executor::DefaultExecutor; - /// - /// # let (tx, rx) = futures::channel::oneshot::channel(); - /// - /// let spawner = DefaultExecutor::current().compat(); - /// let future03 = async move { - /// println!("Running on the pool"); - /// spawner.spawn(async { - /// println!("Spawned!"); - /// # tx.send(42).unwrap(); - /// }).unwrap(); - /// }; - /// - /// let future01 = future03.unit_error().boxed().compat(); - /// - /// tokio::run(future01); - /// # futures::executor::block_on(rx).unwrap(); - /// ``` - fn compat(self) -> Executor01As03 - where - Self: Sized; -} - -impl Executor01CompatExt for Ex -where - Ex: Executor01 + Clone + Send + 'static, -{ - fn compat(self) -> Executor01As03 { - Executor01As03 { executor01: self } - } -} - -/// Converts a futures 0.1 [`Executor`](futures_01::future::Executor) into a -/// futures 0.3 [`Spawn`](futures_task::Spawn). -#[derive(Debug, Clone)] -pub struct Executor01As03 { - executor01: Ex, -} - -impl Spawn03 for Executor01As03 -where - Ex: Executor01 + Clone + Send + 'static, -{ - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError03> { - let future = future.unit_error().compat(); - - self.executor01.execute(future).map_err(|_| SpawnError03::shutdown()) - } -} - -impl Executor01 for Compat -where - for<'a> &'a Sp: Spawn03, - Fut: Future01 + Send + 'static, -{ - fn execute(&self, future: Fut) -> Result<(), ExecuteError01> { - (&self.inner) - .spawn(future.compat().map(|_| ())) - .expect("unable to spawn future from Compat executor"); - Ok(()) - } -} diff --git a/futures-util/src/compat/mod.rs b/futures-util/src/compat/mod.rs deleted file mode 100644 index 4812803eb6..0000000000 --- a/futures-util/src/compat/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Interop between `futures` 0.1 and 0.3. -//! -//! This module is only available when the `compat` feature of this -//! library is activated. - -mod executor; -pub use self::executor::{Executor01As03, Executor01CompatExt, Executor01Future}; - -mod compat01as03; -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -pub use self::compat01as03::{AsyncRead01CompatExt, AsyncWrite01CompatExt}; -pub use self::compat01as03::{Compat01As03, Future01CompatExt, Stream01CompatExt}; -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::compat01as03::{Compat01As03Sink, Sink01CompatExt}; - -mod compat03as01; -pub use self::compat03as01::Compat; -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::compat03as01::CompatSink; diff --git a/futures-util/src/fns.rs b/futures-util/src/fns.rs deleted file mode 100644 index d9c062e1e1..0000000000 --- a/futures-util/src/fns.rs +++ /dev/null @@ -1,369 +0,0 @@ -use core::fmt::{self, Debug}; -use core::marker::PhantomData; - -pub trait FnOnce1 { - type Output; - fn call_once(self, arg: A) -> Self::Output; -} - -impl FnOnce1 for T -where - T: FnOnce(A) -> R, -{ - type Output = R; - fn call_once(self, arg: A) -> R { - self(arg) - } -} - -pub trait FnMut1: FnOnce1 { - fn call_mut(&mut self, arg: A) -> Self::Output; -} - -impl FnMut1 for T -where - T: FnMut(A) -> R, -{ - fn call_mut(&mut self, arg: A) -> R { - self(arg) - } -} - -// Not used, but present for completeness -#[allow(dead_code, unreachable_pub)] -pub trait Fn1: FnMut1 { - fn call(&self, arg: A) -> Self::Output; -} - -impl Fn1 for T -where - T: Fn(A) -> R, -{ - fn call(&self, arg: A) -> R { - self(arg) - } -} - -macro_rules! trivial_fn_impls { - ($name:ident <$($arg:ident),*> $t:ty = $debug:literal) => { - impl<$($arg),*> Copy for $t {} - impl<$($arg),*> Clone for $t { - fn clone(&self) -> Self { *self } - } - impl<$($arg),*> Debug for $t { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str($debug) - } - } - impl<$($arg,)* A> FnMut1 for $t where Self: FnOnce1 { - fn call_mut(&mut self, arg: A) -> Self::Output { - self.call_once(arg) - } - } - impl<$($arg,)* A> Fn1 for $t where Self: FnOnce1 { - fn call(&self, arg: A) -> Self::Output { - self.call_once(arg) - } - } - pub(crate) fn $name<$($arg),*>() -> $t { - Default::default() - } - } -} - -pub struct OkFn(PhantomData); - -impl Default for OkFn { - fn default() -> Self { - Self(PhantomData) - } -} - -impl FnOnce1 for OkFn { - type Output = Result; - fn call_once(self, arg: A) -> Self::Output { - Ok(arg) - } -} - -trivial_fn_impls!(ok_fn OkFn = "Ok"); - -#[derive(Debug, Copy, Clone, Default)] -pub struct ChainFn(F, G); - -impl FnOnce1 for ChainFn -where - F: FnOnce1, - G: FnOnce1, -{ - type Output = G::Output; - fn call_once(self, arg: A) -> Self::Output { - self.1.call_once(self.0.call_once(arg)) - } -} -impl FnMut1 for ChainFn -where - F: FnMut1, - G: FnMut1, -{ - fn call_mut(&mut self, arg: A) -> Self::Output { - self.1.call_mut(self.0.call_mut(arg)) - } -} -impl Fn1 for ChainFn -where - F: Fn1, - G: Fn1, -{ - fn call(&self, arg: A) -> Self::Output { - self.1.call(self.0.call(arg)) - } -} -pub(crate) fn chain_fn(f: F, g: G) -> ChainFn { - ChainFn(f, g) -} - -#[derive(Default)] -pub struct MergeResultFn; - -impl FnOnce1> for MergeResultFn { - type Output = T; - fn call_once(self, arg: Result) -> Self::Output { - match arg { - Ok(x) => x, - Err(x) => x, - } - } -} -trivial_fn_impls!(merge_result_fn <> MergeResultFn = "merge_result"); - -#[derive(Debug, Copy, Clone, Default)] -pub struct InspectFn(F); - -impl FnOnce1 for InspectFn -where - F: for<'a> FnOnce1<&'a A, Output = ()>, -{ - type Output = A; - fn call_once(self, arg: A) -> Self::Output { - self.0.call_once(&arg); - arg - } -} -impl FnMut1 for InspectFn -where - F: for<'a> FnMut1<&'a A, Output = ()>, -{ - fn call_mut(&mut self, arg: A) -> Self::Output { - self.0.call_mut(&arg); - arg - } -} -impl Fn1 for InspectFn -where - F: for<'a> Fn1<&'a A, Output = ()>, -{ - fn call(&self, arg: A) -> Self::Output { - self.0.call(&arg); - arg - } -} -pub(crate) fn inspect_fn(f: F) -> InspectFn { - InspectFn(f) -} - -#[derive(Debug, Copy, Clone, Default)] -pub struct MapOkFn(F); - -impl FnOnce1> for MapOkFn -where - F: FnOnce1, -{ - type Output = Result; - fn call_once(self, arg: Result) -> Self::Output { - arg.map(|x| self.0.call_once(x)) - } -} -impl FnMut1> for MapOkFn -where - F: FnMut1, -{ - fn call_mut(&mut self, arg: Result) -> Self::Output { - arg.map(|x| self.0.call_mut(x)) - } -} -impl Fn1> for MapOkFn -where - F: Fn1, -{ - fn call(&self, arg: Result) -> Self::Output { - arg.map(|x| self.0.call(x)) - } -} -pub(crate) fn map_ok_fn(f: F) -> MapOkFn { - MapOkFn(f) -} - -#[derive(Debug, Copy, Clone, Default)] -pub struct MapErrFn(F); - -impl FnOnce1> for MapErrFn -where - F: FnOnce1, -{ - type Output = Result; - fn call_once(self, arg: Result) -> Self::Output { - arg.map_err(|x| self.0.call_once(x)) - } -} -impl FnMut1> for MapErrFn -where - F: FnMut1, -{ - fn call_mut(&mut self, arg: Result) -> Self::Output { - arg.map_err(|x| self.0.call_mut(x)) - } -} -impl Fn1> for MapErrFn -where - F: Fn1, -{ - fn call(&self, arg: Result) -> Self::Output { - arg.map_err(|x| self.0.call(x)) - } -} -pub(crate) fn map_err_fn(f: F) -> MapErrFn { - MapErrFn(f) -} - -#[derive(Debug, Copy, Clone)] -pub struct InspectOkFn(F); - -impl<'a, F, T, E> FnOnce1<&'a Result> for InspectOkFn -where - F: FnOnce1<&'a T, Output = ()>, -{ - type Output = (); - fn call_once(self, arg: &'a Result) -> Self::Output { - if let Ok(x) = arg { - self.0.call_once(x) - } - } -} -impl<'a, F, T, E> FnMut1<&'a Result> for InspectOkFn -where - F: FnMut1<&'a T, Output = ()>, -{ - fn call_mut(&mut self, arg: &'a Result) -> Self::Output { - if let Ok(x) = arg { - self.0.call_mut(x) - } - } -} -impl<'a, F, T, E> Fn1<&'a Result> for InspectOkFn -where - F: Fn1<&'a T, Output = ()>, -{ - fn call(&self, arg: &'a Result) -> Self::Output { - if let Ok(x) = arg { - self.0.call(x) - } - } -} -pub(crate) fn inspect_ok_fn(f: F) -> InspectOkFn { - InspectOkFn(f) -} - -#[derive(Debug, Copy, Clone)] -pub struct InspectErrFn(F); - -impl<'a, F, T, E> FnOnce1<&'a Result> for InspectErrFn -where - F: FnOnce1<&'a E, Output = ()>, -{ - type Output = (); - fn call_once(self, arg: &'a Result) -> Self::Output { - if let Err(x) = arg { - self.0.call_once(x) - } - } -} -impl<'a, F, T, E> FnMut1<&'a Result> for InspectErrFn -where - F: FnMut1<&'a E, Output = ()>, -{ - fn call_mut(&mut self, arg: &'a Result) -> Self::Output { - if let Err(x) = arg { - self.0.call_mut(x) - } - } -} -impl<'a, F, T, E> Fn1<&'a Result> for InspectErrFn -where - F: Fn1<&'a E, Output = ()>, -{ - fn call(&self, arg: &'a Result) -> Self::Output { - if let Err(x) = arg { - self.0.call(x) - } - } -} -pub(crate) fn inspect_err_fn(f: F) -> InspectErrFn { - InspectErrFn(f) -} - -pub(crate) type MapOkOrElseFn = ChainFn, ChainFn, MergeResultFn>>; -pub(crate) fn map_ok_or_else_fn(f: F, g: G) -> MapOkOrElseFn { - chain_fn(map_ok_fn(f), chain_fn(map_err_fn(g), merge_result_fn())) -} - -#[derive(Debug, Copy, Clone, Default)] -pub struct UnwrapOrElseFn(F); - -impl FnOnce1> for UnwrapOrElseFn -where - F: FnOnce1, -{ - type Output = T; - fn call_once(self, arg: Result) -> Self::Output { - arg.unwrap_or_else(|x| self.0.call_once(x)) - } -} -impl FnMut1> for UnwrapOrElseFn -where - F: FnMut1, -{ - fn call_mut(&mut self, arg: Result) -> Self::Output { - arg.unwrap_or_else(|x| self.0.call_mut(x)) - } -} -impl Fn1> for UnwrapOrElseFn -where - F: Fn1, -{ - fn call(&self, arg: Result) -> Self::Output { - arg.unwrap_or_else(|x| self.0.call(x)) - } -} -pub(crate) fn unwrap_or_else_fn(f: F) -> UnwrapOrElseFn { - UnwrapOrElseFn(f) -} - -pub struct IntoFn(PhantomData T>); - -impl Default for IntoFn { - fn default() -> Self { - Self(PhantomData) - } -} -impl FnOnce1 for IntoFn -where - A: Into, -{ - type Output = T; - fn call_once(self, arg: A) -> Self::Output { - arg.into() - } -} - -trivial_fn_impls!(into_fn IntoFn = "Into::into"); diff --git a/futures-util/src/future/abortable.rs b/futures-util/src/future/abortable.rs deleted file mode 100644 index d017ab7340..0000000000 --- a/futures-util/src/future/abortable.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::assert_future; -use crate::future::{AbortHandle, Abortable, Aborted}; -use futures_core::future::Future; - -/// Creates a new `Abortable` future and an `AbortHandle` which can be used to stop it. -/// -/// This function is a convenient (but less flexible) alternative to calling -/// `AbortHandle::new` and `Abortable::new` manually. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -pub fn abortable(future: Fut) -> (Abortable, AbortHandle) -where - Fut: Future, -{ - let (handle, reg) = AbortHandle::new_pair(); - let abortable = assert_future::, _>(Abortable::new(future, reg)); - (abortable, handle) -} diff --git a/futures-util/src/future/always_ready.rs b/futures-util/src/future/always_ready.rs deleted file mode 100644 index 28625e7272..0000000000 --- a/futures-util/src/future/always_ready.rs +++ /dev/null @@ -1,62 +0,0 @@ -use super::assert_future; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`always_ready`](always_ready()) function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct AlwaysReady T>(F); - -impl T> core::fmt::Debug for AlwaysReady { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("AlwaysReady").finish() - } -} - -impl T + Clone> Clone for AlwaysReady { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl T + Copy> Copy for AlwaysReady {} - -impl T> Unpin for AlwaysReady {} - -impl T> FusedFuture for AlwaysReady { - fn is_terminated(&self) -> bool { - false - } -} - -impl T> Future for AlwaysReady { - type Output = T; - - #[inline] - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - Poll::Ready(self.0()) - } -} - -/// 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>`], -/// as [`AlwaysReady`] does not have to store a boolean for `is_finished`. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use std::mem::size_of_val; -/// -/// use futures::future; -/// -/// let a = future::always_ready(|| 1); -/// assert_eq!(size_of_val(&a), 0); -/// assert_eq!(a.await, 1); -/// assert_eq!(a.await, 1); -/// # }); -/// ``` -pub fn always_ready T>(prod: F) -> AlwaysReady { - assert_future::(AlwaysReady(prod)) -} diff --git a/futures-util/src/future/either.rs b/futures-util/src/future/either.rs deleted file mode 100644 index 018e51e72f..0000000000 --- a/futures-util/src/future/either.rs +++ /dev/null @@ -1,314 +0,0 @@ -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, Stream}; -#[cfg(feature = "sink")] -use futures_sink::Sink; - -/// Combines two different futures, streams, or sinks having the same associated types into a single type. -/// -/// This is useful when conditionally choosing between two distinct future types: -/// -/// ```rust -/// use futures::future::Either; -/// -/// # futures::executor::block_on(async { -/// let cond = true; -/// -/// let fut = if cond { -/// Either::Left(async move { 12 }) -/// } else { -/// Either::Right(async move { 44 }) -/// }; -/// -/// assert_eq!(fut.await, 12); -/// # }) -/// ``` -#[derive(Debug, Clone)] -pub enum Either { - /// First branch of the type - Left(/* #[pin] */ A), - /// Second branch of the type - Right(/* #[pin] */ B), -} - -impl Either { - /// Convert `Pin<&Either>` to `Either, Pin<&B>>`, - /// pinned projections of the inner variants. - pub fn as_pin_ref(self: Pin<&Self>) -> Either, Pin<&B>> { - // SAFETY: We can use `new_unchecked` because the `inner` parts are - // guaranteed to be pinned, as they come from `self` which is pinned. - unsafe { - match self.get_ref() { - Self::Left(inner) => Either::Left(Pin::new_unchecked(inner)), - Self::Right(inner) => Either::Right(Pin::new_unchecked(inner)), - } - } - } - - /// Convert `Pin<&mut Either>` to `Either, Pin<&mut B>>`, - /// pinned projections of the inner variants. - pub fn as_pin_mut(self: Pin<&mut Self>) -> Either, Pin<&mut B>> { - // SAFETY: `get_unchecked_mut` is fine because we don't move anything. - // We can use `new_unchecked` because the `inner` parts are guaranteed - // to be pinned, as they come from `self` which is pinned, and we never - // offer an unpinned `&mut A` or `&mut B` through `Pin<&mut Self>`. We - // also don't have an implementation of `Drop`, nor manual `Unpin`. - unsafe { - match self.get_unchecked_mut() { - Self::Left(inner) => Either::Left(Pin::new_unchecked(inner)), - Self::Right(inner) => Either::Right(Pin::new_unchecked(inner)), - } - } - } -} - -impl Either<(T, A), (T, B)> { - /// Factor out a homogeneous type from an either of pairs. - /// - /// Here, the homogeneous type is the first element of the pairs. - pub fn factor_first(self) -> (T, Either) { - match self { - Self::Left((x, a)) => (x, Either::Left(a)), - Self::Right((x, b)) => (x, Either::Right(b)), - } - } -} - -impl Either<(A, T), (B, T)> { - /// Factor out a homogeneous type from an either of pairs. - /// - /// Here, the homogeneous type is the second element of the pairs. - pub fn factor_second(self) -> (Either, T) { - match self { - Self::Left((a, x)) => (Either::Left(a), x), - Self::Right((b, x)) => (Either::Right(b), x), - } - } -} - -impl Either { - /// Extract the value of an either over two equivalent types. - pub fn into_inner(self) -> T { - match self { - Self::Left(x) | Self::Right(x) => x, - } - } -} - -impl Future for Either -where - A: Future, - B: Future, -{ - type Output = A::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.as_pin_mut() { - Either::Left(x) => x.poll(cx), - Either::Right(x) => x.poll(cx), - } - } -} - -impl FusedFuture for Either -where - A: FusedFuture, - B: FusedFuture, -{ - fn is_terminated(&self) -> bool { - match self { - Self::Left(x) => x.is_terminated(), - Self::Right(x) => x.is_terminated(), - } - } -} - -impl Stream for Either -where - A: Stream, - B: Stream, -{ - type Item = A::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_next(cx), - Either::Right(x) => x.poll_next(cx), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - Self::Left(x) => x.size_hint(), - Self::Right(x) => x.size_hint(), - } - } -} - -impl FusedStream for Either -where - A: FusedStream, - B: FusedStream, -{ - fn is_terminated(&self) -> bool { - match self { - Self::Left(x) => x.is_terminated(), - Self::Right(x) => x.is_terminated(), - } - } -} - -#[cfg(feature = "sink")] -impl Sink for Either -where - A: Sink, - B: Sink, -{ - type Error = A::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_ready(cx), - Either::Right(x) => x.poll_ready(cx), - } - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - match self.as_pin_mut() { - Either::Left(x) => x.start_send(item), - Either::Right(x) => x.start_send(item), - } - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_flush(cx), - Either::Right(x) => x.poll_flush(cx), - } - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_close(cx), - Either::Right(x) => x.poll_close(cx), - } - } -} - -#[cfg(feature = "io")] -#[cfg(feature = "std")] -mod if_std { - use super::*; - - use futures_io::{ - AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, Result, SeekFrom, - }; - - impl AsyncRead for Either - where - A: AsyncRead, - B: AsyncRead, - { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_read(cx, buf), - Either::Right(x) => x.poll_read(cx, buf), - } - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_read_vectored(cx, bufs), - Either::Right(x) => x.poll_read_vectored(cx, bufs), - } - } - } - - impl AsyncWrite for Either - where - A: AsyncWrite, - B: AsyncWrite, - { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_write(cx, buf), - Either::Right(x) => x.poll_write(cx, buf), - } - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_write_vectored(cx, bufs), - Either::Right(x) => x.poll_write_vectored(cx, bufs), - } - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_flush(cx), - Either::Right(x) => x.poll_flush(cx), - } - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_close(cx), - Either::Right(x) => x.poll_close(cx), - } - } - } - - impl AsyncSeek for Either - where - A: AsyncSeek, - B: AsyncSeek, - { - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_seek(cx, pos), - Either::Right(x) => x.poll_seek(cx, pos), - } - } - } - - impl AsyncBufRead for Either - where - A: AsyncBufRead, - B: AsyncBufRead, - { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.as_pin_mut() { - Either::Left(x) => x.poll_fill_buf(cx), - Either::Right(x) => x.poll_fill_buf(cx), - } - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - match self.as_pin_mut() { - Either::Left(x) => x.consume(amt), - Either::Right(x) => x.consume(amt), - } - } - } -} diff --git a/futures-util/src/future/future/catch_unwind.rs b/futures-util/src/future/future/catch_unwind.rs deleted file mode 100644 index ed49e314d2..0000000000 --- a/futures-util/src/future/future/catch_unwind.rs +++ /dev/null @@ -1,39 +0,0 @@ -use core::any::Any; -use core::pin::Pin; -use std::boxed::Box; -use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe}; - -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`catch_unwind`](super::FutureExt::catch_unwind) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct CatchUnwind { - #[pin] - future: Fut, - } -} - -impl CatchUnwind -where - Fut: Future + UnwindSafe, -{ - pub(super) fn new(future: Fut) -> Self { - Self { future } - } -} - -impl Future for CatchUnwind -where - Fut: Future + UnwindSafe, -{ - type Output = Result>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let f = self.project().future; - catch_unwind(AssertUnwindSafe(|| f.poll(cx)))?.map(Ok) - } -} diff --git a/futures-util/src/future/future/flatten.rs b/futures-util/src/future/future/flatten.rs deleted file mode 100644 index 12105e6202..0000000000 --- a/futures-util/src/future/future/flatten.rs +++ /dev/null @@ -1,147 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - #[project = FlattenProj] - #[derive(Debug)] - pub enum Flatten { - First { #[pin] f: Fut1 }, - Second { #[pin] f: Fut2 }, - Empty, - } -} - -impl Flatten { - pub(crate) fn new(future: Fut1) -> Self { - Self::First { f: future } - } -} - -impl FusedFuture for Flatten -where - Fut: Future, - Fut::Output: Future, -{ - fn is_terminated(&self) -> bool { - matches!(self, Self::Empty) - } -} - -impl Future for Flatten -where - Fut: Future, - Fut::Output: Future, -{ - type Output = ::Output; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready(loop { - match self.as_mut().project() { - FlattenProj::First { f } => { - let f = ready!(f.poll(cx)); - self.set(Self::Second { f }); - } - FlattenProj::Second { f } => { - let output = ready!(f.poll(cx)); - self.set(Self::Empty); - break output; - } - FlattenProj::Empty => panic!("Flatten polled after completion"), - } - }) - } -} - -impl FusedStream for Flatten -where - Fut: Future, - Fut::Output: Stream, -{ - fn is_terminated(&self) -> bool { - matches!(self, Self::Empty) - } -} - -impl Stream for Flatten -where - Fut: Future, - Fut::Output: Stream, -{ - type Item = ::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(loop { - match self.as_mut().project() { - FlattenProj::First { f } => { - let f = ready!(f.poll(cx)); - self.set(Self::Second { f }); - } - FlattenProj::Second { f } => { - let output = ready!(f.poll_next(cx)); - if output.is_none() { - self.set(Self::Empty); - } - break output; - } - FlattenProj::Empty => break None, - } - }) - } -} - -#[cfg(feature = "sink")] -impl Sink for Flatten -where - Fut: Future, - Fut::Output: Sink, -{ - type Error = >::Error; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(loop { - match self.as_mut().project() { - FlattenProj::First { f } => { - let f = ready!(f.poll(cx)); - self.set(Self::Second { f }); - } - FlattenProj::Second { f } => { - break ready!(f.poll_ready(cx)); - } - FlattenProj::Empty => panic!("poll_ready called after eof"), - } - }) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - match self.project() { - FlattenProj::First { .. } => panic!("poll_ready not called first"), - FlattenProj::Second { f } => f.start_send(item), - FlattenProj::Empty => panic!("start_send called after eof"), - } - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.project() { - FlattenProj::First { .. } => Poll::Ready(Ok(())), - FlattenProj::Second { f } => f.poll_flush(cx), - FlattenProj::Empty => panic!("poll_flush called after eof"), - } - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let res = match self.as_mut().project() { - FlattenProj::Second { f } => f.poll_close(cx), - _ => Poll::Ready(Ok(())), - }; - if res.is_ready() { - self.set(Self::Empty); - } - res - } -} diff --git a/futures-util/src/future/future/fuse.rs b/futures-util/src/future/future/fuse.rs deleted file mode 100644 index 100e910776..0000000000 --- a/futures-util/src/future/future/fuse.rs +++ /dev/null @@ -1,92 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`fuse`](super::FutureExt::fuse) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Fuse { - #[pin] - inner: Option, - } -} - -impl Fuse { - pub(super) fn new(f: Fut) -> Self { - Self { inner: Some(f) } - } -} - -impl Fuse { - /// Creates a new `Fuse`-wrapped future which is already terminated. - /// - /// This can be useful in combination with looping and the `select!` - /// macro, which bypasses terminated futures. - /// - /// # Examples - /// - /// ``` - /// # 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; - /// - /// let (sender, mut stream) = mpsc::unbounded(); - /// - /// // Send a few messages into the stream - /// sender.unbounded_send(()).unwrap(); - /// sender.unbounded_send(()).unwrap(); - /// drop(sender); - /// - /// // Use `Fuse::terminated()` to create an already-terminated future - /// // which may be instantiated later. - /// let foo_printer = Fuse::terminated(); - /// let mut foo_printer = pin!(foo_printer); - /// - /// loop { - /// select! { - /// _ = foo_printer => {}, - /// () = stream.select_next_some() => { - /// if !foo_printer.is_terminated() { - /// println!("Foo is already being printed!"); - /// } else { - /// foo_printer.set(async { - /// // do some other async operations - /// println!("Printing foo from `foo_printer` future"); - /// }.fuse()); - /// } - /// }, - /// complete => break, // `foo_printer` is terminated and the stream is done - /// } - /// } - /// # }); - /// ``` - pub fn terminated() -> Self { - Self { inner: None } - } -} - -impl FusedFuture for Fuse { - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl Future for Fuse { - type Output = Fut::Output; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.as_mut().project().inner.as_pin_mut() { - Some(fut) => fut.poll(cx).map(|output| { - self.project().inner.set(None); - output - }), - None => Poll::Pending, - } - } -} diff --git a/futures-util/src/future/future/map.rs b/futures-util/src/future/future/map.rs deleted file mode 100644 index 6991a35022..0000000000 --- a/futures-util/src/future/future/map.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -use crate::fns::FnOnce1; - -pin_project! { - /// Internal Map future - #[project = MapProj] - #[project_replace = MapProjReplace] - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub enum Map { - Incomplete { - #[pin] - future: Fut, - f: F, - }, - Complete, - } -} - -impl Map { - /// Creates a new Map. - pub(crate) fn new(future: Fut, f: F) -> Self { - Self::Incomplete { future, f } - } -} - -impl FusedFuture for Map -where - Fut: Future, - F: FnOnce1, -{ - fn is_terminated(&self) -> bool { - match self { - Self::Incomplete { .. } => false, - Self::Complete => true, - } - } -} - -impl Future for Map -where - Fut: Future, - F: FnOnce1, -{ - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.as_mut().project() { - MapProj::Incomplete { future, .. } => { - let output = ready!(future.poll(cx)); - match self.project_replace(Self::Complete) { - MapProjReplace::Incomplete { f, .. } => Poll::Ready(f.call_once(output)), - MapProjReplace::Complete => unreachable!(), - } - } - MapProj::Complete => { - panic!("Map must not be polled after it returned `Poll::Ready`") - } - } - } -} diff --git a/futures-util/src/future/future/mod.rs b/futures-util/src/future/future/mod.rs deleted file mode 100644 index 13aa201a62..0000000000 --- a/futures-util/src/future/future/mod.rs +++ /dev/null @@ -1,600 +0,0 @@ -//! Futures -//! -//! This module contains a number of functions for working with `Future`s, -//! including the `FutureExt` trait which adds methods to `Future` types. - -use crate::fns::{inspect_fn, into_fn, ok_fn, InspectFn, IntoFn, OkFn}; -use crate::future::{assert_future, Either}; -use crate::stream::assert_stream; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; -use core::convert::Infallible; -use core::pin::pin; -use core::pin::Pin; -#[cfg(feature = "alloc")] -use futures_core::future::{BoxFuture, LocalBoxFuture}; -use futures_core::{ - future::Future, - stream::Stream, - task::{Context, Poll}, -}; - -// Combinators - -mod flatten; -mod fuse; -mod map; - -delegate_all!( - /// Future for the [`flatten`](super::FutureExt::flatten) method. - Flatten( - flatten::Flatten::Output> - ): Debug + Future + FusedFuture + New[|x: F| flatten::Flatten::new(x)] - where F: Future -); - -delegate_all!( - /// Stream for the [`flatten_stream`](FutureExt::flatten_stream) method. - FlattenStream( - flatten::Flatten::Output> - ): Debug + Sink + Stream + FusedStream + New[|x: F| flatten::Flatten::new(x)] - where F: Future -); - -pub use fuse::Fuse; - -delegate_all!( - /// Future for the [`map`](super::FutureExt::map) method. - Map( - map::Map - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| map::Map::new(x, f)] -); - -delegate_all!( - /// Stream for the [`into_stream`](FutureExt::into_stream) method. - IntoStream( - crate::stream::Once - ): Debug + Stream + FusedStream + New[|x: F| crate::stream::Once::new(x)] -); - -delegate_all!( - /// Future for the [`map_into`](FutureExt::map_into) combinator. - MapInto( - Map> - ): Debug + Future + FusedFuture + New[|x: Fut| Map::new(x, into_fn())] -); - -delegate_all!( - /// Future for the [`then`](FutureExt::then) method. - Then( - flatten::Flatten, Fut2> - ): Debug + Future + FusedFuture + New[|x: Fut1, y: F| flatten::Flatten::new(Map::new(x, y))] -); - -delegate_all!( - /// Future for the [`inspect`](FutureExt::inspect) method. - Inspect( - map::Map> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| map::Map::new(x, inspect_fn(f))] -); - -delegate_all!( - /// Future for the [`never_error`](super::FutureExt::never_error) combinator. - NeverError( - Map> - ): Debug + Future + FusedFuture + New[|x: Fut| Map::new(x, ok_fn())] -); - -delegate_all!( - /// Future for the [`unit_error`](super::FutureExt::unit_error) combinator. - UnitError( - Map> - ): Debug + Future + FusedFuture + New[|x: Fut| Map::new(x, ok_fn())] -); - -#[cfg(feature = "std")] -mod catch_unwind; -#[cfg(feature = "std")] -pub use self::catch_unwind::CatchUnwind; - -#[cfg(feature = "channel")] -#[cfg_attr(docsrs, doc(cfg(feature = "channel")))] -#[cfg(feature = "std")] -mod remote_handle; -#[cfg(feature = "channel")] -#[cfg_attr(docsrs, doc(cfg(feature = "channel")))] -#[cfg(feature = "std")] -pub use self::remote_handle::{Remote, RemoteHandle}; - -#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] -mod shared; -#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] -pub use self::shared::{Shared, WeakShared}; - -impl FutureExt for T where T: Future {} - -/// An extension trait for `Future`s that provides a variety of convenient -/// adapters. -pub trait FutureExt: Future { - /// Map this future's output to a different type, returning a new future of - /// the resulting type. - /// - /// This function is similar to the `Option::map` or `Iterator::map` where - /// it will change the type of the underlying future. This is useful to - /// chain along a computation once a future has been resolved. - /// - /// Note that this function consumes the receiving future and returns a - /// wrapped version of it, similar to the existing `map` methods in the - /// standard library. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let future = async { 1 }; - /// let new_future = future.map(|x| x + 3); - /// assert_eq!(new_future.await, 4); - /// # }); - /// ``` - fn map(self, f: F) -> Map - where - F: FnOnce(Self::Output) -> U, - Self: Sized, - { - assert_future::(Map::new(self, f)) - } - - /// Map this future's output to a different type, returning a new future of - /// the resulting type. - /// - /// This function is equivalent to calling `map(Into::into)` but allows naming - /// the return type. - fn map_into(self) -> MapInto - where - Self::Output: Into, - Self: Sized, - { - assert_future::(MapInto::new(self)) - } - - /// Chain on a computation for when a future finished, passing the result of - /// the future to the provided closure `f`. - /// - /// The returned value of the closure must implement the `Future` trait - /// and can represent some more work to be done before the composed future - /// is finished. - /// - /// The closure `f` is only run *after* successful completion of the `self` - /// future. - /// - /// Note that this function consumes the receiving future and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let future_of_1 = async { 1 }; - /// let future_of_4 = future_of_1.then(|x| async move { x + 3 }); - /// assert_eq!(future_of_4.await, 4); - /// # }); - /// ``` - fn then(self, f: F) -> Then - where - F: FnOnce(Self::Output) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::(Then::new(self, f)) - } - - /// Wrap this future in an `Either` future, making it the left-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `right_future` method to write `if` - /// statements that evaluate to different futures in different branches. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let x = 6; - /// let future = if x < 10 { - /// async { true }.left_future() - /// } else { - /// async { false }.right_future() - /// }; - /// - /// assert_eq!(future.await, true); - /// # }); - /// ``` - fn left_future(self) -> Either - where - B: Future, - Self: Sized, - { - assert_future::(Either::Left(self)) - } - - /// Wrap this future in an `Either` future, making it the right-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `left_future` method to write `if` - /// statements that evaluate to different futures in different branches. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let x = 6; - /// let future = if x > 10 { - /// async { true }.left_future() - /// } else { - /// async { false }.right_future() - /// }; - /// - /// assert_eq!(future.await, false); - /// # }); - /// ``` - fn right_future(self) -> Either - where - A: Future, - Self: Sized, - { - assert_future::(Either::Right(self)) - } - - /// Convert this future into a single element stream. - /// - /// The returned stream contains single success if this future resolves to - /// success or single error if this future resolves into error. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// use futures::stream::StreamExt; - /// - /// let future = async { 17 }; - /// let stream = future.into_stream(); - /// let collected: Vec<_> = stream.collect().await; - /// assert_eq!(collected, vec![17]); - /// # }); - /// ``` - fn into_stream(self) -> IntoStream - where - Self: Sized, - { - assert_stream::(IntoStream::new(self)) - } - - /// Flatten the execution of this future when the output of this - /// future is itself another future. - /// - /// This can be useful when combining futures together to flatten the - /// computation out the final result. - /// - /// This method is roughly equivalent to `self.then(|x| x)`. - /// - /// Note that this function consumes the receiving future and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let nested_future = async { async { 1 } }; - /// let future = nested_future.flatten(); - /// assert_eq!(future.await, 1); - /// # }); - /// ``` - fn flatten(self) -> Flatten - where - Self::Output: Future, - Self: Sized, - { - let f = Flatten::new(self); - assert_future::<<::Output as Future>::Output, _>(f) - } - - /// Flatten the execution of this future when the successful result of this - /// future is a stream. - /// - /// This can be useful when stream initialization is deferred, and it is - /// convenient to work with that stream as if stream was available at the - /// call site. - /// - /// Note that this function consumes this future and returns a wrapped - /// version of it. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// use futures::stream::{self, StreamExt}; - /// - /// let stream_items = vec![17, 18, 19]; - /// let future_of_a_stream = async { stream::iter(stream_items) }; - /// - /// let stream = future_of_a_stream.flatten_stream(); - /// let list: Vec<_> = stream.collect().await; - /// assert_eq!(list, vec![17, 18, 19]); - /// # }); - /// ``` - fn flatten_stream(self) -> FlattenStream - where - Self::Output: Stream, - Self: Sized, - { - assert_stream::<::Item, _>(FlattenStream::new(self)) - } - - /// Fuse a future such that `poll` will never again be called once it has - /// completed. This method can be used to turn any `Future` into a - /// `FusedFuture`. - /// - /// Normally, once a future has returned `Poll::Ready` from `poll`, - /// any further calls could exhibit bad behavior such as blocking - /// forever, panicking, never returning, etc. If it is known that `poll` - /// may be called too often then this method can be used to ensure that it - /// has defined semantics. - /// - /// If a `fuse`d future is `poll`ed after having returned `Poll::Ready` - /// previously, it will return `Poll::Pending`, from `poll` again (and will - /// continue to do so for all future calls to `poll`). - /// - /// This combinator will drop the underlying future as soon as it has been - /// completed to ensure resources are reclaimed as soon as possible. - fn fuse(self) -> Fuse - where - Self: Sized, - { - let f = Fuse::new(self); - assert_future::(f) - } - - /// Do something with the output of a future before passing it on. - /// - /// When using futures, you'll often chain several of them together. While - /// working on such code, you might want to check out what's happening at - /// various parts in the pipeline, without consuming the intermediate - /// value. To do that, insert a call to `inspect`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let future = async { 1 }; - /// let new_future = future.inspect(|&x| println!("about to resolve: {}", x)); - /// assert_eq!(new_future.await, 1); - /// # }); - /// ``` - fn inspect(self, f: F) -> Inspect - where - F: FnOnce(&Self::Output), - Self: Sized, - { - assert_future::(Inspect::new(self, f)) - } - - /// Catches unwinding panics while polling the future. - /// - /// In general, panics within a future can propagate all the way out to the - /// task level. This combinator makes it possible to halt unwinding within - /// the future itself. It's most commonly used within task executors. It's - /// not recommended to use this for error handling. - /// - /// Note that this method requires the `UnwindSafe` bound from the standard - /// library. This isn't always applied automatically, and the standard - /// library provides an `AssertUnwindSafe` wrapper type to apply it - /// after-the fact. To assist using this method, the `Future` trait is also - /// implemented for `AssertUnwindSafe` where `F` implements `Future`. - /// - /// This method is only available when the `std` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::{self, FutureExt, Ready}; - /// - /// let future = future::ready(2); - /// assert!(future.catch_unwind().await.is_ok()); - /// - /// let future = future::lazy(|_| -> Ready { - /// unimplemented!() - /// }); - /// assert!(future.catch_unwind().await.is_err()); - /// # }); - /// ``` - #[cfg(feature = "std")] - fn catch_unwind(self) -> CatchUnwind - where - Self: Sized + ::std::panic::UnwindSafe, - { - assert_future::>, _>(CatchUnwind::new( - self, - )) - } - - /// Create a cloneable handle to this future where all handles will resolve - /// to the same result. - /// - /// The `shared` combinator method provides a method to convert any future - /// into a cloneable future. It enables a future to be polled by multiple - /// threads. - /// - /// This method is only available when the `std` or 'spin' feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// - /// let future = async { 6 }; - /// let shared1 = future.shared(); - /// let shared2 = shared1.clone(); - /// - /// assert_eq!(6, shared1.await); - /// assert_eq!(6, shared2.await); - /// # }); - /// ``` - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::FutureExt; - /// use futures::executor::block_on; - /// use std::thread; - /// - /// let future = async { 6 }; - /// let shared1 = future.shared(); - /// let shared2 = shared1.clone(); - /// let join_handle = thread::spawn(move || { - /// assert_eq!(6, block_on(shared2)); - /// }); - /// assert_eq!(6, shared1.await); - /// join_handle.join().unwrap(); - /// # }); - /// ``` - #[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] - fn shared(self) -> Shared - where - Self: Sized, - Self::Output: Clone, - { - assert_future::(Shared::new(self)) - } - - /// Turn this future into a future that yields `()` on completion and sends - /// its output to another future on a separate task. - /// - /// This can be used with spawning executors to easily retrieve the result - /// of a future executing on a separate task or thread. - /// - /// This method is only available when the `std` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "channel")] - #[cfg_attr(docsrs, doc(cfg(feature = "channel")))] - #[cfg(feature = "std")] - fn remote_handle(self) -> (Remote, RemoteHandle) - where - Self: Sized, - { - let (wrapped, handle) = remote_handle::remote_handle(self); - (assert_future::<(), _>(wrapped), handle) - } - - /// Wrap the future in a Box, pinning it. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "alloc")] - fn boxed<'a>(self) -> BoxFuture<'a, Self::Output> - where - Self: Sized + Send + 'a, - { - assert_future::(Box::pin(self)) - } - - /// Wrap the future in a Box, pinning it. - /// - /// Similar to `boxed`, but without the `Send` requirement. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "alloc")] - fn boxed_local<'a>(self) -> LocalBoxFuture<'a, Self::Output> - where - Self: Sized + 'a, - { - assert_future::(Box::pin(self)) - } - - /// Turns a [`Future`](Future) into a - /// [`TryFuture](futures_core::future::TryFuture). - fn unit_error(self) -> UnitError - where - Self: Sized, - { - assert_future::, _>(UnitError::new(self)) - } - - /// Turns a [`Future`](Future) into a - /// [`TryFuture](futures_core::future::TryFuture). - fn never_error(self) -> NeverError - where - Self: Sized, - { - assert_future::, _>(NeverError::new(self)) - } - - /// A convenience for calling `Future::poll` on `Unpin` future types. - fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll - where - Self: Unpin, - { - Pin::new(self).poll(cx) - } - - /// Evaluates and consumes the future, returning the resulting output if - /// the future is ready after the first call to `Future::poll`. - /// - /// If `poll` instead returns `Poll::Pending`, `None` is returned. - /// - /// This method is useful in cases where immediacy is more important than - /// waiting for a result. It is also convenient for quickly obtaining - /// the value of a future that is known to always resolve immediately. - /// - /// # Examples - /// - /// ``` - /// # use futures::prelude::*; - /// use futures::{future::ready, future::pending}; - /// let future_ready = ready("foobar"); - /// let future_pending = pending::<&'static str>(); - /// - /// assert_eq!(future_ready.now_or_never(), Some("foobar")); - /// assert_eq!(future_pending.now_or_never(), None); - /// ``` - /// - /// In cases where it is absolutely known that a future should always - /// resolve immediately and never return `Poll::Pending`, this method can - /// be combined with `expect()`: - /// - /// ``` - /// # use futures::{prelude::*, future::ready}; - /// let future_ready = ready("foobar"); - /// - /// assert_eq!(future_ready.now_or_never().expect("Future not ready"), "foobar"); - /// ``` - fn now_or_never(self) -> Option - where - Self: Sized, - { - let noop_waker = crate::task::noop_waker(); - let mut cx = Context::from_waker(&noop_waker); - - let this = pin!(self); - match this.poll(&mut cx) { - Poll::Ready(x) => Some(x), - _ => None, - } - } -} diff --git a/futures-util/src/future/future/remote_handle.rs b/futures-util/src/future/future/remote_handle.rs deleted file mode 100644 index 4aacd2d6be..0000000000 --- a/futures-util/src/future/future/remote_handle.rs +++ /dev/null @@ -1,127 +0,0 @@ -use { - crate::future::{CatchUnwind, FutureExt}, - futures_channel::oneshot::{self, Receiver, Sender}, - futures_core::{ - future::Future, - ready, - task::{Context, Poll}, - }, - pin_project_lite::pin_project, - std::{ - any::Any, - boxed::Box, - fmt, - panic::{self, AssertUnwindSafe}, - pin::Pin, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - thread, - }, -}; - -/// The handle to a remote future returned by -/// [`remote_handle`](crate::future::FutureExt::remote_handle). When you drop this, -/// the remote future will be woken up to be dropped by the executor. -/// -/// ## Unwind safety -/// -/// When the remote future panics, [Remote] will catch the unwind and transfer it to -/// the thread where `RemoteHandle` is being awaited. This is good for the common -/// case where [Remote] is spawned on a threadpool. It is unlikely that other code -/// in the executor working thread shares mutable data with the spawned future and we -/// preserve the executor from losing its working threads. -/// -/// If you run the future locally and send the handle of to be awaited elsewhere, you -/// must be careful with regard to unwind safety because the thread in which the future -/// is polled will keep running after the panic and the thread running the [RemoteHandle] -/// will unwind. -#[must_use = "dropping a remote handle cancels the underlying future"] -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "channel")))] -pub struct RemoteHandle { - rx: Receiver>, - keep_running: Arc, -} - -impl RemoteHandle { - /// Drops this handle *without* canceling the underlying future. - /// - /// This method can be used if you want to drop the handle, but let the - /// execution continue. - pub fn forget(self) { - self.keep_running.store(true, Ordering::SeqCst); - } -} - -impl Future for RemoteHandle { - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match ready!(self.rx.poll_unpin(cx)) { - Ok(Ok(output)) => Poll::Ready(output), - // the remote future panicked. - Ok(Err(e)) => panic::resume_unwind(e), - // The oneshot sender was dropped. - Err(e) => panic::resume_unwind(Box::new(e)), - } - } -} - -type SendMsg = Result<::Output, Box>; - -pin_project! { - /// A future which sends its output to the corresponding `RemoteHandle`. - /// Created by [`remote_handle`](crate::future::FutureExt::remote_handle). - #[must_use = "futures do nothing unless you `.await` or poll them"] - #[cfg_attr(docsrs, doc(cfg(feature = "channel")))] - pub struct Remote { - tx: Option>>, - keep_running: Arc, - #[pin] - future: CatchUnwind>, - } -} - -impl fmt::Debug for Remote { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Remote").field(&self.future).finish() - } -} - -impl Future for Remote { - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let this = self.project(); - - if this.tx.as_mut().unwrap().poll_canceled(cx).is_ready() - && !this.keep_running.load(Ordering::SeqCst) - { - // Cancelled, bail out - return Poll::Ready(()); - } - - let output = ready!(this.future.poll(cx)); - - // if the receiving end has gone away then that's ok, we just ignore the - // send error here. - drop(this.tx.take().unwrap().send(output)); - Poll::Ready(()) - } -} - -pub(super) fn remote_handle(future: Fut) -> (Remote, RemoteHandle) { - let (tx, rx) = oneshot::channel(); - let keep_running = Arc::new(AtomicBool::new(false)); - - // Unwind Safety: See the docs for RemoteHandle. - let wrapped = Remote { - future: AssertUnwindSafe(future).catch_unwind(), - tx: Some(tx), - keep_running: keep_running.clone(), - }; - - (wrapped, RemoteHandle { rx, keep_running }) -} diff --git a/futures-util/src/future/future/shared.rs b/futures-util/src/future/future/shared.rs deleted file mode 100644 index f26b20d926..0000000000 --- a/futures-util/src/future/future/shared.rs +++ /dev/null @@ -1,430 +0,0 @@ -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; - -#[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"] -pub struct Shared { - inner: Option>>, - waker_key: usize, -} - -struct Inner { - future_or_output: UnsafeCell>, - notifier: Arc, -} - -struct Notifier { - state: AtomicUsize, - wakers: Mutex>>>, -} - -/// A weak reference to a [`Shared`] that can be upgraded much like an `Arc`. -pub struct WeakShared(Weak>); - -impl Clone for WeakShared { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl fmt::Debug for Shared { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Shared") - .field("inner", &self.inner) - .field("waker_key", &self.waker_key) - .finish() - } -} - -impl fmt::Debug for Inner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Inner").finish() - } -} - -impl fmt::Debug for WeakShared { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("WeakShared").finish() - } -} - -enum FutureOrOutput { - Future(Fut), - Output(Fut::Output), -} - -unsafe impl Send for Inner -where - Fut: Future + Send, - Fut::Output: Send + Sync, -{ -} - -unsafe impl Sync for Inner -where - Fut: Future + Send, - Fut::Output: Send + Sync, -{ -} - -const IDLE: usize = 0; -const POLLING: usize = 1; -const COMPLETE: usize = 2; -const POISONED: usize = 3; - -const NULL_WAKER_KEY: usize = usize::MAX; - -impl Shared { - pub(super) fn new(future: Fut) -> Self { - let inner = Inner { - future_or_output: UnsafeCell::new(FutureOrOutput::Future(future)), - notifier: Arc::new(Notifier { - state: AtomicUsize::new(IDLE), - wakers: Mutex::new(Some(Slab::new())), - }), - }; - - Self { inner: Some(Arc::new(inner)), waker_key: NULL_WAKER_KEY } - } -} - -impl Shared -where - Fut: Future, -{ - /// Returns [`Some`] containing a reference to this [`Shared`]'s output if - /// it has already been computed by a clone or [`None`] if it hasn't been - /// computed yet or this [`Shared`] already returned its output from - /// [`poll`](Future::poll). - pub fn peek(&self) -> Option<&Fut::Output> { - if let Some(inner) = self.inner.as_ref() { - match inner.notifier.state.load(SeqCst) { - COMPLETE => unsafe { return Some(inner.output()) }, - POISONED => panic!("inner future panicked during poll"), - _ => {} - } - } - None - } - - /// Creates a new [`WeakShared`] for this [`Shared`]. - /// - /// Returns [`None`] if it has already been polled to completion. - pub fn downgrade(&self) -> Option> { - if let Some(inner) = self.inner.as_ref() { - return Some(WeakShared(Arc::downgrade(inner))); - } - None - } - - /// Gets the number of strong pointers to this allocation. - /// - /// Returns [`None`] if it has already been polled to completion. - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. Another thread - /// can change the strong count at any time, including potentially between calling this method - /// and acting on the result. - pub fn strong_count(&self) -> Option { - self.inner.as_ref().map(Arc::strong_count) - } - - /// Gets the number of weak pointers to this allocation. - /// - /// Returns [`None`] if it has already been polled to completion. - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. Another thread - /// can change the weak count at any time, including potentially between calling this method - /// and acting on the result. - pub fn weak_count(&self) -> Option { - self.inner.as_ref().map(Arc::weak_count) - } - - /// Hashes the internal state of this `Shared` in a way that's compatible with `ptr_eq`. - pub fn ptr_hash(&self, state: &mut H) { - match self.inner.as_ref() { - Some(arc) => { - state.write_u8(1); - ptr::hash(Arc::as_ptr(arc), state); - } - None => { - state.write_u8(0); - } - } - } - - /// Returns `true` if the two `Shared`s point to the same future (in a vein similar to - /// `Arc::ptr_eq`). - /// - /// Returns `false` if either `Shared` has terminated. - pub fn ptr_eq(&self, rhs: &Self) -> bool { - let lhs = match self.inner.as_ref() { - Some(lhs) => lhs, - None => return false, - }; - let rhs = match rhs.inner.as_ref() { - Some(rhs) => rhs, - None => return false, - }; - Arc::ptr_eq(lhs, rhs) - } -} - -impl Inner -where - Fut: Future, -{ - /// Safety: callers must first ensure that `self.inner.state` - /// is `COMPLETE` - unsafe fn output(&self) -> &Fut::Output { - match unsafe { &*self.future_or_output.get() } { - FutureOrOutput::Output(item) => item, - FutureOrOutput::Future(_) => unreachable!(), - } - } -} - -impl Inner -where - Fut: Future, - Fut::Output: Clone, -{ - /// 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_mut = wakers_guard.as_mut(); - - let wakers = match wakers_mut { - Some(wakers) => wakers, - None => return, - }; - - let new_waker = cx.waker(); - - if *waker_key == NULL_WAKER_KEY { - *waker_key = wakers.insert(Some(new_waker.clone())); - } else { - match wakers[*waker_key] { - Some(ref old_waker) if new_waker.will_wake(old_waker) => {} - // Could use clone_from here, but Waker doesn't specialize it. - ref mut slot => *slot = Some(new_waker.clone()), - } - } - debug_assert!(*waker_key != NULL_WAKER_KEY); - } - - /// Safety: callers must first ensure that `inner.state` - /// is `COMPLETE` - unsafe fn take_or_clone_output(self: Arc) -> Fut::Output { - match Arc::try_unwrap(self) { - Ok(inner) => match inner.future_or_output.into_inner() { - FutureOrOutput::Output(item) => item, - FutureOrOutput::Future(_) => unreachable!(), - }, - Err(inner) => unsafe { inner.output().clone() }, - } - } -} - -impl FusedFuture for Shared -where - Fut: Future, - Fut::Output: Clone, -{ - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl Future for Shared -where - Fut: Future, - Fut::Output: Clone, -{ - type Output = Fut::Output; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - - let inner = this.inner.take().expect("Shared future polled again after completion"); - - // Fast path for when the wrapped future has already completed - if inner.notifier.state.load(Acquire) == COMPLETE { - // Safety: We're in the COMPLETE state - return unsafe { Poll::Ready(inner.take_or_clone_output()) }; - } - - inner.record_waker(&mut this.waker_key, cx); - - match inner - .notifier - .state - .compare_exchange(IDLE, POLLING, SeqCst, SeqCst) - .unwrap_or_else(|x| x) - { - IDLE => { - // Lock acquired, fall through - } - POLLING => { - // Another task is currently polling, at this point we just want - // to ensure that the waker for this task is registered - this.inner = Some(inner); - return Poll::Pending; - } - COMPLETE => { - // Safety: We're in the COMPLETE state - return unsafe { Poll::Ready(inner.take_or_clone_output()) }; - } - POISONED => panic!("inner future panicked during poll"), - _ => unreachable!(), - } - - let waker = waker_ref(&inner.notifier); - let mut cx = Context::from_waker(&waker); - - struct Reset<'a> { - state: &'a AtomicUsize, - did_not_panic: bool, - } - - impl Drop for Reset<'_> { - fn drop(&mut self) { - if !self.did_not_panic { - self.state.store(POISONED, SeqCst); - } - } - } - - let mut reset = Reset { state: &inner.notifier.state, did_not_panic: false }; - - let output = { - let future = unsafe { - match &mut *inner.future_or_output.get() { - FutureOrOutput::Future(fut) => Pin::new_unchecked(fut), - _ => unreachable!(), - } - }; - - let poll_result = future.poll(&mut cx); - reset.did_not_panic = true; - - match poll_result { - Poll::Pending => { - if inner.notifier.state.compare_exchange(POLLING, IDLE, SeqCst, SeqCst).is_ok() - { - // Success - drop(reset); - this.inner = Some(inner); - return Poll::Pending; - } else { - unreachable!() - } - } - Poll::Ready(output) => output, - } - }; - - unsafe { - *inner.future_or_output.get() = FutureOrOutput::Output(output); - } - - 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(); - } - - drop(reset); // Make borrow checker happy - drop(wakers_guard); - - // Safety: We're in the COMPLETE state - unsafe { Poll::Ready(inner.take_or_clone_output()) } - } -} - -impl Clone for Shared -where - Fut: Future, -{ - fn clone(&self) -> Self { - Self { inner: self.inner.clone(), waker_key: NULL_WAKER_KEY } - } -} - -impl Drop for Shared -where - Fut: Future, -{ - 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); - } - } - } - } -} - -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() { - waker.wake(); - } - } - } - } -} - -impl WeakShared { - /// Attempts to upgrade this [`WeakShared`] into a [`Shared`]. - /// - /// Returns [`None`] if all clones of the [`Shared`] have been dropped or polled - /// to completion. - pub fn upgrade(&self) -> Option> { - Some(Shared { inner: Some(self.0.upgrade()?), waker_key: NULL_WAKER_KEY }) - } -} diff --git a/futures-util/src/future/join.rs b/futures-util/src/future/join.rs deleted file mode 100644 index 8c16c3e331..0000000000 --- a/futures-util/src/future/join.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::future::{assert_future, maybe_done, MaybeDone}; -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`join`](super::FutureExt::join) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Join where Fut1: Future, Fut2: Future { - #[pin] fut1: MaybeDone, - #[pin] fut2: MaybeDone, - } -} - -impl Join { - pub(crate) fn new(fut1: Fut1, fut2: Fut2) -> Self { - Self { fut1: maybe_done(fut1), fut2: maybe_done(fut2) } - } -} - -impl fmt::Debug for Join -where - Fut1: Future + fmt::Debug, - Fut1::Output: fmt::Debug, - Fut2: Future + fmt::Debug, - Fut2::Output: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Join").field("fut1", &self.fut1).field("fut2", &self.fut2).finish() - } -} - -impl Future for Join { - type Output = (Fut1::Output, Fut2::Output); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut all_done = true; - let mut futures = self.project(); - - all_done &= futures.fut1.as_mut().poll(cx).is_ready(); - all_done &= futures.fut2.as_mut().poll(cx).is_ready(); - - if all_done { - Poll::Ready((futures.fut1.take_output().unwrap(), futures.fut2.take_output().unwrap())) - } else { - Poll::Pending - } - } -} - -impl FusedFuture for Join { - fn is_terminated(&self) -> bool { - self.fut1.is_terminated() && self.fut2.is_terminated() - } -} - -/// Joins the result of two futures, waiting for them both to complete. -/// -/// This function will return a new future which awaits both futures to -/// complete. The returned future will finish with a tuple of both results. -/// -/// Note that this function consumes the passed futures and returns a -/// wrapped version of it. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = async { 1 }; -/// let b = async { 2 }; -/// let pair = future::join(a, b); -/// -/// assert_eq!(pair.await, (1, 2)); -/// # }); -/// ``` -pub fn join(future1: Fut1, future2: Fut2) -> Join -where - Fut1: Future, - Fut2: Future, -{ - assert_future::<(Fut1::Output, Fut2::Output), _>(Join::new(future1, future2)) -} diff --git a/futures-util/src/future/join_all.rs b/futures-util/src/future/join_all.rs deleted file mode 100644 index 79eee8dffc..0000000000 --- a/futures-util/src/future/join_all.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! Definition of the `JoinAll` combinator, waiting for all of a list of futures -//! to finish. - -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt; -use core::future::Future; -use core::iter::FromIterator; -use core::mem; -use core::pin::Pin; -use core::task::{Context, Poll}; - -use super::{assert_future, MaybeDone}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -use crate::stream::{Collect, FuturesOrdered, StreamExt}; - -pub(crate) fn iter_pin_mut(slice: Pin<&mut [T]>) -> impl Iterator> { - // Safety: `std` _could_ make this unsound if it were to decide Pin's - // invariants aren't required to transmit through slices. Otherwise this has - // the same safety as a normal field pin projection. - unsafe { slice.get_unchecked_mut() }.iter_mut().map(|t| unsafe { Pin::new_unchecked(t) }) -} - -#[must_use = "futures do nothing unless you `.await` or poll them"] -/// Future for the [`join_all`] function. -pub struct JoinAll -where - F: Future, -{ - kind: JoinAllKind, -} - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -pub(crate) const SMALL: usize = 30; - -enum JoinAllKind -where - F: Future, -{ - Small { - elems: Pin]>>, - }, - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - Big { - fut: Collect, Vec>, - }, -} - -impl fmt::Debug for JoinAll -where - F: Future + fmt::Debug, - F::Output: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - JoinAllKind::Small { ref elems } => { - f.debug_struct("JoinAll").field("elems", elems).finish() - } - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - JoinAllKind::Big { ref fut, .. } => fmt::Debug::fmt(fut, f), - } - } -} - -/// Creates a future which represents a collection of the outputs of the futures -/// given. -/// -/// The returned future will drive execution for all of its underlying futures, -/// collecting the results into a destination `Vec` in the same order as they -/// were provided. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -/// -/// # See Also -/// -/// `join_all` will switch to the more powerful [`FuturesOrdered`] for performance -/// reasons if the number of futures is large. You may want to look into using it or -/// its counterpart [`FuturesUnordered`][crate::stream::FuturesUnordered] directly. -/// -/// Some examples for additional functionality provided by these are: -/// -/// * Adding new futures to the set even after it has been started. -/// -/// * Only polling the specific futures that have been woken. In cases where -/// you have a lot of futures this will result in much more efficient polling. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future::join_all; -/// -/// async fn foo(i: u32) -> u32 { i } -/// -/// let futures = vec![foo(1), foo(2), foo(3)]; -/// -/// assert_eq!(join_all(futures).await, [1, 2, 3]); -/// # }); -/// ``` -pub fn join_all(iter: I) -> JoinAll -where - I: IntoIterator, - I::Item: Future, -{ - let iter = iter.into_iter(); - - #[cfg(target_os = "none")] - #[cfg_attr(target_os = "none", cfg(not(target_has_atomic = "ptr")))] - { - let kind = - JoinAllKind::Small { elems: iter.map(MaybeDone::Future).collect::>().into() }; - - assert_future::::Output>, _>(JoinAll { kind }) - } - - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - { - let kind = match iter.size_hint().1 { - Some(max) if max <= SMALL => JoinAllKind::Small { - elems: iter.map(MaybeDone::Future).collect::>().into(), - }, - _ => JoinAllKind::Big { fut: iter.collect::>().collect() }, - }; - - assert_future::::Output>, _>(JoinAll { kind }) - } -} - -impl Future for JoinAll -where - F: Future, -{ - type Output = Vec; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match &mut self.kind { - JoinAllKind::Small { elems } => { - let mut all_done = true; - - for elem in iter_pin_mut(elems.as_mut()) { - if elem.poll(cx).is_pending() { - all_done = false; - } - } - - if all_done { - let mut elems = mem::replace(elems, Box::pin([])); - let result = - iter_pin_mut(elems.as_mut()).map(|e| e.take_output().unwrap()).collect(); - Poll::Ready(result) - } else { - Poll::Pending - } - } - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - JoinAllKind::Big { fut } => Pin::new(fut).poll(cx), - } - } -} - -impl FromIterator for JoinAll { - fn from_iter>(iter: T) -> Self { - join_all(iter) - } -} diff --git a/futures-util/src/future/lazy.rs b/futures-util/src/future/lazy.rs deleted file mode 100644 index e9a8cf2fa9..0000000000 --- a/futures-util/src/future/lazy.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::assert_future; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`lazy`] function. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Lazy { - f: Option, -} - -// safe because we never generate `Pin<&mut F>` -impl Unpin for Lazy {} - -/// Creates a new future that allows delayed execution of a closure. -/// -/// The provided closure is only run once the future is polled. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::lazy(|_| 1); -/// assert_eq!(a.await, 1); -/// -/// let b = future::lazy(|_| -> i32 { -/// panic!("oh no!") -/// }); -/// drop(b); // closure is never run -/// # }); -/// ``` -pub fn lazy(f: F) -> Lazy -where - F: FnOnce(&mut Context<'_>) -> R, -{ - assert_future::(Lazy { f: Some(f) }) -} - -impl FusedFuture for Lazy -where - F: FnOnce(&mut Context<'_>) -> R, -{ - fn is_terminated(&self) -> bool { - self.f.is_none() - } -} - -impl Future for Lazy -where - F: FnOnce(&mut Context<'_>) -> R, -{ - type Output = R; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready((self.f.take().expect("Lazy polled after completion"))(cx)) - } -} diff --git a/futures-util/src/future/maybe_done.rs b/futures-util/src/future/maybe_done.rs deleted file mode 100644 index fa8787a874..0000000000 --- a/futures-util/src/future/maybe_done.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Definition of the MaybeDone combinator - -use super::assert_future; -use core::mem; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; - -/// A future that may have completed. -/// -/// This is created by the [`maybe_done()`] function. -#[derive(Debug)] -pub enum MaybeDone { - /// A not-yet-completed future - Future(/* #[pin] */ Fut), - /// The output of the completed future - Done(Fut::Output), - /// The empty variant after the result of a [`MaybeDone`] has been - /// taken using the [`take_output`](MaybeDone::take_output) method. - Gone, -} - -impl Unpin for MaybeDone {} - -/// Wraps a future into a `MaybeDone` -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use core::pin::pin; -/// -/// use futures::future; -/// -/// let future = future::maybe_done(async { 5 }); -/// 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)); -/// assert_eq!(future.as_mut().take_output(), None); -/// # }); -/// ``` -pub fn maybe_done(future: Fut) -> MaybeDone { - assert_future::<(), _>(MaybeDone::Future(future)) -} - -impl MaybeDone { - /// Returns an [`Option`] containing a mutable reference to the output of the future. - /// The output of this method will be [`Some`] if and only if the inner - /// future has been completed and [`take_output`](MaybeDone::take_output) - /// has not yet been called. - #[inline] - pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { - unsafe { - match self.get_unchecked_mut() { - Self::Done(res) => Some(res), - _ => None, - } - } - } - - /// Attempt to take the output of a `MaybeDone` without driving it - /// towards completion. - #[inline] - pub fn take_output(self: Pin<&mut Self>) -> Option { - match &*self { - Self::Done(_) => {} - Self::Future(_) | Self::Gone => return None, - } - unsafe { - match mem::replace(self.get_unchecked_mut(), Self::Gone) { - Self::Done(output) => Some(output), - _ => unreachable!(), - } - } - } -} - -impl FusedFuture for MaybeDone { - fn is_terminated(&self) -> bool { - match self { - Self::Future(_) => false, - Self::Done(_) | Self::Gone => true, - } - } -} - -impl Future for MaybeDone { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unsafe { - match self.as_mut().get_unchecked_mut() { - Self::Future(f) => { - let res = ready!(Pin::new_unchecked(f).poll(cx)); - self.set(Self::Done(res)); - } - Self::Done(_) => {} - Self::Gone => panic!("MaybeDone polled after value taken"), - } - } - Poll::Ready(()) - } -} diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs deleted file mode 100644 index 2209ffd56e..0000000000 --- a/futures-util/src/future/mod.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! Asynchronous values. -//! -//! This module contains: -//! -//! - The [`Future`] trait. -//! - The [`FutureExt`] and [`TryFutureExt`] trait, which provides adapters for -//! chaining and composing futures. -//! - Top-level future combinators like [`lazy`](lazy()) which creates a future -//! from a closure that defines its return value, and [`ready`](ready()), -//! which constructs a future with an immediate defined value. - -#[doc(no_inline)] -pub use core::future::Future; - -#[cfg(feature = "alloc")] -pub use futures_core::future::{BoxFuture, LocalBoxFuture}; -pub use futures_core::future::{FusedFuture, TryFuture}; -pub use futures_task::{FutureObj, LocalFutureObj, UnsafeFutureObj}; - -// Extension traits and combinators -#[allow(clippy::module_inception)] -mod future; -pub use self::future::{ - Flatten, Fuse, FutureExt, Inspect, IntoStream, Map, MapInto, NeverError, Then, UnitError, -}; - -#[deprecated(note = "This is now an alias for [Flatten](Flatten)")] -pub use self::future::FlattenStream; - -#[cfg(feature = "std")] -pub use self::future::CatchUnwind; - -#[cfg(feature = "channel")] -#[cfg_attr(docsrs, doc(cfg(feature = "channel")))] -#[cfg(feature = "std")] -pub use self::future::{Remote, RemoteHandle}; - -#[cfg(any(feature = "std", all(feature = "alloc", feature = "spin")))] -pub use self::future::{Shared, WeakShared}; - -mod try_future; -pub use self::try_future::{ - AndThen, ErrInto, InspectErr, InspectOk, IntoFuture, MapErr, MapOk, MapOkOrElse, OkInto, - OrElse, TryFlatten, TryFlattenStream, TryFutureExt, UnwrapOrElse, -}; - -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::try_future::FlattenSink; - -// Primitive futures - -mod lazy; -pub use self::lazy::{lazy, Lazy}; - -mod pending; -pub use self::pending::{pending, Pending}; - -mod maybe_done; -pub use self::maybe_done::{maybe_done, MaybeDone}; - -mod try_maybe_done; -pub use self::try_maybe_done::{try_maybe_done, TryMaybeDone}; - -mod option; -pub use self::option::OptionFuture; - -mod poll_fn; -pub use self::poll_fn::{poll_fn, PollFn}; - -mod poll_immediate; -pub use self::poll_immediate::{poll_immediate, PollImmediate}; - -mod ready; -pub use self::ready::{err, ok, ready, Ready}; - -mod always_ready; -pub use self::always_ready::{always_ready, AlwaysReady}; - -mod join; -pub use self::join::{join, Join}; - -#[cfg(feature = "alloc")] -mod join_all; -#[cfg(feature = "alloc")] -pub use self::join_all::{join_all, JoinAll}; - -mod select; -pub use self::select::{select, Select}; - -#[cfg(feature = "alloc")] -mod select_all; -#[cfg(feature = "alloc")] -pub use self::select_all::{select_all, SelectAll}; - -mod try_join; -pub use self::try_join::{try_join, TryJoin}; - -#[cfg(feature = "alloc")] -mod try_join_all; -#[cfg(feature = "alloc")] -pub use self::try_join_all::{try_join_all, TryJoinAll}; - -mod try_select; -pub use self::try_select::{try_select, TrySelect}; - -#[cfg(feature = "alloc")] -mod select_ok; -#[cfg(feature = "alloc")] -pub use self::select_ok::{select_ok, SelectOk}; - -mod either; -pub use self::either::Either; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod abortable; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted}; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use abortable::abortable; - -// Just a helper function to ensure the futures we're returning all have the -// right implementations. -pub(crate) fn assert_future(future: F) -> F -where - F: Future, -{ - future -} diff --git a/futures-util/src/future/option.rs b/futures-util/src/future/option.rs deleted file mode 100644 index 0bc377758a..0000000000 --- a/futures-util/src/future/option.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Definition of the `Option` (optional step) combinator - -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// A future representing a value which may or may not be present. - /// - /// Created by the [`From`] implementation for [`Option`](std::option::Option). - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::OptionFuture; - /// - /// let mut a: OptionFuture<_> = Some(async { 123 }).into(); - /// assert_eq!(a.await, Some(123)); - /// - /// a = None.into(); - /// assert_eq!(a.await, None); - /// # }); - /// ``` - #[derive(Debug, Clone)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct OptionFuture { - #[pin] - inner: Option, - } -} - -impl Default for OptionFuture { - fn default() -> Self { - Self { inner: None } - } -} - -impl Future for OptionFuture { - type Output = Option; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.project().inner.as_pin_mut() { - Some(x) => x.poll(cx).map(Some), - None => Poll::Ready(None), - } - } -} - -impl FusedFuture for OptionFuture { - fn is_terminated(&self) -> bool { - match &self.inner { - Some(x) => x.is_terminated(), - None => true, - } - } -} - -impl From> for OptionFuture { - fn from(option: Option) -> Self { - Self { inner: option } - } -} diff --git a/futures-util/src/future/pending.rs b/futures-util/src/future/pending.rs deleted file mode 100644 index b8e28686e1..0000000000 --- a/futures-util/src/future/pending.rs +++ /dev/null @@ -1,55 +0,0 @@ -use super::assert_future; -use core::marker; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`pending()`] function. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Pending { - _data: marker::PhantomData, -} - -impl FusedFuture for Pending { - fn is_terminated(&self) -> bool { - true - } -} - -/// Creates a future which never resolves, representing a computation that never -/// finishes. -/// -/// The returned future will forever return [`Poll::Pending`]. -/// -/// # Examples -/// -/// ```ignore -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let future = future::pending(); -/// let () = future.await; -/// unreachable!(); -/// # }); -/// ``` -#[cfg_attr(docsrs, doc(alias = "never"))] -pub fn pending() -> Pending { - assert_future::(Pending { _data: marker::PhantomData }) -} - -impl Future for Pending { - type Output = T; - - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { - Poll::Pending - } -} - -impl Unpin for Pending {} - -impl Clone for Pending { - fn clone(&self) -> Self { - pending() - } -} diff --git a/futures-util/src/future/poll_fn.rs b/futures-util/src/future/poll_fn.rs deleted file mode 100644 index 19311570b5..0000000000 --- a/futures-util/src/future/poll_fn.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Definition of the `PollFn` adapter combinator - -use super::assert_future; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; - -/// Future for the [`poll_fn`] function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct PollFn { - f: F, -} - -impl Unpin for PollFn {} - -/// Creates a new future wrapping around a function returning [`Poll`]. -/// -/// Polling the returned future delegates to the wrapped function. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future::poll_fn; -/// use futures::task::{Context, Poll}; -/// -/// fn read_line(_cx: &mut Context<'_>) -> Poll { -/// Poll::Ready("Hello, World!".into()) -/// } -/// -/// let read_future = poll_fn(read_line); -/// assert_eq!(read_future.await, "Hello, World!".to_owned()); -/// # }); -/// ``` -pub fn poll_fn(f: F) -> PollFn -where - F: FnMut(&mut Context<'_>) -> Poll, -{ - assert_future::(PollFn { f }) -} - -impl fmt::Debug for PollFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PollFn").finish() - } -} - -impl Future for PollFn -where - F: FnMut(&mut Context<'_>) -> Poll, -{ - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - (&mut self.f)(cx) - } -} diff --git a/futures-util/src/future/poll_immediate.rs b/futures-util/src/future/poll_immediate.rs deleted file mode 100644 index 8247011375..0000000000 --- a/futures-util/src/future/poll_immediate.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::assert_future; -use core::pin::Pin; -use futures_core::task::{Context, Poll}; -use futures_core::{FusedFuture, Future, Stream}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`poll_immediate`](poll_immediate()) function. - /// - /// It will never return [Poll::Pending](core::task::Poll::Pending) - #[derive(Debug, Clone)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct PollImmediate { - #[pin] - future: Option - } -} - -impl Future for PollImmediate -where - F: Future, -{ - type Output = Option; - - #[inline] - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - let inner = - this.future.as_mut().as_pin_mut().expect("PollImmediate polled after completion"); - match inner.poll(cx) { - Poll::Ready(t) => { - this.future.set(None); - Poll::Ready(Some(t)) - } - Poll::Pending => Poll::Ready(None), - } - } -} - -impl FusedFuture for PollImmediate { - fn is_terminated(&self) -> bool { - self.future.is_none() - } -} - -/// A [Stream](crate::stream::Stream) implementation that can be polled repeatedly until the future is done. -/// The stream will never return [Poll::Pending](core::task::Poll::Pending) -/// so polling it in a tight loop is worse than using a blocking synchronous function. -/// ``` -/// # futures::executor::block_on(async { -/// use core::pin::pin; -/// -/// use futures::task::Poll; -/// use futures::{StreamExt, future}; -/// use future::FusedFuture; -/// -/// let f = async { 1_u32 }; -/// 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}; -/// let f = pin!(f); -/// let mut p = future::poll_immediate(f); -/// assert_eq!(p.next().await, Some(Poll::Pending)); -/// assert!(!p.is_terminated()); -/// assert_eq!(p.next().await, Some(Poll::Ready(42))); -/// assert!(p.is_terminated()); -/// assert_eq!(p.next().await, None); -/// # }); -/// ``` -impl Stream for PollImmediate -where - F: Future, -{ - type Item = Poll; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - match this.future.as_mut().as_pin_mut() { - // inner is gone, so we can signal that the stream is closed. - None => Poll::Ready(None), - Some(fut) => Poll::Ready(Some(fut.poll(cx).map(|t| { - this.future.set(None); - t - }))), - } - } -} - -/// Creates a future that is immediately ready with an Option of a value. -/// Specifically this means that [poll](core::future::Future::poll()) always returns [Poll::Ready](core::task::Poll::Ready). -/// -/// # Caution -/// -/// When consuming the future by this function, note the following: -/// -/// - This function does not guarantee that the future will run to completion, so it is generally incompatible with passing the non-cancellation-safe future by value. -/// - Even if the future is cancellation-safe, creating and dropping new futures frequently may lead to performance problems. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let r = future::poll_immediate(async { 1_u32 }); -/// assert_eq!(r.await, Some(1)); -/// -/// let p = future::poll_immediate(future::pending::()); -/// assert_eq!(p.await, None); -/// # }); -/// ``` -/// -/// ### Reusing a future -/// -/// ``` -/// # futures::executor::block_on(async { -/// use core::pin::pin; -/// -/// use futures::future; -/// -/// let f = async {futures::pending!(); 42_u8}; -/// let mut f = pin!(f); -/// assert_eq!(None, future::poll_immediate(&mut f).await); -/// assert_eq!(42, f.await); -/// # }); -/// ``` -pub fn poll_immediate(f: F) -> PollImmediate { - assert_future::, PollImmediate>(PollImmediate { future: Some(f) }) -} diff --git a/futures-util/src/future/ready.rs b/futures-util/src/future/ready.rs deleted file mode 100644 index e3d791b3cf..0000000000 --- a/futures-util/src/future/ready.rs +++ /dev/null @@ -1,82 +0,0 @@ -use super::assert_future; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`ready`](ready()) function. -#[derive(Debug, Clone)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Ready(Option); - -impl Ready { - /// Unwraps the value from this immediately ready future. - #[inline] - pub fn into_inner(mut self) -> T { - self.0.take().unwrap() - } -} - -impl Unpin for Ready {} - -impl FusedFuture for Ready { - fn is_terminated(&self) -> bool { - self.0.is_none() - } -} - -impl Future for Ready { - type Output = T; - - #[inline] - fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - Poll::Ready(self.0.take().expect("Ready polled after completion")) - } -} - -/// Creates a future that is immediately ready with a value. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::ready(1); -/// assert_eq!(a.await, 1); -/// # }); -/// ``` -pub fn ready(t: T) -> Ready { - assert_future::(Ready(Some(t))) -} - -/// Create a future that is immediately ready with a success value. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::ok::(1); -/// assert_eq!(a.await, Ok(1)); -/// # }); -/// ``` -pub fn ok(t: T) -> Ready> { - Ready(Some(Ok(t))) -} - -/// Create a future that is immediately ready with an error value. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::err::(1); -/// assert_eq!(a.await, Err(1)); -/// # }); -/// ``` -pub fn err(err: E) -> Ready> { - Ready(Some(Err(err))) -} diff --git a/futures-util/src/future/select.rs b/futures-util/src/future/select.rs deleted file mode 100644 index 4aa539e8ab..0000000000 --- a/futures-util/src/future/select.rs +++ /dev/null @@ -1,133 +0,0 @@ -use super::assert_future; -use crate::future::{Either, FutureExt}; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`select()`] function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -#[derive(Debug)] -pub struct Select { - inner: Option<(A, B)>, -} - -impl Unpin for Select {} - -/// Waits for either one of two differently-typed futures to complete. -/// -/// This function will return a new future which awaits for either one of both -/// futures to complete. The returned future will finish with both the value -/// resolved and a future representing the completion of the other work. -/// -/// Note that this function consumes the receiving futures and returns a -/// wrapped version of them. -/// -/// Also note that if both this and the second future have the same -/// output type you can use the `Either::factor_first` method to -/// conveniently extract out the value at the end. -/// -/// # Examples -/// -/// A simple example -/// -/// ``` -/// # futures::executor::block_on(async { -/// 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 { -/// future::pending::<()>().await; // will never finish -/// 1 -/// }; -/// let future2 = async { -/// future::ready(2).await -/// }; -/// -/// // 'select' requires Future + Unpin bounds -/// 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` -/// // `_` represents `future2` -/// Either::Right((value2, _)) => value2, // `value2` is resolved from `future2` -/// // `_` represents `future1` -/// }; -/// -/// assert!(value == 2); -/// # }); -/// ``` -/// -/// A more complex example -/// -/// ``` -/// use futures::future::{self, Either, Future, FutureExt}; -/// -/// // A poor-man's join implemented on top of select -/// -/// fn join(a: A, b: B) -> impl Future -/// where A: Future + Unpin, -/// B: Future + Unpin, -/// { -/// future::select(a, b).then(|either| { -/// match either { -/// Either::Left((x, b)) => b.map(move |y| (x, y)).left_future(), -/// Either::Right((y, a)) => a.map(move |x| (x, y)).right_future(), -/// } -/// }) -/// } -/// ``` -pub fn select(future1: A, future2: B) -> Select -where - A: Future + Unpin, - B: Future + Unpin, -{ - assert_future::, _>(Select { - inner: Some((future1, future2)), - }) -} - -impl Future for Select -where - A: Future + Unpin, - B: Future + Unpin, -{ - type Output = Either<(A::Output, B), (B::Output, A)>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - /// When compiled with `-C opt-level=z`, this function will help the compiler eliminate the `None` branch, where - /// `Option::unwrap` does not. - #[inline(always)] - fn unwrap_option(value: Option) -> T { - match value { - None => unreachable!(), - Some(value) => value, - } - } - - let (a, b) = self.inner.as_mut().expect("cannot poll Select twice"); - - if let Poll::Ready(val) = a.poll_unpin(cx) { - return Poll::Ready(Either::Left((val, unwrap_option(self.inner.take()).1))); - } - - if let Poll::Ready(val) = b.poll_unpin(cx) { - return Poll::Ready(Either::Right((val, unwrap_option(self.inner.take()).0))); - } - - Poll::Pending - } -} - -impl FusedFuture for Select -where - A: Future + Unpin, - B: Future + Unpin, -{ - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} diff --git a/futures-util/src/future/select_all.rs b/futures-util/src/future/select_all.rs deleted file mode 100644 index 0a51d0da6c..0000000000 --- a/futures-util/src/future/select_all.rs +++ /dev/null @@ -1,75 +0,0 @@ -use super::assert_future; -use crate::future::FutureExt; -use alloc::vec::Vec; -use core::iter::FromIterator; -use core::mem; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; - -/// Future for the [`select_all`] function. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct SelectAll { - inner: Vec, -} - -impl Unpin for SelectAll {} - -/// Creates a new future which will select over a list of futures. -/// -/// The returned future will wait for any future within `iter` to be ready. Upon -/// completion the item resolved will be returned, along with the index of the -/// future that was ready and the list of all the remaining futures. -/// -/// There are no guarantees provided on the order of the list with the remaining -/// futures. They might be swapped around, reversed, or completely random. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -/// -/// # Panics -/// -/// This function will panic if the iterator specified contains no items. -pub fn select_all(iter: I) -> SelectAll -where - I: IntoIterator, - I::Item: Future + Unpin, -{ - let ret = SelectAll { inner: iter.into_iter().collect() }; - assert!(!ret.inner.is_empty()); - assert_future::<(::Output, usize, Vec), _>(ret) -} - -impl SelectAll { - /// Consumes this combinator, returning the underlying futures. - pub fn into_inner(self) -> Vec { - self.inner - } -} - -impl Future for SelectAll { - type Output = (Fut::Output, usize, Vec); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.poll_unpin(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - }); - match item { - Some((idx, res)) => { - #[allow(clippy::let_underscore_future)] - let _ = self.inner.swap_remove(idx); - let rest = mem::take(&mut self.inner); - Poll::Ready((res, idx, rest)) - } - None => Poll::Pending, - } - } -} - -impl FromIterator for SelectAll { - fn from_iter>(iter: T) -> Self { - select_all(iter) - } -} diff --git a/futures-util/src/future/select_ok.rs b/futures-util/src/future/select_ok.rs deleted file mode 100644 index 5d5579930b..0000000000 --- a/futures-util/src/future/select_ok.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::assert_future; -use crate::future::TryFutureExt; -use alloc::vec::Vec; -use core::iter::FromIterator; -use core::mem; -use core::pin::Pin; -use futures_core::future::{Future, TryFuture}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`select_ok`] function. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct SelectOk { - inner: Vec, -} - -impl Unpin for SelectOk {} - -/// Creates a new future which will select the first successful future over a list of futures. -/// -/// The returned future will wait for any future within `iter` to be ready and Ok. Unlike -/// `select_all`, this will only return the first successful completion, or the last -/// failure. This is useful in contexts where any success is desired and failures -/// are ignored, unless all the futures fail. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -/// -/// # Panics -/// -/// This function will panic if the iterator specified contains no items. -pub fn select_ok(iter: I) -> SelectOk -where - I: IntoIterator, - I::Item: TryFuture + Unpin, -{ - let ret = SelectOk { inner: iter.into_iter().collect() }; - assert!(!ret.inner.is_empty(), "iterator provided to select_ok was empty"); - assert_future::< - Result<(::Ok, Vec), ::Error>, - _, - >(ret) -} - -impl Future for SelectOk { - type Output = Result<(Fut::Ok, Vec), Fut::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // loop until we've either exhausted all errors, a success was hit, or nothing is ready - loop { - let item = - self.inner.iter_mut().enumerate().find_map(|(i, f)| match f.try_poll_unpin(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - }); - match item { - Some((idx, res)) => { - // always remove Ok or Err, if it's not the last Err continue looping - drop(self.inner.remove(idx)); - match res { - Ok(e) => { - let rest = mem::take(&mut self.inner); - return Poll::Ready(Ok((e, rest))); - } - Err(e) => { - if self.inner.is_empty() { - return Poll::Ready(Err(e)); - } - } - } - } - None => { - // based on the filter above, nothing is ready, return - return Poll::Pending; - } - } - } - } -} - -impl FromIterator for SelectOk { - fn from_iter>(iter: T) -> Self { - select_ok(iter) - } -} diff --git a/futures-util/src/future/try_future/into_future.rs b/futures-util/src/future/try_future/into_future.rs deleted file mode 100644 index 9f093d0e2e..0000000000 --- a/futures-util/src/future/try_future/into_future.rs +++ /dev/null @@ -1,36 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future, TryFuture}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`into_future`](super::TryFutureExt::into_future) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct IntoFuture { - #[pin] - future: Fut, - } -} - -impl IntoFuture { - #[inline] - pub(crate) fn new(future: Fut) -> Self { - Self { future } - } -} - -impl FusedFuture for IntoFuture { - fn is_terminated(&self) -> bool { - self.future.is_terminated() - } -} - -impl Future for IntoFuture { - type Output = Result; - - #[inline] - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().future.try_poll(cx) - } -} diff --git a/futures-util/src/future/try_future/mod.rs b/futures-util/src/future/try_future/mod.rs deleted file mode 100644 index 4ae544aa91..0000000000 --- a/futures-util/src/future/try_future/mod.rs +++ /dev/null @@ -1,624 +0,0 @@ -//! Futures -//! -//! This module contains a number of functions for working with `Future`s, -//! including the `FutureExt` trait which adds methods to `Future` types. - -#[cfg(feature = "compat")] -use crate::compat::Compat; -use core::pin::Pin; -use futures_core::{ - future::TryFuture, - stream::TryStream, - task::{Context, Poll}, -}; -#[cfg(feature = "sink")] -use futures_sink::Sink; - -use crate::fns::{ - inspect_err_fn, inspect_ok_fn, into_fn, map_err_fn, map_ok_fn, map_ok_or_else_fn, - unwrap_or_else_fn, InspectErrFn, InspectOkFn, IntoFn, MapErrFn, MapOkFn, MapOkOrElseFn, - UnwrapOrElseFn, -}; -use crate::future::{assert_future, Inspect, Map}; -use crate::stream::assert_stream; - -// Combinators -mod into_future; -mod try_flatten; -mod try_flatten_err; - -delegate_all!( - /// Future for the [`try_flatten`](TryFutureExt::try_flatten) method. - TryFlatten( - try_flatten::TryFlatten - ): Debug + Future + FusedFuture + New[|x: Fut1| try_flatten::TryFlatten::new(x)] -); - -delegate_all!( - /// Future for the [`try_flatten_err`](TryFutureExt::try_flatten_err) method. - TryFlattenErr( - try_flatten_err::TryFlattenErr - ): Debug + Future + FusedFuture + New[|x: Fut1| try_flatten_err::TryFlattenErr::new(x)] -); - -delegate_all!( - /// Future for the [`try_flatten_stream`](TryFutureExt::try_flatten_stream) method. - TryFlattenStream( - try_flatten::TryFlatten - ): Debug + Sink + Stream + FusedStream + New[|x: Fut| try_flatten::TryFlatten::new(x)] - where Fut: TryFuture -); - -#[cfg(feature = "sink")] -delegate_all!( - /// Sink for the [`flatten_sink`](TryFutureExt::flatten_sink) method. - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - FlattenSink( - try_flatten::TryFlatten - ): Debug + Sink + Stream + FusedStream + New[|x: Fut| try_flatten::TryFlatten::new(x)] -); - -delegate_all!( - /// Future for the [`and_then`](TryFutureExt::and_then) method. - AndThen( - TryFlatten, Fut2> - ): Debug + Future + FusedFuture + New[|x: Fut1, f: F| TryFlatten::new(MapOk::new(x, f))] -); - -delegate_all!( - /// Future for the [`or_else`](TryFutureExt::or_else) method. - OrElse( - TryFlattenErr, Fut2> - ): Debug + Future + FusedFuture + New[|x: Fut1, f: F| TryFlattenErr::new(MapErr::new(x, f))] -); - -delegate_all!( - /// Future for the [`err_into`](TryFutureExt::err_into) method. - ErrInto( - MapErr> - ): Debug + Future + FusedFuture + New[|x: Fut| MapErr::new(x, into_fn())] -); - -delegate_all!( - /// Future for the [`ok_into`](TryFutureExt::ok_into) method. - OkInto( - MapOk> - ): Debug + Future + FusedFuture + New[|x: Fut| MapOk::new(x, into_fn())] -); - -delegate_all!( - /// Future for the [`inspect_ok`](super::TryFutureExt::inspect_ok) method. - InspectOk( - Inspect, InspectOkFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| Inspect::new(IntoFuture::new(x), inspect_ok_fn(f))] -); - -delegate_all!( - /// Future for the [`inspect_err`](super::TryFutureExt::inspect_err) method. - InspectErr( - Inspect, InspectErrFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| Inspect::new(IntoFuture::new(x), inspect_err_fn(f))] -); - -pub use self::into_future::IntoFuture; - -delegate_all!( - /// Future for the [`map_ok`](TryFutureExt::map_ok) method. - MapOk( - Map, MapOkFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| Map::new(IntoFuture::new(x), map_ok_fn(f))] -); - -delegate_all!( - /// Future for the [`map_err`](TryFutureExt::map_err) method. - MapErr( - Map, MapErrFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| Map::new(IntoFuture::new(x), map_err_fn(f))] -); - -delegate_all!( - /// Future for the [`map_ok_or_else`](TryFutureExt::map_ok_or_else) method. - MapOkOrElse( - Map, MapOkOrElseFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F, g: G| Map::new(IntoFuture::new(x), map_ok_or_else_fn(f, g))] -); - -delegate_all!( - /// Future for the [`unwrap_or_else`](TryFutureExt::unwrap_or_else) method. - UnwrapOrElse( - Map, UnwrapOrElseFn> - ): Debug + Future + FusedFuture + New[|x: Fut, f: F| Map::new(IntoFuture::new(x), unwrap_or_else_fn(f))] -); - -impl TryFutureExt for Fut {} - -/// Adapters specific to [`Result`]-returning futures -pub trait TryFutureExt: TryFuture { - /// Flattens the execution of this future when the successful result of this - /// future is a [`Sink`]. - /// - /// This can be useful when sink initialization is deferred, and it is - /// convenient to work with that sink as if the sink was available at the - /// call site. - /// - /// Note that this function consumes this future and returns a wrapped - /// version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::{Future, TryFutureExt}; - /// use futures::sink::Sink; - /// # use futures::channel::mpsc::{self, SendError}; - /// # type T = i32; - /// # type E = SendError; - /// - /// fn make_sink_async() -> impl Future, - /// E, - /// >> { // ... } - /// # let (tx, _rx) = mpsc::unbounded::(); - /// # futures::future::ready(Ok(tx)) - /// # } - /// fn take_sink(sink: impl Sink) { /* ... */ } - /// - /// let fut = make_sink_async(); - /// take_sink(fut.flatten_sink()) - /// ``` - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - fn flatten_sink(self) -> FlattenSink - where - Self::Ok: Sink, - Self: Sized, - { - crate::sink::assert_sink::(FlattenSink::new(self)) - } - - /// Maps this future's success value to a different value. - /// - /// This method can be used to change the [`Ok`](TryFuture::Ok) type of the - /// future into a different type. It is similar to the [`Result::map`] - /// method. You can use this method to chain along a computation once the - /// future has been resolved. - /// - /// The provided closure `f` will only be called if this future is resolved - /// to an [`Ok`]. If it resolves to an [`Err`], panics, or is dropped, then - /// the provided closure will never be invoked. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Ok::(1) }; - /// let future = future.map_ok(|x| x + 3); - /// assert_eq!(future.await, Ok(4)); - /// # }); - /// ``` - /// - /// Calling [`map_ok`](TryFutureExt::map_ok) on an errored future has no - /// effect: - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Err::(1) }; - /// let future = future.map_ok(|x| x + 3); - /// assert_eq!(future.await, Err(1)); - /// # }); - /// ``` - fn map_ok(self, f: F) -> MapOk - where - F: FnOnce(Self::Ok) -> T, - Self: Sized, - { - assert_future::, _>(MapOk::new(self, f)) - } - - /// Maps this future's success value to a different value, and permits for error handling resulting in the same type. - /// - /// This method can be used to coalesce your [`Ok`](TryFuture::Ok) type and [`Error`](TryFuture::Error) into another type, - /// where that type is the same for both outcomes. - /// - /// The provided closure `f` will only be called if this future is resolved - /// to an [`Ok`]. If it resolves to an [`Err`], panics, or is dropped, then - /// the provided closure will never be invoked. - /// - /// The provided closure `e` will only be called if this future is resolved - /// to an [`Err`]. If it resolves to an [`Ok`], panics, or is dropped, then - /// the provided closure will never be invoked. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Ok::(5) }; - /// let future = future.map_ok_or_else(|x| x * 2, |x| x + 3); - /// assert_eq!(future.await, 8); - /// - /// let future = async { Err::(5) }; - /// let future = future.map_ok_or_else(|x| x * 2, |x| x + 3); - /// assert_eq!(future.await, 10); - /// # }); - /// ``` - /// - fn map_ok_or_else(self, e: E, f: F) -> MapOkOrElse - where - F: FnOnce(Self::Ok) -> T, - E: FnOnce(Self::Error) -> T, - Self: Sized, - { - assert_future::(MapOkOrElse::new(self, f, e)) - } - - /// Maps this future's error value to a different value. - /// - /// This method can be used to change the [`Error`](TryFuture::Error) type - /// of the future into a different type. It is similar to the - /// [`Result::map_err`] method. You can use this method for example to - /// ensure that futures have the same [`Error`](TryFuture::Error) type when - /// using [`select!`] or [`join!`]. - /// - /// The provided closure `f` will only be called if this future is resolved - /// to an [`Err`]. If it resolves to an [`Ok`], panics, or is dropped, then - /// the provided closure will never be invoked. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Err::(1) }; - /// let future = future.map_err(|x| x + 3); - /// assert_eq!(future.await, Err(4)); - /// # }); - /// ``` - /// - /// Calling [`map_err`](TryFutureExt::map_err) on a successful future has - /// no effect: - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Ok::(1) }; - /// let future = future.map_err(|x| x + 3); - /// assert_eq!(future.await, Ok(1)); - /// # }); - /// ``` - /// - /// [`join!`]: crate::join - /// [`select!`]: crate::select - fn map_err(self, f: F) -> MapErr - where - F: FnOnce(Self::Error) -> E, - Self: Sized, - { - assert_future::, _>(MapErr::new(self, f)) - } - - /// Maps this future's [`Error`](TryFuture::Error) to a new error type - /// using the [`Into`](std::convert::Into) trait. - /// - /// This method does for futures what the `?`-operator does for - /// [`Result`]: It lets the compiler infer the type of the resulting - /// error. Just as [`map_err`](TryFutureExt::map_err), this is useful for - /// example to ensure that futures have the same [`Error`](TryFuture::Error) - /// type when using [`select!`] or [`join!`]. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future_err_u8 = async { Err::<(), u8>(1) }; - /// let future_err_i32 = future_err_u8.err_into::(); - /// # }); - /// ``` - /// - /// [`join!`]: crate::join - /// [`select!`]: crate::select - fn err_into(self) -> ErrInto - where - Self: Sized, - Self::Error: Into, - { - assert_future::, _>(ErrInto::new(self)) - } - - /// Maps this future's [`Ok`](TryFuture::Ok) to a new type - /// using the [`Into`](std::convert::Into) trait. - fn ok_into(self) -> OkInto - where - Self: Sized, - Self::Ok: Into, - { - assert_future::, _>(OkInto::new(self)) - } - - /// Executes another future after this one resolves successfully. The - /// success value is passed to a closure to create this subsequent future. - /// - /// The provided closure `f` will only be called if this future is resolved - /// to an [`Ok`]. If this future resolves to an [`Err`], panics, or is - /// dropped, then the provided closure will never be invoked. The - /// [`Error`](TryFuture::Error) type of this future and the future - /// returned by `f` have to match. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Ok::(1) }; - /// let future = future.and_then(|x| async move { Ok::(x + 3) }); - /// assert_eq!(future.await, Ok(4)); - /// # }); - /// ``` - /// - /// Calling [`and_then`](TryFutureExt::and_then) on an errored future has no - /// effect: - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Err::(1) }; - /// let future = future.and_then(|x| async move { Err::(x + 3) }); - /// assert_eq!(future.await, Err(1)); - /// # }); - /// ``` - fn and_then(self, f: F) -> AndThen - where - F: FnOnce(Self::Ok) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_future::, _>(AndThen::new(self, f)) - } - - /// Executes another future if this one resolves to an error. The - /// error value is passed to a closure to create this subsequent future. - /// - /// The provided closure `f` will only be called if this future is resolved - /// to an [`Err`]. If this future resolves to an [`Ok`], panics, or is - /// dropped, then the provided closure will never be invoked. The - /// [`Ok`](TryFuture::Ok) type of this future and the future returned by `f` - /// have to match. - /// - /// Note that this method consumes the future it is called on and returns a - /// wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Err::(1) }; - /// let future = future.or_else(|x| async move { Err::(x + 3) }); - /// assert_eq!(future.await, Err(4)); - /// # }); - /// ``` - /// - /// Calling [`or_else`](TryFutureExt::or_else) on a successful future has - /// no effect: - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Ok::(1) }; - /// let future = future.or_else(|x| async move { Ok::(x + 3) }); - /// assert_eq!(future.await, Ok(1)); - /// # }); - /// ``` - fn or_else(self, f: F) -> OrElse - where - F: FnOnce(Self::Error) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_future::, _>(OrElse::new(self, f)) - } - - /// Do something with the success value of a future before passing it on. - /// - /// When using futures, you'll often chain several of them together. While - /// working on such code, you might want to check out what's happening at - /// various parts in the pipeline, without consuming the intermediate - /// value. To do that, insert a call to `inspect_ok`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::TryFutureExt; - /// - /// let future = async { Ok::<_, ()>(1) }; - /// let new_future = future.inspect_ok(|&x| println!("about to resolve: {}", x)); - /// assert_eq!(new_future.await, Ok(1)); - /// # }); - /// ``` - fn inspect_ok(self, f: F) -> InspectOk - where - F: FnOnce(&Self::Ok), - Self: Sized, - { - assert_future::, _>(InspectOk::new(self, f)) - } - - /// Do something with the error value of a future before passing it on. - /// - /// When using futures, you'll often chain several of them together. While - /// working on such code, you might want to check out what's happening at - /// various parts in the pipeline, without consuming the intermediate - /// value. To do that, insert a call to `inspect_err`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::TryFutureExt; - /// - /// let future = async { Err::<(), _>(1) }; - /// let new_future = future.inspect_err(|&x| println!("about to error: {}", x)); - /// assert_eq!(new_future.await, Err(1)); - /// # }); - /// ``` - fn inspect_err(self, f: F) -> InspectErr - where - F: FnOnce(&Self::Error), - Self: Sized, - { - assert_future::, _>(InspectErr::new(self, f)) - } - - /// Flatten the execution of this future when the successful result of this - /// future is another future. - /// - /// This is equivalent to `future.and_then(|x| x)`. - fn try_flatten(self) -> TryFlatten - where - Self::Ok: TryFuture, - Self: Sized, - { - assert_future::::Ok, Self::Error>, _>(TryFlatten::new(self)) - } - - /// Flatten the execution of this future when the successful result of this - /// future is a stream. - /// - /// This can be useful when stream initialization is deferred, and it is - /// convenient to work with that stream as if stream was available at the - /// call site. - /// - /// Note that this function consumes this future and returns a wrapped - /// version of it. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future::TryFutureExt; - /// use futures::stream::{self, TryStreamExt}; - /// - /// let stream_items = vec![17, 18, 19].into_iter().map(Ok); - /// let future_of_a_stream = async { Ok::<_, ()>(stream::iter(stream_items)) }; - /// - /// let stream = future_of_a_stream.try_flatten_stream(); - /// let list = stream.try_collect::>().await; - /// assert_eq!(list, Ok(vec![17, 18, 19])); - /// # }); - /// ``` - fn try_flatten_stream(self) -> TryFlattenStream - where - Self::Ok: TryStream, - Self: Sized, - { - assert_stream::::Ok, Self::Error>, _>(TryFlattenStream::new( - self, - )) - } - - /// Unwraps this future's output, producing a future with this future's - /// [`Ok`](TryFuture::Ok) type as its - /// [`Output`](std::future::Future::Output) type. - /// - /// If this future is resolved successfully, the returned future will - /// contain the original future's success value as output. Otherwise, the - /// closure `f` is called with the error value to produce an alternate - /// success value. - /// - /// This method is similar to the [`Result::unwrap_or_else`] method. - /// - /// # Examples - /// - /// ``` - /// use futures::future::TryFutureExt; - /// - /// # futures::executor::block_on(async { - /// let future = async { Err::<(), &str>("Boom!") }; - /// let future = future.unwrap_or_else(|_| ()); - /// assert_eq!(future.await, ()); - /// # }); - /// ``` - fn unwrap_or_else(self, f: F) -> UnwrapOrElse - where - Self: Sized, - F: FnOnce(Self::Error) -> Self::Ok, - { - assert_future::(UnwrapOrElse::new(self, f)) - } - - /// Wraps a [`TryFuture`] into a future compatible with libraries using - /// futures 0.1 future definitions. Requires the `compat` feature to enable. - #[cfg(feature = "compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "compat")))] - fn compat(self) -> Compat - where - Self: Sized + Unpin, - { - Compat::new(self) - } - - /// Wraps a [`TryFuture`] into a type that implements - /// [`Future`](std::future::Future). - /// - /// [`TryFuture`]s currently do not implement the - /// [`Future`](std::future::Future) trait due to limitations of the - /// compiler. - /// - /// # Examples - /// - /// ``` - /// use futures::future::{Future, TryFuture, TryFutureExt}; - /// - /// # type T = i32; - /// # type E = (); - /// fn make_try_future() -> impl TryFuture { // ... } - /// # async { Ok::(1) } - /// # } - /// fn take_future(future: impl Future>) { /* ... */ } - /// - /// take_future(make_try_future().into_future()); - /// ``` - fn into_future(self) -> IntoFuture - where - Self: Sized, - { - assert_future::, _>(IntoFuture::new(self)) - } - - /// A convenience method for calling [`TryFuture::try_poll`] on [`Unpin`] - /// future types. - fn try_poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll> - where - Self: Unpin, - { - Pin::new(self).try_poll(cx) - } -} diff --git a/futures-util/src/future/try_future/try_flatten.rs b/futures-util/src/future/try_future/try_flatten.rs deleted file mode 100644 index 4587ae8493..0000000000 --- a/futures-util/src/future/try_future/try_flatten.rs +++ /dev/null @@ -1,156 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future, TryFuture}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - #[project = TryFlattenProj] - #[derive(Debug)] - pub enum TryFlatten { - First { #[pin] f: Fut1 }, - Second { #[pin] f: Fut2 }, - Empty, - } -} - -impl TryFlatten { - pub(crate) fn new(future: Fut1) -> Self { - Self::First { f: future } - } -} - -impl FusedFuture for TryFlatten -where - Fut: TryFuture, - Fut::Ok: TryFuture, -{ - fn is_terminated(&self) -> bool { - matches!(self, Self::Empty) - } -} - -impl Future for TryFlatten -where - Fut: TryFuture, - Fut::Ok: TryFuture, -{ - type Output = Result<::Ok, Fut::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready(loop { - match self.as_mut().project() { - TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Err(e); - } - }, - TryFlattenProj::Second { f } => { - let output = ready!(f.try_poll(cx)); - self.set(Self::Empty); - break output; - } - TryFlattenProj::Empty => panic!("TryFlatten polled after completion"), - } - }) - } -} - -impl FusedStream for TryFlatten -where - Fut: TryFuture, - Fut::Ok: TryStream, -{ - fn is_terminated(&self) -> bool { - matches!(self, Self::Empty) - } -} - -impl Stream for TryFlatten -where - Fut: TryFuture, - Fut::Ok: TryStream, -{ - type Item = Result<::Ok, Fut::Error>; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(loop { - match self.as_mut().project() { - TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Some(Err(e)); - } - }, - TryFlattenProj::Second { f } => { - let output = ready!(f.try_poll_next(cx)); - if output.is_none() { - self.set(Self::Empty); - } - break output; - } - TryFlattenProj::Empty => break None, - } - }) - } -} - -#[cfg(feature = "sink")] -impl Sink for TryFlatten -where - Fut: TryFuture, - Fut::Ok: Sink, -{ - type Error = Fut::Error; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(loop { - match self.as_mut().project() { - TryFlattenProj::First { f } => match ready!(f.try_poll(cx)) { - Ok(f) => self.set(Self::Second { f }), - Err(e) => { - self.set(Self::Empty); - break Err(e); - } - }, - TryFlattenProj::Second { f } => { - break ready!(f.poll_ready(cx)); - } - TryFlattenProj::Empty => panic!("poll_ready called after eof"), - } - }) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - match self.project() { - TryFlattenProj::First { .. } => panic!("poll_ready not called first"), - TryFlattenProj::Second { f } => f.start_send(item), - TryFlattenProj::Empty => panic!("start_send called after eof"), - } - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.project() { - TryFlattenProj::First { .. } => Poll::Ready(Ok(())), - TryFlattenProj::Second { f } => f.poll_flush(cx), - TryFlattenProj::Empty => panic!("poll_flush called after eof"), - } - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let res = match self.as_mut().project() { - TryFlattenProj::Second { f } => f.poll_close(cx), - _ => Poll::Ready(Ok(())), - }; - if res.is_ready() { - self.set(Self::Empty); - } - res - } -} diff --git a/futures-util/src/future/try_future/try_flatten_err.rs b/futures-util/src/future/try_future/try_flatten_err.rs deleted file mode 100644 index 6b371644d5..0000000000 --- a/futures-util/src/future/try_future/try_flatten_err.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future, TryFuture}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - #[project = TryFlattenErrProj] - #[derive(Debug)] - pub enum TryFlattenErr { - First { #[pin] f: Fut1 }, - Second { #[pin] f: Fut2 }, - Empty, - } -} - -impl TryFlattenErr { - pub(crate) fn new(future: Fut1) -> Self { - Self::First { f: future } - } -} - -impl FusedFuture for TryFlattenErr -where - Fut: TryFuture, - Fut::Error: TryFuture, -{ - fn is_terminated(&self) -> bool { - matches!(self, Self::Empty) - } -} - -impl Future for TryFlattenErr -where - Fut: TryFuture, - Fut::Error: TryFuture, -{ - type Output = Result::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready(loop { - match self.as_mut().project() { - TryFlattenErrProj::First { f } => match ready!(f.try_poll(cx)) { - Err(f) => self.set(Self::Second { f }), - Ok(e) => { - self.set(Self::Empty); - break Ok(e); - } - }, - TryFlattenErrProj::Second { f } => { - let output = ready!(f.try_poll(cx)); - self.set(Self::Empty); - break output; - } - TryFlattenErrProj::Empty => panic!("TryFlattenErr polled after completion"), - } - }) - } -} diff --git a/futures-util/src/future/try_join.rs b/futures-util/src/future/try_join.rs deleted file mode 100644 index 05a6fd7001..0000000000 --- a/futures-util/src/future/try_join.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::future::{assert_future, try_maybe_done, TryMaybeDone}; -use core::fmt; -use core::pin::Pin; -use futures_core::future::{Future, TryFuture}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_join`](super::TryFutureExt::try_join) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryJoin { - #[pin] fut1: TryMaybeDone, - #[pin] fut2: TryMaybeDone - } -} - -impl TryJoin { - pub(crate) fn new(fut1: Fut1, fut2: Fut2) -> Self { - Self { fut1: try_maybe_done(fut1), fut2: try_maybe_done(fut2) } - } -} - -impl fmt::Debug for TryJoin -where - Fut1: TryFuture + fmt::Debug, - Fut1::Ok: fmt::Debug, - Fut1::Error: fmt::Debug, - Fut2: TryFuture + fmt::Debug, - Fut2::Ok: fmt::Debug, - Fut2::Error: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryJoin").field("fut1", &self.fut1).field("fut2", &self.fut2).finish() - } -} - -impl Future for TryJoin -where - Fut1: TryFuture, - Fut2: TryFuture, -{ - type Output = Result<(Fut1::Ok, Fut2::Ok), Fut1::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut all_done = true; - let mut futures = self.project(); - - all_done &= futures.fut1.as_mut().poll(cx)?.is_ready(); - all_done &= futures.fut2.as_mut().poll(cx)?.is_ready(); - - if all_done { - Poll::Ready(Ok(( - futures.fut1.take_output().unwrap(), - futures.fut2.take_output().unwrap(), - ))) - } else { - Poll::Pending - } - } -} - -/// Joins the result of two futures, waiting for them both to complete or -/// for one to produce an error. -/// -/// This function will return a new future which awaits both futures to -/// complete. If successful, the returned future will finish with a tuple of -/// both results. If unsuccessful, it will complete with the first error -/// encountered. -/// -/// Note that this function consumes the passed futures and returns a -/// wrapped version of it. -/// -/// # Examples -/// -/// When used on multiple futures that return [`Ok`], `try_join` will return -/// [`Ok`] of a tuple of the values: -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::ready(Ok::(1)); -/// let b = future::ready(Ok::(2)); -/// let pair = future::try_join(a, b); -/// -/// assert_eq!(pair.await, Ok((1, 2))); -/// # }); -/// ``` -/// -/// If one of the futures resolves to an error, `try_join` will return -/// that error: -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future; -/// -/// let a = future::ready(Ok::(1)); -/// let b = future::ready(Err::(2)); -/// let pair = future::try_join(a, b); -/// -/// assert_eq!(pair.await, Err(2)); -/// # }); -/// ``` -pub fn try_join(future1: Fut1, future2: Fut2) -> TryJoin -where - Fut1: TryFuture, - Fut2: TryFuture, -{ - assert_future::, _>(TryJoin::new(future1, future2)) -} diff --git a/futures-util/src/future/try_join_all.rs b/futures-util/src/future/try_join_all.rs deleted file mode 100644 index 2d6a2a02cb..0000000000 --- a/futures-util/src/future/try_join_all.rs +++ /dev/null @@ -1,201 +0,0 @@ -//! Definition of the `TryJoinAll` combinator, waiting for all of a list of -//! futures to finish with either success or error. - -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt; -use core::future::Future; -use core::iter::FromIterator; -use core::mem; -use core::pin::Pin; -use core::task::{Context, Poll}; - -use super::{assert_future, join_all, IntoFuture, TryFuture, TryMaybeDone}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -use crate::stream::{FuturesOrdered, TryCollect, TryStreamExt}; -use crate::TryFutureExt; - -enum FinalState { - Pending, - AllDone, - Error(E), -} - -/// Future for the [`try_join_all`] function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct TryJoinAll -where - F: TryFuture, -{ - kind: TryJoinAllKind, -} - -enum TryJoinAllKind -where - F: TryFuture, -{ - Small { - elems: Pin>]>>, - }, - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - Big { - fut: TryCollect>, Vec>, - }, -} - -impl fmt::Debug for TryJoinAll -where - F: TryFuture + fmt::Debug, - F::Ok: fmt::Debug, - F::Error: fmt::Debug, - F::Output: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - TryJoinAllKind::Small { ref elems } => { - f.debug_struct("TryJoinAll").field("elems", elems).finish() - } - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - TryJoinAllKind::Big { ref fut, .. } => fmt::Debug::fmt(fut, f), - } - } -} - -/// Creates a future which represents either a collection of the results of the -/// futures given or an error. -/// -/// The returned future will drive execution for all of its underlying futures, -/// collecting the results into a destination `Vec` in the same order as they -/// were provided. -/// -/// If any future returns an error then all other futures will be canceled and -/// an error will be returned immediately. If all futures complete successfully, -/// however, then the returned future will succeed with a `Vec` of all the -/// successful results. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -/// -/// # See Also -/// -/// `try_join_all` will switch to the more powerful [`FuturesOrdered`] for performance -/// reasons if the number of futures is large. You may want to look into using it or -/// it's counterpart [`FuturesUnordered`][crate::stream::FuturesUnordered] directly. -/// -/// Some examples for additional functionality provided by these are: -/// -/// * Adding new futures to the set even after it has been started. -/// -/// * Only polling the specific futures that have been woken. In cases where -/// you have a lot of futures this will result in much more efficient polling. -/// -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::future::{self, try_join_all}; -/// -/// let futures = vec![ -/// future::ok::(1), -/// future::ok::(2), -/// future::ok::(3), -/// ]; -/// -/// assert_eq!(try_join_all(futures).await, Ok(vec![1, 2, 3])); -/// -/// let futures = vec![ -/// future::ok::(1), -/// future::err::(2), -/// future::ok::(3), -/// ]; -/// -/// assert_eq!(try_join_all(futures).await, Err(2)); -/// # }); -/// ``` -pub fn try_join_all(iter: I) -> TryJoinAll -where - I: IntoIterator, - I::Item: TryFuture, -{ - let iter = iter.into_iter().map(TryFutureExt::into_future); - - #[cfg(target_os = "none")] - #[cfg_attr(target_os = "none", cfg(not(target_has_atomic = "ptr")))] - { - let kind = TryJoinAllKind::Small { - elems: iter.map(TryMaybeDone::Future).collect::>().into(), - }; - - assert_future::::Ok>, ::Error>, _>( - TryJoinAll { kind }, - ) - } - - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - { - let kind = match iter.size_hint().1 { - Some(max) if max <= join_all::SMALL => TryJoinAllKind::Small { - elems: iter.map(TryMaybeDone::Future).collect::>().into(), - }, - _ => TryJoinAllKind::Big { fut: iter.collect::>().try_collect() }, - }; - - assert_future::::Ok>, ::Error>, _>( - TryJoinAll { kind }, - ) - } -} - -impl Future for TryJoinAll -where - F: TryFuture, -{ - type Output = Result, F::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match &mut self.kind { - TryJoinAllKind::Small { elems } => { - let mut state = FinalState::AllDone; - - for elem in join_all::iter_pin_mut(elems.as_mut()) { - match elem.try_poll(cx) { - Poll::Pending => state = FinalState::Pending, - Poll::Ready(Ok(())) => {} - Poll::Ready(Err(e)) => { - state = FinalState::Error(e); - break; - } - } - } - - match state { - FinalState::Pending => Poll::Pending, - FinalState::AllDone => { - let mut elems = mem::replace(elems, Box::pin([])); - let results = join_all::iter_pin_mut(elems.as_mut()) - .map(|e| e.take_output().unwrap()) - .collect(); - Poll::Ready(Ok(results)) - } - FinalState::Error(e) => { - let _ = mem::replace(elems, Box::pin([])); - Poll::Ready(Err(e)) - } - } - } - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - TryJoinAllKind::Big { fut } => Pin::new(fut).poll(cx), - } - } -} - -impl FromIterator for TryJoinAll -where - F: TryFuture, -{ - fn from_iter>(iter: T) -> Self { - try_join_all(iter) - } -} diff --git a/futures-util/src/future/try_maybe_done.rs b/futures-util/src/future/try_maybe_done.rs deleted file mode 100644 index 97af6ad437..0000000000 --- a/futures-util/src/future/try_maybe_done.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Definition of the TryMaybeDone combinator - -use super::assert_future; -use core::mem; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future, TryFuture}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; - -/// A future that may have completed with an error. -/// -/// This is created by the [`try_maybe_done()`] function. -#[derive(Debug)] -pub enum TryMaybeDone { - /// A not-yet-completed future - Future(/* #[pin] */ Fut), - /// The output of the completed future - Done(Fut::Ok), - /// The empty variant after the result of a [`TryMaybeDone`] has been - /// taken using the [`take_output`](TryMaybeDone::take_output) method, - /// or if the future returned an error. - Gone, -} - -impl Unpin for TryMaybeDone {} - -/// Wraps a future into a `TryMaybeDone` -pub fn try_maybe_done(future: Fut) -> TryMaybeDone { - assert_future::, _>(TryMaybeDone::Future(future)) -} - -impl TryMaybeDone { - /// Returns an [`Option`] containing a mutable reference to the output of the future. - /// The output of this method will be [`Some`] if and only if the inner - /// future has completed successfully and [`take_output`](TryMaybeDone::take_output) - /// has not yet been called. - #[inline] - pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Ok> { - unsafe { - match self.get_unchecked_mut() { - Self::Done(res) => Some(res), - _ => None, - } - } - } - - /// Attempt to take the output of a `TryMaybeDone` without driving it - /// towards completion. - #[inline] - pub fn take_output(self: Pin<&mut Self>) -> Option { - match &*self { - Self::Done(_) => {} - Self::Future(_) | Self::Gone => return None, - } - unsafe { - match mem::replace(self.get_unchecked_mut(), Self::Gone) { - Self::Done(output) => Some(output), - _ => unreachable!(), - } - } - } -} - -impl FusedFuture for TryMaybeDone { - fn is_terminated(&self) -> bool { - match self { - Self::Future(_) => false, - Self::Done(_) | Self::Gone => true, - } - } -} - -impl Future for TryMaybeDone { - type Output = Result<(), Fut::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unsafe { - match self.as_mut().get_unchecked_mut() { - Self::Future(f) => match ready!(Pin::new_unchecked(f).try_poll(cx)) { - Ok(res) => self.set(Self::Done(res)), - Err(e) => { - self.set(Self::Gone); - return Poll::Ready(Err(e)); - } - }, - Self::Done(_) => {} - Self::Gone => panic!("TryMaybeDone polled after value taken"), - } - } - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/future/try_select.rs b/futures-util/src/future/try_select.rs deleted file mode 100644 index bc282f7db1..0000000000 --- a/futures-util/src/future/try_select.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::future::{Either, TryFutureExt}; -use core::pin::Pin; -use futures_core::future::{Future, TryFuture}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`try_select()`] function. -#[must_use = "futures do nothing unless you `.await` or poll them"] -#[derive(Debug)] -pub struct TrySelect { - inner: Option<(A, B)>, -} - -impl Unpin for TrySelect {} - -type EitherOk = Either<(::Ok, B), (::Ok, A)>; -type EitherErr = Either<(::Error, B), (::Error, A)>; - -/// Waits for either one of two differently-typed futures to complete. -/// -/// This function will return a new future which awaits for either one of both -/// futures to complete. The returned future will finish with both the value -/// resolved and a future representing the completion of the other work. -/// -/// Note that this function consumes the receiving futures and returns a -/// wrapped version of them. -/// -/// Also note that if both this and the second future have the same -/// success/error type you can use the `Either::factor_first` method to -/// conveniently extract out the value at the end. -/// -/// # Examples -/// -/// ``` -/// use futures::future::{self, Either, Future, FutureExt, TryFuture, TryFutureExt}; -/// -/// // A poor-man's try_join implemented on top of select -/// -/// fn try_join(a: A, b: B) -> impl TryFuture -/// where A: TryFuture + Unpin + 'static, -/// B: TryFuture + Unpin + 'static, -/// E: 'static, -/// { -/// future::try_select(a, b).then(|res| -> Box> + Unpin> { -/// match res { -/// Ok(Either::Left((x, b))) => Box::new(b.map_ok(move |y| (x, y))), -/// Ok(Either::Right((y, a))) => Box::new(a.map_ok(move |x| (x, y))), -/// Err(Either::Left((e, _))) => Box::new(future::err(e)), -/// Err(Either::Right((e, _))) => Box::new(future::err(e)), -/// } -/// }) -/// } -/// ``` -pub fn try_select(future1: A, future2: B) -> TrySelect -where - A: TryFuture + Unpin, - B: TryFuture + Unpin, -{ - super::assert_future::, EitherErr>, _>(TrySelect { - inner: Some((future1, future2)), - }) -} - -impl Future for TrySelect -where - A: TryFuture, - B: TryFuture, -{ - type Output = Result, EitherErr>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice"); - match a.try_poll_unpin(cx) { - Poll::Ready(Err(x)) => Poll::Ready(Err(Either::Left((x, b)))), - Poll::Ready(Ok(x)) => Poll::Ready(Ok(Either::Left((x, b)))), - Poll::Pending => match b.try_poll_unpin(cx) { - Poll::Ready(Err(x)) => Poll::Ready(Err(Either::Right((x, a)))), - Poll::Ready(Ok(x)) => Poll::Ready(Ok(Either::Right((x, a)))), - Poll::Pending => { - self.inner = Some((a, b)); - Poll::Pending - } - }, - } - } -} diff --git a/futures-util/src/io/allow_std.rs b/futures-util/src/io/allow_std.rs deleted file mode 100644 index 96133cbc6f..0000000000 --- a/futures-util/src/io/allow_std.rs +++ /dev/null @@ -1,202 +0,0 @@ -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, SeekFrom}; -use std::pin::Pin; -use std::string::String; -use std::vec::Vec; -use std::{fmt, io}; - -/// A simple wrapper type which allows types which implement only -/// implement `std::io::Read` or `std::io::Write` -/// to be used in contexts which expect an `AsyncRead` or `AsyncWrite`. -/// -/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`, -/// it is expected that they will notify the current task on readiness. -/// Synchronous `std` types should not issue errors of this kind and -/// are safe to use in this context. However, using these types with -/// `AllowStdIo` will cause the event loop to block, so they should be used -/// with care. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct AllowStdIo(T); - -impl Unpin for AllowStdIo {} - -macro_rules! try_with_interrupt { - ($e:expr) => { - loop { - match $e { - Ok(e) => { - break e; - } - Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => { - continue; - } - Err(e) => { - return Poll::Ready(Err(e)); - } - } - } - }; -} - -impl AllowStdIo { - /// Creates a new `AllowStdIo` from an existing IO object. - pub fn new(io: T) -> Self { - Self(io) - } - - /// Returns a reference to the contained IO object. - pub fn get_ref(&self) -> &T { - &self.0 - } - - /// Returns a mutable reference to the contained IO object. - pub fn get_mut(&mut self) -> &mut T { - &mut self.0 - } - - /// Consumes self and returns the contained IO object. - pub fn into_inner(self) -> T { - self.0 - } -} - -impl io::Write for AllowStdIo -where - T: io::Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0.write_all(buf) - } - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - self.0.write_fmt(fmt) - } -} - -impl AsyncWrite for AllowStdIo -where - T: io::Write, -{ - fn poll_write( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Poll::Ready(Ok(try_with_interrupt!(self.0.write(buf)))) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - Poll::Ready(Ok(try_with_interrupt!(self.0.write_vectored(bufs)))) - } - - fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - try_with_interrupt!(self.0.flush()); - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } -} - -impl io::Read for AllowStdIo -where - T: io::Read, -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.0.read_to_string(buf) - } - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.0.read_exact(buf) - } -} - -impl AsyncRead for AllowStdIo -where - T: io::Read, -{ - fn poll_read( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - Poll::Ready(Ok(try_with_interrupt!(self.0.read(buf)))) - } - - fn poll_read_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - Poll::Ready(Ok(try_with_interrupt!(self.0.read_vectored(bufs)))) - } -} - -impl io::Seek for AllowStdIo -where - T: io::Seek, -{ - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.0.seek(pos) - } -} - -impl AsyncSeek for AllowStdIo -where - T: io::Seek, -{ - fn poll_seek( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - Poll::Ready(Ok(try_with_interrupt!(self.0.seek(pos)))) - } -} - -impl io::BufRead for AllowStdIo -where - T: io::BufRead, -{ - fn fill_buf(&mut self) -> io::Result<&[u8]> { - self.0.fill_buf() - } - fn consume(&mut self, amt: usize) { - self.0.consume(amt) - } -} - -impl AsyncBufRead for AllowStdIo -where - T: io::BufRead, -{ - fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - let this: *mut Self = &mut *self as *mut _; - Poll::Ready(Ok(try_with_interrupt!(unsafe { &mut *this }.0.fill_buf()))) - } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - self.0.consume(amt) - } -} diff --git a/futures-util/src/io/buf_reader.rs b/futures-util/src/io/buf_reader.rs deleted file mode 100644 index 30611bd8d9..0000000000 --- a/futures-util/src/io/buf_reader.rs +++ /dev/null @@ -1,264 +0,0 @@ -use super::DEFAULT_BUF_SIZE; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSliceMut, SeekFrom}; -use pin_project_lite::pin_project; -use std::boxed::Box; -use std::io::{self, Read}; -use std::pin::Pin; -use std::vec; -use std::{cmp, fmt}; - -pin_project! { - /// The `BufReader` struct adds buffering to any reader. - /// - /// It can be excessively inefficient to work directly with a [`AsyncRead`] - /// instance. A `BufReader` performs large, infrequent reads on the underlying - /// [`AsyncRead`] and maintains an in-memory buffer of the results. - /// - /// `BufReader` can improve the speed of programs that make *small* and - /// *repeated* read calls to the same file or network socket. It does not - /// help when reading very large amounts at once, or reading just one or a few - /// times. It also provides no advantage when reading from a source that is - /// already in memory, like a `Vec`. - /// - /// When the `BufReader` is dropped, the contents of its buffer will be - /// discarded. Creating multiple instances of a `BufReader` on the same - /// stream can cause data loss. - /// - /// [`AsyncRead`]: futures_io::AsyncRead - /// - // TODO: Examples - pub struct BufReader { - #[pin] - inner: R, - buffer: Box<[u8]>, - pos: usize, - cap: usize, - } -} - -impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - pub fn new(inner: R) -> Self { - Self::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader` with the specified buffer capacity. - pub fn with_capacity(capacity: usize, inner: R) -> Self { - // TODO: consider using Box<[u8]>::new_uninit_slice once it stabilized - let buffer = vec![0; capacity]; - Self { inner, buffer: buffer.into_boxed_slice(), pos: 0, cap: 0 } - } -} - -impl BufReader { - delegate_access_inner!(inner, R, ()); - - /// Returns a reference to the internally buffered data. - /// - /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. - pub fn buffer(&self) -> &[u8] { - &self.buffer[self.pos..self.cap] - } - - /// Invalidates all data in the internal buffer. - #[inline] - fn discard_buffer(self: Pin<&mut Self>) { - let this = self.project(); - *this.pos = 0; - *this.cap = 0; - } -} - -impl BufReader { - /// Seeks relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - pub fn seek_relative(self: Pin<&mut Self>, offset: i64) -> SeekRelative<'_, R> { - SeekRelative { inner: self, offset, first: true } - } - - /// Attempts to seek relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - pub fn poll_seek_relative( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - offset: i64, - ) -> Poll> { - let pos = self.pos as u64; - if offset < 0 { - if let Some(new_pos) = pos.checked_sub((-offset) as u64) { - *self.project().pos = new_pos as usize; - return Poll::Ready(Ok(())); - } - } else if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - *self.project().pos = new_pos as usize; - return Poll::Ready(Ok(())); - } - } - self.poll_seek(cx, SeekFrom::Current(offset)).map(|res| res.map(|_| ())) - } -} - -impl AsyncRead for BufReader { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buffer.len() { - let res = ready!(self.as_mut().project().inner.poll_read(cx, buf)); - self.discard_buffer(); - return Poll::Ready(res); - } - let mut rem = ready!(self.as_mut().poll_fill_buf(cx))?; - let nread = rem.read(buf)?; - self.consume(nread); - Poll::Ready(Ok(nread)) - } - - fn poll_read_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.pos == self.cap && total_len >= self.buffer.len() { - let res = ready!(self.as_mut().project().inner.poll_read_vectored(cx, bufs)); - self.discard_buffer(); - return Poll::Ready(res); - } - let mut rem = ready!(self.as_mut().poll_fill_buf(cx))?; - let nread = rem.read_vectored(bufs)?; - self.consume(nread); - Poll::Ready(Ok(nread)) - } -} - -impl AsyncBufRead for BufReader { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if *this.pos >= *this.cap { - debug_assert!(*this.pos == *this.cap); - *this.cap = ready!(this.inner.poll_read(cx, this.buffer))?; - *this.pos = 0; - } - Poll::Ready(Ok(&this.buffer[*this.pos..*this.cap])) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - *self.project().pos = cmp::min(self.pos + amt, self.cap); - } -} - -impl AsyncWrite for BufReader { - delegate_async_write!(inner); -} - -impl fmt::Debug for BufReader { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buffer.len())) - .finish() - } -} - -impl AsyncSeek for BufReader { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with `SeekFrom::Current(_)` is the - /// position the underlying reader would be at if the `BufReader` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// `.into_inner()` immediately after a seek yields the underlying reader - /// at the same position. - /// - /// To seek without discarding the internal buffer, use - /// [`BufReader::seek_relative`](BufReader::seek_relative) or - /// [`BufReader::poll_seek_relative`](BufReader::poll_seek_relative). - /// - /// See [`AsyncSeek`](futures_io::AsyncSeek) for more details. - /// - /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` - /// where `n` minus the internal buffer length overflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// `Err`, the underlying reader will be left at the same position it would - /// have if you called `seek` with `SeekFrom::Current(0)`. - fn poll_seek( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 exbibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::MIN so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = - ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(offset)))?; - } else { - // seek backwards by our remainder, and then by the offset - ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(-remainder)))?; - self.as_mut().discard_buffer(); - result = ready!(self.as_mut().project().inner.poll_seek(cx, SeekFrom::Current(n)))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = ready!(self.as_mut().project().inner.poll_seek(cx, pos))?; - } - self.discard_buffer(); - Poll::Ready(Ok(result)) - } -} - -/// Future for the [`BufReader::seek_relative`](self::BufReader::seek_relative) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless polled"] -pub struct SeekRelative<'a, R> { - inner: Pin<&'a mut BufReader>, - offset: i64, - first: bool, -} - -impl Future for SeekRelative<'_, R> -where - R: AsyncRead + AsyncSeek, -{ - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let offset = self.offset; - if self.first { - self.first = false; - self.inner.as_mut().poll_seek_relative(cx, offset) - } else { - self.inner - .as_mut() - .as_mut() - .poll_seek(cx, SeekFrom::Current(offset)) - .map(|res| res.map(|_| ())) - } - } -} diff --git a/futures-util/src/io/buf_writer.rs b/futures-util/src/io/buf_writer.rs deleted file mode 100644 index ddcf5e1b4d..0000000000 --- a/futures-util/src/io/buf_writer.rs +++ /dev/null @@ -1,229 +0,0 @@ -use super::DEFAULT_BUF_SIZE; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, SeekFrom}; -use pin_project_lite::pin_project; -use std::fmt; -use std::io::{self, Write}; -use std::pin::Pin; -use std::ptr; -use std::vec::Vec; - -pin_project! { - /// Wraps a writer and buffers its output. - /// - /// It can be excessively inefficient to work directly with something that - /// implements [`AsyncWrite`]. A `BufWriter` keeps an in-memory buffer of data and - /// writes it to an underlying writer in large, infrequent batches. - /// - /// `BufWriter` can improve the speed of programs that make *small* and - /// *repeated* write calls to the same file or network socket. It does not - /// help when writing very large amounts at once, or writing just one or a few - /// times. It also provides no advantage when writing to a destination that is - /// in memory, like a `Vec`. - /// - /// When the `BufWriter` is dropped, the contents of its buffer will be - /// discarded. Creating multiple instances of a `BufWriter` on the same - /// stream can cause data loss. If you need to write out the contents of its - /// buffer, you must manually call flush before the writer is dropped. - /// - /// [`AsyncWrite`]: futures_io::AsyncWrite - /// [`flush`]: super::AsyncWriteExt::flush - /// - // TODO: Examples - pub struct BufWriter { - #[pin] - inner: W, - buf: Vec, - written: usize, - } -} - -impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - pub fn new(inner: W) -> Self { - Self::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter` with the specified buffer capacity. - pub fn with_capacity(cap: usize, inner: W) -> Self { - Self { inner, buf: Vec::with_capacity(cap), written: 0 } - } - - pub(super) fn flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - let len = this.buf.len(); - let mut ret = Ok(()); - while *this.written < len { - match ready!(this.inner.as_mut().poll_write(cx, &this.buf[*this.written..])) { - Ok(0) => { - ret = Err(io::Error::new( - io::ErrorKind::WriteZero, - "failed to write the buffered data", - )); - break; - } - Ok(n) => *this.written += n, - Err(e) => { - ret = Err(e); - break; - } - } - } - if *this.written > 0 { - this.buf.drain(..*this.written); - } - *this.written = 0; - Poll::Ready(ret) - } - - /// Write directly using `inner`, bypassing buffering - pub(super) fn inner_poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.project().inner.poll_write(cx, buf) - } - - /// Write directly using `inner`, bypassing buffering - pub(super) fn inner_poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - self.project().inner.poll_write_vectored(cx, bufs) - } -} - -impl BufWriter { - delegate_access_inner!(inner, W, ()); - - /// Returns a reference to the internally buffered data. - pub fn buffer(&self) -> &[u8] { - &self.buf - } - - /// Capacity of `buf`. how many chars can be held in buffer - pub(super) fn capacity(&self) -> usize { - self.buf.capacity() - } - - /// Remaining number of bytes to reach `buf` 's capacity - #[inline] - pub(super) fn spare_capacity(&self) -> usize { - self.buf.capacity() - self.buf.len() - } - - /// Write a byte slice directly into buffer - /// - /// Will truncate the number of bytes written to `spare_capacity()` so you want to - /// calculate the size of your slice to avoid losing bytes - /// - /// Based on `std::io::BufWriter` - pub(super) fn write_to_buf(self: Pin<&mut Self>, buf: &[u8]) -> usize { - let available = self.spare_capacity(); - let amt_to_buffer = available.min(buf.len()); - - // SAFETY: `amt_to_buffer` is <= buffer's spare capacity by construction. - unsafe { - self.write_to_buffer_unchecked(&buf[..amt_to_buffer]); - } - - amt_to_buffer - } - - /// Write byte slice directly into `self.buf` - /// - /// Based on `std::io::BufWriter` - #[inline] - unsafe fn write_to_buffer_unchecked(self: Pin<&mut Self>, buf: &[u8]) { - debug_assert!(buf.len() <= self.spare_capacity()); - let this = self.project(); - let old_len = this.buf.len(); - let buf_len = buf.len(); - let src = buf.as_ptr(); - unsafe { - let dst = this.buf.as_mut_ptr().add(old_len); - ptr::copy_nonoverlapping(src, dst, buf_len); - this.buf.set_len(old_len + buf_len); - } - } -} - -impl AsyncWrite for BufWriter { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - if self.buf.len() + buf.len() > self.buf.capacity() { - ready!(self.as_mut().flush_buf(cx))?; - } - if buf.len() >= self.buf.capacity() { - self.project().inner.poll_write(cx, buf) - } else { - Poll::Ready(self.project().buf.write(buf)) - } - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.buf.len() + total_len > self.buf.capacity() { - ready!(self.as_mut().flush_buf(cx))?; - } - if total_len >= self.buf.capacity() { - self.project().inner.poll_write_vectored(cx, bufs) - } else { - Poll::Ready(self.project().buf.write_vectored(bufs)) - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().flush_buf(cx))?; - self.project().inner.poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().flush_buf(cx))?; - self.project().inner.poll_close(cx) - } -} - -impl AsyncRead for BufWriter { - delegate_async_read!(inner); -} - -impl AsyncBufRead for BufWriter { - delegate_async_buf_read!(inner); -} - -impl fmt::Debug for BufWriter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BufWriter") - .field("writer", &self.inner) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .field("written", &self.written) - .finish() - } -} - -impl AsyncSeek for BufWriter { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn poll_seek( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - ready!(self.as_mut().flush_buf(cx))?; - self.project().inner.poll_seek(cx, pos) - } -} diff --git a/futures-util/src/io/chain.rs b/futures-util/src/io/chain.rs deleted file mode 100644 index 410ff0dc7c..0000000000 --- a/futures-util/src/io/chain.rs +++ /dev/null @@ -1,140 +0,0 @@ -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, IoSliceMut}; -use pin_project_lite::pin_project; -use std::fmt; -use std::io; -use std::pin::Pin; - -pin_project! { - /// Reader for the [`chain`](super::AsyncReadExt::chain) method. - #[must_use = "readers do nothing unless polled"] - pub struct Chain { - #[pin] - first: T, - #[pin] - second: U, - done_first: bool, - } -} - -impl Chain -where - T: AsyncRead, - U: AsyncRead, -{ - pub(super) fn new(first: T, second: U) -> Self { - Self { first, second, done_first: false } - } - - /// Gets references to the underlying readers in this `Chain`. - pub fn get_ref(&self) -> (&T, &U) { - (&self.first, &self.second) - } - - /// Gets mutable references to the underlying readers in this `Chain`. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying readers as doing so may corrupt the internal state of this - /// `Chain`. - pub fn get_mut(&mut self) -> (&mut T, &mut U) { - (&mut self.first, &mut self.second) - } - - /// Gets pinned mutable references to the underlying readers in this `Chain`. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying readers as doing so may corrupt the internal state of this - /// `Chain`. - pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) { - let this = self.project(); - (this.first, this.second) - } - - /// Consumes the `Chain`, returning the wrapped readers. - pub fn into_inner(self) -> (T, U) { - (self.first, self.second) - } -} - -impl fmt::Debug for Chain -where - T: fmt::Debug, - U: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Chain") - .field("t", &self.first) - .field("u", &self.second) - .field("done_first", &self.done_first) - .finish() - } -} - -impl AsyncRead for Chain -where - T: AsyncRead, - U: AsyncRead, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let this = self.project(); - - if !*this.done_first { - match ready!(this.first.poll_read(cx, buf)?) { - 0 if !buf.is_empty() => *this.done_first = true, - n => return Poll::Ready(Ok(n)), - } - } - this.second.poll_read(cx, buf) - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - let this = self.project(); - - if !*this.done_first { - let n = ready!(this.first.poll_read_vectored(cx, bufs)?); - if n == 0 && bufs.iter().any(|b| !b.is_empty()) { - *this.done_first = true - } else { - return Poll::Ready(Ok(n)); - } - } - this.second.poll_read_vectored(cx, bufs) - } -} - -impl AsyncBufRead for Chain -where - T: AsyncBufRead, - U: AsyncBufRead, -{ - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - if !*this.done_first { - match ready!(this.first.poll_fill_buf(cx)?) { - [] => *this.done_first = true, - buf => return Poll::Ready(Ok(buf)), - } - } - this.second.poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - let this = self.project(); - - if !*this.done_first { - this.first.consume(amt) - } else { - this.second.consume(amt) - } - } -} diff --git a/futures-util/src/io/close.rs b/futures-util/src/io/close.rs deleted file mode 100644 index b94459279a..0000000000 --- a/futures-util/src/io/close.rs +++ /dev/null @@ -1,28 +0,0 @@ -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use std::io; -use std::pin::Pin; - -/// Future for the [`close`](super::AsyncWriteExt::close) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Close<'a, W: ?Sized> { - writer: &'a mut W, -} - -impl Unpin for Close<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> Close<'a, W> { - pub(super) fn new(writer: &'a mut W) -> Self { - Self { writer } - } -} - -impl Future for Close<'_, W> { - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut *self.writer).poll_close(cx) - } -} diff --git a/futures-util/src/io/copy.rs b/futures-util/src/io/copy.rs deleted file mode 100644 index c80add271b..0000000000 --- a/futures-util/src/io/copy.rs +++ /dev/null @@ -1,58 +0,0 @@ -use super::{copy_buf, BufReader, CopyBuf}; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncRead, AsyncWrite}; -use pin_project_lite::pin_project; -use std::io; -use std::pin::Pin; - -/// Creates a future which copies all the bytes from one object to another. -/// -/// The returned future will copy all the bytes read from this `AsyncRead` into the -/// `writer` specified. This future will only complete once the `reader` has hit -/// EOF and all bytes have been written to and flushed from the `writer` -/// provided. -/// -/// On success the number of bytes is returned. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncWriteExt, Cursor}; -/// -/// let reader = Cursor::new([1, 2, 3, 4]); -/// let mut writer = Cursor::new(vec![0u8; 5]); -/// -/// let bytes = io::copy(reader, &mut writer).await?; -/// writer.close().await?; -/// -/// assert_eq!(bytes, 4); -/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn copy(reader: R, writer: &mut W) -> Copy<'_, R, W> -where - R: AsyncRead, - W: AsyncWrite + Unpin + ?Sized, -{ - Copy { inner: copy_buf(BufReader::new(reader), writer) } -} - -pin_project! { - /// Future for the [`copy()`] function. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Copy<'a, R, W: ?Sized> { - #[pin] - inner: CopyBuf<'a, BufReader, W>, - } -} - -impl Future for Copy<'_, R, W> { - type Output = io::Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().inner.poll(cx) - } -} diff --git a/futures-util/src/io/copy_buf.rs b/futures-util/src/io/copy_buf.rs deleted file mode 100644 index 50f7abdca9..0000000000 --- a/futures-util/src/io/copy_buf.rs +++ /dev/null @@ -1,78 +0,0 @@ -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncWrite}; -use pin_project_lite::pin_project; -use std::io; -use std::pin::Pin; - -/// Creates a future which copies all the bytes from one object to another. -/// -/// The returned future will copy all the bytes read from this `AsyncBufRead` into the -/// `writer` specified. This future will only complete once the `reader` has hit -/// EOF and all bytes have been written to and flushed from the `writer` -/// provided. -/// -/// On success the number of bytes is returned. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncWriteExt, Cursor}; -/// -/// let reader = Cursor::new([1, 2, 3, 4]); -/// let mut writer = Cursor::new(vec![0u8; 5]); -/// -/// let bytes = io::copy_buf(reader, &mut writer).await?; -/// writer.close().await?; -/// -/// assert_eq!(bytes, 4); -/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn copy_buf(reader: R, writer: &mut W) -> CopyBuf<'_, R, W> -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, -{ - CopyBuf { reader, writer, amt: 0 } -} - -pin_project! { - /// Future for the [`copy_buf()`] function. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct CopyBuf<'a, R, W: ?Sized> { - #[pin] - reader: R, - writer: &'a mut W, - amt: u64, - } -} - -impl Future for CopyBuf<'_, R, W> -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, -{ - type Output = io::Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - loop { - let buffer = ready!(this.reader.as_mut().poll_fill_buf(cx))?; - if buffer.is_empty() { - ready!(Pin::new(&mut this.writer).poll_flush(cx))?; - return Poll::Ready(Ok(*this.amt)); - } - - let i = ready!(Pin::new(&mut this.writer).poll_write(cx, buffer))?; - if i == 0 { - return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); - } - *this.amt += i as u64; - this.reader.as_mut().consume(i); - } - } -} diff --git a/futures-util/src/io/copy_buf_abortable.rs b/futures-util/src/io/copy_buf_abortable.rs deleted file mode 100644 index ed22d62338..0000000000 --- a/futures-util/src/io/copy_buf_abortable.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::abortable::{AbortHandle, AbortInner, Aborted}; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncWrite}; -use pin_project_lite::pin_project; -use std::io; -use std::pin::Pin; -use std::sync::atomic::Ordering; -use std::sync::Arc; - -/// Creates a future which copies all the bytes from one object to another, with its `AbortHandle`. -/// -/// The returned future will copy all the bytes read from this `AsyncBufRead` into the -/// `writer` specified. This future will only complete once abort has been requested or the `reader` has hit -/// EOF and all bytes have been written to and flushed from the `writer` -/// provided. -/// -/// On success the number of bytes is returned. If aborted, `Aborted` is returned. Otherwise, the underlying error is returned. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncWriteExt, Cursor}; -/// use futures::future::Aborted; -/// -/// let reader = Cursor::new([1, 2, 3, 4]); -/// let mut writer = Cursor::new(vec![0u8; 5]); -/// -/// let (fut, abort_handle) = io::copy_buf_abortable(reader, &mut writer); -/// let bytes = fut.await; -/// abort_handle.abort(); -/// writer.close().await.unwrap(); -/// match bytes { -/// Ok(Ok(n)) => { -/// assert_eq!(n, 4); -/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); -/// Ok(n) -/// }, -/// Ok(Err(a)) => { -/// Err::(a) -/// } -/// Err(e) => panic!("{}", e) -/// } -/// # }).unwrap(); -/// ``` -pub fn copy_buf_abortable( - reader: R, - writer: &mut W, -) -> (CopyBufAbortable<'_, R, W>, AbortHandle) -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, -{ - let (handle, reg) = AbortHandle::new_pair(); - (CopyBufAbortable { reader, writer, amt: 0, inner: reg.inner }, handle) -} - -pin_project! { - /// Future for the [`copy_buf_abortable()`] function. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct CopyBufAbortable<'a, R, W: ?Sized> { - #[pin] - reader: R, - writer: &'a mut W, - amt: u64, - inner: Arc - } -} - -macro_rules! ready_or_break { - ($e:expr $(,)?) => { - match $e { - $crate::task::Poll::Ready(t) => t, - $crate::task::Poll::Pending => break, - } - }; -} - -impl Future for CopyBufAbortable<'_, R, W> -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + Sized, -{ - type Output = Result, io::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - loop { - // Check if the task has been aborted - if this.inner.aborted.load(Ordering::Relaxed) { - return Poll::Ready(Ok(Err(Aborted))); - } - - // Read some bytes from the reader, and if we have reached EOF, return total bytes read - let buffer = ready_or_break!(this.reader.as_mut().poll_fill_buf(cx))?; - if buffer.is_empty() { - ready_or_break!(Pin::new(&mut this.writer).poll_flush(cx))?; - return Poll::Ready(Ok(Ok(*this.amt))); - } - - // Pass the buffer to the writer, and update the amount written - let i = ready_or_break!(Pin::new(&mut this.writer).poll_write(cx, buffer))?; - if i == 0 { - return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); - } - *this.amt += i as u64; - this.reader.as_mut().consume(i); - } - // Schedule the task to be woken up again. - // Never called unless Poll::Pending is returned from io objects. - this.inner.waker.register(cx.waker()); - - // Check to see if the task was aborted between the first check and - // registration. - // Checking with `Relaxed` is sufficient because - // `register` introduces an `AcqRel` barrier. - if this.inner.aborted.load(Ordering::Relaxed) { - return Poll::Ready(Ok(Err(Aborted))); - } - Poll::Pending - } -} diff --git a/futures-util/src/io/cursor.rs b/futures-util/src/io/cursor.rs deleted file mode 100644 index 01c8e5f4dc..0000000000 --- a/futures-util/src/io/cursor.rs +++ /dev/null @@ -1,234 +0,0 @@ -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, SeekFrom}; -use std::boxed::Box; -use std::io; -use std::pin::Pin; -use std::vec::Vec; - -/// A `Cursor` wraps an in-memory buffer and provides it with a -/// [`AsyncSeek`] implementation. -/// -/// `Cursor`s are used with in-memory buffers, anything implementing -/// `AsRef<[u8]>`, to allow them to implement [`AsyncRead`] and/or [`AsyncWrite`], -/// allowing these buffers to be used anywhere you might use a reader or writer -/// that does actual I/O. -/// -/// This library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and -/// `Cursor<`[`&[u8]`][bytes]`>`. -/// -/// [`AsyncSeek`]: trait.AsyncSeek.html -/// [`AsyncRead`]: trait.AsyncRead.html -/// [`AsyncWrite`]: trait.AsyncWrite.html -/// [bytes]: https://doc.rust-lang.org/std/primitive.slice.html -#[derive(Clone, Debug, Default)] -pub struct Cursor { - inner: io::Cursor, -} - -impl Cursor { - /// Creates a new cursor wrapping the provided underlying in-memory buffer. - /// - /// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`) - /// is not empty. So writing to cursor starts with overwriting `Vec` - /// content, not with appending to it. - /// - /// # Examples - /// - /// ``` - /// use futures::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// ``` - pub fn new(inner: T) -> Self { - Self { inner: io::Cursor::new(inner) } - } - - /// Consumes this cursor, returning the underlying value. - /// - /// # Examples - /// - /// ``` - /// use futures::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let vec = buff.into_inner(); - /// ``` - pub fn into_inner(self) -> T { - self.inner.into_inner() - } - - /// Gets a reference to the underlying value in this cursor. - /// - /// # Examples - /// - /// ``` - /// use futures::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_ref(); - /// ``` - pub fn get_ref(&self) -> &T { - self.inner.get_ref() - } - - /// Gets a mutable reference to the underlying value in this cursor. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying value as it may corrupt this cursor's position. - /// - /// # Examples - /// - /// ``` - /// use futures::io::Cursor; - /// - /// let mut buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_mut(); - /// ``` - pub fn get_mut(&mut self) -> &mut T { - self.inner.get_mut() - } - - /// Returns the current position of this cursor. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncSeekExt, Cursor, SeekFrom}; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.seek(SeekFrom::Current(2)).await?; - /// assert_eq!(buff.position(), 2); - /// - /// buff.seek(SeekFrom::Current(-1)).await?; - /// assert_eq!(buff.position(), 1); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - pub fn position(&self) -> u64 { - self.inner.position() - } - - /// Sets the position of this cursor. - /// - /// # Examples - /// - /// ``` - /// use futures::io::Cursor; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.set_position(2); - /// assert_eq!(buff.position(), 2); - /// - /// buff.set_position(4); - /// assert_eq!(buff.position(), 4); - /// ``` - pub fn set_position(&mut self, pos: u64) { - self.inner.set_position(pos) - } -} - -impl AsyncSeek for Cursor -where - T: AsRef<[u8]> + Unpin, -{ - fn poll_seek( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - Poll::Ready(io::Seek::seek(&mut self.inner, pos)) - } -} - -impl + Unpin> AsyncRead for Cursor { - fn poll_read( - mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - Poll::Ready(io::Read::read(&mut self.inner, buf)) - } - - fn poll_read_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - Poll::Ready(io::Read::read_vectored(&mut self.inner, bufs)) - } -} - -impl AsyncBufRead for Cursor -where - T: AsRef<[u8]> + Unpin, -{ - fn poll_fill_buf(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(io::BufRead::fill_buf(&mut self.get_mut().inner)) - } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - io::BufRead::consume(&mut self.inner, amt) - } -} - -macro_rules! delegate_async_write_to_stdio { - () => { - fn poll_write( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Poll::Ready(io::Write::write(&mut self.inner, buf)) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - Poll::Ready(io::Write::write_vectored(&mut self.inner, bufs)) - } - - fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(io::Write::flush(&mut self.inner)) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } - }; -} - -impl AsyncWrite for Cursor<&mut [u8]> { - delegate_async_write_to_stdio!(); -} - -impl AsyncWrite for Cursor<&mut Vec> { - delegate_async_write_to_stdio!(); -} - -impl AsyncWrite for Cursor> { - delegate_async_write_to_stdio!(); -} - -impl AsyncWrite for Cursor> { - delegate_async_write_to_stdio!(); -} diff --git a/futures-util/src/io/empty.rs b/futures-util/src/io/empty.rs deleted file mode 100644 index 02f6103f54..0000000000 --- a/futures-util/src/io/empty.rs +++ /dev/null @@ -1,59 +0,0 @@ -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead}; -use std::fmt; -use std::io; -use std::pin::Pin; - -/// Reader for the [`empty()`] function. -#[must_use = "readers do nothing unless polled"] -pub struct Empty { - _priv: (), -} - -/// Constructs a new handle to an empty reader. -/// -/// All reads from the returned reader will return `Poll::Ready(Ok(0))`. -/// -/// # Examples -/// -/// A slightly sad example of not reading anything into a buffer: -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncReadExt}; -/// -/// let mut buffer = String::new(); -/// let mut reader = io::empty(); -/// reader.read_to_string(&mut buffer).await?; -/// assert!(buffer.is_empty()); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn empty() -> Empty { - Empty { _priv: () } -} - -impl AsyncRead for Empty { - #[inline] - fn poll_read( - self: Pin<&mut Self>, - _: &mut Context<'_>, - _: &mut [u8], - ) -> Poll> { - Poll::Ready(Ok(0)) - } -} - -impl AsyncBufRead for Empty { - #[inline] - fn poll_fill_buf(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(&[])) - } - #[inline] - fn consume(self: Pin<&mut Self>, _: usize) {} -} - -impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Empty { .. }") - } -} diff --git a/futures-util/src/io/fill_buf.rs b/futures-util/src/io/fill_buf.rs deleted file mode 100644 index 45862b8e29..0000000000 --- a/futures-util/src/io/fill_buf.rs +++ /dev/null @@ -1,47 +0,0 @@ -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncBufRead; -use std::io; -use std::pin::Pin; -use std::slice; - -/// Future for the [`fill_buf`](super::AsyncBufReadExt::fill_buf) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct FillBuf<'a, R: ?Sized> { - reader: Option<&'a mut R>, -} - -impl Unpin for FillBuf<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> FillBuf<'a, R> { - pub(super) fn new(reader: &'a mut R) -> Self { - Self { reader: Some(reader) } - } -} - -impl<'a, R> Future for FillBuf<'a, R> -where - R: AsyncBufRead + ?Sized + Unpin, -{ - type Output = io::Result<&'a [u8]>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - let reader = this.reader.take().expect("Polled FillBuf after completion"); - - match Pin::new(&mut *reader).poll_fill_buf(cx) { - Poll::Ready(Ok(slice)) => { - // With polonius it is possible to remove this lifetime transmutation and just have - // the correct lifetime of the reference inferred based on which branch is taken - let slice: &'a [u8] = unsafe { slice::from_raw_parts(slice.as_ptr(), slice.len()) }; - Poll::Ready(Ok(slice)) - } - Poll::Ready(Err(err)) => Poll::Ready(Err(err)), - Poll::Pending => { - this.reader = Some(reader); - Poll::Pending - } - } - } -} diff --git a/futures-util/src/io/flush.rs b/futures-util/src/io/flush.rs deleted file mode 100644 index b75d14c5d3..0000000000 --- a/futures-util/src/io/flush.rs +++ /dev/null @@ -1,31 +0,0 @@ -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use std::io; -use std::pin::Pin; - -/// Future for the [`flush`](super::AsyncWriteExt::flush) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Flush<'a, W: ?Sized> { - writer: &'a mut W, -} - -impl Unpin for Flush<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> Flush<'a, W> { - pub(super) fn new(writer: &'a mut W) -> Self { - Self { writer } - } -} - -impl Future for Flush<'_, W> -where - W: AsyncWrite + ?Sized + Unpin, -{ - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut *self.writer).poll_flush(cx) - } -} diff --git a/futures-util/src/io/into_sink.rs b/futures-util/src/io/into_sink.rs deleted file mode 100644 index 6a41ee2269..0000000000 --- a/futures-util/src/io/into_sink.rs +++ /dev/null @@ -1,82 +0,0 @@ -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use futures_sink::Sink; -use pin_project_lite::pin_project; -use std::io; -use std::pin::Pin; - -#[derive(Debug)] -struct Block { - offset: usize, - bytes: Item, -} - -pin_project! { - /// Sink for the [`into_sink`](super::AsyncWriteExt::into_sink) method. - #[must_use = "sinks do nothing unless polled"] - #[derive(Debug)] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - pub struct IntoSink { - #[pin] - writer: W, - // An outstanding block for us to push into the underlying writer, along with an offset of how - // far into this block we have written already. - buffer: Option>, - } -} - -impl> IntoSink { - pub(super) fn new(writer: W) -> Self { - Self { writer, buffer: None } - } - - /// If we have an outstanding block in `buffer` attempt to push it into the writer, does _not_ - /// flush the writer after it succeeds in pushing the block into it. - fn poll_flush_buffer( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - let mut this = self.project(); - - if let Some(buffer) = this.buffer { - loop { - let bytes = buffer.bytes.as_ref(); - let written = ready!(this.writer.as_mut().poll_write(cx, &bytes[buffer.offset..]))?; - buffer.offset += written; - if buffer.offset == bytes.len() { - break; - } - } - } - *this.buffer = None; - Poll::Ready(Ok(())) - } -} - -impl> Sink for IntoSink { - type Error = io::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.poll_flush_buffer(cx))?; - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - debug_assert!(self.buffer.is_none()); - *self.project().buffer = Some(Block { offset: 0, bytes: item }); - Ok(()) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().poll_flush_buffer(cx))?; - ready!(self.project().writer.poll_flush(cx))?; - Poll::Ready(Ok(())) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().poll_flush_buffer(cx))?; - ready!(self.project().writer.poll_close(cx))?; - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/io/line_writer.rs b/futures-util/src/io/line_writer.rs deleted file mode 100644 index de1bb53924..0000000000 --- a/futures-util/src/io/line_writer.rs +++ /dev/null @@ -1,155 +0,0 @@ -use super::buf_writer::BufWriter; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use futures_io::IoSlice; -use pin_project_lite::pin_project; -use std::io; -use std::pin::Pin; - -pin_project! { -/// Wrap a writer, like [`BufWriter`] does, but prioritizes buffering lines -/// -/// This was written based on `std::io::LineWriter` which goes into further details -/// explaining the code. -/// -/// Buffering is actually done using `BufWriter`. This class will leverage `BufWriter` -/// to write on-each-line. -#[derive(Debug)] -pub struct LineWriter { - #[pin] - buf_writer: BufWriter, -} -} - -impl LineWriter { - /// Create a new `LineWriter` with default buffer capacity. The default is currently 1KB - /// which was taken from `std::io::LineWriter` - pub fn new(inner: W) -> Self { - Self::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with the specified buffer capacity. - pub fn with_capacity(capacity: usize, inner: W) -> Self { - Self { buf_writer: BufWriter::with_capacity(capacity, inner) } - } - - /// Flush `buf_writer` if last char is "new line" - fn flush_if_completed_line(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - match this.buf_writer.buffer().last().copied() { - Some(b'\n') => this.buf_writer.flush_buf(cx), - _ => Poll::Ready(Ok(())), - } - } - - /// Returns a reference to `buf_writer`'s internally buffered data. - pub fn buffer(&self) -> &[u8] { - self.buf_writer.buffer() - } - - /// Acquires a reference to the underlying sink or stream that this combinator is - /// pulling from. - pub fn get_ref(&self) -> &W { - self.buf_writer.get_ref() - } -} - -impl AsyncWrite for LineWriter { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let mut this = self.as_mut().project(); - let newline_index = match memchr::memrchr(b'\n', buf) { - None => { - ready!(self.as_mut().flush_if_completed_line(cx)?); - return self.project().buf_writer.poll_write(cx, buf); - } - Some(newline_index) => newline_index + 1, - }; - - ready!(this.buf_writer.as_mut().poll_flush(cx)?); - - let lines = &buf[..newline_index]; - - let flushed = { ready!(this.buf_writer.as_mut().inner_poll_write(cx, lines))? }; - - if flushed == 0 { - return Poll::Ready(Ok(0)); - } - - let tail = if flushed >= newline_index { - &buf[flushed..] - } else if newline_index - flushed <= this.buf_writer.capacity() { - &buf[flushed..newline_index] - } else { - let scan_area = &buf[flushed..]; - let scan_area = &scan_area[..this.buf_writer.capacity()]; - match memchr::memrchr(b'\n', scan_area) { - Some(newline_index) => &scan_area[..newline_index + 1], - None => scan_area, - } - }; - - let buffered = this.buf_writer.as_mut().write_to_buf(tail); - Poll::Ready(Ok(flushed + buffered)) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - let mut this = self.as_mut().project(); - // `is_write_vectored()` is handled in original code, but not in this crate - // see https://github.com/rust-lang/rust/issues/70436 - - let last_newline_buf_idx = bufs - .iter() - .enumerate() - .rev() - .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); - let last_newline_buf_idx = match last_newline_buf_idx { - None => { - ready!(self.as_mut().flush_if_completed_line(cx)?); - return self.project().buf_writer.poll_write_vectored(cx, bufs); - } - Some(i) => i, - }; - - ready!(this.buf_writer.as_mut().poll_flush(cx)?); - - let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); - - let flushed = { ready!(this.buf_writer.as_mut().inner_poll_write_vectored(cx, lines))? }; - if flushed == 0 { - return Poll::Ready(Ok(0)); - } - - let lines_len = lines.iter().map(|buf| buf.len()).sum(); - if flushed < lines_len { - return Poll::Ready(Ok(flushed)); - } - - let buffered: usize = tail - .iter() - .filter(|buf| !buf.is_empty()) - .map(|buf| this.buf_writer.as_mut().write_to_buf(buf)) - .take_while(|&n| n > 0) - .sum(); - - Poll::Ready(Ok(flushed + buffered)) - } - - /// Forward to `buf_writer` 's `BufWriter::poll_flush()` - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.as_mut().project().buf_writer.poll_flush(cx) - } - - /// Forward to `buf_writer` 's `BufWriter::poll_close()` - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.as_mut().project().buf_writer.poll_close(cx) - } -} diff --git a/futures-util/src/io/lines.rs b/futures-util/src/io/lines.rs deleted file mode 100644 index 0a1abf4bf6..0000000000 --- a/futures-util/src/io/lines.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::read_line::read_line_internal; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncBufRead; -use pin_project_lite::pin_project; -use std::io; -use std::mem; -use std::pin::Pin; -use std::string::String; -use std::vec::Vec; - -pin_project! { - /// Stream for the [`lines`](super::AsyncBufReadExt::lines) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Lines { - #[pin] - reader: R, - buf: String, - bytes: Vec, - read: usize, - } -} - -impl Lines { - pub(super) fn new(reader: R) -> Self { - Self { reader, buf: String::new(), bytes: Vec::new(), read: 0 } - } -} - -impl Stream for Lines { - type Item = io::Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - let n = ready!(read_line_internal(this.reader, cx, this.buf, this.bytes, this.read))?; - *this.read = 0; - if n == 0 && this.buf.is_empty() { - return Poll::Ready(None); - } - if this.buf.ends_with('\n') { - this.buf.pop(); - if this.buf.ends_with('\r') { - this.buf.pop(); - } - } - Poll::Ready(Some(Ok(mem::take(this.buf)))) - } -} diff --git a/futures-util/src/io/mod.rs b/futures-util/src/io/mod.rs deleted file mode 100644 index bf46dcaad0..0000000000 --- a/futures-util/src/io/mod.rs +++ /dev/null @@ -1,836 +0,0 @@ -//! Asynchronous I/O. -//! -//! This module is the asynchronous version of `std::io`. It defines four -//! traits, [`AsyncRead`], [`AsyncWrite`], [`AsyncSeek`], and [`AsyncBufRead`], -//! which mirror the `Read`, `Write`, `Seek`, and `BufRead` traits of the -//! standard library. However, these traits integrate with the asynchronous -//! task system, so that if an I/O object isn't ready for reading (or writing), -//! the thread is not blocked, and instead the current task is queued to be -//! woken when I/O is ready. -//! -//! In addition, the [`AsyncReadExt`], [`AsyncWriteExt`], [`AsyncSeekExt`], and -//! [`AsyncBufReadExt`] extension traits offer a variety of useful combinators -//! for operating with asynchronous I/O objects, including ways to work with -//! them using futures, streams and sinks. -//! -//! This module is only available when the `std` feature of this -//! library is activated, and it is activated by default. - -#[cfg(feature = "io-compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] -use crate::compat::Compat; -use crate::future::assert_future; -use crate::stream::assert_stream; -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`. -#[doc(no_inline)] -pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom}; - -pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; - -// used by `BufReader` and `BufWriter` -// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1 -const DEFAULT_BUF_SIZE: usize = 8 * 1024; - -mod allow_std; -pub use self::allow_std::AllowStdIo; - -mod buf_reader; -pub use self::buf_reader::{BufReader, SeekRelative}; - -mod buf_writer; -pub use self::buf_writer::BufWriter; - -mod line_writer; -pub use self::line_writer::LineWriter; - -mod chain; -pub use self::chain::Chain; - -mod close; -pub use self::close::Close; - -mod copy; -pub use self::copy::{copy, Copy}; - -mod copy_buf; -pub use self::copy_buf::{copy_buf, CopyBuf}; - -mod copy_buf_abortable; -pub use self::copy_buf_abortable::{copy_buf_abortable, CopyBufAbortable}; - -mod cursor; -pub use self::cursor::Cursor; - -mod empty; -pub use self::empty::{empty, Empty}; - -mod fill_buf; -pub use self::fill_buf::FillBuf; - -mod flush; -pub use self::flush::Flush; - -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -mod into_sink; -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::into_sink::IntoSink; - -mod lines; -pub use self::lines::Lines; - -mod read; -pub use self::read::Read; - -mod read_vectored; -pub use self::read_vectored::ReadVectored; - -mod read_exact; -pub use self::read_exact::ReadExact; - -mod read_line; -pub use self::read_line::ReadLine; - -mod read_to_end; -pub use self::read_to_end::ReadToEnd; - -mod read_to_string; -pub use self::read_to_string::ReadToString; - -mod read_until; -pub use self::read_until::ReadUntil; - -mod repeat; -pub use self::repeat::{repeat, Repeat}; - -mod seek; -pub use self::seek::Seek; - -mod sink; -pub use self::sink::{sink, Sink}; - -mod split; -pub use self::split::{ReadHalf, ReuniteError, WriteHalf}; - -mod take; -pub use self::take::Take; - -mod window; -pub use self::window::Window; - -mod write; -pub use self::write::Write; - -mod write_vectored; -pub use self::write_vectored::WriteVectored; - -mod write_all; -pub use self::write_all::WriteAll; - -#[cfg(feature = "write-all-vectored")] -mod write_all_vectored; -#[cfg(feature = "write-all-vectored")] -pub use self::write_all_vectored::WriteAllVectored; - -/// An extension trait which adds utility methods to `AsyncRead` types. -pub trait AsyncReadExt: AsyncRead { - /// Creates an adaptor which will chain this stream with another. - /// - /// The returned `AsyncRead` instance will first read all bytes from this object - /// until EOF is encountered. Afterwards the output is equivalent to the - /// output of `next`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let reader1 = Cursor::new([1, 2, 3, 4]); - /// let reader2 = Cursor::new([5, 6, 7, 8]); - /// - /// let mut reader = reader1.chain(reader2); - /// let mut buffer = Vec::new(); - /// - /// // read the value into a Vec. - /// reader.read_to_end(&mut buffer).await?; - /// assert_eq!(buffer, [1, 2, 3, 4, 5, 6, 7, 8]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn chain(self, next: R) -> Chain - where - Self: Sized, - R: AsyncRead, - { - assert_read(Chain::new(self, next)) - } - - /// Tries to read some bytes directly into the given `buf` in asynchronous - /// manner, returning a future type. - /// - /// The returned future will resolve to the number of bytes read once the read - /// operation is completed. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let mut reader = Cursor::new([1, 2, 3, 4]); - /// let mut output = [0u8; 5]; - /// - /// let bytes = reader.read(&mut output[..]).await?; - /// - /// // This is only guaranteed to be 4 because `&[u8]` is a synchronous - /// // reader. In a real system you could get anywhere from 1 to - /// // `output.len()` bytes in a single read. - /// assert_eq!(bytes, 4); - /// assert_eq!(output, [1, 2, 3, 4, 0]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(Read::new(self, buf)) - } - - /// Creates a future which will read from the `AsyncRead` into `bufs` using vectored - /// IO operations. - /// - /// The returned future will resolve to the number of bytes read once the read - /// operation is completed. - fn read_vectored<'a, 'b>( - &'a mut self, - bufs: &'a mut [IoSliceMut<'b>], - ) -> ReadVectored<'a, 'b, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadVectored::new(self, bufs)) - } - - /// Creates a future which will read exactly enough bytes to fill `buf`, - /// returning an error if end of file (EOF) is hit sooner. - /// - /// The returned future will resolve once the read operation is completed. - /// - /// In the case of an error the buffer and the object will be discarded, with - /// the error yielded. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let mut reader = Cursor::new([1, 2, 3, 4]); - /// let mut output = [0u8; 4]; - /// - /// reader.read_exact(&mut output).await?; - /// - /// assert_eq!(output, [1, 2, 3, 4]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - /// - /// ## EOF is hit before `buf` is filled - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{self, AsyncReadExt, Cursor}; - /// - /// let mut reader = Cursor::new([1, 2, 3, 4]); - /// let mut output = [0u8; 5]; - /// - /// let result = reader.read_exact(&mut output).await; - /// - /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - /// # }); - /// ``` - fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadExact::new(self, buf)) - } - - /// Creates a future which will read all the bytes from this `AsyncRead`. - /// - /// On success the total number of bytes read is returned. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let mut reader = Cursor::new([1, 2, 3, 4]); - /// let mut output = Vec::with_capacity(4); - /// - /// let bytes = reader.read_to_end(&mut output).await?; - /// - /// assert_eq!(bytes, 4); - /// assert_eq!(output, vec![1, 2, 3, 4]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec) -> ReadToEnd<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadToEnd::new(self, buf)) - } - - /// Creates a future which will read all the bytes from this `AsyncRead`. - /// - /// On success the total number of bytes read is returned. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let mut reader = Cursor::new(&b"1234"[..]); - /// let mut buffer = String::with_capacity(4); - /// - /// let bytes = reader.read_to_string(&mut buffer).await?; - /// - /// assert_eq!(bytes, 4); - /// assert_eq!(buffer, String::from("1234")); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn read_to_string<'a>(&'a mut self, buf: &'a mut String) -> ReadToString<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadToString::new(self, buf)) - } - - /// Helper method for splitting this read/write object into two halves. - /// - /// The two halves returned implement the `AsyncRead` and `AsyncWrite` - /// traits, respectively. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{self, AsyncReadExt, Cursor}; - /// - /// // Note that for `Cursor` the read and write halves share a single - /// // seek position. This may or may not be true for other types that - /// // implement both `AsyncRead` and `AsyncWrite`. - /// - /// let reader = Cursor::new([1, 2, 3, 4]); - /// let mut buffer = Cursor::new(vec![0, 0, 0, 0, 5, 6, 7, 8]); - /// let mut writer = Cursor::new(vec![0u8; 5]); - /// - /// { - /// let (buffer_reader, mut buffer_writer) = (&mut buffer).split(); - /// io::copy(reader, &mut buffer_writer).await?; - /// io::copy(buffer_reader, &mut writer).await?; - /// } - /// - /// assert_eq!(buffer.into_inner(), [1, 2, 3, 4, 5, 6, 7, 8]); - /// assert_eq!(writer.into_inner(), [5, 6, 7, 8, 0]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn split(self) -> (ReadHalf, WriteHalf) - where - Self: AsyncWrite + Sized, - { - let (r, w) = split::split(self); - (assert_read(r), assert_write(w)) - } - - /// Creates an AsyncRead adapter which will read at most `limit` bytes - /// from the underlying reader. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let reader = Cursor::new(&b"12345678"[..]); - /// let mut buffer = [0; 5]; - /// - /// let mut take = reader.take(4); - /// let n = take.read(&mut buffer).await?; - /// - /// assert_eq!(n, 4); - /// assert_eq!(&buffer, b"1234\0"); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn take(self, limit: u64) -> Take - where - Self: Sized, - { - assert_read(Take::new(self, limit)) - } - - /// Wraps an [`AsyncRead`] in a compatibility wrapper that allows it to be - /// used as a futures 0.1 / tokio-io 0.1 `AsyncRead`. If the wrapped type - /// implements [`AsyncWrite`] as well, the result will also implement the - /// futures 0.1 / tokio 0.1 `AsyncWrite` trait. - /// - /// Requires the `io-compat` feature to enable. - #[cfg(feature = "io-compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] - fn compat(self) -> Compat - where - Self: Sized + Unpin, - { - Compat::new(self) - } -} - -impl AsyncReadExt for R {} - -/// An extension trait which adds utility methods to `AsyncWrite` types. -pub trait AsyncWriteExt: AsyncWrite { - /// Creates a future which will entirely flush this `AsyncWrite`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AllowStdIo, AsyncWriteExt}; - /// use std::io::{BufWriter, Cursor}; - /// - /// let mut output = vec![0u8; 5]; - /// - /// { - /// let writer = Cursor::new(&mut output); - /// let mut buffered = AllowStdIo::new(BufWriter::new(writer)); - /// buffered.write_all(&[1, 2]).await?; - /// buffered.write_all(&[3, 4]).await?; - /// buffered.flush().await?; - /// } - /// - /// assert_eq!(output, [1, 2, 3, 4, 0]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn flush(&mut self) -> Flush<'_, Self> - where - Self: Unpin, - { - assert_future::, _>(Flush::new(self)) - } - - /// Creates a future which will entirely close this `AsyncWrite`. - fn close(&mut self) -> Close<'_, Self> - where - Self: Unpin, - { - assert_future::, _>(Close::new(self)) - } - - /// Creates a future which will write bytes from `buf` into the object. - /// - /// The returned future will resolve to the number of bytes written once the write - /// operation is completed. - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(Write::new(self, buf)) - } - - /// Creates a future which will write bytes from `bufs` into the object using vectored - /// IO operations. - /// - /// The returned future will resolve to the number of bytes written once the write - /// operation is completed. - fn write_vectored<'a, 'b>(&'a mut self, bufs: &'a [IoSlice<'b>]) -> WriteVectored<'a, 'b, Self> - where - Self: Unpin, - { - assert_future::, _>(WriteVectored::new(self, bufs)) - } - - /// Write data into this object. - /// - /// Creates a future that will write the entire contents of the buffer `buf` into - /// this `AsyncWrite`. - /// - /// The returned future will not complete until all the data has been written. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncWriteExt, Cursor}; - /// - /// let mut writer = Cursor::new(vec![0u8; 5]); - /// - /// writer.write_all(&[1, 2, 3, 4]).await?; - /// - /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(WriteAll::new(self, buf)) - } - - /// Attempts to write multiple buffers into this writer. - /// - /// Creates a future that will write the entire contents of `bufs` into this - /// `AsyncWrite` using [vectored writes]. - /// - /// The returned future will not complete until all the data has been - /// written. - /// - /// [vectored writes]: std::io::Write::write_vectored - /// - /// # Notes - /// - /// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to - /// a slice of `IoSlice`s, not an immutable one. That's because we need to - /// modify the slice to keep track of the bytes already written. - /// - /// Once this futures returns, the contents of `bufs` are unspecified, as - /// this depends on how many calls to `write_vectored` were necessary. It is - /// best to understand this function as taking ownership of `bufs` and to - /// not use `bufs` afterwards. The underlying buffers, to which the - /// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and - /// can be reused. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::AsyncWriteExt; - /// use futures_util::io::Cursor; - /// use std::io::IoSlice; - /// - /// let mut writer = Cursor::new(Vec::new()); - /// let bufs = &mut [ - /// IoSlice::new(&[1]), - /// IoSlice::new(&[2, 3]), - /// IoSlice::new(&[4, 5, 6]), - /// ]; - /// - /// writer.write_all_vectored(bufs).await?; - /// // Note: the contents of `bufs` is now unspecified, see the Notes section. - /// - /// assert_eq!(writer.into_inner(), &[1, 2, 3, 4, 5, 6]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - #[cfg(feature = "write-all-vectored")] - fn write_all_vectored<'a, 'b>( - &'a mut self, - bufs: &'a mut [IoSlice<'b>], - ) -> WriteAllVectored<'a, 'b, Self> - where - Self: Unpin, - { - assert_future::, _>(WriteAllVectored::new(self, bufs)) - } - - /// Wraps an [`AsyncWrite`] in a compatibility wrapper that allows it to be - /// used as a futures 0.1 / tokio-io 0.1 `AsyncWrite`. - /// Requires the `io-compat` feature to enable. - #[cfg(feature = "io-compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] - fn compat_write(self) -> Compat - where - Self: Sized + Unpin, - { - Compat::new(self) - } - - /// Allow using an [`AsyncWrite`] as a [`Sink`](futures_sink::Sink)`>`. - /// - /// This adapter produces a sink that will write each value passed to it - /// into the underlying writer. - /// - /// Note that this function consumes the given writer, returning a wrapped - /// version. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::AsyncWriteExt; - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(vec![[1, 2, 3], [4, 5, 6]]); - /// - /// let mut writer = vec![]; - /// - /// stream.forward((&mut writer).into_sink()).await?; - /// - /// assert_eq!(writer, vec![1, 2, 3, 4, 5, 6]); - /// # Ok::<(), Box>(()) - /// # })?; - /// # Ok::<(), Box>(()) - /// ``` - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - fn into_sink>(self) -> IntoSink - where - Self: Sized, - { - crate::sink::assert_sink::(IntoSink::new(self)) - } -} - -impl AsyncWriteExt for W {} - -/// An extension trait which adds utility methods to `AsyncSeek` types. -pub trait AsyncSeekExt: AsyncSeek { - /// Creates a future which will seek an IO object, and then yield the - /// new position in the object and the object itself. - /// - /// In the case of an error the buffer and the object will be discarded, with - /// the error yielded. - fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self> - where - Self: Unpin, - { - assert_future::, _>(Seek::new(self, pos)) - } - - /// Creates a future which will return the current seek position from the - /// start of the stream. - /// - /// This is equivalent to `self.seek(SeekFrom::Current(0))`. - fn stream_position(&mut self) -> Seek<'_, Self> - where - Self: Unpin, - { - self.seek(SeekFrom::Current(0)) - } -} - -impl AsyncSeekExt for S {} - -/// An extension trait which adds utility methods to `AsyncBufRead` types. -pub trait AsyncBufReadExt: AsyncBufRead { - /// Creates a future which will wait for a non-empty buffer to be available from this I/O - /// object or EOF to be reached. - /// - /// This method is the async equivalent to [`BufRead::fill_buf`](std::io::BufRead::fill_buf). - /// - /// ```rust - /// # futures::executor::block_on(async { - /// use futures::{io::AsyncBufReadExt as _, stream::{iter, TryStreamExt as _}}; - /// - /// let mut stream = iter(vec![Ok(vec![1, 2, 3]), Ok(vec![4, 5, 6])]).into_async_read(); - /// - /// assert_eq!(stream.fill_buf().await?, vec![1, 2, 3]); - /// stream.consume_unpin(2); - /// - /// assert_eq!(stream.fill_buf().await?, vec![3]); - /// stream.consume_unpin(1); - /// - /// assert_eq!(stream.fill_buf().await?, vec![4, 5, 6]); - /// stream.consume_unpin(3); - /// - /// assert_eq!(stream.fill_buf().await?, vec![]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn fill_buf(&mut self) -> FillBuf<'_, Self> - where - Self: Unpin, - { - assert_future::, _>(FillBuf::new(self)) - } - - /// A convenience for calling [`AsyncBufRead::consume`] on [`Unpin`] IO types. - /// - /// ```rust - /// # futures::executor::block_on(async { - /// use futures::{io::AsyncBufReadExt as _, stream::{iter, TryStreamExt as _}}; - /// - /// let mut stream = iter(vec![Ok(vec![1, 2, 3])]).into_async_read(); - /// - /// assert_eq!(stream.fill_buf().await?, vec![1, 2, 3]); - /// stream.consume_unpin(2); - /// - /// assert_eq!(stream.fill_buf().await?, vec![3]); - /// stream.consume_unpin(1); - /// - /// assert_eq!(stream.fill_buf().await?, vec![]); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn consume_unpin(&mut self, amt: usize) - where - Self: Unpin, - { - Pin::new(self).consume(amt) - } - - /// Creates a future which will read all the bytes associated with this I/O - /// object into `buf` until the delimiter `byte` or EOF is reached. - /// This method is the async equivalent to [`BufRead::read_until`](std::io::BufRead::read_until). - /// - /// This function will read bytes from the underlying stream until the - /// delimiter or EOF is found. Once found, all bytes up to, and including, - /// the delimiter (if found) will be appended to `buf`. - /// - /// The returned future will resolve to the number of bytes read once the read - /// operation is completed. - /// - /// In the case of an error the buffer and the object will be discarded, with - /// the error yielded. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncBufReadExt, Cursor}; - /// - /// let mut cursor = Cursor::new(b"lorem-ipsum"); - /// let mut buf = vec![]; - /// - /// // cursor is at 'l' - /// let num_bytes = cursor.read_until(b'-', &mut buf).await?; - /// assert_eq!(num_bytes, 6); - /// assert_eq!(buf, b"lorem-"); - /// buf.clear(); - /// - /// // cursor is at 'i' - /// let num_bytes = cursor.read_until(b'-', &mut buf).await?; - /// assert_eq!(num_bytes, 5); - /// assert_eq!(buf, b"ipsum"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_until(b'-', &mut buf).await?; - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, b""); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec) -> ReadUntil<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadUntil::new(self, byte, buf)) - } - - /// Creates a future which will read all the bytes associated with this I/O - /// object into `buf` until a newline (the 0xA byte) or EOF is reached, - /// This method is the async equivalent to [`BufRead::read_line`](std::io::BufRead::read_line). - /// - /// This function will read bytes from the underlying stream until the - /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes - /// up to, and including, the delimiter (if found) will be appended to - /// `buf`. - /// - /// The returned future will resolve to the number of bytes read once the read - /// operation is completed. - /// - /// In the case of an error the buffer and the object will be discarded, with - /// the error yielded. - /// - /// # Errors - /// - /// This function has the same error semantics as [`read_until`] and will - /// also return an error if the read bytes are not valid UTF-8. If an I/O - /// error is encountered then `buf` may contain some bytes already read in - /// the event that all data read so far was valid UTF-8. - /// - /// [`read_until`]: AsyncBufReadExt::read_until - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncBufReadExt, Cursor}; - /// - /// let mut cursor = Cursor::new(b"foo\nbar"); - /// let mut buf = String::new(); - /// - /// // cursor is at 'f' - /// let num_bytes = cursor.read_line(&mut buf).await?; - /// assert_eq!(num_bytes, 4); - /// assert_eq!(buf, "foo\n"); - /// buf.clear(); - /// - /// // cursor is at 'b' - /// let num_bytes = cursor.read_line(&mut buf).await?; - /// assert_eq!(num_bytes, 3); - /// assert_eq!(buf, "bar"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_line(&mut buf).await?; - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, ""); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self> - where - Self: Unpin, - { - assert_future::, _>(ReadLine::new(self, buf)) - } - - /// Returns a stream over the lines of this reader. - /// This method is the async equivalent to [`BufRead::lines`](std::io::BufRead::lines). - /// - /// The stream returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline - /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. - /// - /// [`io::Result`]: std::io::Result - /// [`String`]: String - /// - /// # Errors - /// - /// Each line of the stream has the same error semantics as [`AsyncBufReadExt::read_line`]. - /// - /// [`AsyncBufReadExt::read_line`]: AsyncBufReadExt::read_line - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncBufReadExt, Cursor}; - /// use futures::stream::StreamExt; - /// - /// let cursor = Cursor::new(b"lorem\nipsum\xc2\r\ndolor"); - /// - /// let mut lines_stream = cursor.lines().map(|l| l.unwrap_or(String::from("invalid UTF_8"))); - /// assert_eq!(lines_stream.next().await, Some(String::from("lorem"))); - /// assert_eq!(lines_stream.next().await, Some(String::from("invalid UTF_8"))); - /// assert_eq!(lines_stream.next().await, Some(String::from("dolor"))); - /// assert_eq!(lines_stream.next().await, None); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - fn lines(self) -> Lines - where - Self: Sized, - { - assert_stream::, _>(Lines::new(self)) - } -} - -impl AsyncBufReadExt for R {} - -// Just a helper function to ensure the reader we're returning all have the -// right implementations. -pub(crate) fn assert_read(reader: R) -> R -where - R: AsyncRead, -{ - reader -} -// Just a helper function to ensure the writer we're returning all have the -// right implementations. -pub(crate) fn assert_write(writer: W) -> W -where - W: AsyncWrite, -{ - writer -} diff --git a/futures-util/src/io/read.rs b/futures-util/src/io/read.rs deleted file mode 100644 index 677ba818d9..0000000000 --- a/futures-util/src/io/read.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::io::AsyncRead; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use std::io; -use std::pin::Pin; - -/// Future for the [`read`](super::AsyncReadExt::read) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Read<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut [u8], -} - -impl Unpin for Read<'_, R> {} - -impl<'a, R: AsyncRead + ?Sized + Unpin> Read<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { - Self { reader, buf } - } -} - -impl Future for Read<'_, R> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - Pin::new(&mut this.reader).poll_read(cx, this.buf) - } -} diff --git a/futures-util/src/io/read_exact.rs b/futures-util/src/io/read_exact.rs deleted file mode 100644 index cd0b20e597..0000000000 --- a/futures-util/src/io/read_exact.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::io::AsyncRead; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use std::io; -use std::mem; -use std::pin::Pin; - -/// Future for the [`read_exact`](super::AsyncReadExt::read_exact) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadExact<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut [u8], -} - -impl Unpin for ReadExact<'_, R> {} - -impl<'a, R: AsyncRead + ?Sized + Unpin> ReadExact<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { - Self { reader, buf } - } -} - -impl Future for ReadExact<'_, R> { - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - while !this.buf.is_empty() { - let n = ready!(Pin::new(&mut this.reader).poll_read(cx, this.buf))?; - { - let (_, rest) = mem::take(&mut this.buf).split_at_mut(n); - this.buf = rest; - } - if n == 0 { - return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into())); - } - } - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/io/read_line.rs b/futures-util/src/io/read_line.rs deleted file mode 100644 index 43942add54..0000000000 --- a/futures-util/src/io/read_line.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::read_until::read_until_internal; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncBufRead; -use std::io; -use std::mem; -use std::pin::Pin; -use std::str; -use std::string::String; -use std::vec::Vec; - -/// Future for the [`read_line`](super::AsyncBufReadExt::read_line) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadLine<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut String, - bytes: Vec, - read: usize, - finished: bool, -} - -impl Unpin for ReadLine<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadLine<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut String) -> Self { - Self { reader, bytes: mem::take(buf).into_bytes(), buf, read: 0, finished: false } - } -} - -pub(super) fn read_line_internal( - reader: Pin<&mut R>, - cx: &mut Context<'_>, - buf: &mut String, - bytes: &mut Vec, - read: &mut usize, -) -> Poll> { - let mut ret = ready!(read_until_internal(reader, cx, b'\n', bytes, read)); - if str::from_utf8(&bytes[bytes.len() - *read..bytes.len()]).is_err() { - bytes.truncate(bytes.len() - *read); - if ret.is_ok() { - ret = Err(io::Error::new( - io::ErrorKind::InvalidData, - "stream did not contain valid UTF-8", - )); - } - } - *read = 0; - // Safety: `bytes` is valid UTF-8 because it was taken from a String - // and the newly read bytes are either valid UTF-8 or have been removed. - mem::swap(unsafe { buf.as_mut_vec() }, bytes); - Poll::Ready(ret) -} - -impl Future for ReadLine<'_, R> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, buf, bytes, read, finished: _ } = &mut *self; - let ret = ready!(read_line_internal(Pin::new(reader), cx, buf, bytes, read)); - self.finished = true; - Poll::Ready(ret) - } -} - -impl Drop for ReadLine<'_, R> { - fn drop(&mut self) { - // restore old string contents - if !self.finished { - self.bytes.truncate(self.bytes.len() - self.read); - // Safety: `bytes` is valid UTF-8 because it was taken from a String - // and the newly read bytes have been removed. - mem::swap(unsafe { self.buf.as_mut_vec() }, &mut self.bytes); - } - } -} diff --git a/futures-util/src/io/read_to_end.rs b/futures-util/src/io/read_to_end.rs deleted file mode 100644 index 82a36d2164..0000000000 --- a/futures-util/src/io/read_to_end.rs +++ /dev/null @@ -1,90 +0,0 @@ -use futures_core::future::Future; -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; - -/// Future for the [`read_to_end`](super::AsyncReadExt::read_to_end) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadToEnd<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut Vec, - start_len: usize, -} - -impl Unpin for ReadToEnd<'_, R> {} - -impl<'a, R: AsyncRead + ?Sized + Unpin> ReadToEnd<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut Vec) -> Self { - let start_len = buf.len(); - Self { reader, buf, start_len } - } -} - -struct Guard<'a> { - buf: &'a mut Vec, - len: usize, -} - -impl Drop for Guard<'_> { - fn drop(&mut self) { - unsafe { - self.buf.set_len(self.len); - } - } -} - -// This uses an adaptive system to extend the vector when it fills. We want to -// avoid paying to allocate and zero a huge chunk of memory if the reader only -// has 4 bytes while still making large reads if the reader does have a ton -// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than this if the reader has a very small -// amount of data to return. -// -// Because we're extending the buffer with uninitialized data for trusted -// readers, we need to make sure to truncate that if any of this panics. -pub(super) fn read_to_end_internal( - mut rd: Pin<&mut R>, - cx: &mut Context<'_>, - buf: &mut Vec, - start_len: usize, -) -> Poll> { - let mut g = Guard { len: buf.len(), buf }; - loop { - if g.len == g.buf.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..]; - match ready!(rd.as_mut().poll_read(cx, buf)) { - Ok(0) => return Poll::Ready(Ok(g.len - start_len)), - Ok(n) => { - // We can't allow bogus values from read. If it is too large, the returned vec could have its length - // set past its capacity, or if it overflows the vec could be shortened which could create an invalid - // string if this is called via read_to_string. - assert!(n <= buf.len()); - g.len += n; - } - Err(e) => return Poll::Ready(Err(e)), - } - } -} - -impl Future for ReadToEnd<'_, A> -where - A: AsyncRead + ?Sized + Unpin, -{ - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - read_to_end_internal(Pin::new(&mut this.reader), cx, this.buf, this.start_len) - } -} diff --git a/futures-util/src/io/read_to_string.rs b/futures-util/src/io/read_to_string.rs deleted file mode 100644 index a075ca2662..0000000000 --- a/futures-util/src/io/read_to_string.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::read_to_end::read_to_end_internal; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncRead; -use std::pin::Pin; -use std::string::String; -use std::vec::Vec; -use std::{io, mem, str}; - -/// Future for the [`read_to_string`](super::AsyncReadExt::read_to_string) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadToString<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut String, - bytes: Vec, - start_len: usize, -} - -impl Unpin for ReadToString<'_, R> {} - -impl<'a, R: AsyncRead + ?Sized + Unpin> ReadToString<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut String) -> Self { - let start_len = buf.len(); - Self { reader, bytes: mem::take(buf).into_bytes(), buf, start_len } - } -} - -fn read_to_string_internal( - reader: Pin<&mut R>, - cx: &mut Context<'_>, - buf: &mut String, - bytes: &mut Vec, - start_len: usize, -) -> Poll> { - let ret = ready!(read_to_end_internal(reader, cx, bytes, start_len)); - if str::from_utf8(bytes).is_err() { - Poll::Ready(ret.and_then(|_| { - Err(io::Error::new(io::ErrorKind::InvalidData, "stream did not contain valid UTF-8")) - })) - } else { - debug_assert!(buf.is_empty()); - // Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`. - mem::swap(unsafe { buf.as_mut_vec() }, bytes); - Poll::Ready(ret) - } -} - -impl Future for ReadToString<'_, A> -where - A: AsyncRead + ?Sized + Unpin, -{ - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, buf, bytes, start_len } = &mut *self; - read_to_string_internal(Pin::new(reader), cx, buf, bytes, *start_len) - } -} diff --git a/futures-util/src/io/read_until.rs b/futures-util/src/io/read_until.rs deleted file mode 100644 index adc359db51..0000000000 --- a/futures-util/src/io/read_until.rs +++ /dev/null @@ -1,60 +0,0 @@ -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncBufRead; -use std::io; -use std::pin::Pin; -use std::vec::Vec; - -/// Future for the [`read_until`](super::AsyncBufReadExt::read_until) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadUntil<'a, R: ?Sized> { - reader: &'a mut R, - byte: u8, - buf: &'a mut Vec, - read: usize, -} - -impl Unpin for ReadUntil<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadUntil<'a, R> { - pub(super) fn new(reader: &'a mut R, byte: u8, buf: &'a mut Vec) -> Self { - Self { reader, byte, buf, read: 0 } - } -} - -pub(super) fn read_until_internal( - mut reader: Pin<&mut R>, - cx: &mut Context<'_>, - byte: u8, - buf: &mut Vec, - read: &mut usize, -) -> Poll> { - loop { - let (done, used) = { - let available = ready!(reader.as_mut().poll_fill_buf(cx))?; - if let Some(i) = memchr::memchr(byte, available) { - buf.extend_from_slice(&available[..=i]); - (true, i + 1) - } else { - buf.extend_from_slice(available); - (false, available.len()) - } - }; - reader.as_mut().consume(used); - *read += used; - if done || used == 0 { - return Poll::Ready(Ok(*read)); - } - } -} - -impl Future for ReadUntil<'_, R> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, byte, buf, read } = &mut *self; - read_until_internal(Pin::new(reader), cx, *byte, buf, read) - } -} diff --git a/futures-util/src/io/read_vectored.rs b/futures-util/src/io/read_vectored.rs deleted file mode 100644 index 64ad5e8b38..0000000000 --- a/futures-util/src/io/read_vectored.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::io::AsyncRead; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use std::io::{self, IoSliceMut}; -use std::pin::Pin; - -/// Future for the [`read_vectored`](super::AsyncReadExt::read_vectored) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadVectored<'a, 'b, R: ?Sized> { - reader: &'a mut R, - bufs: &'a mut [IoSliceMut<'b>], -} - -impl Unpin for ReadVectored<'_, '_, R> {} - -impl<'a, 'b, R: AsyncRead + ?Sized + Unpin> ReadVectored<'a, 'b, R> { - pub(super) fn new(reader: &'a mut R, bufs: &'a mut [IoSliceMut<'b>]) -> Self { - Self { reader, bufs } - } -} - -impl Future for ReadVectored<'_, '_, R> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - Pin::new(&mut this.reader).poll_read_vectored(cx, this.bufs) - } -} diff --git a/futures-util/src/io/repeat.rs b/futures-util/src/io/repeat.rs deleted file mode 100644 index 2828bf0114..0000000000 --- a/futures-util/src/io/repeat.rs +++ /dev/null @@ -1,66 +0,0 @@ -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncRead, IoSliceMut}; -use std::fmt; -use std::io; -use std::pin::Pin; - -/// Reader for the [`repeat()`] function. -#[must_use = "readers do nothing unless polled"] -pub struct Repeat { - byte: u8, -} - -/// Creates an instance of a reader that infinitely repeats one byte. -/// -/// All reads from this reader will succeed by filling the specified buffer with -/// the given byte. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncReadExt}; -/// -/// let mut buffer = [0; 3]; -/// let mut reader = io::repeat(0b101); -/// reader.read_exact(&mut buffer).await.unwrap(); -/// assert_eq!(buffer, [0b101, 0b101, 0b101]); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn repeat(byte: u8) -> Repeat { - Repeat { byte } -} - -impl AsyncRead for Repeat { - #[inline] - fn poll_read( - self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - for slot in &mut *buf { - *slot = self.byte; - } - Poll::Ready(Ok(buf.len())) - } - - #[inline] - fn poll_read_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - let mut nwritten = 0; - for buf in bufs { - nwritten += ready!(self.as_mut().poll_read(cx, buf))?; - } - Poll::Ready(Ok(nwritten)) - } -} - -impl fmt::Debug for Repeat { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Repeat { .. }") - } -} diff --git a/futures-util/src/io/seek.rs b/futures-util/src/io/seek.rs deleted file mode 100644 index 0aa2371393..0000000000 --- a/futures-util/src/io/seek.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::io::{AsyncSeek, SeekFrom}; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use std::io; -use std::pin::Pin; - -/// Future for the [`seek`](crate::io::AsyncSeekExt::seek) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Seek<'a, S: ?Sized> { - seek: &'a mut S, - pos: SeekFrom, -} - -impl Unpin for Seek<'_, S> {} - -impl<'a, S: AsyncSeek + ?Sized + Unpin> Seek<'a, S> { - pub(super) fn new(seek: &'a mut S, pos: SeekFrom) -> Self { - Self { seek, pos } - } -} - -impl Future for Seek<'_, S> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - Pin::new(&mut this.seek).poll_seek(cx, this.pos) - } -} diff --git a/futures-util/src/io/sink.rs b/futures-util/src/io/sink.rs deleted file mode 100644 index 4a32ca7041..0000000000 --- a/futures-util/src/io/sink.rs +++ /dev/null @@ -1,67 +0,0 @@ -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncWrite, IoSlice}; -use std::fmt; -use std::io; -use std::pin::Pin; - -/// Writer for the [`sink()`] function. -#[must_use = "writers do nothing unless polled"] -pub struct Sink { - _priv: (), -} - -/// Creates an instance of a writer which will successfully consume all data. -/// -/// All calls to `poll_write` on the returned instance will return `Poll::Ready(Ok(buf.len()))` -/// and the contents of the buffer will not be inspected. -/// -/// # Examples -/// -/// ```rust -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncWriteExt}; -/// -/// let buffer = vec![1, 2, 3, 5, 8]; -/// let mut writer = io::sink(); -/// let num_bytes = writer.write(&buffer).await?; -/// assert_eq!(num_bytes, 5); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn sink() -> Sink { - Sink { _priv: () } -} - -impl AsyncWrite for Sink { - #[inline] - fn poll_write( - self: Pin<&mut Self>, - _: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Poll::Ready(Ok(buf.len())) - } - - #[inline] - fn poll_write_vectored( - self: Pin<&mut Self>, - _: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - Poll::Ready(Ok(bufs.iter().map(|b| b.len()).sum())) - } - - #[inline] - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - #[inline] - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -impl fmt::Debug for Sink { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Sink { .. }") - } -} diff --git a/futures-util/src/io/split.rs b/futures-util/src/io/split.rs deleted file mode 100644 index 5b6bc18937..0000000000 --- a/futures-util/src/io/split.rs +++ /dev/null @@ -1,129 +0,0 @@ -use crate::lock::BiLock; -use core::fmt; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncRead, AsyncWrite, IoSlice, IoSliceMut}; -use std::io; -use std::pin::Pin; - -/// The readable half of an object returned from `AsyncRead::split`. -#[derive(Debug)] -pub struct ReadHalf { - handle: BiLock, -} - -/// The writable half of an object returned from `AsyncRead::split`. -#[derive(Debug)] -pub struct WriteHalf { - handle: BiLock, -} - -fn lock_and_then(lock: &BiLock, cx: &mut Context<'_>, f: F) -> Poll> -where - F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> Poll>, -{ - let mut l = ready!(lock.poll_lock(cx)); - f(l.as_pin_mut(), cx) -} - -pub(super) fn split(t: T) -> (ReadHalf, WriteHalf) { - let (a, b) = BiLock::new(t); - (ReadHalf { handle: a }, WriteHalf { handle: b }) -} - -impl ReadHalf { - /// Checks if this `ReadHalf` and some `WriteHalf` were split from the same stream. - pub fn is_pair_of(&self, other: &WriteHalf) -> bool { - self.handle.is_pair_of(&other.handle) - } -} - -impl ReadHalf { - /// Attempts to put the two "halves" of a split `AsyncRead + AsyncWrite` back - /// together. Succeeds only if the `ReadHalf` and `WriteHalf` are - /// a matching pair originating from the same call to `AsyncReadExt::split`. - pub fn reunite(self, other: WriteHalf) -> Result> { - self.handle - .reunite(other.handle) - .map_err(|err| ReuniteError(Self { handle: err.0 }, WriteHalf { handle: err.1 })) - } -} - -impl WriteHalf { - /// Checks if this `WriteHalf` and some `ReadHalf` were split from the same stream. - pub fn is_pair_of(&self, other: &ReadHalf) -> bool { - self.handle.is_pair_of(&other.handle) - } -} - -impl WriteHalf { - /// Attempts to put the two "halves" of a split `AsyncRead + AsyncWrite` back - /// together. Succeeds only if the `ReadHalf` and `WriteHalf` are - /// a matching pair originating from the same call to `AsyncReadExt::split`. - pub fn reunite(self, other: ReadHalf) -> Result> { - other.reunite(self) - } -} - -impl AsyncRead for ReadHalf { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_read(cx, buf)) - } - - fn poll_read_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &mut [IoSliceMut<'_>], - ) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_read_vectored(cx, bufs)) - } -} - -impl AsyncWrite for WriteHalf { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_write(cx, buf)) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_write_vectored(cx, bufs)) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_flush(cx)) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - lock_and_then(&self.handle, cx, |l, cx| l.poll_close(cx)) - } -} - -/// Error indicating a `ReadHalf` and `WriteHalf` were not two halves -/// of a `AsyncRead + AsyncWrite`, and thus could not be `reunite`d. -pub struct ReuniteError(pub ReadHalf, pub WriteHalf); - -impl fmt::Debug for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError").field(&"...").finish() - } -} - -impl fmt::Display for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "tried to reunite a ReadHalf and WriteHalf that don't form a pair") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ReuniteError {} diff --git a/futures-util/src/io/take.rs b/futures-util/src/io/take.rs deleted file mode 100644 index 2c494804d9..0000000000 --- a/futures-util/src/io/take.rs +++ /dev/null @@ -1,125 +0,0 @@ -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead}; -use pin_project_lite::pin_project; -use std::pin::Pin; -use std::{cmp, io}; - -pin_project! { - /// Reader for the [`take`](super::AsyncReadExt::take) method. - #[derive(Debug)] - #[must_use = "readers do nothing unless you `.await` or poll them"] - pub struct Take { - #[pin] - inner: R, - limit: u64, - } -} - -impl Take { - pub(super) fn new(inner: R, limit: u64) -> Self { - Self { inner, limit } - } - - /// Returns the remaining number of bytes that can be - /// read before this instance will return EOF. - /// - /// # Note - /// - /// This instance may reach `EOF` after reading fewer bytes than indicated by - /// this method if the underlying [`AsyncRead`] instance reaches EOF. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let reader = Cursor::new(&b"12345678"[..]); - /// let mut buffer = [0; 2]; - /// - /// let mut take = reader.take(4); - /// let n = take.read(&mut buffer).await?; - /// - /// assert_eq!(take.limit(), 2); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - pub fn limit(&self) -> u64 { - self.limit - } - - /// Sets the number of bytes that can be read before this instance will - /// return EOF. This is the same as constructing a new `Take` instance, so - /// the amount of bytes read and the previous limit value don't matter when - /// calling this method. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::io::{AsyncReadExt, Cursor}; - /// - /// let reader = Cursor::new(&b"12345678"[..]); - /// let mut buffer = [0; 4]; - /// - /// let mut take = reader.take(4); - /// let n = take.read(&mut buffer).await?; - /// - /// assert_eq!(n, 4); - /// assert_eq!(take.limit(), 0); - /// - /// take.set_limit(10); - /// let n = take.read(&mut buffer).await?; - /// assert_eq!(n, 4); - /// - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - pub fn set_limit(&mut self, limit: u64) { - self.limit = limit - } - - delegate_access_inner!(inner, R, ()); -} - -impl AsyncRead for Take { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let this = self.project(); - - if *this.limit == 0 { - return Poll::Ready(Ok(0)); - } - - let max = cmp::min(buf.len() as u64, *this.limit) as usize; - let n = ready!(this.inner.poll_read(cx, &mut buf[..max]))?; - *this.limit -= n as u64; - Poll::Ready(Ok(n)) - } -} - -impl AsyncBufRead for Take { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - // Don't call into inner reader at all at EOF because it may still block - if *this.limit == 0 { - return Poll::Ready(Ok(&[])); - } - - let buf = ready!(this.inner.poll_fill_buf(cx)?); - let cap = cmp::min(buf.len() as u64, *this.limit) as usize; - Poll::Ready(Ok(&buf[..cap])) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - let this = self.project(); - - // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt as u64, *this.limit) as usize; - *this.limit -= amt as u64; - this.inner.consume(amt); - } -} diff --git a/futures-util/src/io/window.rs b/futures-util/src/io/window.rs deleted file mode 100644 index d857282383..0000000000 --- a/futures-util/src/io/window.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::ops::{Bound, Range, RangeBounds}; - -/// An owned window around an underlying buffer. -/// -/// Normally slices work great for considering sub-portions of a buffer, but -/// unfortunately a slice is a *borrowed* type in Rust which has an associated -/// lifetime. When working with future and async I/O these lifetimes are not -/// always appropriate, and are sometimes difficult to store in tasks. This -/// type strives to fill this gap by providing an "owned slice" around an -/// underlying buffer of bytes. -/// -/// A `Window` wraps an underlying buffer, `T`, and has configurable -/// start/end indexes to alter the behavior of the `AsRef<[u8]>` implementation -/// that this type carries. -/// -/// This type can be particularly useful when working with the `write_all` -/// combinator in this crate. Data can be sliced via `Window`, consumed by -/// `write_all`, and then earned back once the write operation finishes through -/// the `into_inner` method on this type. -#[derive(Debug)] -pub struct Window { - inner: T, - range: Range, -} - -impl> Window { - /// Creates a new window around the buffer `t` defaulting to the entire - /// slice. - /// - /// Further methods can be called on the returned `Window` to alter the - /// window into the data provided. - pub fn new(t: T) -> Self { - Self { range: 0..t.as_ref().len(), inner: t } - } - - /// Gets a shared reference to the underlying buffer inside of this - /// `Window`. - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Gets a mutable reference to the underlying buffer inside of this - /// `Window`. - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - /// Consumes this `Window`, returning the underlying buffer. - pub fn into_inner(self) -> T { - self.inner - } - - /// Returns the starting index of this window into the underlying buffer - /// `T`. - pub fn start(&self) -> usize { - self.range.start - } - - /// Returns the end index of this window into the underlying buffer - /// `T`. - pub fn end(&self) -> usize { - self.range.end - } - - /// Changes the range of this window to the range specified. - /// - /// # Panics - /// - /// This method will panic if `range` is out of bounds for the underlying - /// slice or if [`start_bound()`] of `range` comes after the [`end_bound()`]. - /// - /// [`start_bound()`]: std::ops::RangeBounds::start_bound - /// [`end_bound()`]: std::ops::RangeBounds::end_bound - pub fn set>(&mut self, range: R) { - let start = match range.start_bound() { - Bound::Included(n) => *n, - Bound::Excluded(n) => *n + 1, - Bound::Unbounded => 0, - }; - let end = match range.end_bound() { - Bound::Included(n) => *n + 1, - Bound::Excluded(n) => *n, - Bound::Unbounded => self.inner.as_ref().len(), - }; - - assert!(end <= self.inner.as_ref().len()); - assert!(start <= end); - - self.range.start = start; - self.range.end = end; - } -} - -impl> AsRef<[u8]> for Window { - fn as_ref(&self) -> &[u8] { - &self.inner.as_ref()[self.range.start..self.range.end] - } -} - -impl> AsMut<[u8]> for Window { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner.as_mut()[self.range.start..self.range.end] - } -} diff --git a/futures-util/src/io/write.rs b/futures-util/src/io/write.rs deleted file mode 100644 index c47ef9e2eb..0000000000 --- a/futures-util/src/io/write.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::io::AsyncWrite; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use std::io; -use std::pin::Pin; - -/// Future for the [`write`](super::AsyncWriteExt::write) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Write<'a, W: ?Sized> { - writer: &'a mut W, - buf: &'a [u8], -} - -impl Unpin for Write<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> Write<'a, W> { - pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { - Self { writer, buf } - } -} - -impl Future for Write<'_, W> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - Pin::new(&mut this.writer).poll_write(cx, this.buf) - } -} diff --git a/futures-util/src/io/write_all.rs b/futures-util/src/io/write_all.rs deleted file mode 100644 index 08c025f94d..0000000000 --- a/futures-util/src/io/write_all.rs +++ /dev/null @@ -1,43 +0,0 @@ -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use std::io; -use std::mem; -use std::pin::Pin; - -/// Future for the [`write_all`](super::AsyncWriteExt::write_all) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct WriteAll<'a, W: ?Sized> { - writer: &'a mut W, - buf: &'a [u8], -} - -impl Unpin for WriteAll<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteAll<'a, W> { - pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { - Self { writer, buf } - } -} - -impl Future for WriteAll<'_, W> { - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - while !this.buf.is_empty() { - let n = ready!(Pin::new(&mut this.writer).poll_write(cx, this.buf))?; - { - let (_, rest) = mem::take(&mut this.buf).split_at(n); - this.buf = rest; - } - if n == 0 { - return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); - } - } - - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/io/write_all_vectored.rs b/futures-util/src/io/write_all_vectored.rs deleted file mode 100644 index b7965ea1ad..0000000000 --- a/futures-util/src/io/write_all_vectored.rs +++ /dev/null @@ -1,221 +0,0 @@ -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_io::AsyncWrite; -use futures_io::IoSlice; -use std::io; -use std::pin::Pin; - -/// Future for the -/// [`write_all_vectored`](super::AsyncWriteExt::write_all_vectored) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct WriteAllVectored<'a, 'b, W: ?Sized + Unpin> { - writer: &'a mut W, - bufs: &'a mut [IoSlice<'b>], -} - -impl Unpin for WriteAllVectored<'_, '_, W> {} - -impl<'a, 'b, W: AsyncWrite + ?Sized + Unpin> WriteAllVectored<'a, 'b, W> { - pub(super) fn new(writer: &'a mut W, mut bufs: &'a mut [IoSlice<'b>]) -> Self { - IoSlice::advance_slices(&mut bufs, 0); - Self { writer, bufs } - } -} - -impl Future for WriteAllVectored<'_, '_, W> { - type Output = io::Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - while !this.bufs.is_empty() { - let n = ready!(Pin::new(&mut this.writer).poll_write_vectored(cx, this.bufs))?; - if n == 0 { - return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); - } else { - IoSlice::advance_slices(&mut this.bufs, n); - } - } - - Poll::Ready(Ok(())) - } -} - -#[cfg(test)] -mod tests { - use std::cmp::min; - use std::future::Future; - use std::io; - use std::pin::Pin; - use std::task::{Context, Poll}; - use std::vec; - use std::vec::Vec; - - use crate::io::{AsyncWrite, AsyncWriteExt, IoSlice}; - use crate::task::noop_waker; - - /// Create a new writer that reads from at most `n_bufs` and reads - /// `per_call` bytes (in total) per call to write. - fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { - TestWriter { n_bufs, per_call, written: Vec::new() } - } - - // TODO: maybe move this the future-test crate? - struct TestWriter { - n_bufs: usize, - per_call: usize, - written: Vec, - } - - impl AsyncWrite for TestWriter { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.poll_write_vectored(cx, &[IoSlice::new(buf)]) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - let mut left = self.per_call; - let mut written = 0; - for buf in bufs.iter().take(self.n_bufs) { - let n = min(left, buf.len()); - self.written.extend_from_slice(&buf[0..n]); - left -= n; - written += n; - } - Poll::Ready(Ok(written)) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - } - - // TODO: maybe move this the future-test crate? - macro_rules! assert_poll_ok { - ($e:expr, $expected:expr) => { - let expected = $expected; - match $e { - Poll::Ready(Ok(ok)) if ok == expected => {} - got => { - panic!("unexpected result, got: {:?}, wanted: Ready(Ok({:?}))", got, expected) - } - } - }; - } - - #[test] - fn test_writer_read_from_one_buf() { - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - - let mut dst = test_writer(1, 2); - let mut dst = Pin::new(&mut dst); - - assert_poll_ok!(dst.as_mut().poll_write(&mut cx, &[]), 0); - assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, &[]), 0); - - // Read at most 2 bytes. - assert_poll_ok!(dst.as_mut().poll_write(&mut cx, &[1, 1, 1]), 2); - let bufs = &[IoSlice::new(&[2, 2, 2])]; - assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 2); - - // Only read from first buf. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; - assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 1); - - assert_eq!(dst.written, &[1, 1, 2, 2, 3]); - } - - #[test] - fn test_writer_read_from_multiple_bufs() { - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - - let mut dst = test_writer(3, 3); - let mut dst = Pin::new(&mut dst); - - // Read at most 3 bytes from two buffers. - let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; - assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 3); - - // Read at most 3 bytes from three buffers. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; - assert_poll_ok!(dst.as_mut().poll_write_vectored(&mut cx, bufs), 3); - - assert_eq!(dst.written, &[1, 2, 2, 3, 4, 5]); - } - - #[test] - fn test_write_all_vectored() { - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - - #[rustfmt::skip] // Becomes unreadable otherwise. - let tests: Vec<(_, &'static [u8])> = vec![ - (vec![], &[]), - (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]), - (vec![IoSlice::new(&[1])], &[1]), - (vec![IoSlice::new(&[1, 2])], &[1, 2]), - (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), - (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), - ]; - - for (mut input, wanted) in tests { - let mut dst = test_writer(2, 2); - { - let mut future = dst.write_all_vectored(&mut input); - match Pin::new(&mut future).poll(&mut cx) { - Poll::Ready(Ok(())) => {} - other => panic!("unexpected result polling future: {:?}", other), - } - } - assert_eq!(&*dst.written, wanted); - } - } - - #[test] - fn test_write_all_vectored_distinct_lifetimes() { - struct WrapVec(Vec); - impl Drop for WrapVec { - fn drop(&mut self) {} - } - - let waker = noop_waker(); - let mut cx = Context::from_waker(&waker); - let mut dst = test_writer(2, 2); - - { - // Force the lifetimes of the underlying data and IOSlice to be unequal - let data = vec![1, 2, 3, 4]; - { - let mut slices = WrapVec(data.chunks(2).map(IoSlice::new).collect()); - let mut future = dst.write_all_vectored(&mut slices.0); - match Pin::new(&mut future).poll(&mut cx) { - Poll::Ready(Ok(())) => {} - other => panic!("unexpected result polling future: {:?}", other), - } - } - assert_eq!(&*dst.written, &*data); - } - } -} diff --git a/futures-util/src/io/write_vectored.rs b/futures-util/src/io/write_vectored.rs deleted file mode 100644 index 538ed30019..0000000000 --- a/futures-util/src/io/write_vectored.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::io::AsyncWrite; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use std::io::{self, IoSlice}; -use std::pin::Pin; - -/// Future for the [`write_vectored`](super::AsyncWriteExt::write_vectored) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct WriteVectored<'a, 'b, W: ?Sized> { - writer: &'a mut W, - bufs: &'a [IoSlice<'b>], -} - -impl Unpin for WriteVectored<'_, '_, W> {} - -impl<'a, 'b, W: AsyncWrite + ?Sized + Unpin> WriteVectored<'a, 'b, W> { - pub(super) fn new(writer: &'a mut W, bufs: &'a [IoSlice<'b>]) -> Self { - Self { writer, bufs } - } -} - -impl Future for WriteVectored<'_, '_, W> { - type Output = io::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - Pin::new(&mut this.writer).poll_write_vectored(cx, this.bufs) - } -} diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs deleted file mode 100644 index 93d7c5e2ff..0000000000 --- a/futures-util/src/lib.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s, -//! and the `AsyncRead` and `AsyncWrite` traits. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] -#![cfg_attr(docsrs, feature(doc_cfg))] -#![allow(clippy::needless_borrow)] // https://github.com/rust-lang/futures-rs/pull/2558#issuecomment-1030745203 - -#[cfg(all(feature = "bilock", not(feature = "unstable")))] -compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features"); - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -// Macro re-exports -pub use futures_core::ready; - -#[cfg(feature = "async-await")] -#[macro_use] -mod async_await; -#[cfg(feature = "async-await")] -#[doc(hidden)] -pub use self::async_await::*; - -// Not public API. -#[doc(hidden)] -pub mod __private { - pub use crate::*; - pub use core::{ - option::Option::{self, None, Some}, - pin::Pin, - result::Result::{Err, Ok}, - }; - - #[cfg(feature = "async-await")] - pub mod async_await { - pub use crate::async_await::*; - } -} - -#[cfg(feature = "sink")] -macro_rules! delegate_sink { - ($field:ident, $item:ty) => { - fn poll_ready( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_ready(cx) - } - - fn start_send(self: core::pin::Pin<&mut Self>, item: $item) -> Result<(), Self::Error> { - self.project().$field.start_send(item) - } - - fn poll_flush( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_flush(cx) - } - - fn poll_close( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_close(cx) - } - }; -} - -macro_rules! delegate_future { - ($field:ident) => { - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - self.project().$field.poll(cx) - } - }; -} - -macro_rules! delegate_stream { - ($field:ident) => { - fn poll_next( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_next(cx) - } - fn size_hint(&self) -> (usize, Option) { - self.$field.size_hint() - } - }; -} - -#[cfg(feature = "io")] -#[cfg(feature = "std")] -macro_rules! delegate_async_write { - ($field:ident) => { - fn poll_write( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - buf: &[u8], - ) -> core::task::Poll> { - self.project().$field.poll_write(cx, buf) - } - fn poll_write_vectored( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - bufs: &[std::io::IoSlice<'_>], - ) -> core::task::Poll> { - self.project().$field.poll_write_vectored(cx, bufs) - } - fn poll_flush( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_flush(cx) - } - fn poll_close( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_close(cx) - } - }; -} - -#[cfg(feature = "io")] -#[cfg(feature = "std")] -macro_rules! delegate_async_read { - ($field:ident) => { - fn poll_read( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - buf: &mut [u8], - ) -> core::task::Poll> { - self.project().$field.poll_read(cx, buf) - } - - fn poll_read_vectored( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - bufs: &mut [std::io::IoSliceMut<'_>], - ) -> core::task::Poll> { - self.project().$field.poll_read_vectored(cx, bufs) - } - }; -} - -#[cfg(feature = "io")] -#[cfg(feature = "std")] -macro_rules! delegate_async_buf_read { - ($field:ident) => { - fn poll_fill_buf( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll> { - self.project().$field.poll_fill_buf(cx) - } - - fn consume(self: core::pin::Pin<&mut Self>, amt: usize) { - self.project().$field.consume(amt) - } - }; -} - -macro_rules! delegate_access_inner { - ($field:ident, $inner:ty, ($($ind:tt)*)) => { - /// Acquires a reference to the underlying sink or stream that this combinator is - /// pulling from. - pub fn get_ref(&self) -> &$inner { - (&self.$field) $($ind get_ref())* - } - - /// Acquires a mutable reference to the underlying sink or stream that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// sink or stream which may otherwise confuse this combinator. - pub fn get_mut(&mut self) -> &mut $inner { - (&mut self.$field) $($ind get_mut())* - } - - /// Acquires a pinned mutable reference to the underlying sink or stream that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// sink or stream which may otherwise confuse this combinator. - pub fn get_pin_mut(self: core::pin::Pin<&mut Self>) -> core::pin::Pin<&mut $inner> { - self.project().$field $($ind get_pin_mut())* - } - - /// Consumes this combinator, returning the underlying sink or stream. - /// - /// Note that this may discard intermediate state of this combinator, so - /// care should be taken to avoid losing resources when this is called. - pub fn into_inner(self) -> $inner { - self.$field $($ind into_inner())* - } - } -} - -macro_rules! delegate_all { - (@trait Future $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> futures_core::future::Future for $name<$($arg),*> where $t: futures_core::future::Future $(, $($bound)*)* { - type Output = <$t as futures_core::future::Future>::Output; - - delegate_future!(inner); - } - }; - (@trait FusedFuture $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> futures_core::future::FusedFuture for $name<$($arg),*> where $t: futures_core::future::FusedFuture $(, $($bound)*)* { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } - } - }; - (@trait Stream $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> futures_core::stream::Stream for $name<$($arg),*> where $t: futures_core::stream::Stream $(, $($bound)*)* { - type Item = <$t as futures_core::stream::Stream>::Item; - - delegate_stream!(inner); - } - }; - (@trait FusedStream $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> futures_core::stream::FusedStream for $name<$($arg),*> where $t: futures_core::stream::FusedStream $(, $($bound)*)* { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } - } - }; - (@trait Sink $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - #[cfg(feature = "sink")] - impl<_Item, $($arg),*> futures_sink::Sink<_Item> for $name<$($arg),*> where $t: futures_sink::Sink<_Item> $(, $($bound)*)* { - type Error = <$t as futures_sink::Sink<_Item>>::Error; - - delegate_sink!(inner, _Item); - } - }; - (@trait Debug $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> core::fmt::Debug for $name<$($arg),*> where $t: core::fmt::Debug $(, $($bound)*)* { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Debug::fmt(&self.inner, f) - } - } - }; - (@trait AccessInner[$inner:ty, ($($ind:tt)*)] $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> $name<$($arg),*> $(where $($bound)*)* { - delegate_access_inner!(inner, $inner, ($($ind)*)); - } - }; - (@trait New[|$($param:ident: $paramt:ty),*| $cons:expr] $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => { - impl<$($arg),*> $name<$($arg),*> $(where $($bound)*)* { - pub(crate) fn new($($param: $paramt),*) -> Self { - Self { inner: $cons } - } - } - }; - ($(#[$attr:meta])* $name:ident<$($arg:ident),*>($t:ty) : $ftrait:ident $([$($targs:tt)*])* $({$($item:tt)*})* $(where $($bound:tt)*)*) => { - pin_project_lite::pin_project! { - #[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"] - $(#[$attr])* - pub struct $name< $($arg),* > $(where $($bound)*)* { #[pin] inner: $t } - } - - impl<$($arg),*> $name< $($arg),* > $(where $($bound)*)* { - $($($item)*)* - } - - delegate_all!(@trait $ftrait $([$($targs)*])* $name<$($arg),*>($t) $(where $($bound)*)*); - }; - ($(#[$attr:meta])* $name:ident<$($arg:ident),*>($t:ty) : $ftrait:ident $([$($ftargs:tt)*])* + $strait:ident $([$($stargs:tt)*])* $(+ $trait:ident $([$($targs:tt)*])*)* $({$($item:tt)*})* $(where $($bound:tt)*)*) => { - delegate_all!($(#[$attr])* $name<$($arg),*>($t) : $strait $([$($stargs)*])* $(+ $trait $([$($targs)*])*)* $({$($item)*})* $(where $($bound)*)*); - - delegate_all!(@trait $ftrait $([$($ftargs)*])* $name<$($arg),*>($t) $(where $($bound)*)*); - }; -} - -pub mod future; -#[doc(no_inline)] -pub use crate::future::{Future, FutureExt, TryFuture, TryFutureExt}; - -pub mod stream; -#[doc(no_inline)] -pub use crate::stream::{Stream, StreamExt, TryStream, TryStreamExt}; - -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub mod sink; -#[cfg(feature = "sink")] -#[doc(no_inline)] -pub use crate::sink::{Sink, SinkExt}; - -pub mod task; - -#[cfg(feature = "compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "compat")))] -pub mod compat; - -#[cfg(feature = "io")] -#[cfg_attr(docsrs, doc(cfg(feature = "io")))] -#[cfg(feature = "std")] -pub mod io; -#[cfg(feature = "io")] -#[cfg(feature = "std")] -#[doc(no_inline)] -pub use crate::io::{ - AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, - AsyncWriteExt, -}; - -#[cfg(feature = "alloc")] -pub mod lock; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod abortable; - -mod fns; -mod unfold_state; diff --git a/futures-util/src/lock/bilock.rs b/futures-util/src/lock/bilock.rs deleted file mode 100644 index 5970ca2b6d..0000000000 --- a/futures-util/src/lock/bilock.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! Futures-powered synchronization primitives. - -use alloc::boxed::Box; -use alloc::sync::Arc; -use core::cell::UnsafeCell; -use core::ops::{Deref, DerefMut}; -use core::pin::Pin; -use core::sync::atomic::AtomicPtr; -use core::sync::atomic::Ordering::SeqCst; -use core::{fmt, ptr}; -#[cfg(feature = "bilock")] -use futures_core::future::Future; -use futures_core::task::{Context, Poll, Waker}; - -/// A type of futures-powered synchronization primitive which is a mutex between -/// two possible owners. -/// -/// This primitive is not as generic as a full-blown mutex but is sufficient for -/// many use cases where there are only two possible owners of a resource. The -/// implementation of `BiLock` can be more optimized for just the two possible -/// owners. -/// -/// Note that it's possible to use this lock through a poll-style interface with -/// the `poll_lock` method but you can also use it as a future with the `lock` -/// method that consumes a `BiLock` and returns a future that will resolve when -/// it's locked. -/// -/// A `BiLock` is typically used for "split" operations where data which serves -/// two purposes wants to be split into two to be worked with separately. For -/// example a TCP stream could be both a reader and a writer or a framing layer -/// could be both a stream and a sink for messages. A `BiLock` enables splitting -/// these two and then using each independently in a futures-powered fashion. -/// -/// This type is only available when the `bilock` feature of this -/// library is activated. -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -pub struct BiLock { - arc: Arc>, -} - -#[derive(Debug)] -struct Inner { - state: AtomicPtr, - value: Option>, -} - -unsafe impl Send for Inner {} -unsafe impl Sync for Inner {} - -impl BiLock { - /// Creates a new `BiLock` protecting the provided data. - /// - /// Two handles to the lock are returned, and these are the only two handles - /// that will ever be available to the lock. These can then be sent to separate - /// tasks to be managed there. - /// - /// The data behind the bilock is considered to be pinned, which allows `Pin` - /// references to locked data. However, this means that the locked value - /// will only be available through `Pin<&mut T>` (not `&mut T`) unless `T` is `Unpin`. - /// Similarly, reuniting the lock and extracting the inner value is only - /// possible when `T` is `Unpin`. - pub fn new(t: T) -> (Self, Self) { - let arc = Arc::new(Inner { - state: AtomicPtr::new(ptr::null_mut()), - value: Some(UnsafeCell::new(t)), - }); - - (Self { arc: arc.clone() }, Self { arc }) - } - - /// Attempt to acquire this lock, returning `Pending` if it can't be - /// acquired. - /// - /// This function will acquire the lock in a nonblocking fashion, returning - /// immediately if the lock is already held. If the lock is successfully - /// acquired then `Poll::Ready` is returned with a value that represents - /// the locked value (and can be used to access the protected data). The - /// lock is unlocked when the returned `BiLockGuard` is dropped. - /// - /// If the lock is already held then this function will return - /// `Poll::Pending`. In this case the current task will also be scheduled - /// to receive a notification when the lock would otherwise become - /// available. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn poll_lock(&self, cx: &mut Context<'_>) -> Poll> { - let mut waker = None; - loop { - let n = self.arc.state.swap(invalid_ptr(1), SeqCst); - match n as usize { - // Woohoo, we grabbed the lock! - 0 => return Poll::Ready(BiLockGuard { bilock: self }), - - // Oops, someone else has locked the lock - 1 => {} - - // A task was previously blocked on this lock, likely our task, - // so we need to update that task. - _ => unsafe { - let mut prev = Box::from_raw(n); - (*prev).clone_from(cx.waker()); - waker = Some(prev); - }, - } - - // type ascription for safety's sake! - let me: Box = waker.take().unwrap_or_else(|| Box::new(cx.waker().clone())); - let me = Box::into_raw(me); - - match self.arc.state.compare_exchange(invalid_ptr(1), me, SeqCst, SeqCst) { - // The lock is still locked, but we've now parked ourselves, so - // just report that we're scheduled to receive a notification. - Ok(_) => return Poll::Pending, - - // Oops, looks like the lock was unlocked after our swap above - // and before the compare_exchange. Deallocate what we just - // allocated and go through the loop again. - Err(n) if n.is_null() => unsafe { - waker = Some(Box::from_raw(me)); - }, - - // The top of this loop set the previous state to 1, so if we - // failed the CAS above then it's because the previous value was - // *not* zero or one. This indicates that a task was blocked, - // but we're trying to acquire the lock and there's only one - // other reference of the lock, so it should be impossible for - // that task to ever block itself. - Err(n) => panic!("invalid state: {}", n as usize), - } - } - } - - /// Perform a "blocking lock" of this lock, consuming this lock handle and - /// returning a future to the acquired lock. - /// - /// 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. - #[cfg(feature = "bilock")] - #[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] - pub fn lock(&self) -> BiLockAcquire<'_, T> { - BiLockAcquire { bilock: self } - } - - /// Returns `true` only if the other `BiLock` originated from the same call to `BiLock::new`. - pub fn is_pair_of(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.arc, &other.arc) - } - - /// Attempts to put the two "halves" of a `BiLock` back together and - /// recover the original value. Succeeds only if the two `BiLock`s - /// originated from the same call to `BiLock::new`. - pub fn reunite(self, other: Self) -> Result> - where - T: Unpin, - { - if self.is_pair_of(&other) { - drop(other); - let inner = Arc::try_unwrap(self.arc) - .ok() - .expect("futures: try_unwrap failed in BiLock::reunite"); - Ok(unsafe { inner.into_value() }) - } else { - Err(ReuniteError(self, other)) - } - } - - fn unlock(&self) { - let n = self.arc.state.swap(ptr::null_mut(), SeqCst); - match n as usize { - // we've locked the lock, shouldn't be possible for us to see an - // unlocked lock. - 0 => panic!("invalid unlocked state"), - - // Ok, no one else tried to get the lock, we're done. - 1 => {} - - // Another task has parked themselves on this lock, let's wake them - // up as its now their turn. - _ => unsafe { - Box::from_raw(n).wake(); - }, - } - } -} - -impl Inner { - unsafe fn into_value(mut self) -> T { - self.value.take().unwrap().into_inner() - } -} - -impl Drop for Inner { - fn drop(&mut self) { - assert!(self.state.load(SeqCst).is_null()); - } -} - -/// Error indicating two `BiLock`s were not two halves of a whole, and -/// thus could not be `reunite`d. -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -pub struct ReuniteError(pub BiLock, pub BiLock); - -impl fmt::Debug for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError").field(&"...").finish() - } -} - -impl fmt::Display for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "tried to reunite two BiLocks that don't form a pair") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ReuniteError {} - -/// Returned RAII guard from the `poll_lock` method. -/// -/// This structure acts as a sentinel to the data in the `BiLock` itself, -/// implementing `Deref` and `DerefMut` to `T`. When dropped, the lock will be -/// unlocked. -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -pub struct BiLockGuard<'a, T> { - bilock: &'a BiLock, -} - -// We allow parallel access to T via Deref, so Sync bound is also needed here. -unsafe impl Sync for BiLockGuard<'_, T> {} - -impl Deref for BiLockGuard<'_, T> { - type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.bilock.arc.value.as_ref().unwrap().get() } - } -} - -impl DerefMut for BiLockGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.bilock.arc.value.as_ref().unwrap().get() } - } -} - -impl BiLockGuard<'_, T> { - /// Get a mutable pinned reference to the locked value. - pub fn as_pin_mut(&mut self) -> Pin<&mut T> { - // Safety: we never allow moving a !Unpin value out of a bilock, nor - // allow mutable access to it - unsafe { Pin::new_unchecked(&mut *self.bilock.arc.value.as_ref().unwrap().get()) } - } -} - -impl Drop for BiLockGuard<'_, T> { - fn drop(&mut self) { - self.bilock.unlock(); - } -} - -/// Future returned by `BiLock::lock` which will resolve when the lock is -/// acquired. -#[cfg(feature = "bilock")] -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -#[must_use = "futures do nothing unless you `.await` or poll them"] -#[derive(Debug)] -pub struct BiLockAcquire<'a, T> { - bilock: &'a BiLock, -} - -// Pinning is never projected to fields -#[cfg(feature = "bilock")] -impl Unpin for BiLockAcquire<'_, T> {} - -#[cfg(feature = "bilock")] -impl<'a, T> Future for BiLockAcquire<'a, T> { - type Output = BiLockGuard<'a, T>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.bilock.poll_lock(cx) - } -} - -// Based on core::ptr::invalid_mut. Equivalent to `addr as *mut T`, but is strict-provenance compatible. -#[allow(clippy::useless_transmute)] -#[inline] -fn invalid_ptr(addr: usize) -> *mut T { - // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that - // pointer). - unsafe { core::mem::transmute(addr) } -} diff --git a/futures-util/src/lock/mod.rs b/futures-util/src/lock/mod.rs deleted file mode 100644 index 8ca0ff6255..0000000000 --- a/futures-util/src/lock/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Futures-powered synchronization primitives. -//! -//! This module is only available when the `std` or `alloc` feature of this -//! library is activated, and it is activated by default. - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(any(feature = "sink", feature = "io"))] -#[cfg(not(feature = "bilock"))] -pub(crate) use self::bilock::BiLock; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "bilock")] -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -pub use self::bilock::{BiLock, BiLockAcquire, BiLockGuard, ReuniteError}; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "std")] -pub use self::mutex::{ - MappedMutexGuard, Mutex, MutexGuard, MutexLockFuture, OwnedMutexGuard, OwnedMutexLockFuture, -}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(any(feature = "bilock", feature = "sink", feature = "io"))] -#[cfg_attr(docsrs, doc(cfg(feature = "bilock")))] -#[cfg_attr(not(feature = "bilock"), allow(unreachable_pub))] -mod bilock; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "std")] -mod mutex; diff --git a/futures-util/src/lock/mutex.rs b/futures-util/src/lock/mutex.rs deleted file mode 100644 index 1a6363ea76..0000000000 --- a/futures-util/src/lock/mutex.rs +++ /dev/null @@ -1,560 +0,0 @@ -use std::cell::UnsafeCell; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::pin::Pin; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex as StdMutex}; -use std::{fmt, mem}; - -use slab::Slab; - -use futures_core::future::{FusedFuture, Future}; -use futures_core::task::{Context, Poll, Waker}; - -/// A futures-aware mutex. -/// -/// # Fairness -/// -/// This mutex provides no fairness guarantees. Tasks may not acquire the mutex -/// in the order that they requested the lock, and it's possible for a single task -/// which repeatedly takes the lock to starve other tasks, which may be left waiting -/// indefinitely. -pub struct Mutex { - state: AtomicUsize, - waiters: StdMutex>, - value: UnsafeCell, -} - -impl fmt::Debug for Mutex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let state = self.state.load(Ordering::SeqCst); - f.debug_struct("Mutex") - .field("is_locked", &((state & IS_LOCKED) != 0)) - .field("has_waiters", &((state & HAS_WAITERS) != 0)) - .finish() - } -} - -impl From for Mutex { - fn from(t: T) -> Self { - Self::new(t) - } -} - -impl Default for Mutex { - fn default() -> Self { - Self::new(Default::default()) - } -} - -enum Waiter { - Waiting(Waker), - Woken, -} - -impl Waiter { - fn register(&mut self, waker: &Waker) { - match self { - Self::Waiting(w) if waker.will_wake(w) => {} - _ => *self = Self::Waiting(waker.clone()), - } - } - - fn wake(&mut self) { - match mem::replace(self, Self::Woken) { - Self::Waiting(waker) => waker.wake(), - Self::Woken => {} - } - } -} - -const IS_LOCKED: usize = 1 << 0; -const HAS_WAITERS: usize = 1 << 1; - -impl Mutex { - /// Creates a new futures-aware mutex. - pub const fn new(t: T) -> Self { - Self { - state: AtomicUsize::new(0), - waiters: StdMutex::new(Slab::new()), - value: UnsafeCell::new(t), - } - } - - /// Consumes this mutex, returning the underlying data. - /// - /// # Examples - /// - /// ``` - /// use futures::lock::Mutex; - /// - /// let mutex = Mutex::new(0); - /// assert_eq!(mutex.into_inner(), 0); - /// ``` - pub fn into_inner(self) -> T { - self.value.into_inner() - } -} - -impl Mutex { - /// Attempt to acquire the lock immediately. - /// - /// If the lock is currently held, this will return `None`. - pub fn try_lock(&self) -> Option> { - let old_state = self.state.fetch_or(IS_LOCKED, Ordering::Acquire); - if (old_state & IS_LOCKED) == 0 { - Some(MutexGuard { mutex: self }) - } else { - None - } - } - - /// Attempt to acquire the lock immediately. - /// - /// If the lock is currently held, this will return `None`. - pub fn try_lock_owned(self: &Arc) -> Option> { - let old_state = self.state.fetch_or(IS_LOCKED, Ordering::Acquire); - if (old_state & IS_LOCKED) == 0 { - Some(OwnedMutexGuard { mutex: self.clone() }) - } else { - None - } - } - - /// Acquire the lock asynchronously. - /// - /// This method returns a future that will resolve once the lock has been - /// successfully acquired. - pub fn lock(&self) -> MutexLockFuture<'_, T> { - MutexLockFuture { mutex: Some(self), wait_key: WAIT_KEY_NONE } - } - - /// Acquire the lock asynchronously. - /// - /// This method returns a future that will resolve once the lock has been - /// successfully acquired. - pub fn lock_owned(self: Arc) -> OwnedMutexLockFuture { - OwnedMutexLockFuture { mutex: Some(self), wait_key: WAIT_KEY_NONE } - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the `Mutex` mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::lock::Mutex; - /// - /// let mut mutex = Mutex::new(0); - /// *mutex.get_mut() = 10; - /// assert_eq!(*mutex.lock().await, 10); - /// # }); - /// ``` - pub fn get_mut(&mut self) -> &mut T { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - unsafe { &mut *self.value.get() } - } - - fn remove_waker(&self, wait_key: usize, wake_another: bool) { - if wait_key != WAIT_KEY_NONE { - let mut waiters = self.waiters.lock().unwrap(); - - let removed_waker = waiters.remove(wait_key); - - match removed_waker { - Waiter::Waiting(_) => {} - Waiter::Woken => { - // We were awoken, but then dropped before we could - // wake up to acquire the lock. Wake up another - // waiter. - if wake_another { - if let Some((_i, waiter)) = waiters.iter_mut().next() { - waiter.wake(); - } - } - } - } - if waiters.is_empty() { - self.state.fetch_and(!HAS_WAITERS, Ordering::Relaxed); // released by mutex unlock - } - } - } - - // Unlocks the mutex. Called by MutexGuard and MappedMutexGuard when they are - // dropped. - fn unlock(&self) { - let old_state = self.state.fetch_and(!IS_LOCKED, Ordering::AcqRel); - if (old_state & HAS_WAITERS) != 0 { - let mut waiters = self.waiters.lock().unwrap(); - if let Some((_i, waiter)) = waiters.iter_mut().next() { - waiter.wake(); - } - } - } -} - -// Sentinel for when no slot in the `Slab` has been dedicated to this object. -const WAIT_KEY_NONE: usize = usize::MAX; - -/// A future which resolves when the target mutex has been successfully acquired, owned version. -pub struct OwnedMutexLockFuture { - // `None` indicates that the mutex was successfully acquired. - mutex: Option>>, - wait_key: usize, -} - -impl fmt::Debug for OwnedMutexLockFuture { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedMutexLockFuture") - .field("was_acquired", &self.mutex.is_none()) - .field("mutex", &self.mutex) - .field( - "wait_key", - &(if self.wait_key == WAIT_KEY_NONE { None } else { Some(self.wait_key) }), - ) - .finish() - } -} - -impl FusedFuture for OwnedMutexLockFuture { - fn is_terminated(&self) -> bool { - self.mutex.is_none() - } -} - -impl Future for OwnedMutexLockFuture { - type Output = OwnedMutexGuard; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.get_mut(); - - let mutex = this.mutex.as_ref().expect("polled OwnedMutexLockFuture after completion"); - - if let Some(lock) = mutex.try_lock_owned() { - mutex.remove_waker(this.wait_key, false); - this.mutex = None; - return Poll::Ready(lock); - } - - { - let mut waiters = mutex.waiters.lock().unwrap(); - if this.wait_key == WAIT_KEY_NONE { - this.wait_key = waiters.insert(Waiter::Waiting(cx.waker().clone())); - if waiters.len() == 1 { - mutex.state.fetch_or(HAS_WAITERS, Ordering::Relaxed); // released by mutex unlock - } - } else { - waiters[this.wait_key].register(cx.waker()); - } - } - - // Ensure that we haven't raced `MutexGuard::drop`'s unlock path by - // attempting to acquire the lock again. - if let Some(lock) = mutex.try_lock_owned() { - mutex.remove_waker(this.wait_key, false); - this.mutex = None; - return Poll::Ready(lock); - } - - Poll::Pending - } -} - -impl Drop for OwnedMutexLockFuture { - fn drop(&mut self) { - if let Some(mutex) = self.mutex.as_ref() { - // This future was dropped before it acquired the mutex. - // - // Remove ourselves from the map, waking up another waiter if we - // had been awoken to acquire the lock. - mutex.remove_waker(self.wait_key, true); - } - } -} - -/// 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. -pub struct OwnedMutexGuard { - mutex: Arc>, -} - -impl fmt::Debug for OwnedMutexGuard { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedMutexGuard") - .field("value", &&**self) - .field("mutex", &self.mutex) - .finish() - } -} - -impl Drop for OwnedMutexGuard { - fn drop(&mut self) { - self.mutex.unlock() - } -} - -impl Deref for OwnedMutexGuard { - type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.mutex.value.get() } - } -} - -impl DerefMut for OwnedMutexGuard { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.mutex.value.get() } - } -} - -/// A future which resolves when the target mutex has been successfully acquired. -pub struct MutexLockFuture<'a, T: ?Sized> { - // `None` indicates that the mutex was successfully acquired. - mutex: Option<&'a Mutex>, - wait_key: usize, -} - -impl fmt::Debug for MutexLockFuture<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MutexLockFuture") - .field("was_acquired", &self.mutex.is_none()) - .field("mutex", &self.mutex) - .field( - "wait_key", - &(if self.wait_key == WAIT_KEY_NONE { None } else { Some(self.wait_key) }), - ) - .finish() - } -} - -impl FusedFuture for MutexLockFuture<'_, T> { - fn is_terminated(&self) -> bool { - self.mutex.is_none() - } -} - -impl<'a, T: ?Sized> Future for MutexLockFuture<'a, T> { - type Output = MutexGuard<'a, T>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mutex = self.mutex.expect("polled MutexLockFuture after completion"); - - if let Some(lock) = mutex.try_lock() { - mutex.remove_waker(self.wait_key, false); - self.mutex = None; - return Poll::Ready(lock); - } - - { - let mut waiters = mutex.waiters.lock().unwrap(); - if self.wait_key == WAIT_KEY_NONE { - self.wait_key = waiters.insert(Waiter::Waiting(cx.waker().clone())); - if waiters.len() == 1 { - mutex.state.fetch_or(HAS_WAITERS, Ordering::Relaxed); // released by mutex unlock - } - } else { - waiters[self.wait_key].register(cx.waker()); - } - } - - // Ensure that we haven't raced `MutexGuard::drop`'s unlock path by - // attempting to acquire the lock again. - if let Some(lock) = mutex.try_lock() { - mutex.remove_waker(self.wait_key, false); - self.mutex = None; - return Poll::Ready(lock); - } - - Poll::Pending - } -} - -impl Drop for MutexLockFuture<'_, T> { - fn drop(&mut self) { - if let Some(mutex) = self.mutex { - // This future was dropped before it acquired the mutex. - // - // Remove ourselves from the map, waking up another waiter if we - // had been awoken to acquire the lock. - mutex.remove_waker(self.wait_key, true); - } - } -} - -/// 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. -pub struct MutexGuard<'a, T: ?Sized> { - mutex: &'a Mutex, -} - -impl<'a, T: ?Sized> MutexGuard<'a, T> { - /// Returns a locked view over a portion of the locked data. - /// - /// # Example - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::lock::{Mutex, MutexGuard}; - /// - /// let data = Mutex::new(Some("value".to_string())); - /// { - /// let locked_str = MutexGuard::map(data.lock().await, |opt| opt.as_mut().unwrap()); - /// assert_eq!(&*locked_str, "value"); - /// } - /// # }); - /// ``` - #[inline] - pub fn map(this: Self, f: F) -> MappedMutexGuard<'a, T, U> - where - F: FnOnce(&mut T) -> &mut U, - { - let mutex = this.mutex; - let value = f(unsafe { &mut *this.mutex.value.get() }); - // Don't run the `drop` method for MutexGuard. The ownership of the underlying - // locked state is being moved to the returned MappedMutexGuard. - mem::forget(this); - MappedMutexGuard { mutex, value, _marker: PhantomData } - } -} - -impl fmt::Debug for MutexGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MutexGuard").field("value", &&**self).field("mutex", &self.mutex).finish() - } -} - -impl Drop for MutexGuard<'_, T> { - fn drop(&mut self) { - self.mutex.unlock() - } -} - -impl Deref for MutexGuard<'_, T> { - type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.mutex.value.get() } - } -} - -impl DerefMut for MutexGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.mutex.value.get() } - } -} - -/// 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. -pub struct MappedMutexGuard<'a, T: ?Sized, U: ?Sized> { - mutex: &'a Mutex, - value: *mut U, - _marker: PhantomData<&'a mut U>, -} - -impl<'a, T: ?Sized, U: ?Sized> MappedMutexGuard<'a, T, U> { - /// Returns a locked view over a portion of the locked data. - /// - /// # Example - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::lock::{MappedMutexGuard, Mutex, MutexGuard}; - /// - /// let data = Mutex::new(Some("value".to_string())); - /// { - /// let locked_str = MutexGuard::map(data.lock().await, |opt| opt.as_mut().unwrap()); - /// let locked_char = MappedMutexGuard::map(locked_str, |s| s.get_mut(0..1).unwrap()); - /// assert_eq!(&*locked_char, "v"); - /// } - /// # }); - /// ``` - #[inline] - pub fn map(this: Self, f: F) -> MappedMutexGuard<'a, T, V> - where - F: FnOnce(&mut U) -> &mut V, - { - let mutex = this.mutex; - let value = f(unsafe { &mut *this.value }); - // Don't run the `drop` method for MappedMutexGuard. The ownership of the underlying - // locked state is being moved to the returned MappedMutexGuard. - mem::forget(this); - MappedMutexGuard { mutex, value, _marker: PhantomData } - } -} - -impl fmt::Debug for MappedMutexGuard<'_, T, U> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MappedMutexGuard") - .field("value", &&**self) - .field("mutex", &self.mutex) - .finish() - } -} - -impl Drop for MappedMutexGuard<'_, T, U> { - fn drop(&mut self) { - self.mutex.unlock() - } -} - -impl Deref for MappedMutexGuard<'_, T, U> { - type Target = U; - fn deref(&self) -> &U { - unsafe { &*self.value } - } -} - -impl DerefMut for MappedMutexGuard<'_, T, U> { - fn deref_mut(&mut self) -> &mut U { - unsafe { &mut *self.value } - } -} - -// Mutexes can be moved freely between threads and acquired on any thread so long -// as the inner value can be safely sent between threads. -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -// It's safe to switch which thread the acquire is being attempted on so long as -// `T` can be accessed on that thread. -unsafe impl Send for MutexLockFuture<'_, T> {} - -// doesn't have any interesting `&self` methods (only Debug) -unsafe impl Sync for MutexLockFuture<'_, T> {} - -// It's safe to switch which thread the acquire is being attempted on so long as -// `T` can be accessed on that thread. -unsafe impl Send for OwnedMutexLockFuture {} - -// doesn't have any interesting `&self` methods (only Debug) -unsafe impl Sync for OwnedMutexLockFuture {} - -// Safe to send since we don't track any thread-specific details-- the inner -// lock is essentially spinlock-equivalent (attempt to flip an atomic bool) -unsafe impl Send for MutexGuard<'_, T> {} -unsafe impl Sync for MutexGuard<'_, T> {} - -unsafe impl Send for OwnedMutexGuard {} -unsafe impl Sync for OwnedMutexGuard {} - -unsafe impl Send for MappedMutexGuard<'_, T, U> {} -unsafe impl Sync for MappedMutexGuard<'_, T, U> {} - -#[cfg(test)] -mod tests { - use super::*; - use std::format; - - #[test] - fn test_mutex_guard_debug_not_recurse() { - let mutex = Mutex::new(42); - let guard = mutex.try_lock().unwrap(); - let _ = format!("{guard:?}"); - let guard = MutexGuard::map(guard, |n| n); - let _ = format!("{guard:?}"); - } -} diff --git a/futures-util/src/sink/buffer.rs b/futures-util/src/sink/buffer.rs deleted file mode 100644 index 4aa6c36033..0000000000 --- a/futures-util/src/sink/buffer.rs +++ /dev/null @@ -1,105 +0,0 @@ -use alloc::collections::VecDeque; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`buffer`](super::SinkExt::buffer) method. - #[derive(Debug)] - #[must_use = "sinks do nothing unless polled"] - pub struct Buffer { - #[pin] - sink: Si, - buf: VecDeque, - - // Track capacity separately from the `VecDeque`, which may be rounded up - capacity: usize, - } -} - -impl, Item> Buffer { - pub(super) fn new(sink: Si, capacity: usize) -> Self { - Self { sink, buf: VecDeque::with_capacity(capacity), capacity } - } - - delegate_access_inner!(sink, Si, ()); - - fn try_empty_buffer(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - ready!(this.sink.as_mut().poll_ready(cx))?; - while let Some(item) = this.buf.pop_front() { - this.sink.as_mut().start_send(item)?; - if !this.buf.is_empty() { - ready!(this.sink.as_mut().poll_ready(cx))?; - } - } - Poll::Ready(Ok(())) - } -} - -// Forwarding impl of Stream from the underlying sink -impl Stream for Buffer -where - S: Sink + Stream, -{ - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().sink.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - self.sink.size_hint() - } -} - -impl FusedStream for Buffer -where - S: Sink + FusedStream, -{ - fn is_terminated(&self) -> bool { - self.sink.is_terminated() - } -} - -impl, Item> Sink for Buffer { - type Error = Si::Error; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.capacity == 0 { - return self.project().sink.poll_ready(cx); - } - - let _ = self.as_mut().try_empty_buffer(cx)?; - - if self.buf.len() >= self.capacity { - Poll::Pending - } else { - Poll::Ready(Ok(())) - } - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - if self.capacity == 0 { - self.project().sink.start_send(item) - } else { - self.project().buf.push_back(item); - Ok(()) - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().try_empty_buffer(cx))?; - debug_assert!(self.buf.is_empty()); - self.project().sink.poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().try_empty_buffer(cx))?; - debug_assert!(self.buf.is_empty()); - self.project().sink.poll_close(cx) - } -} diff --git a/futures-util/src/sink/close.rs b/futures-util/src/sink/close.rs deleted file mode 100644 index 43eea74b0f..0000000000 --- a/futures-util/src/sink/close.rs +++ /dev/null @@ -1,32 +0,0 @@ -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -/// Future for the [`close`](super::SinkExt::close) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Close<'a, Si: ?Sized, Item> { - sink: &'a mut Si, - _phantom: PhantomData, -} - -impl Unpin for Close<'_, Si, Item> {} - -/// A future that completes when the sink has finished closing. -/// -/// The sink itself is returned after closing is complete. -impl<'a, Si: Sink + Unpin + ?Sized, Item> Close<'a, Si, Item> { - pub(super) fn new(sink: &'a mut Si) -> Self { - Self { sink, _phantom: PhantomData } - } -} - -impl + Unpin + ?Sized, Item> Future for Close<'_, Si, Item> { - type Output = Result<(), Si::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.sink).poll_close(cx) - } -} diff --git a/futures-util/src/sink/drain.rs b/futures-util/src/sink/drain.rs deleted file mode 100644 index 3ef8072bdc..0000000000 --- a/futures-util/src/sink/drain.rs +++ /dev/null @@ -1,59 +0,0 @@ -use super::assert_sink; -use core::convert::Infallible; -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -/// Sink for the [`drain`] function. -#[derive(Debug)] -#[must_use = "sinks do nothing unless polled"] -pub struct Drain { - marker: PhantomData, -} - -/// Create a sink that will just discard all items given to it. -/// -/// Similar to [`io::Sink`](::std::io::Sink). -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::sink::{self, SinkExt}; -/// -/// let mut drain = sink::drain(); -/// drain.send(5).await?; -/// # Ok::<(), std::convert::Infallible>(()) }).unwrap(); -/// ``` -pub fn drain() -> Drain { - assert_sink::(Drain { marker: PhantomData }) -} - -impl Unpin for Drain {} - -impl Clone for Drain { - fn clone(&self) -> Self { - drain() - } -} - -impl Sink for Drain { - type Error = Infallible; - - fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, _item: T) -> Result<(), Self::Error> { - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/sink/err_into.rs b/futures-util/src/sink/err_into.rs deleted file mode 100644 index a64d1337ba..0000000000 --- a/futures-util/src/sink/err_into.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::sink::{SinkExt, SinkMapErr}; -use futures_core::stream::{FusedStream, Stream}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`sink_err_into`](super::SinkExt::sink_err_into) method. - #[derive(Debug)] - #[must_use = "sinks do nothing unless polled"] - pub struct SinkErrInto, Item, E> { - #[pin] - sink: SinkMapErr E>, - } -} - -impl SinkErrInto -where - Si: Sink, - Si::Error: Into, -{ - pub(super) fn new(sink: Si) -> Self { - Self { sink: SinkExt::sink_map_err(sink, Into::into) } - } - - delegate_access_inner!(sink, Si, (.)); -} - -impl Sink for SinkErrInto -where - Si: Sink, - Si::Error: Into, -{ - type Error = E; - - delegate_sink!(sink, Item); -} - -// Forwarding impl of Stream from the underlying sink -impl Stream for SinkErrInto -where - S: Sink + Stream, - S::Error: Into, -{ - type Item = S::Item; - - delegate_stream!(sink); -} - -impl FusedStream for SinkErrInto -where - S: Sink + FusedStream, - S::Error: Into, -{ - fn is_terminated(&self) -> bool { - self.sink.is_terminated() - } -} diff --git a/futures-util/src/sink/fanout.rs b/futures-util/src/sink/fanout.rs deleted file mode 100644 index fe2038f27f..0000000000 --- a/futures-util/src/sink/fanout.rs +++ /dev/null @@ -1,111 +0,0 @@ -use core::fmt::{Debug, Formatter, Result as FmtResult}; -use core::pin::Pin; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink that clones incoming items and forwards them to two sinks at the same time. - /// - /// Backpressure from any downstream sink propagates up, which means that this sink - /// can only process items as fast as its _slowest_ downstream sink. - #[must_use = "sinks do nothing unless polled"] - pub struct Fanout { - #[pin] - sink1: Si1, - #[pin] - sink2: Si2 - } -} - -impl Fanout { - pub(super) fn new(sink1: Si1, sink2: Si2) -> Self { - Self { sink1, sink2 } - } - - /// Get a shared reference to the inner sinks. - pub fn get_ref(&self) -> (&Si1, &Si2) { - (&self.sink1, &self.sink2) - } - - /// Get a mutable reference to the inner sinks. - pub fn get_mut(&mut self) -> (&mut Si1, &mut Si2) { - (&mut self.sink1, &mut self.sink2) - } - - /// Get a pinned mutable reference to the inner sinks. - pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut Si1>, Pin<&mut Si2>) { - let this = self.project(); - (this.sink1, this.sink2) - } - - /// Consumes this combinator, returning the underlying sinks. - /// - /// Note that this may discard intermediate state of this combinator, - /// so care should be taken to avoid losing resources when this is called. - pub fn into_inner(self) -> (Si1, Si2) { - (self.sink1, self.sink2) - } -} - -impl Debug for Fanout { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_struct("Fanout").field("sink1", &self.sink1).field("sink2", &self.sink2).finish() - } -} - -impl Sink for Fanout -where - Si1: Sink, - Item: Clone, - Si2: Sink, -{ - type Error = Si1::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - let sink1_ready = this.sink1.poll_ready(cx)?.is_ready(); - let sink2_ready = this.sink2.poll_ready(cx)?.is_ready(); - let ready = sink1_ready && sink2_ready; - if ready { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - let this = self.project(); - - this.sink1.start_send(item.clone())?; - this.sink2.start_send(item)?; - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - let sink1_ready = this.sink1.poll_flush(cx)?.is_ready(); - let sink2_ready = this.sink2.poll_flush(cx)?.is_ready(); - let ready = sink1_ready && sink2_ready; - if ready { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - let sink1_ready = this.sink1.poll_close(cx)?.is_ready(); - let sink2_ready = this.sink2.poll_close(cx)?.is_ready(); - let ready = sink1_ready && sink2_ready; - if ready { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - } -} diff --git a/futures-util/src/sink/feed.rs b/futures-util/src/sink/feed.rs deleted file mode 100644 index 6701f7a1b4..0000000000 --- a/futures-util/src/sink/feed.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -/// Future for the [`feed`](super::SinkExt::feed) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Feed<'a, Si: ?Sized, Item> { - sink: &'a mut Si, - item: Option, -} - -// Pinning is never projected to children -impl Unpin for Feed<'_, Si, Item> {} - -impl<'a, Si: Sink + Unpin + ?Sized, Item> Feed<'a, Si, Item> { - pub(super) fn new(sink: &'a mut Si, item: Item) -> Self { - Feed { sink, item: Some(item) } - } - - pub(super) fn sink_pin_mut(&mut self) -> Pin<&mut Si> { - Pin::new(self.sink) - } - - pub(super) fn is_item_pending(&self) -> bool { - self.item.is_some() - } -} - -impl + Unpin + ?Sized, Item> Future for Feed<'_, Si, Item> { - type Output = Result<(), Si::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.get_mut(); - let mut sink = Pin::new(&mut this.sink); - ready!(sink.as_mut().poll_ready(cx))?; - let item = this.item.take().expect("polled Feed after completion"); - sink.as_mut().start_send(item)?; - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/sink/flush.rs b/futures-util/src/sink/flush.rs deleted file mode 100644 index 35a8372de7..0000000000 --- a/futures-util/src/sink/flush.rs +++ /dev/null @@ -1,36 +0,0 @@ -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -/// Future for the [`flush`](super::SinkExt::flush) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Flush<'a, Si: ?Sized, Item> { - sink: &'a mut Si, - _phantom: PhantomData, -} - -// Pin is never projected to a field. -impl Unpin for Flush<'_, Si, Item> {} - -/// A future that completes when the sink has finished processing all -/// pending requests. -/// -/// The sink itself is returned after flushing is complete; this adapter is -/// intended to be used when you want to stop sending to the sink until -/// all current requests are processed. -impl<'a, Si: Sink + Unpin + ?Sized, Item> Flush<'a, Si, Item> { - pub(super) fn new(sink: &'a mut Si) -> Self { - Self { sink, _phantom: PhantomData } - } -} - -impl + Unpin + ?Sized, Item> Future for Flush<'_, Si, Item> { - type Output = Result<(), Si::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.sink).poll_flush(cx) - } -} diff --git a/futures-util/src/sink/map_err.rs b/futures-util/src/sink/map_err.rs deleted file mode 100644 index 9d2ab7b24b..0000000000 --- a/futures-util/src/sink/map_err.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`sink_map_err`](super::SinkExt::sink_map_err) method. - #[derive(Debug, Clone)] - #[must_use = "sinks do nothing unless polled"] - pub struct SinkMapErr { - #[pin] - sink: Si, - f: Option, - } -} - -impl SinkMapErr { - pub(super) fn new(sink: Si, f: F) -> Self { - Self { sink, f: Some(f) } - } - - delegate_access_inner!(sink, Si, ()); - - fn take_f(self: Pin<&mut Self>) -> F { - self.project().f.take().expect("polled MapErr after completion") - } -} - -impl Sink for SinkMapErr -where - Si: Sink, - F: FnOnce(Si::Error) -> E, -{ - type Error = E; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.as_mut().project().sink.poll_ready(cx).map_err(|e| self.as_mut().take_f()(e)) - } - - fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - self.as_mut().project().sink.start_send(item).map_err(|e| self.as_mut().take_f()(e)) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.as_mut().project().sink.poll_flush(cx).map_err(|e| self.as_mut().take_f()(e)) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.as_mut().project().sink.poll_close(cx).map_err(|e| self.as_mut().take_f()(e)) - } -} - -// Forwarding impl of Stream from the underlying sink -impl Stream for SinkMapErr { - type Item = S::Item; - - delegate_stream!(sink); -} - -impl FusedStream for SinkMapErr { - fn is_terminated(&self) -> bool { - self.sink.is_terminated() - } -} diff --git a/futures-util/src/sink/mod.rs b/futures-util/src/sink/mod.rs deleted file mode 100644 index 6ac5bd3146..0000000000 --- a/futures-util/src/sink/mod.rs +++ /dev/null @@ -1,341 +0,0 @@ -//! Asynchronous sinks. -//! -//! This module contains: -//! -//! - The [`Sink`] trait, which allows you to asynchronously write data. -//! - The [`SinkExt`] trait, which provides adapters for chaining and composing -//! sinks. - -use crate::future::{assert_future, Either}; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; - -#[cfg(feature = "compat")] -use crate::compat::CompatSink; - -pub use futures_sink::Sink; - -mod close; -pub use self::close::Close; - -mod drain; -pub use self::drain::{drain, Drain}; - -mod fanout; -pub use self::fanout::Fanout; - -mod feed; -pub use self::feed::Feed; - -mod flush; -pub use self::flush::Flush; - -mod err_into; -pub use self::err_into::SinkErrInto; - -mod map_err; -pub use self::map_err::SinkMapErr; - -mod send; -pub use self::send::Send; - -mod send_all; -pub use self::send_all::SendAll; - -mod unfold; -pub use self::unfold::{unfold, Unfold}; - -mod with; -pub use self::with::With; - -mod with_flat_map; -pub use self::with_flat_map::WithFlatMap; - -#[cfg(feature = "alloc")] -mod buffer; -#[cfg(feature = "alloc")] -pub use self::buffer::Buffer; - -impl SinkExt for T where T: Sink {} - -/// An extension trait for `Sink`s that provides a variety of convenient -/// combinator functions. -pub trait SinkExt: Sink { - /// Composes a function *in front of* the sink. - /// - /// This adapter produces a new sink that passes each value through the - /// given function `f` before sending it to `self`. - /// - /// To process each value, `f` produces a *future*, which is then polled to - /// completion before passing its result down to the underlying sink. If the - /// future produces an error, that error is returned by the new sink. - /// - /// Note that this function consumes the given sink, returning a wrapped - /// version, much like `Iterator::map`. - fn with(self, f: F) -> With - where - F: FnMut(U) -> Fut, - Fut: Future>, - E: From, - Self: Sized, - { - assert_sink::(With::new(self, f)) - } - - /// Composes a function *in front of* the sink. - /// - /// This adapter produces a new sink that passes each value through the - /// given function `f` before sending it to `self`. - /// - /// To process each value, `f` produces a *stream*, of which each value - /// is passed to the underlying sink. A new value will not be accepted until - /// the stream has been drained - /// - /// Note that this function consumes the given sink, returning a wrapped - /// version, much like `Iterator::flat_map`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::sink::SinkExt; - /// use futures::stream::{self, StreamExt}; - /// - /// let (tx, rx) = mpsc::channel(5); - /// - /// let mut tx = tx.with_flat_map(|x| { - /// stream::iter(vec![Ok(42); x]) - /// }); - /// - /// tx.send(5).await.unwrap(); - /// drop(tx); - /// let received: Vec = rx.collect().await; - /// assert_eq!(received, vec![42, 42, 42, 42, 42]); - /// # }); - /// ``` - fn with_flat_map(self, f: F) -> WithFlatMap - where - F: FnMut(U) -> St, - St: Stream>, - Self: Sized, - { - assert_sink::(WithFlatMap::new(self, f)) - } - - /* - fn with_map(self, f: F) -> WithMap - where F: FnMut(U) -> Self::SinkItem, - Self: Sized; - - fn with_filter(self, f: F) -> WithFilter - where F: FnMut(Self::SinkItem) -> bool, - Self: Sized; - - fn with_filter_map(self, f: F) -> WithFilterMap - where F: FnMut(U) -> Option, - Self: Sized; - */ - - /// Transforms the error returned by the sink. - fn sink_map_err(self, f: F) -> SinkMapErr - where - F: FnOnce(Self::Error) -> E, - Self: Sized, - { - assert_sink::(SinkMapErr::new(self, f)) - } - - /// Map this sink's error to a different error type using the `Into` trait. - /// - /// If wanting to map errors of a `Sink + Stream`, use `.sink_err_into().err_into()`. - fn sink_err_into(self) -> err_into::SinkErrInto - where - Self: Sized, - Self::Error: Into, - { - assert_sink::(SinkErrInto::new(self)) - } - - /// Adds a fixed-size buffer to the current sink. - /// - /// The resulting sink will buffer up to `capacity` items when the - /// underlying sink is unwilling to accept additional items. Calling `flush` - /// on the buffered sink will attempt to both empty the buffer and complete - /// processing on the underlying sink. - /// - /// Note that this function consumes the given sink, returning a wrapped - /// version, much like `Iterator::map`. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "alloc")] - fn buffer(self, capacity: usize) -> Buffer - where - Self: Sized, - { - assert_sink::(Buffer::new(self, capacity)) - } - - /// Close the sink. - fn close(&mut self) -> Close<'_, Self, Item> - where - Self: Unpin, - { - assert_future::, _>(Close::new(self)) - } - - /// Fanout items to multiple sinks. - /// - /// This adapter clones each incoming item and forwards it to both this as well as - /// the other sink at the same time. - fn fanout(self, other: Si) -> Fanout - where - Self: Sized, - Item: Clone, - Si: Sink, - { - assert_sink::(Fanout::new(self, other)) - } - - /// Flush the sink, processing all pending items. - /// - /// This adapter is intended to be used when you want to stop sending to the sink - /// until all current requests are processed. - fn flush(&mut self) -> Flush<'_, Self, Item> - where - Self: Unpin, - { - assert_future::, _>(Flush::new(self)) - } - - /// A future that completes after the given item has been fully processed - /// into the sink, including flushing. - /// - /// Note that, **because of the flushing requirement, it is usually better - /// to batch together items to send via `feed` or `send_all`, - /// rather than flushing between each item.** - fn send(&mut self, item: Item) -> Send<'_, Self, Item> - where - Self: Unpin, - { - assert_future::, _>(Send::new(self, item)) - } - - /// A future that completes after the given item has been received - /// by the sink. - /// - /// Unlike `send`, the returned future does not flush the sink. - /// It is the caller's responsibility to ensure all pending items - /// are processed, which can be done via `flush` or `close`. - fn feed(&mut self, item: Item) -> Feed<'_, Self, Item> - where - Self: Unpin, - { - assert_future::, _>(Feed::new(self, item)) - } - - /// A future that completes after the given stream has been fully processed - /// into the sink, including flushing. - /// - /// This future will drive the stream to keep producing items until it is - /// exhausted, sending each item to the sink. It will complete once both the - /// stream is exhausted, the sink has received all items, and the sink has - /// been flushed. Note that the sink is **not** closed. If the stream produces - /// an error, that error will be returned by this future without flushing the sink. - /// - /// Doing `sink.send_all(stream)` is roughly equivalent to - /// `stream.forward(sink)`. The returned future will exhaust all items from - /// `stream` and send them to `self`. - fn send_all(&mut self, stream: St) -> SendAll<'_, Self, St> - where - St: Stream>, - Self: Unpin, - { - assert_future::, _>(SendAll::new(self, stream)) - } - - /// Wrap this sink in an `Either` sink, making it the left-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `right_sink` method to write `if` - /// statements that evaluate to different streams in different branches. - fn left_sink(self) -> Either - where - Si2: Sink, - Self: Sized, - { - assert_sink::(Either::Left(self)) - } - - /// Wrap this stream in an `Either` stream, making it the right-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `left_sink` method to write `if` - /// statements that evaluate to different streams in different branches. - fn right_sink(self) -> Either - where - Si1: Sink, - Self: Sized, - { - assert_sink::(Either::Right(self)) - } - - /// Wraps a [`Sink`] into a sink compatible with libraries using - /// futures 0.1 `Sink`. Requires the `compat` feature to be enabled. - #[cfg(feature = "compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "compat")))] - fn compat(self) -> CompatSink - where - Self: Sized + Unpin, - { - CompatSink::new(self) - } - - /// A convenience method for calling [`Sink::poll_ready`] on [`Unpin`] - /// sink types. - fn poll_ready_unpin(&mut self, cx: &mut Context<'_>) -> Poll> - where - Self: Unpin, - { - Pin::new(self).poll_ready(cx) - } - - /// A convenience method for calling [`Sink::start_send`] on [`Unpin`] - /// sink types. - fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error> - where - Self: Unpin, - { - Pin::new(self).start_send(item) - } - - /// A convenience method for calling [`Sink::poll_flush`] on [`Unpin`] - /// sink types. - fn poll_flush_unpin(&mut self, cx: &mut Context<'_>) -> Poll> - where - Self: Unpin, - { - Pin::new(self).poll_flush(cx) - } - - /// A convenience method for calling [`Sink::poll_close`] on [`Unpin`] - /// sink types. - fn poll_close_unpin(&mut self, cx: &mut Context<'_>) -> Poll> - where - Self: Unpin, - { - Pin::new(self).poll_close(cx) - } -} - -// Just a helper function to ensure the sinks we're returning all have the -// right implementations. -pub(crate) fn assert_sink(sink: S) -> S -where - S: Sink, -{ - sink -} diff --git a/futures-util/src/sink/send.rs b/futures-util/src/sink/send.rs deleted file mode 100644 index 6d21f33fe4..0000000000 --- a/futures-util/src/sink/send.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::Feed; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -/// Future for the [`send`](super::SinkExt::send) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Send<'a, Si: ?Sized, Item> { - feed: Feed<'a, Si, Item>, -} - -// Pinning is never projected to children -impl Unpin for Send<'_, Si, Item> {} - -impl<'a, Si: Sink + Unpin + ?Sized, Item> Send<'a, Si, Item> { - pub(super) fn new(sink: &'a mut Si, item: Item) -> Self { - Self { feed: Feed::new(sink, item) } - } -} - -impl + Unpin + ?Sized, Item> Future for Send<'_, Si, Item> { - type Output = Result<(), Si::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - - if this.feed.is_item_pending() { - ready!(Pin::new(&mut this.feed).poll(cx))?; - debug_assert!(!this.feed.is_item_pending()); - } - - // we're done sending the item, but want to block on flushing the - // sink - ready!(this.feed.sink_pin_mut().poll_flush(cx))?; - - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/sink/send_all.rs b/futures-util/src/sink/send_all.rs deleted file mode 100644 index 5d8e8fe62d..0000000000 --- a/futures-util/src/sink/send_all.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::stream::{Fuse, StreamExt}; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{Stream, TryStream}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`send_all`](super::SinkExt::send_all) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct SendAll<'a, Si, St> - where - Si: ?Sized, - St: TryStream, - { - sink: &'a mut Si, - #[pin] - stream: Fuse, - buffered: Option, - } -} - -impl fmt::Debug for SendAll<'_, Si, St> -where - Si: fmt::Debug + ?Sized, - St: fmt::Debug + TryStream, - St::Ok: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SendAll") - .field("sink", &self.sink) - .field("stream", &self.stream) - .field("buffered", &self.buffered) - .finish() - } -} - -impl<'a, Si, St, Ok, Error> SendAll<'a, Si, St> -where - Si: Sink + Unpin + ?Sized, - St: TryStream + Stream, -{ - pub(super) fn new(sink: &'a mut Si, stream: St) -> Self { - Self { sink, stream: stream.fuse(), buffered: None } - } - - fn try_start_send( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - item: St::Ok, - ) -> Poll> { - let this = self.project(); - debug_assert!(this.buffered.is_none()); - match Pin::new(&mut *this.sink).poll_ready(cx)? { - Poll::Ready(()) => Poll::Ready(Pin::new(&mut *this.sink).start_send(item)), - Poll::Pending => { - *this.buffered = Some(item); - Poll::Pending - } - } - } -} - -impl Future for SendAll<'_, Si, St> -where - Si: Sink + Unpin + ?Sized, - St: Stream>, -{ - type Output = Result<(), Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // If we've got an item buffered already, we need to write it to the - // sink before we can do anything else - if let Some(item) = self.as_mut().project().buffered.take() { - ready!(self.as_mut().try_start_send(cx, item))? - } - - loop { - let this = self.as_mut().project(); - match this.stream.try_poll_next(cx)? { - Poll::Ready(Some(item)) => ready!(self.as_mut().try_start_send(cx, item))?, - Poll::Ready(None) => { - ready!(Pin::new(this.sink).poll_flush(cx))?; - return Poll::Ready(Ok(())); - } - Poll::Pending => { - ready!(Pin::new(this.sink).poll_flush(cx))?; - return Poll::Pending; - } - } - } - } -} diff --git a/futures-util/src/sink/unfold.rs b/futures-util/src/sink/unfold.rs deleted file mode 100644 index 8b3e13faa7..0000000000 --- a/futures-util/src/sink/unfold.rs +++ /dev/null @@ -1,92 +0,0 @@ -use super::assert_sink; -use crate::unfold_state::UnfoldState; -use core::{future::Future, pin::Pin}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`unfold`] function. - #[derive(Debug)] - #[must_use = "sinks do nothing unless polled"] - pub struct Unfold { - function: F, - #[pin] - state: UnfoldState, - } -} - -/// Create a sink from a function which processes one item at a time. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use core::pin::pin; -/// -/// use futures::sink; -/// use futures::sink::SinkExt; -/// -/// let unfold = sink::unfold(0, |mut sum, i: i32| { -/// async move { -/// sum += i; -/// eprintln!("{}", i); -/// Ok::<_, std::convert::Infallible>(sum) -/// } -/// }); -/// let mut unfold = pin!(unfold); -/// unfold.send(5).await?; -/// # Ok::<(), std::convert::Infallible>(()) }).unwrap(); -/// ``` -pub fn unfold(init: T, function: F) -> Unfold -where - F: FnMut(T, Item) -> Fut, - Fut: Future>, -{ - assert_sink::(Unfold { function, state: UnfoldState::Value { value: init } }) -} - -impl Sink for Unfold -where - F: FnMut(T, Item) -> Fut, - Fut: Future>, -{ - type Error = E; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - let mut this = self.project(); - let future = match this.state.as_mut().take_value() { - Some(value) => (this.function)(value, item), - None => panic!("start_send called without poll_ready being called first"), - }; - this.state.set(UnfoldState::Future { future }); - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - Poll::Ready(if let Some(future) = this.state.as_mut().project_future() { - match ready!(future.poll(cx)) { - Ok(state) => { - this.state.set(UnfoldState::Value { value: state }); - Ok(()) - } - Err(err) => { - this.state.set(UnfoldState::Empty); - Err(err) - } - } - } else { - Ok(()) - }) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } -} diff --git a/futures-util/src/sink/with.rs b/futures-util/src/sink/with.rs deleted file mode 100644 index 5a2c8a089f..0000000000 --- a/futures-util/src/sink/with.rs +++ /dev/null @@ -1,145 +0,0 @@ -use core::fmt; -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`with`](super::SinkExt::with) method. - #[must_use = "sinks do nothing unless polled"] - pub struct With { - #[pin] - sink: Si, - f: F, - #[pin] - state: Option, - _phantom: PhantomData Item>, - } -} - -impl fmt::Debug for With -where - Si: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("With").field("sink", &self.sink).field("state", &self.state).finish() - } -} - -impl With -where - Si: Sink, - F: FnMut(U) -> Fut, - Fut: Future, -{ - pub(super) fn new(sink: Si, f: F) -> Self - where - Fut: Future>, - E: From, - { - Self { state: None, sink, f, _phantom: PhantomData } - } -} - -impl Clone for With -where - Si: Clone, - F: Clone, - Fut: Clone, -{ - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - sink: self.sink.clone(), - f: self.f.clone(), - _phantom: PhantomData, - } - } -} - -// Forwarding impl of Stream from the underlying sink -impl Stream for With -where - S: Stream + Sink, - F: FnMut(U) -> Fut, - Fut: Future, -{ - type Item = S::Item; - - 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, - F: FnMut(U) -> Fut, - Fut: Future>, - E: From, -{ - delegate_access_inner!(sink, Si, ()); - - /// Completes the processing of previous item if any. - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - let item = match this.state.as_mut().as_pin_mut() { - None => return Poll::Ready(Ok(())), - Some(fut) => ready!(fut.poll(cx))?, - }; - this.state.set(None); - this.sink.start_send(item)?; - Poll::Ready(Ok(())) - } -} - -impl Sink for With -where - Si: Sink, - F: FnMut(U) -> Fut, - Fut: Future>, - E: From, -{ - type Error = E; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().poll(cx))?; - ready!(self.project().sink.poll_ready(cx)?); - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, item: U) -> Result<(), Self::Error> { - let mut this = self.project(); - - assert!(this.state.is_none()); - this.state.set(Some((this.f)(item))); - Ok(()) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().poll(cx))?; - ready!(self.project().sink.poll_flush(cx)?); - Poll::Ready(Ok(())) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().poll(cx))?; - ready!(self.project().sink.poll_close(cx)?); - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/sink/with_flat_map.rs b/futures-util/src/sink/with_flat_map.rs deleted file mode 100644 index 2ae877a24b..0000000000 --- a/futures-util/src/sink/with_flat_map.rs +++ /dev/null @@ -1,127 +0,0 @@ -use core::fmt; -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Sink for the [`with_flat_map`](super::SinkExt::with_flat_map) method. - #[must_use = "sinks do nothing unless polled"] - pub struct WithFlatMap { - #[pin] - sink: Si, - f: F, - #[pin] - stream: Option, - buffer: Option, - _marker: PhantomData, - } -} - -impl fmt::Debug for WithFlatMap -where - Si: fmt::Debug, - St: fmt::Debug, - Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("WithFlatMap") - .field("sink", &self.sink) - .field("stream", &self.stream) - .field("buffer", &self.buffer) - .finish() - } -} - -impl WithFlatMap -where - Si: Sink, - F: FnMut(U) -> St, - St: Stream>, -{ - pub(super) fn new(sink: Si, f: F) -> Self { - Self { sink, f, stream: None, buffer: None, _marker: PhantomData } - } - - delegate_access_inner!(sink, Si, ()); - - fn try_empty_stream(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if this.buffer.is_some() { - ready!(this.sink.as_mut().poll_ready(cx))?; - let item = this.buffer.take().unwrap(); - this.sink.as_mut().start_send(item)?; - } - if let Some(mut some_stream) = this.stream.as_mut().as_pin_mut() { - while let Some(item) = ready!(some_stream.as_mut().poll_next(cx)?) { - match this.sink.as_mut().poll_ready(cx)? { - Poll::Ready(()) => this.sink.as_mut().start_send(item)?, - Poll::Pending => { - *this.buffer = Some(item); - return Poll::Pending; - } - }; - } - } - this.stream.set(None); - Poll::Ready(Ok(())) - } -} - -// Forwarding impl of Stream from the underlying sink -impl Stream for WithFlatMap -where - S: Stream + Sink, - F: FnMut(U) -> St, - St: Stream>, -{ - type Item = S::Item; - - delegate_stream!(sink); -} - -impl FusedStream for WithFlatMap -where - S: FusedStream + Sink, - F: FnMut(U) -> St, - St: Stream>, -{ - fn is_terminated(&self) -> bool { - self.sink.is_terminated() - } -} - -impl Sink for WithFlatMap -where - Si: Sink, - F: FnMut(U) -> St, - St: Stream>, -{ - type Error = Si::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.try_empty_stream(cx) - } - - fn start_send(self: Pin<&mut Self>, item: U) -> Result<(), Self::Error> { - let mut this = self.project(); - - assert!(this.stream.is_none()); - this.stream.set(Some((this.f)(item))); - Ok(()) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().try_empty_stream(cx)?); - self.project().sink.poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.as_mut().try_empty_stream(cx)?); - self.project().sink.poll_close(cx) - } -} diff --git a/futures-util/src/stream/abortable.rs b/futures-util/src/stream/abortable.rs deleted file mode 100644 index 1fea895822..0000000000 --- a/futures-util/src/stream/abortable.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::assert_stream; -use crate::stream::{AbortHandle, Abortable}; -use crate::Stream; - -/// Creates a new `Abortable` stream and an `AbortHandle` which can be used to stop it. -/// -/// This function is a convenient (but less flexible) alternative to calling -/// `AbortHandle::new` and `Abortable::new` manually. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -pub fn abortable(stream: St) -> (Abortable, AbortHandle) -where - St: Stream, -{ - let (handle, reg) = AbortHandle::new_pair(); - let abortable = assert_stream::(Abortable::new(stream, reg)); - (abortable, handle) -} diff --git a/futures-util/src/stream/empty.rs b/futures-util/src/stream/empty.rs deleted file mode 100644 index e4fd87326b..0000000000 --- a/futures-util/src/stream/empty.rs +++ /dev/null @@ -1,45 +0,0 @@ -use super::assert_stream; -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -/// Stream for the [`empty`] function. -#[derive(Debug)] -#[must_use = "streams do nothing unless polled"] -pub struct Empty { - _phantom: PhantomData, -} - -/// Creates a stream which contains no elements. -/// -/// The returned stream will always return `Ready(None)` when polled. -pub fn empty() -> Empty { - assert_stream::(Empty { _phantom: PhantomData }) -} - -impl Unpin for Empty {} - -impl FusedStream for Empty { - fn is_terminated(&self) -> bool { - true - } -} - -impl Stream for Empty { - type Item = T; - - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(None) - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -impl Clone for Empty { - fn clone(&self) -> Self { - empty() - } -} diff --git a/futures-util/src/stream/futures_ordered.rs b/futures-util/src/stream/futures_ordered.rs deleted file mode 100644 index 460b352676..0000000000 --- a/futures-util/src/stream/futures_ordered.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::stream::{FuturesUnordered, StreamExt}; -use alloc::collections::binary_heap::{BinaryHeap, PeekMut}; -use core::cmp::Ordering; -use core::fmt::{self, Debug}; -use core::iter::FromIterator; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::{ - task::{Context, Poll}, - FusedStream, -}; -use pin_project_lite::pin_project; - -pin_project! { - #[must_use = "futures do nothing unless you `.await` or poll them"] - #[derive(Debug)] - struct OrderWrapper { - #[pin] - data: T, // A future or a future's output - // Use i64 for index since isize may overflow in 32-bit targets. - index: i64, - } -} - -impl PartialEq for OrderWrapper { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } -} - -impl Eq for OrderWrapper {} - -impl PartialOrd for OrderWrapper { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for OrderWrapper { - fn cmp(&self, other: &Self) -> Ordering { - // BinaryHeap is a max heap, so compare backwards here. - other.index.cmp(&self.index) - } -} - -impl Future for OrderWrapper -where - T: Future, -{ - type Output = OrderWrapper; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let index = self.index; - self.project().data.poll(cx).map(|output| OrderWrapper { data: output, index }) - } -} - -/// An unbounded queue of futures. -/// -/// This "combinator" is similar to [`FuturesUnordered`], but it imposes a FIFO -/// order on top of the set of futures. While futures in the set will race to -/// completion in parallel, results will only be returned in the order their -/// originating futures were added to the queue. -/// -/// Futures are pushed into this queue and their realized values are yielded in -/// order. This structure is optimized to manage a large number of futures. -/// Futures managed by [`FuturesOrdered`] will only be polled when they generate -/// notifications. This reduces the required amount of work needed to coordinate -/// large numbers of futures. -/// -/// When a [`FuturesOrdered`] is first created, it does not contain any futures. -/// Calling [`poll_next`](FuturesOrdered::poll_next) in this state will result -/// in [`Poll::Ready(None)`](Poll::Ready) to be returned. Futures are submitted -/// to the queue using [`push_back`](FuturesOrdered::push_back) (or -/// [`push_front`](FuturesOrdered::push_front)); however, the future will -/// **not** be polled at this point. [`FuturesOrdered`] will only poll managed -/// futures when [`FuturesOrdered::poll_next`] is called. As such, it -/// is important to call [`poll_next`](FuturesOrdered::poll_next) after pushing -/// new futures. -/// -/// If [`FuturesOrdered::poll_next`] returns [`Poll::Ready(None)`](Poll::Ready) -/// this means that the queue is currently not managing any futures. A future -/// may be submitted to the queue at a later time. At that point, a call to -/// [`FuturesOrdered::poll_next`] will either return the future's resolved value -/// **or** [`Poll::Pending`] if the future has not yet completed. When -/// multiple futures are submitted to the queue, [`FuturesOrdered::poll_next`] -/// will return [`Poll::Pending`] until the first future completes, even if -/// some of the later futures have already completed. -/// -/// Note that you can create a ready-made [`FuturesOrdered`] via the -/// [`collect`](Iterator::collect) method, or you can start with an empty queue -/// with the [`FuturesOrdered::new`] constructor. -/// -/// This type is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -#[must_use = "streams do nothing unless polled"] -pub struct FuturesOrdered { - in_progress_queue: FuturesUnordered>, - queued_outputs: BinaryHeap>, - next_incoming_index: i64, - next_outgoing_index: i64, -} - -impl Unpin for FuturesOrdered {} - -impl FuturesOrdered { - /// Constructs a new, empty `FuturesOrdered` - /// - /// The returned [`FuturesOrdered`] does not contain any futures and, in - /// this state, [`FuturesOrdered::poll_next`] will return - /// [`Poll::Ready(None)`](Poll::Ready). - pub fn new() -> Self { - Self { - in_progress_queue: FuturesUnordered::new(), - queued_outputs: BinaryHeap::new(), - next_incoming_index: 0, - next_outgoing_index: 0, - } - } - - /// Returns the number of futures contained in the queue. - /// - /// This represents the total number of in-flight futures, both - /// those currently processing and those that have completed but - /// which are waiting for earlier futures to complete. - pub fn len(&self) -> usize { - self.in_progress_queue.len() + self.queued_outputs.len() - } - - /// Returns `true` if the queue contains no futures - pub fn is_empty(&self) -> bool { - self.in_progress_queue.is_empty() && self.queued_outputs.is_empty() - } - - /// Push a future into the queue. - /// - /// This function submits the given future to the internal set for managing. - /// This function will not call [`poll`](Future::poll) on the submitted - /// future. The caller must ensure that [`FuturesOrdered::poll_next`] is - /// called in order to receive task notifications. - #[deprecated(note = "use `push_back` instead")] - pub fn push(&mut self, future: Fut) { - self.push_back(future); - } - - /// Pushes a future to the back of the queue. - /// - /// This function submits the given future to the internal set for managing. - /// This function will not call [`poll`](Future::poll) on the submitted - /// future. The caller must ensure that [`FuturesOrdered::poll_next`] is - /// called in order to receive task notifications. - pub fn push_back(&mut self, future: Fut) { - let wrapped = OrderWrapper { data: future, index: self.next_incoming_index }; - self.next_incoming_index += 1; - self.in_progress_queue.push(wrapped); - } - - /// Pushes a future to the front of the queue. - /// - /// This function submits the given future to the internal set for managing. - /// This function will not call [`poll`](Future::poll) on the submitted - /// future. The caller must ensure that [`FuturesOrdered::poll_next`] is - /// called in order to receive task notifications. This future will be - /// the next future to be returned complete. - pub fn push_front(&mut self, future: Fut) { - let wrapped = OrderWrapper { data: future, index: self.next_outgoing_index - 1 }; - 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 { - fn default() -> Self { - Self::new() - } -} - -impl Stream for FuturesOrdered { - type Item = Fut::Output; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - - // Check to see if we've already received the next value - if let Some(next_output) = this.queued_outputs.peek_mut() { - if next_output.index == this.next_outgoing_index { - this.next_outgoing_index += 1; - return Poll::Ready(Some(PeekMut::pop(next_output).data)); - } - } - - loop { - match ready!(this.in_progress_queue.poll_next_unpin(cx)) { - Some(output) => { - if output.index == this.next_outgoing_index { - this.next_outgoing_index += 1; - return Poll::Ready(Some(output.data)); - } else { - this.queued_outputs.push(output) - } - } - None => return Poll::Ready(None), - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl Debug for FuturesOrdered { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FuturesOrdered {{ ... }}") - } -} - -impl FromIterator for FuturesOrdered { - fn from_iter(iter: T) -> Self - where - T: IntoIterator, - { - let acc = Self::new(); - iter.into_iter().fold(acc, |mut acc, item| { - acc.push_back(item); - acc - }) - } -} - -impl FusedStream for FuturesOrdered { - fn is_terminated(&self) -> bool { - self.in_progress_queue.is_terminated() && self.queued_outputs.is_empty() - } -} - -impl Extend for FuturesOrdered { - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - for item in iter { - self.push_back(item); - } - } -} diff --git a/futures-util/src/stream/futures_unordered/abort.rs b/futures-util/src/stream/futures_unordered/abort.rs deleted file mode 100644 index 1a42d24369..0000000000 --- a/futures-util/src/stream/futures_unordered/abort.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub(super) fn abort(s: &str) -> ! { - struct DoublePanic; - - impl Drop for DoublePanic { - fn drop(&mut self) { - panic!("panicking twice to abort the program"); - } - } - - let _bomb = DoublePanic; - panic!("{}", s); -} diff --git a/futures-util/src/stream/futures_unordered/iter.rs b/futures-util/src/stream/futures_unordered/iter.rs deleted file mode 100644 index 20248c70fe..0000000000 --- a/futures-util/src/stream/futures_unordered/iter.rs +++ /dev/null @@ -1,172 +0,0 @@ -use super::task::Task; -use super::FuturesUnordered; -use core::marker::PhantomData; -use core::pin::Pin; -use core::ptr; -use core::sync::atomic::Ordering::Relaxed; - -/// Mutable iterator over all futures in the unordered set. -#[derive(Debug)] -pub struct IterPinMut<'a, Fut> { - pub(super) task: *const Task, - pub(super) len: usize, - pub(super) _marker: PhantomData<&'a mut FuturesUnordered>, -} - -/// Mutable iterator over all futures in the unordered set. -#[derive(Debug)] -pub struct IterMut<'a, Fut: Unpin>(pub(super) IterPinMut<'a, Fut>); - -/// Immutable iterator over all futures in the unordered set. -#[derive(Debug)] -pub struct IterPinRef<'a, Fut> { - pub(super) task: *const Task, - pub(super) len: usize, - pub(super) pending_next_all: *mut Task, - pub(super) _marker: PhantomData<&'a FuturesUnordered>, -} - -/// Immutable iterator over all the futures in the unordered set. -#[derive(Debug)] -pub struct Iter<'a, Fut: Unpin>(pub(super) IterPinRef<'a, Fut>); - -/// Owned iterator over all futures in the unordered set. -#[derive(Debug)] -pub struct IntoIter { - pub(super) len: usize, - pub(super) inner: FuturesUnordered, -} - -impl Iterator for IntoIter { - type Item = Fut; - - fn next(&mut self) -> Option { - // `head_all` can be accessed directly and we don't need to spin on - // `Task::next_all` since we have exclusive access to the set. - let task = self.inner.head_all.get_mut(); - - if (*task).is_null() { - return None; - } - - unsafe { - // Moving out of the future is safe because it is `Unpin` - let future = (*(**task).future.get()).take().unwrap(); - - // Mutable access to a previously shared `FuturesUnordered` implies - // that the other threads already released the object before the - // current thread acquired it, so relaxed ordering can be used and - // valid `next_all` checks can be skipped. - let next = (**task).next_all.load(Relaxed); - *task = next; - if !task.is_null() { - *(**task).prev_all.get() = ptr::null_mut(); - } - self.len -= 1; - Some(future) - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} - -impl ExactSizeIterator for IntoIter {} - -impl<'a, Fut> Iterator for IterPinMut<'a, Fut> { - type Item = Pin<&'a mut Fut>; - - fn next(&mut self) -> Option { - if self.task.is_null() { - return None; - } - - unsafe { - let future = (*(*self.task).future.get()).as_mut().unwrap(); - - // Mutable access to a previously shared `FuturesUnordered` implies - // that the other threads already released the object before the - // current thread acquired it, so relaxed ordering can be used and - // valid `next_all` checks can be skipped. - let next = (*self.task).next_all.load(Relaxed); - self.task = next; - self.len -= 1; - Some(Pin::new_unchecked(future)) - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} - -impl ExactSizeIterator for IterPinMut<'_, Fut> {} - -impl<'a, Fut: Unpin> Iterator for IterMut<'a, Fut> { - type Item = &'a mut Fut; - - fn next(&mut self) -> Option { - self.0.next().map(Pin::get_mut) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -impl ExactSizeIterator for IterMut<'_, Fut> {} - -impl<'a, Fut> Iterator for IterPinRef<'a, Fut> { - type Item = Pin<&'a Fut>; - - fn next(&mut self) -> Option { - if self.task.is_null() { - return None; - } - - unsafe { - let future = (*(*self.task).future.get()).as_ref().unwrap(); - - // Relaxed ordering can be used since acquire ordering when - // `head_all` was initially read for this iterator implies acquire - // ordering for all previously inserted nodes (and we don't need to - // read `len_all` again for any other nodes). - let next = (*self.task).spin_next_all(self.pending_next_all, Relaxed); - self.task = next; - self.len -= 1; - Some(Pin::new_unchecked(future)) - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} - -impl ExactSizeIterator for IterPinRef<'_, Fut> {} - -impl<'a, Fut: Unpin> Iterator for Iter<'a, Fut> { - type Item = &'a Fut; - - fn next(&mut self) -> Option { - self.0.next().map(Pin::get_ref) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -impl ExactSizeIterator for Iter<'_, Fut> {} - -// SAFETY: we do nothing thread-local and there is no interior mutability, -// so the usual structural `Send`/`Sync` apply. -unsafe impl Send for IterPinRef<'_, Fut> {} -unsafe impl Sync for IterPinRef<'_, Fut> {} - -unsafe impl Send for IterPinMut<'_, Fut> {} -unsafe impl Sync for IterPinMut<'_, Fut> {} - -unsafe impl Send for IntoIter {} -unsafe impl Sync for IntoIter {} diff --git a/futures-util/src/stream/futures_unordered/mod.rs b/futures-util/src/stream/futures_unordered/mod.rs deleted file mode 100644 index 913e260fda..0000000000 --- a/futures-util/src/stream/futures_unordered/mod.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! An unbounded set of futures. -//! -//! This module is only available when the `std` or `alloc` feature of this -//! library is activated, and it is activated by default. - -use crate::task::AtomicWaker; -use alloc::sync::{Arc, Weak}; -use core::cell::UnsafeCell; -use core::fmt::{self, Debug}; -use core::iter::FromIterator; -use core::marker::PhantomData; -use core::mem; -use core::pin::Pin; -use core::ptr; -use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst}; -use core::sync::atomic::{AtomicBool, AtomicPtr}; -use futures_core::future::Future; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError}; - -mod abort; - -mod iter; -pub use self::iter::{IntoIter, Iter, IterMut, IterPinMut, IterPinRef}; - -mod task; -use self::task::Task; - -mod ready_to_run_queue; -use self::ready_to_run_queue::{Dequeue, ReadyToRunQueue}; - -/// A set of futures which may complete in any order. -/// -/// See [`FuturesOrdered`](crate::stream::FuturesOrdered) for a version of this -/// type that preserves a FIFO order. -/// -/// This structure is optimized to manage a large number of futures. -/// Futures managed by [`FuturesUnordered`] will only be polled when they -/// generate wake-up notifications. This reduces the required amount of work -/// needed to poll large numbers of futures. -/// -/// [`FuturesUnordered`] can be filled by [`collect`](Iterator::collect)ing an -/// iterator of futures into a [`FuturesUnordered`], or by -/// [`push`](FuturesUnordered::push)ing futures onto an existing -/// [`FuturesUnordered`]. When new futures are added, -/// [`poll_next`](Stream::poll_next) must be called in order to begin receiving -/// wake-ups for new futures. -/// -/// Note that you can create a ready-made [`FuturesUnordered`] via the -/// [`collect`](Iterator::collect) method, or you can start with an empty set -/// with the [`FuturesUnordered::new`] constructor. -/// -/// This type is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -#[must_use = "streams do nothing unless polled"] -pub struct FuturesUnordered { - ready_to_run_queue: Arc>, - head_all: AtomicPtr>, - is_terminated: AtomicBool, -} - -unsafe impl Send for FuturesUnordered {} -unsafe impl Sync for FuturesUnordered {} -impl Unpin for FuturesUnordered {} - -impl Spawn for FuturesUnordered> { - fn spawn_obj(&self, future_obj: FutureObj<'static, ()>) -> Result<(), SpawnError> { - self.push(future_obj); - Ok(()) - } -} - -impl LocalSpawn for FuturesUnordered> { - fn spawn_local_obj(&self, future_obj: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { - self.push(future_obj); - Ok(()) - } -} - -// FuturesUnordered is implemented using two linked lists. One which links all -// futures managed by a `FuturesUnordered` and one that tracks futures that have -// been scheduled for polling. The first linked list allows for thread safe -// insertion of nodes at the head as well as forward iteration, but is otherwise -// not thread safe and is only accessed by the thread that owns the -// `FuturesUnordered` value for any other operations. The second linked list is -// an implementation of the intrusive MPSC queue algorithm described by -// 1024cores.net. -// -// When a future is submitted to the set, a task is allocated and inserted in -// both linked lists. The next call to `poll_next` will (eventually) see this -// task and call `poll` on the future. -// -// Before a managed future is polled, the current context's waker is replaced -// with one that is aware of the specific future being run. This ensures that -// wake-up notifications generated by that specific future are visible to -// `FuturesUnordered`. When a wake-up notification is received, the task is -// inserted into the ready to run queue, so that its future can be polled later. -// -// Each task is wrapped in an `Arc` and thereby atomically reference counted. -// Also, each task contains an `AtomicBool` which acts as a flag that indicates -// whether the task is currently inserted in the atomic queue. When a wake-up -// notification is received, the task will only be inserted into the ready to -// run queue if it isn't inserted already. - -impl Default for FuturesUnordered { - fn default() -> Self { - Self::new() - } -} - -impl FuturesUnordered { - /// Constructs a new, empty [`FuturesUnordered`]. - /// - /// The returned [`FuturesUnordered`] does not contain any futures. - /// In this state, [`FuturesUnordered::poll_next`](Stream::poll_next) will - /// return [`Poll::Ready(None)`](Poll::Ready). - pub fn new() -> Self { - let stub = Arc::new(Task { - future: UnsafeCell::new(None), - next_all: AtomicPtr::new(ptr::null_mut()), - prev_all: UnsafeCell::new(ptr::null()), - len_all: UnsafeCell::new(0), - next_ready_to_run: AtomicPtr::new(ptr::null_mut()), - queued: AtomicBool::new(true), - ready_to_run_queue: Weak::new(), - woken: AtomicBool::new(false), - }); - let stub_ptr = Arc::as_ptr(&stub); - let ready_to_run_queue = Arc::new(ReadyToRunQueue { - waker: AtomicWaker::new(), - head: AtomicPtr::new(stub_ptr as *mut _), - tail: UnsafeCell::new(stub_ptr), - stub, - }); - - Self { - head_all: AtomicPtr::new(ptr::null_mut()), - ready_to_run_queue, - is_terminated: AtomicBool::new(false), - } - } - - /// Returns the number of futures contained in the set. - /// - /// This represents the total number of in-flight futures. - pub fn len(&self) -> usize { - let (_, len) = self.atomic_load_head_and_len_all(); - len - } - - /// Returns `true` if the set contains no futures. - pub fn is_empty(&self) -> bool { - // Relaxed ordering can be used here since we don't need to read from - // the head pointer, only check whether it is null. - self.head_all.load(Relaxed).is_null() - } - - /// Push a future into the set. - /// - /// This method adds the given future to the set. This method will not - /// call [`poll`](core::future::Future::poll) on the submitted future. The caller must - /// ensure that [`FuturesUnordered::poll_next`](Stream::poll_next) is called - /// in order to receive wake-up notifications for the given future. - pub fn push(&self, future: Fut) { - let task = Arc::new(Task { - future: UnsafeCell::new(Some(future)), - next_all: AtomicPtr::new(self.pending_next_all()), - prev_all: UnsafeCell::new(ptr::null_mut()), - len_all: UnsafeCell::new(0), - next_ready_to_run: AtomicPtr::new(ptr::null_mut()), - queued: AtomicBool::new(true), - ready_to_run_queue: Arc::downgrade(&self.ready_to_run_queue), - woken: AtomicBool::new(false), - }); - - // Reset the `is_terminated` flag if we've previously marked ourselves - // as terminated. - self.is_terminated.store(false, Relaxed); - - // Right now our task has a strong reference count of 1. We transfer - // ownership of this reference count to our internal linked list - // and we'll reclaim ownership through the `unlink` method below. - let ptr = self.link(task); - - // We'll need to get the future "into the system" to start tracking it, - // e.g. getting its wake-up notifications going to us tracking which - // futures are ready. To do that we unconditionally enqueue it for - // polling here. - self.ready_to_run_queue.enqueue(ptr); - } - - /// Returns an iterator that allows inspecting each future in the set. - pub fn iter(&self) -> Iter<'_, Fut> - where - Fut: Unpin, - { - Iter(Pin::new(self).iter_pin_ref()) - } - - /// Returns an iterator that allows inspecting each future in the set. - pub fn iter_pin_ref(self: Pin<&Self>) -> IterPinRef<'_, Fut> { - let (task, len) = self.atomic_load_head_and_len_all(); - let pending_next_all = self.pending_next_all(); - - IterPinRef { task, len, pending_next_all, _marker: PhantomData } - } - - /// Returns an iterator that allows modifying each future in the set. - pub fn iter_mut(&mut self) -> IterMut<'_, Fut> - where - Fut: Unpin, - { - IterMut(Pin::new(self).iter_pin_mut()) - } - - /// Returns an iterator that allows modifying each future in the set. - pub fn iter_pin_mut(mut self: Pin<&mut Self>) -> IterPinMut<'_, Fut> { - // `head_all` can be accessed directly and we don't need to spin on - // `Task::next_all` since we have exclusive access to the set. - let task = *self.head_all.get_mut(); - let len = if task.is_null() { 0 } else { unsafe { *(*task).len_all.get() } }; - - IterPinMut { task, len, _marker: PhantomData } - } - - /// Returns the current head node and number of futures in the list of all - /// futures within a context where access is shared with other threads - /// (mostly for use with the `len` and `iter_pin_ref` methods). - fn atomic_load_head_and_len_all(&self) -> (*const Task, usize) { - let task = self.head_all.load(Acquire); - let len = if task.is_null() { - 0 - } else { - unsafe { - (*task).spin_next_all(self.pending_next_all(), Acquire); - *(*task).len_all.get() - } - }; - - (task, len) - } - - /// Releases the task. It destroys the future inside and either drops - /// the `Arc` or transfers ownership to the ready to run queue. - /// The task this method is called on must have been unlinked before. - fn release_task(&mut self, task: Arc>) { - // `release_task` must only be called on unlinked tasks - debug_assert_eq!(task.next_all.load(Relaxed), self.pending_next_all()); - unsafe { - debug_assert!((*task.prev_all.get()).is_null()); - } - - // The future is done, try to reset the queued flag. This will prevent - // `wake` from doing any work in the future - let prev = task.queued.swap(true, SeqCst); - - // If the queued flag was previously set, then it means that this task - // is still in our internal ready to run queue. We then transfer - // ownership of our reference count to the ready to run queue, and it'll - // come along and free it later, noticing that the future is `None`. - // - // If, however, the queued flag was *not* set then we're safe to - // release our reference count on the task. The queued flag was set - // above so all future `enqueue` operations will not actually - // enqueue the task, so our task will never see the ready to run queue - // again. The task itself will be deallocated once all reference counts - // have been dropped elsewhere by the various wakers that contain it. - // - // Use ManuallyDrop to transfer the reference count ownership before - // dropping the future so unwinding won't release the reference count. - let md_slot; - let task = if prev { - md_slot = mem::ManuallyDrop::new(task); - &*md_slot - } else { - &task - }; - - // Drop the future, even if it hasn't finished yet. This is safe - // because we're dropping the future on the thread that owns - // `FuturesUnordered`, which correctly tracks `Fut`'s lifetimes and - // such. - unsafe { - // Set to `None` rather than `take()`ing to prevent moving the - // future. - *task.future.get() = None; - } - } - - /// Insert a new task into the internal linked list. - fn link(&self, task: Arc>) -> *const Task { - // `next_all` should already be reset to the pending state before this - // function is called. - debug_assert_eq!(task.next_all.load(Relaxed), self.pending_next_all()); - let ptr = Arc::into_raw(task); - - // Atomically swap out the old head node to get the node that should be - // assigned to `next_all`. - let next = self.head_all.swap(ptr as *mut _, AcqRel); - - unsafe { - // Store the new list length in the new node. - let new_len = if next.is_null() { - 1 - } else { - // Make sure `next_all` has been written to signal that it is - // safe to read `len_all`. - (*next).spin_next_all(self.pending_next_all(), Acquire); - *(*next).len_all.get() + 1 - }; - *(*ptr).len_all.get() = new_len; - - // Write the old head as the next node pointer, signaling to other - // threads that `len_all` and `next_all` are ready to read. - (*ptr).next_all.store(next, Release); - - // `prev_all` updates don't need to be synchronized, as the field is - // only ever used after exclusive access has been acquired. - if !next.is_null() { - *(*next).prev_all.get() = ptr; - } - } - - ptr - } - - /// Remove the task from the linked list tracking all tasks currently - /// managed by `FuturesUnordered`. - /// This method is unsafe because it has be guaranteed that `task` is a - /// valid pointer. - unsafe fn unlink(&mut self, task: *const Task) -> Arc> { - unsafe { - // Compute the new list length now in case we're removing the head node - // and won't be able to retrieve the correct length later. - let head = *self.head_all.get_mut(); - debug_assert!(!head.is_null()); - let new_len = *(*head).len_all.get() - 1; - - let task = Arc::from_raw(task); - let next = task.next_all.load(Relaxed); - let prev = *task.prev_all.get(); - task.next_all.store(self.pending_next_all(), Relaxed); - *task.prev_all.get() = ptr::null_mut(); - - if !next.is_null() { - *(*next).prev_all.get() = prev; - } - - if !prev.is_null() { - (*prev).next_all.store(next, Relaxed); - } else { - *self.head_all.get_mut() = next; - } - - // Store the new list length in the head node. - let head = *self.head_all.get_mut(); - if !head.is_null() { - *(*head).len_all.get() = new_len; - } - - task - } - } - - /// Returns the reserved value for `Task::next_all` to indicate a pending - /// assignment from the thread that inserted the task. - /// - /// `FuturesUnordered::link` needs to update `Task` pointers in an order - /// that ensures any iterators created on other threads can correctly - /// traverse the entire `Task` list using the chain of `next_all` pointers. - /// This could be solved with a compare-exchange loop that stores the - /// current `head_all` in `next_all` and swaps out `head_all` with the new - /// `Task` pointer if the head hasn't already changed. Under heavy thread - /// contention, this compare-exchange loop could become costly. - /// - /// An alternative is to initialize `next_all` to a reserved pending state - /// first, perform an atomic swap on `head_all`, and finally update - /// `next_all` with the old head node. Iterators will then either see the - /// pending state value or the correct next node pointer, and can reload - /// `next_all` as needed until the correct value is loaded. The number of - /// retries needed (if any) would be small and will always be finite, so - /// this should generally perform better than the compare-exchange loop. - /// - /// A valid `Task` pointer in the `head_all` list is guaranteed to never be - /// this value, so it is safe to use as a reserved value until the correct - /// value can be written. - fn pending_next_all(&self) -> *mut Task { - // The `ReadyToRunQueue` stub is never inserted into the `head_all` - // list, and its pointer value will remain valid for the lifetime of - // this `FuturesUnordered`, so we can make use of its value here. - Arc::as_ptr(&self.ready_to_run_queue.stub) as *mut _ - } -} - -impl Stream for FuturesUnordered { - type Item = Fut::Output; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let len = self.len(); - - // Keep track of how many child futures we have polled, - // in case we want to forcibly yield. - let mut polled = 0; - let mut yielded = 0; - - // Ensure `parent` is correctly set. - self.ready_to_run_queue.waker.register(cx.waker()); - - loop { - // Safety: &mut self guarantees the mutual exclusion `dequeue` - // expects - let task = match unsafe { self.ready_to_run_queue.dequeue() } { - Dequeue::Empty => { - if self.is_empty() { - // We can only consider ourselves terminated once we - // have yielded a `None` - *self.is_terminated.get_mut() = true; - return Poll::Ready(None); - } else { - return Poll::Pending; - } - } - Dequeue::Inconsistent => { - // At this point, it may be worth yielding the thread & - // spinning a few times... but for now, just yield using the - // task system. - cx.waker().wake_by_ref(); - return Poll::Pending; - } - Dequeue::Data(task) => task, - }; - - debug_assert!(task != self.ready_to_run_queue.stub()); - - // Safety: - // - `task` is a valid pointer. - // - We are the only thread that accesses the `UnsafeCell` that - // contains the future - let future = match unsafe { &mut *(*task).future.get() } { - Some(future) => future, - - // If the future has already gone away then we're just - // cleaning out this task. See the comment in - // `release_task` for more information, but we're basically - // just taking ownership of our reference count here. - None => { - // This case only happens when `release_task` was called - // for this task before and couldn't drop the task - // because it was already enqueued in the ready to run - // queue. - - // Safety: `task` is a valid pointer - let task = unsafe { Arc::from_raw(task) }; - - // Double check that the call to `release_task` really - // happened. Calling it required the task to be unlinked. - debug_assert_eq!(task.next_all.load(Relaxed), self.pending_next_all()); - unsafe { - debug_assert!((*task.prev_all.get()).is_null()); - } - continue; - } - }; - - // Safety: `task` is a valid pointer - let task = unsafe { self.unlink(task) }; - - // Unset queued flag: This must be done before polling to ensure - // that the future's task gets rescheduled if it sends a wake-up - // notification **during** the call to `poll`. - let prev = task.queued.swap(false, SeqCst); - assert!(prev); - - // We're going to need to be very careful if the `poll` - // method below panics. We need to (a) not leak memory and - // (b) ensure that we still don't have any use-after-frees. To - // manage this we do a few things: - // - // * A "bomb" is created which if dropped abnormally will call - // `release_task`. That way we'll be sure the memory management - // of the `task` is managed correctly. In particular - // `release_task` will drop the future. This ensures that it is - // dropped on this thread and not accidentally on a different - // thread (bad). - // * We unlink the task from our internal queue to preemptively - // assume it'll panic, in which case we'll want to discard it - // regardless. - struct Bomb<'a, Fut> { - queue: &'a mut FuturesUnordered, - task: Option>>, - } - - impl Drop for Bomb<'_, Fut> { - fn drop(&mut self) { - if let Some(task) = self.task.take() { - self.queue.release_task(task); - } - } - } - - let mut bomb = Bomb { task: Some(task), queue: &mut *self }; - - // Poll the underlying future with the appropriate waker - // implementation. This is where a large bit of the unsafety - // starts to stem from internally. The waker is basically just - // our `Arc>` and can schedule the future for polling by - // enqueuing itself in the ready to run queue. - // - // Critically though `Task` won't actually access `Fut`, the - // future, while it's floating around inside of wakers. - // These structs will basically just use `Fut` to size - // the internal allocation, appropriately accessing fields and - // deallocating the task if need be. - let res = { - let task = bomb.task.as_ref().unwrap(); - // We are only interested in whether the future is awoken before it - // finishes polling, so reset the flag here. - task.woken.store(false, Relaxed); - // SAFETY: see the comments of Bomb and this block. - let waker = unsafe { Task::waker_ref(task) }; - let mut cx = Context::from_waker(&waker); - - // Safety: We won't move the future ever again - let future = unsafe { Pin::new_unchecked(future) }; - - future.poll(&mut cx) - }; - polled += 1; - - match res { - Poll::Pending => { - let task = bomb.task.take().unwrap(); - // If the future was awoken during polling, we assume - // the future wanted to explicitly yield. - yielded += task.woken.load(Relaxed) as usize; - bomb.queue.link(task); - - // If a future yields, we respect it and yield here. - // If all futures have been polled, we also yield here to - // avoid starving other tasks waiting on the executor. - // (polling the same future twice per iteration may cause - // the problem: https://github.com/rust-lang/futures-rs/pull/2333) - if yielded >= 2 || polled == len { - cx.waker().wake_by_ref(); - return Poll::Pending; - } - continue; - } - Poll::Ready(output) => return Poll::Ready(Some(output)), - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl Debug for FuturesUnordered { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FuturesUnordered {{ ... }}") - } -} - -impl FuturesUnordered { - /// Clears the set, removing all futures. - pub fn clear(&mut self) { - *self = Self::new(); - } -} - -impl Drop for FuturesUnordered { - fn drop(&mut self) { - // Before the strong reference to the queue is dropped we need all - // futures to be dropped. See note at the bottom of this method. - // - // If there is a panic before this completes, we leak the queue. - struct LeakQueueOnDrop<'a, Fut>(&'a mut FuturesUnordered); - impl Drop for LeakQueueOnDrop<'_, Fut> { - fn drop(&mut self) { - mem::forget(Arc::clone(&self.0.ready_to_run_queue)); - } - } - let guard = LeakQueueOnDrop(self); - // When a `FuturesUnordered` is dropped we want to drop all futures - // associated with it. At the same time though there may be tons of - // wakers flying around which contain `Task` references - // inside them. We'll let those naturally get deallocated. - while !guard.0.head_all.get_mut().is_null() { - let head = *guard.0.head_all.get_mut(); - let task = unsafe { guard.0.unlink(head) }; - guard.0.release_task(task); - } - mem::forget(guard); // safe to release strong reference to queue - - // Note that at this point we could still have a bunch of tasks in the - // ready to run queue. None of those tasks, however, have futures - // associated with them so they're safe to destroy on any thread. At - // this point the `FuturesUnordered` struct, the owner of the one strong - // reference to the ready to run queue will drop the strong reference. - // At that point whichever thread releases the strong refcount last (be - // it this thread or some other thread as part of an `upgrade`) will - // clear out the ready to run queue and free all remaining tasks. - // - // While that freeing operation isn't guaranteed to happen here, it's - // guaranteed to happen "promptly" as no more "blocking work" will - // happen while there's a strong refcount held. - } -} - -impl<'a, Fut: Unpin> IntoIterator for &'a FuturesUnordered { - type Item = &'a Fut; - type IntoIter = Iter<'a, Fut>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, Fut: Unpin> IntoIterator for &'a mut FuturesUnordered { - type Item = &'a mut Fut; - type IntoIter = IterMut<'a, Fut>; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -impl IntoIterator for FuturesUnordered { - type Item = Fut; - type IntoIter = IntoIter; - - fn into_iter(mut self) -> Self::IntoIter { - // `head_all` can be accessed directly and we don't need to spin on - // `Task::next_all` since we have exclusive access to the set. - let task = *self.head_all.get_mut(); - let len = if task.is_null() { 0 } else { unsafe { *(*task).len_all.get() } }; - - IntoIter { len, inner: self } - } -} - -impl FromIterator for FuturesUnordered { - fn from_iter(iter: I) -> Self - where - I: IntoIterator, - { - let acc = Self::new(); - iter.into_iter().fold(acc, |acc, item| { - acc.push(item); - acc - }) - } -} - -impl FusedStream for FuturesUnordered { - fn is_terminated(&self) -> bool { - self.is_terminated.load(Relaxed) - } -} - -impl Extend for FuturesUnordered { - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - for item in iter { - self.push(item); - } - } -} 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 deleted file mode 100644 index e35418dfa5..0000000000 --- a/futures-util/src/stream/futures_unordered/ready_to_run_queue.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::task::AtomicWaker; -use alloc::sync::Arc; -use core::cell::UnsafeCell; -use core::ptr; -use core::sync::atomic::AtomicPtr; -use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; - -use super::abort::abort; -use super::task::Task; - -pub(super) enum Dequeue { - Data(*const Task), - Empty, - Inconsistent, -} - -pub(super) struct ReadyToRunQueue { - // The waker of the task using `FuturesUnordered`. - pub(super) waker: AtomicWaker, - - // Head/tail of the readiness queue - pub(super) head: AtomicPtr>, - pub(super) tail: UnsafeCell<*const Task>, - pub(super) stub: Arc>, -} - -/// An MPSC queue into which the tasks containing the futures are inserted -/// whenever the future inside is scheduled for polling. -impl ReadyToRunQueue { - // FIXME: this takes raw pointer without safety conditions. - - /// The enqueue function from the 1024cores intrusive MPSC queue algorithm. - pub(super) fn enqueue(&self, task: *const Task) { - unsafe { - debug_assert!((*task).queued.load(Relaxed)); - - // This action does not require any coordination - (*task).next_ready_to_run.store(ptr::null_mut(), Relaxed); - - // Note that these atomic orderings come from 1024cores - let task = task as *mut _; - let prev = self.head.swap(task, AcqRel); - (*prev).next_ready_to_run.store(task, Release); - } - } - - /// The dequeue function from the 1024cores intrusive MPSC queue algorithm - /// - /// Note that this is unsafe as it required mutual exclusion (only one - /// thread can call this) to be guaranteed elsewhere. - pub(super) unsafe fn dequeue(&self) -> Dequeue { - unsafe { - let mut tail = *self.tail.get(); - let mut next = (*tail).next_ready_to_run.load(Acquire); - - if tail == self.stub() { - if next.is_null() { - return Dequeue::Empty; - } - - *self.tail.get() = next; - tail = next; - next = (*next).next_ready_to_run.load(Acquire); - } - - if !next.is_null() { - *self.tail.get() = next; - debug_assert!(tail != self.stub()); - return Dequeue::Data(tail); - } - - if !core::ptr::eq(self.head.load(Acquire), tail) { - return Dequeue::Inconsistent; - } - - self.enqueue(self.stub()); - - next = (*tail).next_ready_to_run.load(Acquire); - - if !next.is_null() { - *self.tail.get() = next; - return Dequeue::Data(tail); - } - - Dequeue::Inconsistent - } - } - - pub(super) fn stub(&self) -> *const Task { - Arc::as_ptr(&self.stub) - } -} - -impl Drop for ReadyToRunQueue { - fn drop(&mut self) { - // Once we're in the destructor for `Inner` we need to clear out - // the ready to run queue of tasks if there's anything left in there. - // - // Note that each task has a strong reference count associated with it - // which is owned by the ready to run queue. All tasks should have had - // their futures dropped already by the `FuturesUnordered` destructor - // above, so we're just pulling out tasks and dropping their refcounts. - unsafe { - loop { - match self.dequeue() { - Dequeue::Empty => break, - Dequeue::Inconsistent => abort("inconsistent in drop"), - Dequeue::Data(ptr) => drop(Arc::from_raw(ptr)), - } - } - } - } -} diff --git a/futures-util/src/stream/futures_unordered/task.rs b/futures-util/src/stream/futures_unordered/task.rs deleted file mode 100644 index 2ae4cb7d85..0000000000 --- a/futures-util/src/stream/futures_unordered/task.rs +++ /dev/null @@ -1,214 +0,0 @@ -use alloc::sync::{Arc, Weak}; -use core::cell::UnsafeCell; -use core::sync::atomic::Ordering::{self, Relaxed, SeqCst}; -use core::sync::atomic::{AtomicBool, AtomicPtr}; - -use super::abort::abort; -use super::ReadyToRunQueue; -use crate::task::ArcWake; - -pub(super) struct Task { - // The future - pub(super) future: UnsafeCell>, - - // Next pointer for linked list tracking all active tasks (use - // `spin_next_all` to read when access is shared across threads) - pub(super) next_all: AtomicPtr>, - - // Previous task in linked list tracking all active tasks - pub(super) prev_all: UnsafeCell<*const Task>, - - // Length of the linked list tracking all active tasks when this node was - // inserted (use `spin_next_all` to synchronize before reading when access - // is shared across threads) - pub(super) len_all: UnsafeCell, - - // Next pointer in ready to run queue - pub(super) next_ready_to_run: AtomicPtr>, - - // Queue that we'll be enqueued to when woken - pub(super) ready_to_run_queue: Weak>, - - // Whether or not this task is currently in the ready to run queue - pub(super) queued: AtomicBool, - - // Whether the future was awoken during polling - // It is possible for this flag to be set to true after the polling, - // but it will be ignored. - pub(super) woken: AtomicBool, -} - -// `Task` can be sent across threads safely because it ensures that -// the underlying `Fut` type isn't touched from any of its methods. -// -// The parent (`super`) module is trusted not to access `future` -// across different threads. -unsafe impl Send for Task {} -unsafe impl Sync for Task {} - -impl ArcWake for Task { - fn wake_by_ref(arc_self: &Arc) { - let inner = match arc_self.ready_to_run_queue.upgrade() { - Some(inner) => inner, - None => return, - }; - - arc_self.woken.store(true, Relaxed); - - // It's our job to enqueue this task it into the ready to run queue. To - // do this we set the `queued` flag, and if successful we then do the - // actual queueing operation, ensuring that we're only queued once. - // - // Once the task is inserted call `wake` to notify the parent task, - // as it'll want to come along and run our task later. - // - // Note that we don't change the reference count of the task here, - // we merely enqueue the raw pointer. The `FuturesUnordered` - // implementation guarantees that if we set the `queued` flag that - // there's a reference count held by the main `FuturesUnordered` queue - // still. - let prev = arc_self.queued.swap(true, SeqCst); - if !prev { - inner.enqueue(Arc::as_ptr(arc_self)); - inner.waker.wake(); - } - } -} - -impl Task { - /// Returns a waker reference for this task without cloning the Arc. - pub(super) unsafe fn waker_ref(this: &Arc) -> waker_ref::WakerRef<'_> { - unsafe { waker_ref::waker_ref(this) } - } - - /// Spins until `next_all` is no longer set to `pending_next_all`. - /// - /// The temporary `pending_next_all` value is typically overwritten fairly - /// quickly after a node is inserted into the list of all futures, so this - /// should rarely spin much. - /// - /// When it returns, the correct `next_all` value is returned. - /// - /// `Relaxed` or `Acquire` ordering can be used. `Acquire` ordering must be - /// used before `len_all` can be safely read. - #[inline] - pub(super) fn spin_next_all( - &self, - pending_next_all: *mut Self, - ordering: Ordering, - ) -> *const Self { - loop { - let next = self.next_all.load(ordering); - if next != pending_next_all { - return next; - } - } - } -} - -impl Drop for Task { - fn drop(&mut self) { - // Since `Task` is sent across all threads for any lifetime, - // regardless of `Fut`, we, to guarantee memory safety, can't actually - // touch `Fut` at any time except when we have a reference to the - // `FuturesUnordered` itself . - // - // Consequently it *should* be the case that we always drop futures from - // the `FuturesUnordered` instance. This is a bomb, just in case there's - // a bug in that logic. - unsafe { - if (*self.future.get()).is_some() { - abort("future still here when dropping"); - } - } - } -} - -mod waker_ref { - use alloc::sync::Arc; - use core::marker::PhantomData; - use core::mem; - use core::mem::ManuallyDrop; - use core::ops::Deref; - use core::task::{RawWaker, RawWakerVTable, Waker}; - use futures_task::ArcWake; - - pub(crate) struct WakerRef<'a> { - waker: ManuallyDrop, - _marker: PhantomData<&'a ()>, - } - - impl WakerRef<'_> { - #[inline] - fn new_unowned(waker: ManuallyDrop) -> Self { - Self { waker, _marker: PhantomData } - } - } - - impl Deref for WakerRef<'_> { - type Target = Waker; - - #[inline] - fn deref(&self) -> &Waker { - &self.waker - } - } - - /// Copy of `future_task::waker_ref` without `W: 'static` bound. - /// - /// # Safety - /// - /// The caller must guarantee that use-after-free will not occur. - #[inline] - pub(crate) unsafe fn waker_ref(wake: &Arc) -> WakerRef<'_> - where - W: ArcWake, - { - // simply copy the pointer instead of using Arc::into_raw, - // as we don't actually keep a refcount by using ManuallyDrop.< - let ptr = Arc::as_ptr(wake).cast::<()>(); - - let waker = - ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::())) }); - WakerRef::new_unowned(waker) - } - - fn waker_vtable() -> &'static RawWakerVTable { - &RawWakerVTable::new( - clone_arc_raw::, - wake_arc_raw::, - wake_by_ref_arc_raw::, - drop_arc_raw::, - ) - } - - // FIXME: panics on Arc::clone / refcount changes could wreak havoc on the - // code here. We should guard against this by aborting. - - unsafe fn increase_refcount(data: *const ()) { - // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); - // Now increase refcount, but don't drop new refcount either - let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); - } - - unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { - unsafe { increase_refcount::(data) } - RawWaker::new(data, waker_vtable::()) - } - - unsafe fn wake_arc_raw(data: *const ()) { - let arc: Arc = unsafe { Arc::from_raw(data.cast::()) }; - ArcWake::wake(arc); - } - - unsafe fn wake_by_ref_arc_raw(data: *const ()) { - // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(unsafe { Arc::::from_raw(data.cast::()) }); - ArcWake::wake_by_ref(&arc); - } - - unsafe fn drop_arc_raw(data: *const ()) { - drop(unsafe { Arc::::from_raw(data.cast::()) }) - } -} diff --git a/futures-util/src/stream/iter.rs b/futures-util/src/stream/iter.rs deleted file mode 100644 index 48b6519a39..0000000000 --- a/futures-util/src/stream/iter.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::assert_stream; -use core::pin::Pin; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; - -/// Stream for the [`iter`] function. -#[derive(Debug, Clone)] -#[must_use = "streams do nothing unless polled"] -pub struct Iter { - iter: I, -} - -impl Iter { - /// Acquires a reference to the underlying iterator that this stream is pulling from. - pub fn get_ref(&self) -> &I { - &self.iter - } - - /// Acquires a mutable reference to the underlying iterator that this stream is pulling from. - pub fn get_mut(&mut self) -> &mut I { - &mut self.iter - } - - /// Consumes this stream, returning the underlying iterator. - pub fn into_inner(self) -> I { - self.iter - } -} - -impl Unpin for Iter {} - -/// Converts an `Iterator` into a `Stream` which is always ready -/// to yield the next value. -/// -/// Iterators in Rust don't express the ability to block, so this adapter -/// simply always calls `iter.next()` and returns that. -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// let stream = stream::iter(vec![17, 19]); -/// assert_eq!(vec![17, 19], stream.collect::>().await); -/// # }); -/// ``` -pub fn iter(i: I) -> Iter -where - I: IntoIterator, -{ - assert_stream::(Iter { iter: i.into_iter() }) -} - -impl Stream for Iter -where - I: Iterator, -{ - type Item = I::Item; - - fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(self.iter.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} diff --git a/futures-util/src/stream/mod.rs b/futures-util/src/stream/mod.rs deleted file mode 100644 index 789e1ad221..0000000000 --- a/futures-util/src/stream/mod.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Asynchronous streams. -//! -//! This module contains: -//! -//! - The [`Stream`] trait, for objects that can asynchronously produce a -//! sequence of values. -//! - The [`StreamExt`] and [`TryStreamExt`] trait, which provides adapters for -//! chaining and composing streams. -//! - Top-level stream constructors like [`iter`](iter()) which creates a -//! stream from an iterator. - -#[cfg(feature = "alloc")] -pub use futures_core::stream::{BoxStream, LocalBoxStream}; -pub use futures_core::stream::{FusedStream, Stream, TryStream}; - -// Extension traits and combinators - -#[allow(clippy::module_inception)] -mod stream; -pub use self::stream::{ - All, Any, Chain, Collect, Concat, Count, Cycle, Enumerate, Filter, FilterMap, FlatMap, Flatten, - Fold, ForEach, Fuse, Inspect, Map, Next, NextIf, NextIfEq, Peek, PeekMut, Peekable, Scan, - SelectNextSome, Skip, SkipWhile, StreamExt, StreamFuture, Take, TakeUntil, TakeWhile, Then, - TryFold, TryForEach, Unzip, Zip, -}; - -#[cfg(feature = "std")] -pub use self::stream::CatchUnwind; - -#[cfg(feature = "alloc")] -pub use self::stream::Chunks; - -#[cfg(feature = "alloc")] -pub use self::stream::ReadyChunks; - -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::stream::Forward; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::stream::{ - BufferUnordered, Buffered, FlatMapUnordered, FlattenUnordered, ForEachConcurrent, - TryForEachConcurrent, -}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -#[cfg(feature = "alloc")] -pub use self::stream::{ReuniteError, SplitSink, SplitStream}; - -mod try_stream; -pub use self::try_stream::{ - try_unfold, AndThen, ErrInto, InspectErr, InspectOk, IntoStream, MapErr, MapOk, OrElse, TryAll, - TryAny, TryCollect, TryConcat, TryFilter, TryFilterMap, TryFlatten, TryNext, TrySkipWhile, - TryStreamExt, TryTakeWhile, TryUnfold, -}; - -#[cfg(feature = "io")] -#[cfg_attr(docsrs, doc(cfg(feature = "io")))] -#[cfg(feature = "std")] -pub use self::try_stream::IntoAsyncRead; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::try_stream::{TryBufferUnordered, TryBuffered, TryFlattenUnordered}; - -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub use self::try_stream::TryForward; - -#[cfg(feature = "alloc")] -pub use self::try_stream::{TryChunks, TryChunksError, TryReadyChunks, TryReadyChunksError}; - -// Primitive streams - -mod iter; -pub use self::iter::{iter, Iter}; - -mod repeat; -pub use self::repeat::{repeat, Repeat}; - -mod repeat_with; -pub use self::repeat_with::{repeat_with, RepeatWith}; - -mod empty; -pub use self::empty::{empty, Empty}; - -mod once; -pub use self::once::{once, Once}; - -mod pending; -pub use self::pending::{pending, Pending}; - -mod poll_fn; -pub use self::poll_fn::{poll_fn, PollFn}; - -mod poll_immediate; -pub use self::poll_immediate::{poll_immediate, PollImmediate}; - -mod select; -pub use self::select::{select, Select}; - -mod select_with_strategy; -pub use self::select_with_strategy::{select_with_strategy, PollNext, SelectWithStrategy}; - -mod unfold; -pub use self::unfold::{unfold, Unfold}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod futures_ordered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::futures_ordered::FuturesOrdered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub mod futures_unordered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -#[doc(inline)] -pub use self::futures_unordered::FuturesUnordered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub mod select_all; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -#[doc(inline)] -pub use self::select_all::{select_all, SelectAll}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod abortable; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted}; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use abortable::abortable; - -// Just a helper function to ensure the streams we're returning all have the -// right implementations. -pub(crate) fn assert_stream(stream: S) -> S -where - S: Stream, -{ - stream -} diff --git a/futures-util/src/stream/once.rs b/futures-util/src/stream/once.rs deleted file mode 100644 index ee21c8b594..0000000000 --- a/futures-util/src/stream/once.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::assert_stream; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -/// Creates a stream of a single element. -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// let stream = stream::once(async { 17 }); -/// let collected = stream.collect::>().await; -/// assert_eq!(collected, vec![17]); -/// # }); -/// ``` -pub fn once(future: Fut) -> Once { - assert_stream::(Once::new(future)) -} - -pin_project! { - /// A stream which emits single element and then EOF. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Once { - #[pin] - future: Option - } -} - -impl Once { - pub(crate) fn new(future: Fut) -> Self { - Self { future: Some(future) } - } -} - -impl Stream for Once { - type Item = Fut::Output; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - let v = match this.future.as_mut().as_pin_mut() { - Some(fut) => ready!(fut.poll(cx)), - None => return Poll::Ready(None), - }; - - this.future.set(None); - Poll::Ready(Some(v)) - } - - fn size_hint(&self) -> (usize, Option) { - if self.future.is_some() { - (1, Some(1)) - } else { - (0, Some(0)) - } - } -} - -impl FusedStream for Once { - fn is_terminated(&self) -> bool { - self.future.is_none() - } -} diff --git a/futures-util/src/stream/pending.rs b/futures-util/src/stream/pending.rs deleted file mode 100644 index d7030ff3cc..0000000000 --- a/futures-util/src/stream/pending.rs +++ /dev/null @@ -1,45 +0,0 @@ -use super::assert_stream; -use core::marker; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -/// Stream for the [`pending()`] function. -#[derive(Debug)] -#[must_use = "streams do nothing unless polled"] -pub struct Pending { - _data: marker::PhantomData, -} - -/// Creates a stream which never returns any elements. -/// -/// The returned stream will always return `Pending` when polled. -pub fn pending() -> Pending { - assert_stream::(Pending { _data: marker::PhantomData }) -} - -impl Unpin for Pending {} - -impl FusedStream for Pending { - fn is_terminated(&self) -> bool { - true - } -} - -impl Stream for Pending { - type Item = T; - - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Pending - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -impl Clone for Pending { - fn clone(&self) -> Self { - pending() - } -} diff --git a/futures-util/src/stream/poll_fn.rs b/futures-util/src/stream/poll_fn.rs deleted file mode 100644 index b9bd7d1664..0000000000 --- a/futures-util/src/stream/poll_fn.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Definition of the `PollFn` combinator - -use super::assert_stream; -use core::fmt; -use core::pin::Pin; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; - -/// Stream for the [`poll_fn`] function. -#[must_use = "streams do nothing unless polled"] -pub struct PollFn { - f: F, -} - -impl Unpin for PollFn {} - -impl fmt::Debug for PollFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PollFn").finish() - } -} - -/// Creates a new stream wrapping a function returning `Poll>`. -/// -/// Polling the returned stream calls the wrapped function. -/// -/// # Examples -/// -/// ``` -/// use futures::stream::poll_fn; -/// use futures::task::Poll; -/// -/// let mut counter = 1usize; -/// -/// let read_stream = poll_fn(move |_| -> Poll> { -/// if counter == 0 { return Poll::Ready(None); } -/// counter -= 1; -/// Poll::Ready(Some("Hello, World!".to_owned())) -/// }); -/// ``` -pub fn poll_fn(f: F) -> PollFn -where - F: FnMut(&mut Context<'_>) -> Poll>, -{ - assert_stream::(PollFn { f }) -} - -impl Stream for PollFn -where - F: FnMut(&mut Context<'_>) -> Poll>, -{ - type Item = T; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - (&mut self.f)(cx) - } -} diff --git a/futures-util/src/stream/poll_immediate.rs b/futures-util/src/stream/poll_immediate.rs deleted file mode 100644 index c7e8a5b3c6..0000000000 --- a/futures-util/src/stream/poll_immediate.rs +++ /dev/null @@ -1,80 +0,0 @@ -use core::pin::Pin; -use futures_core::task::{Context, Poll}; -use futures_core::Stream; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [poll_immediate](poll_immediate()) function. - /// - /// It will never return [Poll::Pending](core::task::Poll::Pending) - #[derive(Debug, Clone)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct PollImmediate { - #[pin] - stream: Option - } -} - -impl Stream for PollImmediate -where - S: Stream, -{ - type Item = Poll; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - let stream = match this.stream.as_mut().as_pin_mut() { - // inner is gone, so we can continue to signal that the stream is closed. - None => return Poll::Ready(None), - Some(inner) => inner, - }; - - match stream.poll_next(cx) { - Poll::Ready(Some(t)) => Poll::Ready(Some(Poll::Ready(t))), - Poll::Ready(None) => { - this.stream.set(None); - Poll::Ready(None) - } - Poll::Pending => Poll::Ready(Some(Poll::Pending)), - } - } - - fn size_hint(&self) -> (usize, Option) { - self.stream.as_ref().map_or((0, Some(0)), Stream::size_hint) - } -} - -impl super::FusedStream for PollImmediate { - fn is_terminated(&self) -> bool { - self.stream.is_none() - } -} - -/// Creates a new stream that always immediately returns [Poll::Ready](core::task::Poll::Ready) when awaiting it. -/// -/// This is useful when immediacy is more important than waiting for the next item to be ready. -/// -/// # Examples -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// use futures::task::Poll; -/// -/// let mut r = stream::poll_immediate(Box::pin(stream::iter(1_u32..3))); -/// assert_eq!(r.next().await, Some(Poll::Ready(1))); -/// assert_eq!(r.next().await, Some(Poll::Ready(2))); -/// assert_eq!(r.next().await, None); -/// -/// let mut p = stream::poll_immediate(Box::pin(stream::once(async { -/// futures::pending!(); -/// 42_u8 -/// }))); -/// assert_eq!(p.next().await, Some(Poll::Pending)); -/// assert_eq!(p.next().await, Some(Poll::Ready(42))); -/// assert_eq!(p.next().await, None); -/// # }); -/// ``` -pub fn poll_immediate(s: S) -> PollImmediate { - super::assert_stream::, PollImmediate>(PollImmediate { stream: Some(s) }) -} diff --git a/futures-util/src/stream/repeat.rs b/futures-util/src/stream/repeat.rs deleted file mode 100644 index e09cfa2e41..0000000000 --- a/futures-util/src/stream/repeat.rs +++ /dev/null @@ -1,58 +0,0 @@ -use super::assert_stream; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -/// Stream for the [`repeat`] function. -#[derive(Debug, Clone)] -#[must_use = "streams do nothing unless polled"] -pub struct Repeat { - item: T, -} - -/// Create a stream which produces the same item repeatedly. -/// -/// The stream never terminates. Note that you likely want to avoid -/// usage of `collect` or such on the returned stream as it will exhaust -/// available memory as it tries to just fill up all RAM. -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// let stream = stream::repeat(9); -/// assert_eq!(vec![9, 9, 9], stream.take(3).collect::>().await); -/// # }); -/// ``` -pub fn repeat(item: T) -> Repeat -where - T: Clone, -{ - assert_stream::(Repeat { item }) -} - -impl Unpin for Repeat {} - -impl Stream for Repeat -where - T: Clone, -{ - type Item = T; - - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Some(self.item.clone())) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -impl FusedStream for Repeat -where - T: Clone, -{ - fn is_terminated(&self) -> bool { - false - } -} diff --git a/futures-util/src/stream/repeat_with.rs b/futures-util/src/stream/repeat_with.rs deleted file mode 100644 index a482510705..0000000000 --- a/futures-util/src/stream/repeat_with.rs +++ /dev/null @@ -1,93 +0,0 @@ -use super::assert_stream; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -/// An stream that repeats elements of type `A` endlessly by -/// applying the provided closure `F: FnMut() -> A`. -/// -/// This `struct` is created by the [`repeat_with()`] function. -/// See its documentation for more. -#[derive(Debug, Clone)] -#[must_use = "streams do nothing unless polled"] -pub struct RepeatWith { - repeater: F, -} - -impl A> Unpin for RepeatWith {} - -impl A> Stream for RepeatWith { - type Item = A; - - fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Some((&mut self.repeater)())) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -impl A> FusedStream for RepeatWith { - fn is_terminated(&self) -> bool { - false - } -} - -/// Creates a new stream that repeats elements of type `A` endlessly by -/// applying the provided closure, the repeater, `F: FnMut() -> A`. -/// -/// 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. -/// -/// 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. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// // let's assume we have some value of a type that is not `Clone` -/// // or which don't want to have in memory just yet because it is expensive: -/// #[derive(PartialEq, Debug)] -/// struct Expensive; -/// -/// // a particular value forever: -/// let mut things = stream::repeat_with(|| Expensive); -/// -/// assert_eq!(Some(Expensive), things.next().await); -/// assert_eq!(Some(Expensive), things.next().await); -/// assert_eq!(Some(Expensive), things.next().await); -/// # }); -/// ``` -/// -/// Using mutation and going finite: -/// -/// ```rust -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// // From the zeroth to the third power of two: -/// let mut curr = 1; -/// let mut pow2 = stream::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) -/// .take(4); -/// -/// assert_eq!(Some(1), pow2.next().await); -/// assert_eq!(Some(2), pow2.next().await); -/// assert_eq!(Some(4), pow2.next().await); -/// assert_eq!(Some(8), pow2.next().await); -/// -/// // ... and now we're done -/// assert_eq!(None, pow2.next().await); -/// # }); -/// ``` -pub fn repeat_with A>(repeater: F) -> RepeatWith { - assert_stream::(RepeatWith { repeater }) -} diff --git a/futures-util/src/stream/select.rs b/futures-util/src/stream/select.rs deleted file mode 100644 index 0c1e3af782..0000000000 --- a/futures-util/src/stream/select.rs +++ /dev/null @@ -1,117 +0,0 @@ -use super::assert_stream; -use crate::stream::{select_with_strategy, PollNext, SelectWithStrategy}; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`select()`] function. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Select { - #[pin] - inner: SelectWithStrategy PollNext, PollNext>, - } -} - -/// This function will attempt to pull items from both streams. Each -/// stream will be polled in a round-robin fashion, and whenever a stream is -/// ready to yield an item that item is yielded. -/// -/// After one of the two input streams completes, the remaining one will be -/// polled exclusively. The returned stream completes when both input -/// streams have completed. -/// -/// Note that this function consumes both streams and returns a wrapped -/// version of them. -/// -/// ## Examples -/// -/// ```rust -/// # futures::executor::block_on(async { -/// use futures::stream::{ repeat, select, StreamExt }; -/// -/// let left = repeat(1); -/// let right = repeat(2); -/// -/// let mut out = select(left, right); -/// -/// for _ in 0..100 { -/// // We should be alternating. -/// assert_eq!(1, out.select_next_some().await); -/// assert_eq!(2, out.select_next_some().await); -/// } -/// # }); -/// ``` -pub fn select(stream1: St1, stream2: St2) -> Select -where - St1: Stream, - St2: Stream, -{ - fn round_robin(last: &mut PollNext) -> PollNext { - last.toggle() - } - - assert_stream::(Select { - inner: select_with_strategy(stream1, stream2, round_robin), - }) -} - -impl Select { - /// Acquires a reference to the underlying streams that this combinator is - /// pulling from. - pub fn get_ref(&self) -> (&St1, &St2) { - self.inner.get_ref() - } - - /// Acquires a mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_mut(&mut self) -> (&mut St1, &mut St2) { - self.inner.get_mut() - } - - /// Acquires a pinned mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut St1>, Pin<&mut St2>) { - let this = self.project(); - this.inner.get_pin_mut() - } - - /// Consumes this combinator, returning the underlying streams. - /// - /// Note that this may discard intermediate state of this combinator, so - /// care should be taken to avoid losing resources when this is called. - pub fn into_inner(self) -> (St1, St2) { - self.inner.into_inner() - } -} - -impl FusedStream for Select -where - St1: Stream, - St2: Stream, -{ - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl Stream for Select -where - St1: Stream, - St2: Stream, -{ - type Item = St1::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - this.inner.poll_next(cx) - } -} diff --git a/futures-util/src/stream/select_all.rs b/futures-util/src/stream/select_all.rs deleted file mode 100644 index fe7092cc19..0000000000 --- a/futures-util/src/stream/select_all.rs +++ /dev/null @@ -1,249 +0,0 @@ -//! An unbounded set of streams - -use core::fmt::{self, Debug}; -use core::iter::FromIterator; -use core::pin::Pin; - -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -use super::assert_stream; -use crate::stream::{futures_unordered, FuturesUnordered, StreamExt, StreamFuture}; - -/// An unbounded set of streams -/// -/// This "combinator" provides the ability to maintain a set of streams -/// and drive them all to completion. -/// -/// Streams are pushed into this set and their realized values are -/// yielded as they become ready. Streams will only be polled when they -/// generate notifications. This allows to coordinate a large number of streams. -/// -/// Note that you can create a ready-made `SelectAll` via the -/// `select_all` function in the `stream` module, or you can start with an -/// empty set with the `SelectAll::new` constructor. -#[must_use = "streams do nothing unless polled"] -pub struct SelectAll { - inner: FuturesUnordered>, -} - -impl Debug for SelectAll { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "SelectAll {{ ... }}") - } -} - -impl SelectAll { - /// Constructs a new, empty `SelectAll` - /// - /// The returned `SelectAll` does not contain any streams and, in this - /// state, `SelectAll::poll` will return `Poll::Ready(None)`. - pub fn new() -> Self { - Self { inner: FuturesUnordered::new() } - } - - /// Returns the number of streams contained in the set. - /// - /// This represents the total number of in-flight streams. - pub fn len(&self) -> usize { - self.inner.len() - } - - /// Returns `true` if the set contains no streams - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - /// Push a stream into the set. - /// - /// This function submits the given stream to the set for managing. This - /// function will not call `poll` on the submitted stream. The caller must - /// ensure that `SelectAll::poll` is called in order to receive task - /// notifications. - pub fn push(&self, stream: St) { - self.inner.push(stream.into_future()); - } - - /// Returns an iterator that allows inspecting each stream in the set. - pub fn iter(&self) -> Iter<'_, St> { - Iter(self.inner.iter()) - } - - /// Returns an iterator that allows modifying each stream in the set. - pub fn iter_mut(&mut self) -> IterMut<'_, St> { - IterMut(self.inner.iter_mut()) - } - - /// Clears the set, removing all streams. - pub fn clear(&mut self) { - self.inner.clear() - } -} - -impl Default for SelectAll { - fn default() -> Self { - Self::new() - } -} - -impl Stream for SelectAll { - type Item = St::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - match ready!(self.inner.poll_next_unpin(cx)) { - Some((Some(item), remaining)) => { - self.push(remaining); - return Poll::Ready(Some(item)); - } - Some((None, _)) => { - // `FuturesUnordered` thinks it isn't terminated - // because it yielded a Some. - // We do not return, but poll `FuturesUnordered` - // in the next loop iteration. - } - None => return Poll::Ready(None), - } - } - } -} - -impl FusedStream for SelectAll { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -/// Convert a list of streams into a `Stream` of results from the streams. -/// -/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.) -/// and bundles them together into a single stream. -/// The stream will yield items as they become available on the underlying -/// streams internally, in the order they become available. -/// -/// Note that the returned set can also be used to dynamically push more -/// streams into the set as they become available. -/// -/// This function is only available when the `std` or `alloc` feature of this -/// library is activated, and it is activated by default. -pub fn select_all(streams: I) -> SelectAll -where - I: IntoIterator, - I::Item: Stream + Unpin, -{ - let set = SelectAll::new(); - - for stream in streams { - set.push(stream); - } - - assert_stream::<::Item, _>(set) -} - -impl FromIterator for SelectAll { - fn from_iter>(iter: T) -> Self { - select_all(iter) - } -} - -impl Extend for SelectAll { - fn extend>(&mut self, iter: T) { - for st in iter { - self.push(st) - } - } -} - -impl IntoIterator for SelectAll { - type Item = St; - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter(self.inner.into_iter()) - } -} - -impl<'a, St: Stream + Unpin> IntoIterator for &'a SelectAll { - type Item = &'a St; - type IntoIter = Iter<'a, St>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, St: Stream + Unpin> IntoIterator for &'a mut SelectAll { - type Item = &'a mut St; - type IntoIter = IterMut<'a, St>; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -/// Immutable iterator over all streams in the unordered set. -#[derive(Debug)] -pub struct Iter<'a, St: Unpin>(futures_unordered::Iter<'a, StreamFuture>); - -/// Mutable iterator over all streams in the unordered set. -#[derive(Debug)] -pub struct IterMut<'a, St: Unpin>(futures_unordered::IterMut<'a, StreamFuture>); - -/// Owned iterator over all streams in the unordered set. -#[derive(Debug)] -pub struct IntoIter(futures_unordered::IntoIter>); - -impl<'a, St: Stream + Unpin> Iterator for Iter<'a, St> { - type Item = &'a St; - - fn next(&mut self) -> Option { - let st = self.0.next()?; - let next = st.get_ref(); - // This should always be true because FuturesUnordered removes completed futures. - debug_assert!(next.is_some()); - next - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -impl ExactSizeIterator for Iter<'_, St> {} - -impl<'a, St: Stream + Unpin> Iterator for IterMut<'a, St> { - type Item = &'a mut St; - - fn next(&mut self) -> Option { - let st = self.0.next()?; - let next = st.get_mut(); - // This should always be true because FuturesUnordered removes completed futures. - debug_assert!(next.is_some()); - next - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -impl ExactSizeIterator for IterMut<'_, St> {} - -impl Iterator for IntoIter { - type Item = St; - - fn next(&mut self) -> Option { - let st = self.0.next()?; - let next = st.into_inner(); - // This should always be true because FuturesUnordered removes completed futures. - debug_assert!(next.is_some()); - next - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -impl ExactSizeIterator for IntoIter {} diff --git a/futures-util/src/stream/select_with_strategy.rs b/futures-util/src/stream/select_with_strategy.rs deleted file mode 100644 index 4375f3e259..0000000000 --- a/futures-util/src/stream/select_with_strategy.rs +++ /dev/null @@ -1,302 +0,0 @@ -use super::assert_stream; -use core::{fmt, pin::Pin}; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -/// Type to tell [`SelectWithStrategy`] which stream to poll next. -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum PollNext { - /// Poll the first stream. - Left, - /// Poll the second stream. - Right, -} - -impl PollNext { - /// Toggle the value and return the old one. - #[must_use] - pub fn toggle(&mut self) -> Self { - let old = *self; - *self = self.other(); - old - } - - fn other(&self) -> Self { - match self { - Self::Left => Self::Right, - Self::Right => Self::Left, - } - } -} - -impl Default for PollNext { - fn default() -> Self { - Self::Left - } -} - -enum InternalState { - Start, - LeftFinished, - RightFinished, - BothFinished, -} - -impl InternalState { - fn finish(&mut self, ps: PollNext) { - match (&self, ps) { - (Self::Start, PollNext::Left) => { - *self = Self::LeftFinished; - } - (Self::Start, PollNext::Right) => { - *self = Self::RightFinished; - } - (Self::LeftFinished, PollNext::Right) | (Self::RightFinished, PollNext::Left) => { - *self = Self::BothFinished; - } - _ => {} - } - } -} - -pin_project! { - /// Stream for the [`select_with_strategy()`] function. See function docs for details. - #[must_use = "streams do nothing unless polled"] - #[project = SelectWithStrategyProj] - pub struct SelectWithStrategy { - #[pin] - stream1: St1, - #[pin] - stream2: St2, - internal_state: InternalState, - state: State, - clos: Clos, - } -} - -#[allow(clippy::too_long_first_doc_paragraph)] -/// This function will attempt to pull items from both streams. You provide a -/// closure to tell [`SelectWithStrategy`] which stream to poll. The closure can -/// store state on `SelectWithStrategy` to which it will receive a `&mut` on every -/// invocation. This allows basing the strategy on prior choices. -/// -/// After one of the two input streams completes, the remaining one will be -/// polled exclusively. The returned stream completes when both input -/// streams have completed. -/// -/// Note that this function consumes both streams and returns a wrapped -/// version of them. -/// -/// ## Examples -/// -/// ### Priority -/// This example shows how to always prioritize the left stream. -/// -/// ```rust -/// # futures::executor::block_on(async { -/// use futures::stream::{ repeat, select_with_strategy, PollNext, StreamExt }; -/// -/// let left = repeat(1); -/// let right = repeat(2); -/// -/// // We don't need any state, so let's make it an empty tuple. -/// // We must provide some type here, as there is no way for the compiler -/// // to infer it. As we don't need to capture variables, we can just -/// // use a function pointer instead of a closure. -/// fn prio_left(_: &mut ()) -> PollNext { PollNext::Left } -/// -/// let mut out = select_with_strategy(left, right, prio_left); -/// -/// for _ in 0..100 { -/// // Whenever we poll out, we will always get `1`. -/// assert_eq!(1, out.select_next_some().await); -/// } -/// # }); -/// ``` -/// -/// ### Round Robin -/// This example shows how to select from both streams round robin. -/// Note: this special case is provided by [`futures-util::stream::select`]. -/// -/// ```rust -/// # futures::executor::block_on(async { -/// use futures::stream::{ repeat, select_with_strategy, PollNext, StreamExt }; -/// -/// let left = repeat(1); -/// let right = repeat(2); -/// -/// let rrobin = |last: &mut PollNext| last.toggle(); -/// -/// let mut out = select_with_strategy(left, right, rrobin); -/// -/// for _ in 0..100 { -/// // We should be alternating now. -/// assert_eq!(1, out.select_next_some().await); -/// assert_eq!(2, out.select_next_some().await); -/// } -/// # }); -/// ``` -pub fn select_with_strategy( - stream1: St1, - stream2: St2, - which: Clos, -) -> SelectWithStrategy -where - St1: Stream, - St2: Stream, - Clos: FnMut(&mut State) -> PollNext, - State: Default, -{ - assert_stream::(SelectWithStrategy { - stream1, - stream2, - state: Default::default(), - internal_state: InternalState::Start, - clos: which, - }) -} - -impl SelectWithStrategy { - /// Acquires a reference to the underlying streams that this combinator is - /// pulling from. - pub fn get_ref(&self) -> (&St1, &St2) { - (&self.stream1, &self.stream2) - } - - /// Acquires a mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_mut(&mut self) -> (&mut St1, &mut St2) { - (&mut self.stream1, &mut self.stream2) - } - - /// Acquires a pinned mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut St1>, Pin<&mut St2>) { - let this = self.project(); - (this.stream1, this.stream2) - } - - /// Consumes this combinator, returning the underlying streams. - /// - /// Note that this may discard intermediate state of this combinator, so - /// care should be taken to avoid losing resources when this is called. - pub fn into_inner(self) -> (St1, St2) { - (self.stream1, self.stream2) - } -} - -impl FusedStream for SelectWithStrategy -where - St1: Stream, - St2: Stream, - Clos: FnMut(&mut State) -> PollNext, -{ - fn is_terminated(&self) -> bool { - matches!(self.internal_state, InternalState::BothFinished) - } -} - -#[inline] -fn poll_side( - select: &mut SelectWithStrategyProj<'_, St1, St2, Clos, State>, - side: PollNext, - cx: &mut Context<'_>, -) -> Poll> -where - St1: Stream, - St2: Stream, -{ - match side { - PollNext::Left => select.stream1.as_mut().poll_next(cx), - PollNext::Right => select.stream2.as_mut().poll_next(cx), - } -} - -#[inline] -fn poll_inner( - select: &mut SelectWithStrategyProj<'_, St1, St2, Clos, State>, - side: PollNext, - cx: &mut Context<'_>, -) -> Poll> -where - St1: Stream, - St2: Stream, -{ - let first_done = match poll_side(select, side, cx) { - Poll::Ready(Some(item)) => return Poll::Ready(Some(item)), - Poll::Ready(None) => { - select.internal_state.finish(side); - true - } - Poll::Pending => false, - }; - let other = side.other(); - match poll_side(select, other, cx) { - Poll::Ready(None) => { - select.internal_state.finish(other); - if first_done { - Poll::Ready(None) - } else { - Poll::Pending - } - } - a => a, - } -} - -impl Stream for SelectWithStrategy -where - St1: Stream, - St2: Stream, - Clos: FnMut(&mut State) -> PollNext, -{ - type Item = St1::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - match this.internal_state { - InternalState::Start => { - let next_side = (this.clos)(this.state); - poll_inner(&mut this, next_side, cx) - } - InternalState::LeftFinished => match this.stream2.poll_next(cx) { - Poll::Ready(None) => { - *this.internal_state = InternalState::BothFinished; - Poll::Ready(None) - } - a => a, - }, - InternalState::RightFinished => match this.stream1.poll_next(cx) { - Poll::Ready(None) => { - *this.internal_state = InternalState::BothFinished; - Poll::Ready(None) - } - a => a, - }, - InternalState::BothFinished => Poll::Ready(None), - } - } -} - -impl fmt::Debug for SelectWithStrategy -where - St1: fmt::Debug, - St2: fmt::Debug, - State: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SelectWithStrategy") - .field("stream1", &self.stream1) - .field("stream2", &self.stream2) - .field("state", &self.state) - .finish() - } -} diff --git a/futures-util/src/stream/stream/all.rs b/futures-util/src/stream/stream/all.rs deleted file mode 100644 index 1435c798f2..0000000000 --- a/futures-util/src/stream/stream/all.rs +++ /dev/null @@ -1,93 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`all`](super::StreamExt::all) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct All { - #[pin] - stream: St, - f: F, - done: bool, - #[pin] - future: Option, - } -} - -impl fmt::Debug for All -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("All") - .field("stream", &self.stream) - .field("done", &self.done) - .field("future", &self.future) - .finish() - } -} - -impl All -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, done: false, future: None } - } -} - -impl FusedFuture for All -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.done && self.future.is_none() - } -} - -impl Future for All -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - type Output = bool; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new value - let res = ready!(fut.poll(cx)); - this.future.set(None); - if !res { - *this.done = true; - break false; - } // early exit - } else if !*this.done { - // we're waiting on a new item from the stream - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(item) => { - this.future.set(Some((this.f)(item))); - } - None => { - *this.done = true; - break true; - } - } - } else { - panic!("All polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/stream/any.rs b/futures-util/src/stream/stream/any.rs deleted file mode 100644 index cc3d695b9d..0000000000 --- a/futures-util/src/stream/stream/any.rs +++ /dev/null @@ -1,93 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`any`](super::StreamExt::any) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Any { - #[pin] - stream: St, - f: F, - done: bool, - #[pin] - future: Option, - } -} - -impl fmt::Debug for Any -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Any") - .field("stream", &self.stream) - .field("done", &self.done) - .field("future", &self.future) - .finish() - } -} - -impl Any -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, done: false, future: None } - } -} - -impl FusedFuture for Any -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.done && self.future.is_none() - } -} - -impl Future for Any -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - type Output = bool; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new value - let res = ready!(fut.poll(cx)); - this.future.set(None); - if res { - *this.done = true; - break true; - } // early exit - } else if !*this.done { - // we're waiting on a new item from the stream - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(item) => { - this.future.set(Some((this.f)(item))); - } - None => { - *this.done = true; - break false; - } - } - } else { - panic!("Any polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/stream/buffer_unordered.rs b/futures-util/src/stream/stream/buffer_unordered.rs deleted file mode 100644 index 22a525cde6..0000000000 --- a/futures-util/src/stream/stream/buffer_unordered.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::stream::{Fuse, FuturesUnordered, StreamExt}; -use core::fmt; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`buffer_unordered`](super::StreamExt::buffer_unordered) - /// method. - #[must_use = "streams do nothing unless polled"] - pub struct BufferUnordered - where - St: Stream, - { - #[pin] - stream: Fuse, - in_progress_queue: FuturesUnordered, - max: Option, - } -} - -impl fmt::Debug for BufferUnordered -where - St: Stream + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BufferUnordered") - .field("stream", &self.stream) - .field("in_progress_queue", &self.in_progress_queue) - .field("max", &self.max) - .finish() - } -} - -impl BufferUnordered -where - St: Stream, - St::Item: Future, -{ - pub(super) fn new(stream: St, n: Option) -> Self { - Self { - stream: super::Fuse::new(stream), - in_progress_queue: FuturesUnordered::new(), - max: n.and_then(NonZeroUsize::new), - } - } - - delegate_access_inner!(stream, St, (.)); -} - -impl Stream for BufferUnordered -where - St: Stream, - St::Item: Future, -{ - type Item = ::Output; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - // First up, try to spawn off as many futures as possible by filling up - // our queue of futures. - while this.max.map(|max| this.in_progress_queue.len() < max.get()).unwrap_or(true) { - match this.stream.as_mut().poll_next(cx) { - Poll::Ready(Some(fut)) => this.in_progress_queue.push(fut), - Poll::Ready(None) | Poll::Pending => break, - } - } - - // Attempt to pull the next value from the in_progress_queue - match this.in_progress_queue.poll_next_unpin(cx) { - x @ Poll::Pending | x @ Poll::Ready(Some(_)) => return x, - Poll::Ready(None) => {} - } - - // If more values are still coming from the stream, we're not done yet - if this.stream.is_done() { - Poll::Ready(None) - } else { - Poll::Pending - } - } - - fn size_hint(&self) -> (usize, Option) { - let queue_len = self.in_progress_queue.len(); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(queue_len); - let upper = match upper { - Some(x) => x.checked_add(queue_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for BufferUnordered -where - St: Stream, - St::Item: Future, -{ - fn is_terminated(&self) -> bool { - self.in_progress_queue.is_terminated() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for BufferUnordered -where - S: Stream + Sink, - S::Item: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/buffered.rs b/futures-util/src/stream/stream/buffered.rs deleted file mode 100644 index 41e2948639..0000000000 --- a/futures-util/src/stream/stream/buffered.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::stream::{Fuse, FusedStream, FuturesOrdered, StreamExt}; -use core::fmt; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`buffered`](super::StreamExt::buffered) method. - #[must_use = "streams do nothing unless polled"] - pub struct Buffered - where - St: Stream, - St::Item: Future, - { - #[pin] - stream: Fuse, - in_progress_queue: FuturesOrdered, - max: Option, - } -} - -impl fmt::Debug for Buffered -where - St: Stream + fmt::Debug, - St::Item: Future, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Buffered") - .field("stream", &self.stream) - .field("in_progress_queue", &self.in_progress_queue) - .field("max", &self.max) - .finish() - } -} - -impl Buffered -where - St: Stream, - St::Item: Future, -{ - pub(super) fn new(stream: St, n: Option) -> Self { - Self { - stream: super::Fuse::new(stream), - in_progress_queue: FuturesOrdered::new(), - max: n.and_then(NonZeroUsize::new), - } - } - - delegate_access_inner!(stream, St, (.)); -} - -impl Stream for Buffered -where - St: Stream, - St::Item: Future, -{ - type Item = ::Output; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - // First up, try to spawn off as many futures as possible by filling up - // our queue of futures. - while this.max.map(|max| this.in_progress_queue.len() < max.get()).unwrap_or(true) { - match this.stream.as_mut().poll_next(cx) { - Poll::Ready(Some(fut)) => this.in_progress_queue.push_back(fut), - Poll::Ready(None) | Poll::Pending => break, - } - } - - // Attempt to pull the next value from the in_progress_queue - let res = this.in_progress_queue.poll_next_unpin(cx); - if let Some(val) = ready!(res) { - return Poll::Ready(Some(val)); - } - - // If more values are still coming from the stream, we're not done yet - if this.stream.is_done() { - Poll::Ready(None) - } else { - Poll::Pending - } - } - - fn size_hint(&self) -> (usize, Option) { - let queue_len = self.in_progress_queue.len(); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(queue_len); - let upper = match upper { - Some(x) => x.checked_add(queue_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for Buffered -where - St: Stream, - St::Item: Future, -{ - fn is_terminated(&self) -> bool { - self.stream.is_done() && self.in_progress_queue.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Buffered -where - S: Stream + Sink, - S::Item: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/catch_unwind.rs b/futures-util/src/stream/stream/catch_unwind.rs deleted file mode 100644 index dfc388839d..0000000000 --- a/futures-util/src/stream/stream/catch_unwind.rs +++ /dev/null @@ -1,62 +0,0 @@ -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; -use std::any::Any; -use std::boxed::Box; -use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe}; -use std::pin::Pin; - -pin_project! { - /// Stream for the [`catch_unwind`](super::StreamExt::catch_unwind) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct CatchUnwind { - #[pin] - stream: St, - caught_unwind: bool, - } -} - -impl CatchUnwind { - pub(super) fn new(stream: St) -> Self { - Self { stream, caught_unwind: false } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for CatchUnwind { - type Item = Result>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if *this.caught_unwind { - Poll::Ready(None) - } else { - let res = catch_unwind(AssertUnwindSafe(|| this.stream.as_mut().poll_next(cx))); - - match res { - Ok(poll) => poll.map(|opt| opt.map(Ok)), - Err(e) => { - *this.caught_unwind = true; - Poll::Ready(Some(Err(e))) - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.caught_unwind { - (0, Some(0)) - } else { - self.stream.size_hint() - } - } -} - -impl FusedStream for CatchUnwind { - fn is_terminated(&self) -> bool { - self.caught_unwind || self.stream.is_terminated() - } -} diff --git a/futures-util/src/stream/stream/chain.rs b/futures-util/src/stream/stream/chain.rs deleted file mode 100644 index 36ff1e533d..0000000000 --- a/futures-util/src/stream/stream/chain.rs +++ /dev/null @@ -1,76 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`chain`](super::StreamExt::chain) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Chain { - #[pin] - first: Option, - #[pin] - second: St2, - } -} - -// All interactions with `Pin<&mut Chain<..>>` happen through these methods -impl Chain -where - St1: Stream, - St2: Stream, -{ - pub(super) fn new(stream1: St1, stream2: St2) -> Self { - Self { first: Some(stream1), second: stream2 } - } -} - -impl FusedStream for Chain -where - St1: Stream, - St2: FusedStream, -{ - fn is_terminated(&self) -> bool { - self.first.is_none() && self.second.is_terminated() - } -} - -impl Stream for Chain -where - St1: Stream, - St2: Stream, -{ - type Item = St1::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - if let Some(first) = this.first.as_mut().as_pin_mut() { - if let Some(item) = ready!(first.poll_next(cx)) { - return Poll::Ready(Some(item)); - } - - this.first.set(None); - } - this.second.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - if let Some(first) = &self.first { - let (first_lower, first_upper) = first.size_hint(); - let (second_lower, second_upper) = self.second.size_hint(); - - let lower = first_lower.saturating_add(second_lower); - - let upper = match (first_upper, second_upper) { - (Some(x), Some(y)) => x.checked_add(y), - _ => None, - }; - - (lower, upper) - } else { - self.second.size_hint() - } - } -} diff --git a/futures-util/src/stream/stream/chunks.rs b/futures-util/src/stream/stream/chunks.rs deleted file mode 100644 index 2a71ebc6cc..0000000000 --- a/futures-util/src/stream/stream/chunks.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::stream::Fuse; -use alloc::vec::Vec; -use core::mem; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`chunks`](super::StreamExt::chunks) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Chunks { - #[pin] - stream: Fuse, - items: Vec, - cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 - } -} - -impl Chunks { - pub(super) fn new(stream: St, capacity: usize) -> Self { - assert!(capacity > 0); - - Self { - stream: super::Fuse::new(stream), - items: Vec::with_capacity(capacity), - cap: capacity, - } - } - - fn take(self: Pin<&mut Self>) -> Vec { - let cap = self.cap; - mem::replace(self.project().items, Vec::with_capacity(cap)) - } - - delegate_access_inner!(stream, St, (.)); -} - -impl Stream for Chunks { - type Item = Vec; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.as_mut().project(); - loop { - match ready!(this.stream.as_mut().poll_next(cx)) { - // Push the item into the buffer and check whether it is full. - // If so, replace our buffer with a new and empty one and return - // the full one. - Some(item) => { - this.items.push(item); - if this.items.len() >= *this.cap { - return Poll::Ready(Some(self.take())); - } - } - - // Since the underlying stream ran out of values, return what we - // have buffered, if we have anything. - None => { - let last = if this.items.is_empty() { - None - } else { - let full_buf = mem::take(this.items); - Some(full_buf) - }; - - return Poll::Ready(last); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let chunk_len = usize::from(!self.items.is_empty()); - let (lower, upper) = self.stream.size_hint(); - let lower = (lower / self.cap).saturating_add(chunk_len); - let upper = match upper { - Some(x) => x.checked_add(chunk_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for Chunks { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() && self.items.is_empty() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Chunks -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/collect.rs b/futures-util/src/stream/stream/collect.rs deleted file mode 100644 index 970ac26dbf..0000000000 --- a/futures-util/src/stream/stream/collect.rs +++ /dev/null @@ -1,56 +0,0 @@ -use core::mem; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`collect`](super::StreamExt::collect) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Collect { - #[pin] - stream: St, - collection: C, - } -} - -impl Collect { - fn finish(self: Pin<&mut Self>) -> C { - mem::take(self.project().collection) - } - - pub(super) fn new(stream: St) -> Self { - Self { stream, collection: Default::default() } - } -} - -impl FusedFuture for Collect -where - St: FusedStream, - C: Default + Extend, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for Collect -where - St: Stream, - C: Default + Extend, -{ - type Output = C; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.as_mut().project(); - loop { - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(e) => this.collection.extend(Some(e)), - None => return Poll::Ready(self.finish()), - } - } - } -} diff --git a/futures-util/src/stream/stream/concat.rs b/futures-util/src/stream/stream/concat.rs deleted file mode 100644 index 7e058b2315..0000000000 --- a/futures-util/src/stream/stream/concat.rs +++ /dev/null @@ -1,62 +0,0 @@ -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`concat`](super::StreamExt::concat) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Concat { - #[pin] - stream: St, - accum: Option, - } -} - -impl Concat -where - St: Stream, - St::Item: Extend<::Item> + IntoIterator + Default, -{ - pub(super) fn new(stream: St) -> Self { - Self { stream, accum: None } - } -} - -impl Future for Concat -where - St: Stream, - St::Item: Extend<::Item> + IntoIterator + Default, -{ - type Output = St::Item; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - - loop { - match ready!(this.stream.as_mut().poll_next(cx)) { - None => return Poll::Ready(this.accum.take().unwrap_or_default()), - Some(e) => { - if let Some(a) = this.accum { - a.extend(e) - } else { - *this.accum = Some(e) - } - } - } - } - } -} - -impl FusedFuture for Concat -where - St: FusedStream, - St::Item: Extend<::Item> + IntoIterator + Default, -{ - fn is_terminated(&self) -> bool { - self.accum.is_none() && self.stream.is_terminated() - } -} diff --git a/futures-util/src/stream/stream/count.rs b/futures-util/src/stream/stream/count.rs deleted file mode 100644 index 513cab7b6a..0000000000 --- a/futures-util/src/stream/stream/count.rs +++ /dev/null @@ -1,53 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`count`](super::StreamExt::count) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Count { - #[pin] - stream: St, - count: usize - } -} - -impl fmt::Debug for Count -where - St: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Count").field("stream", &self.stream).field("count", &self.count).finish() - } -} - -impl Count { - pub(super) fn new(stream: St) -> Self { - Self { stream, count: 0 } - } -} - -impl FusedFuture for Count { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for Count { - type Output = usize; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - - Poll::Ready(loop { - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(_) => *this.count += 1, - None => break *this.count, - } - }) - } -} diff --git a/futures-util/src/stream/stream/cycle.rs b/futures-util/src/stream/stream/cycle.rs deleted file mode 100644 index 9e0f50e92f..0000000000 --- a/futures-util/src/stream/stream/cycle.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`cycle`](super::StreamExt::cycle) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Cycle { - orig: St, - #[pin] - stream: St, - } -} - -impl Cycle -where - St: Clone + Stream, -{ - pub(super) fn new(stream: St) -> Self { - Self { orig: stream.clone(), stream } - } -} - -impl Stream for Cycle -where - St: Clone + Stream, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - match ready!(this.stream.as_mut().poll_next(cx)) { - None => { - this.stream.set(this.orig.clone()); - this.stream.poll_next(cx) - } - item => Poll::Ready(item), - } - } - - fn size_hint(&self) -> (usize, Option) { - // the cycle stream is either empty or infinite - match self.orig.size_hint() { - size @ (0, Some(0)) => size, - (0, _) => (0, None), - _ => (usize::MAX, None), - } - } -} - -impl FusedStream for Cycle -where - St: Clone + Stream, -{ - fn is_terminated(&self) -> bool { - // the cycle stream is either empty or infinite - matches!(self.size_hint(), (0, Some(0))) - } -} diff --git a/futures-util/src/stream/stream/enumerate.rs b/futures-util/src/stream/stream/enumerate.rs deleted file mode 100644 index 1cf9d49aaa..0000000000 --- a/futures-util/src/stream/stream/enumerate.rs +++ /dev/null @@ -1,64 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`enumerate`](super::StreamExt::enumerate) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Enumerate { - #[pin] - stream: St, - count: usize, - } -} - -impl Enumerate { - pub(super) fn new(stream: St) -> Self { - Self { stream, count: 0 } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Enumerate { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Stream for Enumerate { - type Item = (usize, St::Item); - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - match ready!(this.stream.poll_next(cx)) { - Some(item) => { - let prev_count = *this.count; - *this.count += 1; - Poll::Ready(Some((prev_count, item))) - } - None => Poll::Ready(None), - } - } - - fn size_hint(&self) -> (usize, Option) { - self.stream.size_hint() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Enumerate -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/filter.rs b/futures-util/src/stream/stream/filter.rs deleted file mode 100644 index db67144bc1..0000000000 --- a/futures-util/src/stream/stream/filter.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::fns::FnMut1; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`filter`](super::StreamExt::filter) method. - #[must_use = "streams do nothing unless polled"] - pub struct Filter - where St: Stream, - { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - } -} - -impl fmt::Debug for Filter -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Filter") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .finish() - } -} - -impl Filter -where - St: Stream, - F: for<'a> FnMut1<&'a St::Item, Output = Fut>, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Filter -where - St: Stream + FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.pending_fut.is_none() && self.stream.is_terminated() - } -} - -impl Stream for Filter -where - St: Stream, - F: for<'a> FnMut1<&'a St::Item, Output = Fut>, - Fut: Future, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let res = ready!(fut.poll(cx)); - this.pending_fut.set(None); - if res { - break this.pending_item.take(); - } - *this.pending_item = None; - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - this.pending_fut.set(Some(this.f.call_mut(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let pending_len = usize::from(self.pending_item.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Filter -where - S: Stream + Sink, - F: FnMut(&S::Item) -> Fut, - Fut: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/filter_map.rs b/futures-util/src/stream/stream/filter_map.rs deleted file mode 100644 index 6b7d0070df..0000000000 --- a/futures-util/src/stream/stream/filter_map.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::fns::FnMut1; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`filter_map`](super::StreamExt::filter_map) method. - #[must_use = "streams do nothing unless polled"] - pub struct FilterMap { - #[pin] - stream: St, - f: F, - #[pin] - pending: Option, - } -} - -impl fmt::Debug for FilterMap -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FilterMap") - .field("stream", &self.stream) - .field("pending", &self.pending) - .finish() - } -} - -impl FilterMap -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for FilterMap -where - St: Stream + FusedStream, - F: FnMut1, - Fut: Future>, -{ - fn is_terminated(&self) -> bool { - self.pending.is_none() && self.stream.is_terminated() - } -} - -impl Stream for FilterMap -where - St: Stream, - F: FnMut1, - Fut: Future>, -{ - type Item = T; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(p) = this.pending.as_mut().as_pin_mut() { - // We have an item in progress, poll that until it's done - let item = ready!(p.poll(cx)); - this.pending.set(None); - if item.is_some() { - break item; - } - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - // No item in progress, but the stream is still going - this.pending.set(Some(this.f.call_mut(item))); - } else { - // The stream is done - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let pending_len = usize::from(self.pending.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for FilterMap -where - S: Stream + Sink, - F: FnMut1, - Fut: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/flatten.rs b/futures-util/src/stream/stream/flatten.rs deleted file mode 100644 index 9f6b7a472d..0000000000 --- a/futures-util/src/stream/stream/flatten.rs +++ /dev/null @@ -1,73 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`flatten`](super::StreamExt::flatten) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Flatten { - #[pin] - stream: St, - #[pin] - next: Option, - } -} - -impl Flatten { - pub(super) fn new(stream: St) -> Self { - Self { stream, next: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Flatten -where - St: FusedStream, - St::Item: Stream, -{ - fn is_terminated(&self) -> bool { - self.next.is_none() && self.stream.is_terminated() - } -} - -impl Stream for Flatten -where - St: Stream, - St::Item: Stream, -{ - type Item = ::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(s) = this.next.as_mut().as_pin_mut() { - if let Some(item) = ready!(s.poll_next(cx)) { - break Some(item); - } else { - this.next.set(None); - } - } else if let Some(s) = ready!(this.stream.as_mut().poll_next(cx)) { - this.next.set(Some(s)); - } else { - break None; - } - }) - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Flatten -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/flatten_unordered.rs b/futures-util/src/stream/stream/flatten_unordered.rs deleted file mode 100644 index c79edbd213..0000000000 --- a/futures-util/src/stream/stream/flatten_unordered.rs +++ /dev/null @@ -1,531 +0,0 @@ -use alloc::sync::Arc; -use core::{ - cell::UnsafeCell, - convert::identity, - fmt, - marker::PhantomData, - num::NonZeroUsize, - pin::Pin, - sync::atomic::{AtomicU8, Ordering}, -}; - -use pin_project_lite::pin_project; - -use futures_core::{ - future::Future, - ready, - stream::{FusedStream, Stream}, - task::{Context, Poll, Waker}, -}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use futures_task::{waker, ArcWake}; - -use crate::stream::FuturesUnordered; - -/// Stream for the [`flatten_unordered`](super::StreamExt::flatten_unordered) -/// method. -pub type FlattenUnordered = FlattenUnorderedWithFlowController; - -/// There is nothing to poll and stream isn't being polled/waking/woken at the moment. -const NONE: u8 = 0; - -/// Inner streams need to be polled. -const NEED_TO_POLL_INNER_STREAMS: u8 = 1; - -/// The base stream needs to be polled. -const NEED_TO_POLL_STREAM: u8 = 0b10; - -/// Both base stream and inner streams need to be polled. -const NEED_TO_POLL_ALL: u8 = NEED_TO_POLL_INNER_STREAMS | NEED_TO_POLL_STREAM; - -/// The current stream is being polled at the moment. -const POLLING: u8 = 0b100; - -/// Stream is being woken at the moment. -const WAKING: u8 = 0b1000; - -/// The stream was waked and will be polled. -const WOKEN: u8 = 0b10000; - -/// Internal polling state of the stream. -#[derive(Clone, Debug)] -struct SharedPollState { - state: Arc, -} - -impl SharedPollState { - /// Constructs new `SharedPollState` with the given state. - fn new(value: u8) -> Self { - Self { state: Arc::new(AtomicU8::new(value)) } - } - - /// Attempts to start polling, returning stored state in case of success. - /// Returns `None` if either waker is waking at the moment. - fn start_polling(&self) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&Self) -> u8>)> { - let value = self - .state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { - if value & WAKING == NONE { - Some(POLLING) - } else { - None - } - }) - .ok()?; - let bomb = PollStateBomb::new(self, Self::reset); - - Some((value, bomb)) - } - - /// Attempts to start the waking process and performs bitwise or with the given value. - /// - /// If some waker is already in progress or stream is already woken/being polled, waking process won't start, however - /// state will be disjuncted with the given value. - fn start_waking( - &self, - to_poll: u8, - ) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&Self) -> u8>)> { - let value = self - .state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { - let mut next_value = value | to_poll; - if value & (WOKEN | POLLING) == NONE { - next_value |= WAKING; - } - - if next_value != value { - Some(next_value) - } else { - None - } - }) - .ok()?; - - // Only start the waking process if we're not in the polling/waking phase and the stream isn't woken already - if value & (WOKEN | POLLING | WAKING) == NONE { - let bomb = PollStateBomb::new(self, Self::stop_waking); - - Some((value, bomb)) - } else { - None - } - } - - /// Sets current state to - /// - `!POLLING` allowing to use wakers - /// - `WOKEN` if the state was changed during `POLLING` phase as waker will be called, - /// or `will_be_woken` flag supplied - /// - `!WAKING` as - /// * Wakers called during the `POLLING` phase won't propagate their calls - /// * `POLLING` phase can't start if some of the wakers are active - /// So no wrapped waker can touch the inner waker's cell, it's safe to poll again. - fn stop_polling(&self, to_poll: u8, will_be_woken: bool) -> u8 { - self.state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |mut value| { - let mut next_value = to_poll; - - value &= NEED_TO_POLL_ALL; - if value != NONE || will_be_woken { - next_value |= WOKEN; - } - next_value |= value; - - Some(next_value & !POLLING & !WAKING) - }) - .unwrap() - } - - /// Toggles state to non-waking, allowing to start polling. - fn stop_waking(&self) -> u8 { - let value = self - .state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| { - let next_value = value & !WAKING | WOKEN; - - if next_value != value { - Some(next_value) - } else { - None - } - }) - .unwrap_or_else(identity); - - debug_assert!(value & (WOKEN | POLLING | WAKING) == WAKING); - value - } - - /// Resets current state allowing to poll the stream and wake up wakers. - fn reset(&self) -> u8 { - self.state.swap(NEED_TO_POLL_ALL, Ordering::SeqCst) - } -} - -/// Used to execute some function on the given state when dropped. -struct PollStateBomb<'a, F: FnOnce(&SharedPollState) -> u8> { - state: &'a SharedPollState, - drop: Option, -} - -impl<'a, F: FnOnce(&SharedPollState) -> u8> PollStateBomb<'a, F> { - /// Constructs new bomb with the given state. - fn new(state: &'a SharedPollState, drop: F) -> Self { - Self { state, drop: Some(drop) } - } - - /// Deactivates bomb, forces it to not call provided function when dropped. - fn deactivate(mut self) { - self.drop.take(); - } -} - -impl u8> Drop for PollStateBomb<'_, F> { - fn drop(&mut self) { - if let Some(drop) = self.drop.take() { - (drop)(self.state); - } - } -} - -/// Will update state with the provided value on `wake_by_ref` call -/// and then, if there is a need, call `inner_waker`. -struct WrappedWaker { - inner_waker: UnsafeCell>, - poll_state: SharedPollState, - need_to_poll: u8, -} - -unsafe impl Send for WrappedWaker {} -unsafe impl Sync for WrappedWaker {} - -impl WrappedWaker { - /// Replaces given waker's inner_waker for polling stream/futures which will - /// update poll state on `wake_by_ref` call. Use only if you need several - /// contexts. - /// - /// ## Safety - /// - /// This function will modify waker's `inner_waker` via `UnsafeCell`, so - /// it should be used only during `POLLING` phase by one thread at the time. - unsafe fn replace_waker(self_arc: &mut Arc, cx: &Context<'_>) { - unsafe { *self_arc.inner_waker.get() = cx.waker().clone().into() } - } - - /// Attempts to start the waking process for the waker with the given value. - /// If succeeded, then the stream isn't yet woken and not being polled at the moment. - fn start_waking(&self) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&SharedPollState) -> u8>)> { - self.poll_state.start_waking(self.need_to_poll) - } -} - -impl ArcWake for WrappedWaker { - fn wake_by_ref(self_arc: &Arc) { - if let Some((_, state_bomb)) = self_arc.start_waking() { - // Safety: now state is not `POLLING` - let waker_opt = unsafe { self_arc.inner_waker.get().as_ref().unwrap() }; - - if let Some(inner_waker) = waker_opt.clone() { - // Stop waking to allow polling stream - drop(state_bomb); - - // Wake up inner waker - inner_waker.wake(); - } - } - } -} - -pin_project! { - /// Future which polls optional inner stream. - /// - /// If it's `Some`, it will attempt to call `poll_next` on it, - /// returning `Some((item, next_item_fut))` in case of `Poll::Ready(Some(...))` - /// or `None` in case of `Poll::Ready(None)`. - /// - /// If `poll_next` will return `Poll::Pending`, it will be forwarded to - /// the future and current task will be notified by waker. - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct PollStreamFut { - #[pin] - stream: Option, - } -} - -impl PollStreamFut { - /// Constructs new `PollStreamFut` using given `stream`. - fn new(stream: impl Into>) -> Self { - Self { stream: stream.into() } - } -} - -impl Future for PollStreamFut { - type Output = Option<(St::Item, Self)>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut stream = self.project().stream; - - let item = if let Some(stream) = stream.as_mut().as_pin_mut() { - ready!(stream.poll_next(cx)) - } else { - None - }; - let next_item_fut = Self::new(stream.get_mut().take()); - let out = item.map(|item| (item, next_item_fut)); - - Poll::Ready(out) - } -} - -pin_project! { - /// Stream for the [`flatten_unordered`](super::StreamExt::flatten_unordered) - /// method with ability to specify flow controller. - #[project = FlattenUnorderedWithFlowControllerProj] - #[must_use = "streams do nothing unless polled"] - pub struct FlattenUnorderedWithFlowController where St: Stream { - #[pin] - inner_streams: FuturesUnordered>, - #[pin] - stream: St, - poll_state: SharedPollState, - limit: Option, - is_stream_done: bool, - inner_streams_waker: Arc, - stream_waker: Arc, - flow_controller: PhantomData - } -} - -impl fmt::Debug for FlattenUnorderedWithFlowController -where - St: Stream + fmt::Debug, - St::Item: Stream + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FlattenUnorderedWithFlowController") - .field("poll_state", &self.poll_state) - .field("inner_streams", &self.inner_streams) - .field("limit", &self.limit) - .field("stream", &self.stream) - .field("is_stream_done", &self.is_stream_done) - .field("flow_controller", &self.flow_controller) - .finish() - } -} - -impl FlattenUnorderedWithFlowController -where - St: Stream, - Fc: FlowController::Item>, - St::Item: Stream + Unpin, -{ - pub(crate) fn new(stream: St, limit: Option) -> Self { - let poll_state = SharedPollState::new(NEED_TO_POLL_STREAM); - - Self { - inner_streams: FuturesUnordered::new(), - stream, - is_stream_done: false, - limit: limit.and_then(NonZeroUsize::new), - inner_streams_waker: Arc::new(WrappedWaker { - inner_waker: UnsafeCell::new(None), - poll_state: poll_state.clone(), - need_to_poll: NEED_TO_POLL_INNER_STREAMS, - }), - stream_waker: Arc::new(WrappedWaker { - inner_waker: UnsafeCell::new(None), - poll_state: poll_state.clone(), - need_to_poll: NEED_TO_POLL_STREAM, - }), - poll_state, - flow_controller: PhantomData, - } - } - - delegate_access_inner!(stream, St, ()); -} - -/// Returns the next flow step based on the received item. -pub trait FlowController { - /// Handles an item producing `FlowStep` describing the next flow step. - fn next_step(item: I) -> FlowStep; -} - -impl FlowController for () { - fn next_step(item: I) -> FlowStep { - FlowStep::Continue(item) - } -} - -/// Describes the next flow step. -#[derive(Debug, Clone)] -pub enum FlowStep { - /// Just yields an item and continues standard flow. - Continue(C), - /// Immediately returns an underlying item from the function. - Return(R), -} - -impl FlattenUnorderedWithFlowControllerProj<'_, St, Fc> -where - St: Stream, -{ - /// Checks if current `inner_streams` bucket size is greater than optional limit. - fn is_exceeded_limit(&self) -> bool { - self.limit.map_or(false, |limit| self.inner_streams.len() >= limit.get()) - } -} - -impl FusedStream for FlattenUnorderedWithFlowController -where - St: FusedStream, - Fc: FlowController::Item>, - St::Item: Stream + Unpin, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() && self.inner_streams.is_empty() - } -} - -impl Stream for FlattenUnorderedWithFlowController -where - St: Stream, - Fc: FlowController::Item>, - St::Item: Stream + Unpin, -{ - type Item = ::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut next_item = None; - let mut need_to_poll_next = NONE; - - let mut this = self.as_mut().project(); - - // Attempt to start polling, in case some waker is holding the lock, wait in loop - let (mut poll_state_value, state_bomb) = loop { - if let Some(value) = this.poll_state.start_polling() { - break value; - } - }; - - // Safety: now state is `POLLING`. - unsafe { - WrappedWaker::replace_waker(this.stream_waker, cx); - WrappedWaker::replace_waker(this.inner_streams_waker, cx) - }; - - if poll_state_value & NEED_TO_POLL_STREAM != NONE { - let mut stream_waker = None; - - // Here we need to poll the base stream. - // - // To improve performance, we will attempt to place as many items as we can - // to the `FuturesUnordered` bucket before polling inner streams - loop { - if this.is_exceeded_limit() || *this.is_stream_done { - // We either exceeded the limit or the stream is exhausted - if !*this.is_stream_done { - // The stream needs to be polled in the next iteration - need_to_poll_next |= NEED_TO_POLL_STREAM; - } - - break; - } else { - let mut cx = Context::from_waker( - stream_waker.get_or_insert_with(|| waker(this.stream_waker.clone())), - ); - - match this.stream.as_mut().poll_next(&mut cx) { - Poll::Ready(Some(item)) => { - let next_item_fut = match Fc::next_step(item) { - // Propagates an item immediately (the main use-case is for errors) - FlowStep::Return(item) => { - need_to_poll_next |= NEED_TO_POLL_STREAM - | (poll_state_value & NEED_TO_POLL_INNER_STREAMS); - poll_state_value &= !NEED_TO_POLL_INNER_STREAMS; - - next_item = Some(item); - - break; - } - // Yields an item and continues processing (normal case) - FlowStep::Continue(inner_stream) => { - PollStreamFut::new(inner_stream) - } - }; - // Add new stream to the inner streams bucket - this.inner_streams.as_mut().push(next_item_fut); - // Inner streams must be polled afterward - poll_state_value |= NEED_TO_POLL_INNER_STREAMS; - } - Poll::Ready(None) => { - // Mark the base stream as done - *this.is_stream_done = true; - } - Poll::Pending => { - break; - } - } - } - } - } - - if poll_state_value & NEED_TO_POLL_INNER_STREAMS != NONE { - let inner_streams_waker = waker(this.inner_streams_waker.clone()); - let mut cx = Context::from_waker(&inner_streams_waker); - - match this.inner_streams.as_mut().poll_next(&mut cx) { - Poll::Ready(Some(Some((item, next_item_fut)))) => { - // Push next inner stream item future to the list of inner streams futures - this.inner_streams.as_mut().push(next_item_fut); - // Take the received item - next_item = Some(item); - // On the next iteration, inner streams must be polled again - need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS; - } - Poll::Ready(Some(None)) => { - // On the next iteration, inner streams must be polled again - need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS; - } - _ => {} - } - } - - // We didn't have any `poll_next` panic, so it's time to deactivate the bomb - state_bomb.deactivate(); - - // Call the waker at the end of polling if - let mut force_wake = - // we need to poll the stream and didn't reach the limit yet - need_to_poll_next & NEED_TO_POLL_STREAM != NONE && !this.is_exceeded_limit() - // or we need to poll the inner streams again - || need_to_poll_next & NEED_TO_POLL_INNER_STREAMS != NONE; - - // Stop polling and swap the latest state - poll_state_value = this.poll_state.stop_polling(need_to_poll_next, force_wake); - // If state was changed during `POLLING` phase, we also need to manually call a waker - force_wake |= poll_state_value & NEED_TO_POLL_ALL != NONE; - - let is_done = *this.is_stream_done && this.inner_streams.is_empty(); - - if next_item.is_some() || is_done { - Poll::Ready(next_item) - } else { - if force_wake { - cx.waker().wake_by_ref(); - } - - Poll::Pending - } - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for FlattenUnorderedWithFlowController -where - St: Stream + Sink, -{ - type Error = St::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/fold.rs b/futures-util/src/stream/stream/fold.rs deleted file mode 100644 index b8b55ecb67..0000000000 --- a/futures-util/src/stream/stream/fold.rs +++ /dev/null @@ -1,88 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`fold`](super::StreamExt::fold) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Fold { - #[pin] - stream: St, - f: F, - accum: Option, - #[pin] - future: Option, - } -} - -impl fmt::Debug for Fold -where - St: fmt::Debug, - Fut: fmt::Debug, - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Fold") - .field("stream", &self.stream) - .field("accum", &self.accum) - .field("future", &self.future) - .finish() - } -} - -impl Fold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F, t: T) -> Self { - Self { stream, f, accum: Some(t), future: None } - } -} - -impl FusedFuture for Fold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.accum.is_none() && self.future.is_none() - } -} - -impl Future for Fold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: Future, -{ - type Output = T; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new accum value - *this.accum = Some(ready!(fut.poll(cx))); - this.future.set(None); - } else if this.accum.is_some() { - // we're waiting on a new item from the stream - let res = ready!(this.stream.as_mut().poll_next(cx)); - let a = this.accum.take().unwrap(); - if let Some(item) = res { - this.future.set(Some((this.f)(a, item))); - } else { - break a; - } - } else { - panic!("Fold polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/stream/for_each.rs b/futures-util/src/stream/stream/for_each.rs deleted file mode 100644 index 5302b0e034..0000000000 --- a/futures-util/src/stream/stream/for_each.rs +++ /dev/null @@ -1,78 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`for_each`](super::StreamExt::for_each) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct ForEach { - #[pin] - stream: St, - f: F, - #[pin] - future: Option, - } -} - -impl fmt::Debug for ForEach -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ForEach") - .field("stream", &self.stream) - .field("future", &self.future) - .finish() - } -} - -impl ForEach -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, future: None } - } -} - -impl FusedFuture for ForEach -where - St: FusedStream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.future.is_none() && self.stream.is_terminated() - } -} - -impl Future for ForEach -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let mut this = self.project(); - loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - ready!(fut.poll(cx)); - this.future.set(None); - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - this.future.set(Some((this.f)(item))); - } else { - break; - } - } - Poll::Ready(()) - } -} diff --git a/futures-util/src/stream/stream/for_each_concurrent.rs b/futures-util/src/stream/stream/for_each_concurrent.rs deleted file mode 100644 index 6c18753eb9..0000000000 --- a/futures-util/src/stream/stream/for_each_concurrent.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::stream::{FuturesUnordered, StreamExt}; -use core::fmt; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`for_each_concurrent`](super::StreamExt::for_each_concurrent) - /// method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct ForEachConcurrent { - #[pin] - stream: Option, - f: F, - futures: FuturesUnordered, - limit: Option, - } -} - -impl fmt::Debug for ForEachConcurrent -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ForEachConcurrent") - .field("stream", &self.stream) - .field("futures", &self.futures) - .field("limit", &self.limit) - .finish() - } -} - -impl ForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, limit: Option, f: F) -> Self { - Self { - stream: Some(stream), - // Note: `limit` = 0 gets ignored. - limit: limit.and_then(NonZeroUsize::new), - f, - futures: FuturesUnordered::new(), - } - } -} - -impl FusedFuture for ForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.stream.is_none() && self.futures.is_empty() - } -} - -impl Future for ForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let mut this = self.project(); - loop { - let mut made_progress_this_iter = false; - - // Check if we've already created a number of futures greater than `limit` - if this.limit.map(|limit| limit.get() > this.futures.len()).unwrap_or(true) { - let mut stream_completed = false; - let elem = if let Some(stream) = this.stream.as_mut().as_pin_mut() { - match stream.poll_next(cx) { - Poll::Ready(Some(elem)) => { - made_progress_this_iter = true; - Some(elem) - } - Poll::Ready(None) => { - stream_completed = true; - None - } - Poll::Pending => None, - } - } else { - None - }; - if stream_completed { - this.stream.set(None); - } - if let Some(elem) = elem { - this.futures.push((this.f)(elem)); - } - } - - match this.futures.poll_next_unpin(cx) { - Poll::Ready(Some(())) => made_progress_this_iter = true, - Poll::Ready(None) => { - if this.stream.is_none() { - return Poll::Ready(()); - } - } - Poll::Pending => {} - } - - if !made_progress_this_iter { - return Poll::Pending; - } - } - } -} diff --git a/futures-util/src/stream/stream/forward.rs b/futures-util/src/stream/stream/forward.rs deleted file mode 100644 index ce0b47f79a..0000000000 --- a/futures-util/src/stream/stream/forward.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::stream::Fuse; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`forward`](super::StreamExt::forward) method. - #[project = ForwardProj] - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Forward { - #[pin] - sink: Option, - #[pin] - stream: Fuse, - buffered_item: Option, - } -} - -impl Forward { - pub(crate) fn new(stream: St, sink: Si) -> Self { - Self { sink: Some(sink), stream: Fuse::new(stream), buffered_item: None } - } -} - -impl FusedFuture for Forward -where - Si: Sink, - St: Stream, -{ - fn is_terminated(&self) -> bool { - self.sink.is_none() - } -} - -impl Future for Forward -where - Si: Sink, - St: Stream, -{ - type Output = Result<(), E>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let ForwardProj { mut sink, mut stream, buffered_item } = self.project(); - let mut si = sink.as_mut().as_pin_mut().expect("polled `Forward` after completion"); - - loop { - // If we've got an item buffered already, we need to write it to the - // sink before we can do anything else - if buffered_item.is_some() { - ready!(si.as_mut().poll_ready(cx))?; - si.as_mut().start_send(buffered_item.take().unwrap())?; - } - - match stream.as_mut().poll_next(cx) { - Poll::Ready(Some(item)) => { - *buffered_item = Some(item); - } - Poll::Ready(None) => { - ready!(si.poll_close(cx))?; - sink.set(None); - return Poll::Ready(Ok(())); - } - Poll::Pending => { - ready!(si.poll_flush(cx))?; - return Poll::Pending; - } - } - } - } -} diff --git a/futures-util/src/stream/stream/fuse.rs b/futures-util/src/stream/stream/fuse.rs deleted file mode 100644 index fed34de74c..0000000000 --- a/futures-util/src/stream/stream/fuse.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`fuse`](super::StreamExt::fuse) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Fuse { - #[pin] - stream: St, - done: bool, - } -} - -impl Fuse { - pub(crate) fn new(stream: St) -> Self { - Self { stream, done: false } - } - - /// Returns whether the underlying stream has finished or not. - /// - /// If this method returns `true`, then all future calls to poll are - /// guaranteed to return `None`. If this returns `false`, then the - /// underlying stream is still in use. - pub fn is_done(&self) -> bool { - self.done - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Fuse { - fn is_terminated(&self) -> bool { - self.done - } -} - -impl Stream for Fuse { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - if *this.done { - return Poll::Ready(None); - } - - let item = ready!(this.stream.poll_next(cx)); - if item.is_none() { - *this.done = true; - } - Poll::Ready(item) - } - - fn size_hint(&self) -> (usize, Option) { - if self.done { - (0, Some(0)) - } else { - self.stream.size_hint() - } - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl, Item> Sink for Fuse { - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/into_future.rs b/futures-util/src/stream/stream/into_future.rs deleted file mode 100644 index 8abfddcccd..0000000000 --- a/futures-util/src/stream/stream/into_future.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::stream::StreamExt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; - -/// Future for the [`into_future`](super::StreamExt::into_future) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct StreamFuture { - stream: Option, -} - -impl StreamFuture { - pub(super) fn new(stream: St) -> Self { - Self { stream: Some(stream) } - } - - /// Acquires a reference to the underlying stream that this combinator is - /// pulling from. - /// - /// This method returns an `Option` to account for the fact that `StreamFuture`'s - /// implementation of `Future::poll` consumes the underlying stream during polling - /// in order to return it to the caller of `Future::poll` if the stream yielded - /// an element. - pub fn get_ref(&self) -> Option<&St> { - self.stream.as_ref() - } - - /// Acquires a mutable reference to the underlying stream that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - /// - /// This method returns an `Option` to account for the fact that `StreamFuture`'s - /// implementation of `Future::poll` consumes the underlying stream during polling - /// in order to return it to the caller of `Future::poll` if the stream yielded - /// an element. - pub fn get_mut(&mut self) -> Option<&mut St> { - self.stream.as_mut() - } - - /// Acquires a pinned mutable reference to the underlying stream that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - /// - /// This method returns an `Option` to account for the fact that `StreamFuture`'s - /// implementation of `Future::poll` consumes the underlying stream during polling - /// in order to return it to the caller of `Future::poll` if the stream yielded - /// an element. - pub fn get_pin_mut(self: Pin<&mut Self>) -> Option> { - self.get_mut().stream.as_mut().map(Pin::new) - } - - /// Consumes this combinator, returning the underlying stream. - /// - /// Note that this may discard intermediate state of this combinator, so - /// care should be taken to avoid losing resources when this is called. - /// - /// This method returns an `Option` to account for the fact that `StreamFuture`'s - /// implementation of `Future::poll` consumes the underlying stream during polling - /// in order to return it to the caller of `Future::poll` if the stream yielded - /// an element. - pub fn into_inner(self) -> Option { - self.stream - } -} - -impl FusedFuture for StreamFuture { - fn is_terminated(&self) -> bool { - self.stream.is_none() - } -} - -impl Future for StreamFuture { - type Output = (Option, St); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let item = { - let s = self.stream.as_mut().expect("polling StreamFuture twice"); - ready!(s.poll_next_unpin(cx)) - }; - let stream = self.stream.take().unwrap(); - Poll::Ready((item, stream)) - } -} diff --git a/futures-util/src/stream/stream/map.rs b/futures-util/src/stream/stream/map.rs deleted file mode 100644 index 88bb6129d4..0000000000 --- a/futures-util/src/stream/stream/map.rs +++ /dev/null @@ -1,77 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -use crate::fns::FnMut1; - -pin_project! { - /// Stream for the [`map`](super::StreamExt::map) method. - #[must_use = "streams do nothing unless polled"] - pub struct Map { - #[pin] - stream: St, - f: F, - } -} - -impl fmt::Debug for Map -where - St: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Map").field("stream", &self.stream).finish() - } -} - -impl Map { - pub(crate) fn new(stream: St, f: F) -> Self { - Self { stream, f } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Map -where - St: FusedStream, - F: FnMut1, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Stream for Map -where - St: Stream, - F: FnMut1, -{ - type Item = F::Output; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - let res = ready!(this.stream.as_mut().poll_next(cx)); - Poll::Ready(res.map(|x| this.f.call_mut(x))) - } - - fn size_hint(&self) -> (usize, Option) { - self.stream.size_hint() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Map -where - St: Stream + Sink, - F: FnMut1, -{ - type Error = St::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/mod.rs b/futures-util/src/stream/stream/mod.rs deleted file mode 100644 index ee30f8da6f..0000000000 --- a/futures-util/src/stream/stream/mod.rs +++ /dev/null @@ -1,1817 +0,0 @@ -//! Streams -//! -//! This module contains a number of functions for working with `Stream`s, -//! including the `StreamExt` trait which adds methods to `Stream` types. - -use crate::future::{assert_future, Either}; -use crate::stream::assert_stream; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -use core::pin::Pin; -#[cfg(feature = "alloc")] -use futures_core::stream::{BoxStream, LocalBoxStream}; -use futures_core::{ - future::{Future, TryFuture}, - stream::{FusedStream, Stream}, - task::{Context, Poll}, -}; -#[cfg(feature = "sink")] -use futures_sink::Sink; - -use crate::fns::{inspect_fn, InspectFn}; - -mod chain; -pub use self::chain::Chain; - -mod collect; -pub use self::collect::Collect; - -mod unzip; -pub use self::unzip::Unzip; - -mod concat; -pub use self::concat::Concat; - -mod count; -pub use self::count::Count; - -mod cycle; -pub use self::cycle::Cycle; - -mod enumerate; -pub use self::enumerate::Enumerate; - -mod filter; -pub use self::filter::Filter; - -mod filter_map; -pub use self::filter_map::FilterMap; - -mod flatten; - -delegate_all!( - /// Stream for the [`flatten`](StreamExt::flatten) method. - Flatten( - flatten::Flatten - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (.)] + New[|x: St| flatten::Flatten::new(x)] - where St: Stream -); - -mod fold; -pub use self::fold::Fold; - -mod any; -pub use self::any::Any; - -mod all; -pub use self::all::All; - -#[cfg(feature = "sink")] -mod forward; - -#[cfg(feature = "sink")] -delegate_all!( - /// Future for the [`forward`](super::StreamExt::forward) method. - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - Forward( - forward::Forward - ): Debug + Future + FusedFuture + New[|x: St, y: Si| forward::Forward::new(x, y)] - where St: Stream -); - -mod for_each; -pub use self::for_each::ForEach; - -mod fuse; -pub use self::fuse::Fuse; - -mod into_future; -pub use self::into_future::StreamFuture; - -delegate_all!( - /// Stream for the [`inspect`](StreamExt::inspect) method. - Inspect( - map::Map> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (.)] + New[|x: St, f: F| map::Map::new(x, inspect_fn(f))] -); - -mod map; -pub use self::map::Map; - -delegate_all!( - /// Stream for the [`flat_map`](StreamExt::flat_map) method. - FlatMap( - flatten::Flatten, U> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, f: F| flatten::Flatten::new(Map::new(x, f))] -); - -mod next; -pub use self::next::Next; - -mod select_next_some; -pub use self::select_next_some::SelectNextSome; - -mod peek; -pub use self::peek::{NextIf, NextIfEq, Peek, PeekMut, Peekable}; - -mod skip; -pub use self::skip::Skip; - -mod skip_while; -pub use self::skip_while::SkipWhile; - -mod take; -pub use self::take::Take; - -mod take_while; -pub use self::take_while::TakeWhile; - -mod take_until; -pub use self::take_until::TakeUntil; - -mod then; -pub use self::then::Then; - -mod try_for_each; -pub use self::try_for_each::TryForEach; - -mod try_fold; -pub use self::try_fold::TryFold; - -mod zip; -pub use self::zip::Zip; - -#[cfg(feature = "alloc")] -mod chunks; -#[cfg(feature = "alloc")] -pub use self::chunks::Chunks; - -#[cfg(feature = "alloc")] -mod ready_chunks; -#[cfg(feature = "alloc")] -pub use self::ready_chunks::ReadyChunks; - -mod scan; -pub use self::scan::Scan; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod buffer_unordered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::buffer_unordered::BufferUnordered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod buffered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::buffered::Buffered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub(crate) mod flatten_unordered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::flatten_unordered::FlattenUnordered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -delegate_all!( - /// Stream for the [`flat_map_unordered`](StreamExt::flat_map_unordered) method. - FlatMapUnordered( - FlattenUnordered> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, limit: Option, f: F| FlattenUnordered::new(Map::new(x, f), limit)] - where St: Stream, U: Stream, U: Unpin, F: FnMut(St::Item) -> U -); - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod for_each_concurrent; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::for_each_concurrent::ForEachConcurrent; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -#[cfg(feature = "alloc")] -mod split; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "sink")] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -#[cfg(feature = "alloc")] -pub use self::split::{ReuniteError, SplitSink, SplitStream}; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod try_for_each_concurrent; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::try_for_each_concurrent::TryForEachConcurrent; - -#[cfg(feature = "std")] -mod catch_unwind; -#[cfg(feature = "std")] -pub use self::catch_unwind::CatchUnwind; - -impl StreamExt for T where T: Stream {} - -/// An extension trait for `Stream`s that provides a variety of convenient -/// combinator functions. -pub trait StreamExt: Stream { - /// Creates a future that resolves to the next item in the stream. - /// - /// Note that because `next` doesn't take ownership over the stream, - /// the [`Stream`] type must be [`Unpin`]. If you want to use `next` with a - /// [`!Unpin`](Unpin) stream, you'll first have to pin the stream. This can - /// be done by boxing the stream using [`Box::pin`] or - /// pinning it to the stack using the `pin_mut!` macro from the `pin_utils` - /// crate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let mut stream = stream::iter(1..=3); - /// - /// assert_eq!(stream.next().await, Some(1)); - /// assert_eq!(stream.next().await, Some(2)); - /// assert_eq!(stream.next().await, Some(3)); - /// assert_eq!(stream.next().await, None); - /// # }); - /// ``` - fn next(&mut self) -> Next<'_, Self> - where - Self: Unpin, - { - assert_future::, _>(Next::new(self)) - } - - /// Converts this stream into a future of `(next_item, tail_of_stream)`. - /// If the stream terminates, then the next item is [`None`]. - /// - /// The returned future can be used to compose streams and futures together - /// by placing everything into the "world of futures". - /// - /// Note that because `into_future` moves the stream, the [`Stream`] type - /// must be [`Unpin`]. If you want to use `into_future` with a - /// [`!Unpin`](Unpin) stream, you'll first have to pin the stream. This can - /// be done by boxing the stream using [`Box::pin`] or - /// pinning it to the stack using the `pin_mut!` macro from the `pin_utils` - /// crate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=3); - /// - /// let (item, stream) = stream.into_future().await; - /// assert_eq!(Some(1), item); - /// - /// let (item, stream) = stream.into_future().await; - /// assert_eq!(Some(2), item); - /// # }); - /// ``` - fn into_future(self) -> StreamFuture - where - Self: Sized + Unpin, - { - assert_future::<(Option, Self), _>(StreamFuture::new(self)) - } - - /// Maps this stream's items to a different type, returning a new stream of - /// the resulting type. - /// - /// The provided closure is executed over all elements of this stream as - /// they are made available. It is executed inline with calls to - /// [`poll_next`](Stream::poll_next). - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `map` methods in the - /// standard library. - /// - /// See [`StreamExt::then`](Self::then) if you want to use a closure that - /// returns a future instead of a value. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=3); - /// let stream = stream.map(|x| x + 3); - /// - /// assert_eq!(vec![4, 5, 6], stream.collect::>().await); - /// # }); - /// ``` - fn map(self, f: F) -> Map - where - F: FnMut(Self::Item) -> T, - Self: Sized, - { - assert_stream::(Map::new(self, f)) - } - - /// Creates a stream which gives the current iteration count as well as - /// the next value. - /// - /// The stream returned yields pairs `(i, val)`, where `i` is the - /// current index of iteration and `val` is the value returned by the - /// stream. - /// - /// `enumerate()` keeps its count as a [`usize`]. If you want to count by a - /// different sized integer, the [`zip`](StreamExt::zip) function provides similar - /// functionality. - /// - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// [`usize::MAX`] elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. - /// - /// # Panics - /// - /// The returned stream might panic if the to-be-returned index would - /// overflow a [`usize`]. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(vec!['a', 'b', 'c']); - /// - /// let mut stream = stream.enumerate(); - /// - /// assert_eq!(stream.next().await, Some((0, 'a'))); - /// assert_eq!(stream.next().await, Some((1, 'b'))); - /// assert_eq!(stream.next().await, Some((2, 'c'))); - /// assert_eq!(stream.next().await, None); - /// # }); - /// ``` - fn enumerate(self) -> Enumerate - where - Self: Sized, - { - assert_stream::<(usize, Self::Item), _>(Enumerate::new(self)) - } - - /// Filters the values produced by this stream according to the provided - /// asynchronous predicate. - /// - /// As values of this stream are made available, the provided predicate `f` - /// will be run against them. If the predicate returns a `Future` which - /// resolves to `true`, then the stream will yield the value, but if the - /// predicate returns a `Future` which resolves to `false`, then the value - /// will be discarded and the next value will be produced. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `filter` methods in the - /// standard library. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// let events = stream.filter(|x| future::ready(x % 2 == 0)); - /// - /// assert_eq!(vec![2, 4, 6, 8, 10], events.collect::>().await); - /// # }); - /// ``` - fn filter(self, f: F) -> Filter - where - F: FnMut(&Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_stream::(Filter::new(self, f)) - } - - /// Filters the values produced by this stream while simultaneously mapping - /// them to a different type according to the provided asynchronous closure. - /// - /// As values of this stream are made available, the provided function will - /// be run on them. If the future returned by the predicate `f` resolves to - /// [`Some(item)`](Some) then the stream will yield the value `item`, but if - /// it resolves to [`None`] then the next value will be produced. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `filter_map` methods in - /// the standard library. - /// - /// # Examples - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// let events = stream.filter_map(|x| async move { - /// if x % 2 == 0 { Some(x + 1) } else { None } - /// }); - /// - /// assert_eq!(vec![3, 5, 7, 9, 11], events.collect::>().await); - /// # }); - /// ``` - fn filter_map(self, f: F) -> FilterMap - where - F: FnMut(Self::Item) -> Fut, - Fut: Future>, - Self: Sized, - { - assert_stream::(FilterMap::new(self, f)) - } - - /// Computes from this stream's items new items of a different type using - /// an asynchronous closure. - /// - /// The provided closure `f` will be called with an `Item` once a value is - /// ready, it returns a future which will then be run to completion - /// to produce the next value on this stream. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it. - /// - /// See [`StreamExt::map`](Self::map) if you want to use a closure that - /// returns a value instead of a future. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=3); - /// let stream = stream.then(|x| async move { x + 3 }); - /// - /// assert_eq!(vec![4, 5, 6], stream.collect::>().await); - /// # }); - /// ``` - fn then(self, f: F) -> Then - where - F: FnMut(Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_stream::(Then::new(self, f)) - } - - /// Transforms a stream into a collection, returning a - /// future representing the result of that computation. - /// - /// The returned future will be resolved when the stream terminates. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::StreamExt; - /// use std::thread; - /// - /// let (tx, rx) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// for i in 1..=5 { - /// tx.unbounded_send(i).unwrap(); - /// } - /// }); - /// - /// let output = rx.collect::>().await; - /// assert_eq!(output, vec![1, 2, 3, 4, 5]); - /// # }); - /// ``` - fn collect>(self) -> Collect - where - Self: Sized, - { - assert_future::(Collect::new(self)) - } - - /// Converts a stream of pairs into a future, which - /// resolves to pair of containers. - /// - /// `unzip()` produces a future, which resolves to two - /// collections: one from the left elements of the pairs, - /// and one from the right elements. - /// - /// The returned future will be resolved when the stream terminates. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::StreamExt; - /// use std::thread; - /// - /// let (tx, rx) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// tx.unbounded_send((1, 2)).unwrap(); - /// tx.unbounded_send((3, 4)).unwrap(); - /// tx.unbounded_send((5, 6)).unwrap(); - /// }); - /// - /// let (o1, o2): (Vec<_>, Vec<_>) = rx.unzip().await; - /// assert_eq!(o1, vec![1, 3, 5]); - /// assert_eq!(o2, vec![2, 4, 6]); - /// # }); - /// ``` - fn unzip(self) -> Unzip - where - FromA: Default + Extend, - FromB: Default + Extend, - Self: Sized + Stream, - { - assert_future::<(FromA, FromB), _>(Unzip::new(self)) - } - - /// Concatenate all items of a stream into a single extendable - /// destination, returning a future representing the end result. - /// - /// This combinator will extend the first item with the contents - /// of all the subsequent results of the stream. If the stream is - /// empty, the default value will be returned. - /// - /// Works with all collections that implement the - /// [`Extend`](std::iter::Extend) trait. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::StreamExt; - /// use std::thread; - /// - /// let (tx, rx) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// for i in (0..3).rev() { - /// let n = i * 3; - /// tx.unbounded_send(vec![n + 1, n + 2, n + 3]).unwrap(); - /// } - /// }); - /// - /// let result = rx.concat().await; - /// - /// assert_eq!(result, vec![7, 8, 9, 4, 5, 6, 1, 2, 3]); - /// # }); - /// ``` - fn concat(self) -> Concat - where - Self: Sized, - Self::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default, - { - assert_future::(Concat::new(self)) - } - - /// Drives the stream to completion, counting the number of items. - /// - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so counting elements of a - /// stream with more than [`usize::MAX`] elements either produces the wrong - /// result or panics. If debug assertions are enabled, a panic is guaranteed. - /// - /// # Panics - /// - /// This function might panic if the iterator has more than [`usize::MAX`] - /// elements. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// let count = stream.count().await; - /// - /// assert_eq!(count, 10); - /// # }); - /// ``` - fn count(self) -> Count - where - Self: Sized, - { - assert_future::(Count::new(self)) - } - - /// Repeats a stream endlessly. - /// - /// The stream never terminates. Note that you likely want to avoid - /// usage of `collect` or such on the returned stream as it will exhaust - /// available memory as it tries to just fill up all RAM. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// let a = [1, 2, 3]; - /// let mut s = stream::iter(a.iter()).cycle(); - /// - /// assert_eq!(s.next().await, Some(&1)); - /// assert_eq!(s.next().await, Some(&2)); - /// assert_eq!(s.next().await, Some(&3)); - /// assert_eq!(s.next().await, Some(&1)); - /// assert_eq!(s.next().await, Some(&2)); - /// assert_eq!(s.next().await, Some(&3)); - /// assert_eq!(s.next().await, Some(&1)); - /// # }); - /// ``` - fn cycle(self) -> Cycle - where - Self: Sized + Clone, - { - assert_stream::(Cycle::new(self)) - } - - /// Execute an accumulating asynchronous computation over a stream, - /// collecting all the values into one final result. - /// - /// This combinator will accumulate all values returned by this stream - /// according to the closure provided. The initial state is also provided to - /// this method and then is returned again by each execution of the closure. - /// Once the entire stream has been exhausted the returned future will - /// resolve to this value. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let number_stream = stream::iter(0..6); - /// let sum = number_stream.fold(0, |acc, x| async move { acc + x }); - /// assert_eq!(sum.await, 15); - /// # }); - /// ``` - fn fold(self, init: T, f: F) -> Fold - where - F: FnMut(T, Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::(Fold::new(self, f, init)) - } - - /// Execute predicate over asynchronous stream, and return `true` if any element in stream satisfied a predicate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let number_stream = stream::iter(0..10); - /// let contain_three = number_stream.any(|i| async move { i == 3 }); - /// assert_eq!(contain_three.await, true); - /// # }); - /// ``` - fn any(self, f: F) -> Any - where - F: FnMut(Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::(Any::new(self, f)) - } - - /// Execute predicate over asynchronous stream, and return `true` if all element in stream satisfied a predicate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let number_stream = stream::iter(0..10); - /// let less_then_twenty = number_stream.all(|i| async move { i < 20 }); - /// assert_eq!(less_then_twenty.await, true); - /// # }); - /// ``` - fn all(self, f: F) -> All - where - F: FnMut(Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::(All::new(self, f)) - } - - /// Flattens a stream of streams into just one continuous stream. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::StreamExt; - /// use std::thread; - /// - /// let (tx1, rx1) = mpsc::unbounded(); - /// let (tx2, rx2) = mpsc::unbounded(); - /// let (tx3, rx3) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// tx1.unbounded_send(1).unwrap(); - /// tx1.unbounded_send(2).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx2.unbounded_send(3).unwrap(); - /// tx2.unbounded_send(4).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx3.unbounded_send(rx1).unwrap(); - /// tx3.unbounded_send(rx2).unwrap(); - /// }); - /// - /// let output = rx3.flatten().collect::>().await; - /// assert_eq!(output, vec![1, 2, 3, 4]); - /// # }); - /// ``` - fn flatten(self) -> Flatten - where - Self::Item: Stream, - Self: Sized, - { - assert_stream::<::Item, _>(Flatten::new(self)) - } - - /// Flattens a stream of streams into just one continuous stream. Polls - /// inner streams produced by the base stream concurrently. - /// - /// The only argument is an optional limit on the number of concurrently - /// polled streams. If this limit is not `None`, no more than `limit` streams - /// will be polled at the same time. The `limit` argument is of type - /// `Into>`, and so can be provided as either `None`, - /// `Some(10)`, or just `10`. Note: a limit of zero is interpreted as - /// no limit at all, and will have the same result as passing in `None`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::StreamExt; - /// use std::thread; - /// - /// let (tx1, rx1) = mpsc::unbounded(); - /// let (tx2, rx2) = mpsc::unbounded(); - /// let (tx3, rx3) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// tx1.unbounded_send(1).unwrap(); - /// tx1.unbounded_send(2).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx2.unbounded_send(3).unwrap(); - /// tx2.unbounded_send(4).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx3.unbounded_send(rx1).unwrap(); - /// tx3.unbounded_send(rx2).unwrap(); - /// }); - /// - /// let mut output = rx3.flatten_unordered(None).collect::>().await; - /// output.sort(); - /// - /// assert_eq!(output, vec![1, 2, 3, 4]); - /// # }); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn flatten_unordered(self, limit: impl Into>) -> FlattenUnordered - where - Self::Item: Stream + Unpin, - Self: Sized, - { - assert_stream::<::Item, _>(FlattenUnordered::new(self, limit.into())) - } - - /// Maps a stream like [`StreamExt::map`] but flattens nested `Stream`s. - /// - /// [`StreamExt::map`] is very useful, but if it produces a `Stream` instead, - /// you would have to chain combinators like `.map(f).flatten()` while this - /// combinator provides ability to write `.flat_map(f)` instead of chaining. - /// - /// The provided closure which produces inner streams is executed over all elements - /// of stream as last inner stream is terminated and next stream item is available. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `flat_map` methods in the - /// standard library. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=3); - /// let stream = stream.flat_map(|x| stream::iter(vec![x + 3; x])); - /// - /// assert_eq!(vec![4, 5, 5, 6, 6, 6], stream.collect::>().await); - /// # }); - /// ``` - fn flat_map(self, f: F) -> FlatMap - where - F: FnMut(Self::Item) -> U, - U: Stream, - Self: Sized, - { - assert_stream::(FlatMap::new(self, f)) - } - - /// Maps a stream like [`StreamExt::map`] but flattens nested `Stream`s - /// and polls them concurrently, yielding items in any order, as they made - /// available. - /// - /// [`StreamExt::map`] is very useful, but if it produces `Stream`s - /// instead, and you need to poll all of them concurrently, you would - /// have to use something like `for_each_concurrent` and merge values - /// by hand. This combinator provides ability to collect all values - /// from concurrently polled streams into one stream. - /// - /// The first argument is an optional limit on the number of concurrently - /// polled streams. If this limit is not `None`, no more than `limit` streams - /// will be polled at the same time. The `limit` argument is of type - /// `Into>`, and so can be provided as either `None`, - /// `Some(10)`, or just `10`. Note: a limit of zero is interpreted as - /// no limit at all, and will have the same result as passing in `None`. - /// - /// The provided closure which produces inner streams is executed over - /// all elements of stream as next stream item is available and limit - /// of concurrently processed streams isn't exceeded. - /// - /// Note that this function consumes the stream passed into it and - /// returns a wrapped version of it. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..5); - /// let stream = stream.flat_map_unordered(1, |x| stream::iter(vec![x; x])); - /// let mut values = stream.collect::>().await; - /// values.sort(); - /// - /// assert_eq!(vec![1usize, 2, 2, 3, 3, 3, 4, 4, 4, 4], values); - /// # }); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn flat_map_unordered( - self, - limit: impl Into>, - f: F, - ) -> FlatMapUnordered - where - U: Stream + Unpin, - F: FnMut(Self::Item) -> U, - Self: Sized, - { - assert_stream::(FlatMapUnordered::new(self, limit.into(), f)) - } - - /// Combinator similar to [`StreamExt::fold`] that holds internal state - /// and produces a new stream. - /// - /// Accepts initial state and closure which will be applied to each element - /// of the stream until provided closure returns `None`. Once `None` is - /// returned, stream will be terminated. - /// - /// Unlike [`Iterator::scan`], the closure takes the state by value instead of - /// mutable reference to avoid [the limitation of the async - /// block](https://github.com/rust-lang/futures-rs/issues/2171). - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// - /// let stream = stream.scan(0, |mut state, x| async move { - /// state += x; - /// if state < 10 { - /// Some((state, x)) - /// } else { - /// None - /// } - /// }); - /// - /// assert_eq!(vec![1, 2, 3], stream.collect::>().await); - /// # }); - /// ``` - fn scan(self, initial_state: S, f: F) -> Scan - where - F: FnMut(S, Self::Item) -> Fut, - Fut: Future>, - Self: Sized, - { - assert_stream::(Scan::new(self, initial_state, f)) - } - - /// Skip elements on this stream while the provided asynchronous predicate - /// resolves to `true`. - /// - /// This function, like `Iterator::skip_while`, will skip elements on the - /// stream until the predicate `f` resolves to `false`. Once one element - /// returns `false`, all future elements will be returned from the underlying - /// stream. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// - /// let stream = stream.skip_while(|x| future::ready(*x <= 5)); - /// - /// assert_eq!(vec![6, 7, 8, 9, 10], stream.collect::>().await); - /// # }); - /// ``` - fn skip_while(self, f: F) -> SkipWhile - where - F: FnMut(&Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_stream::(SkipWhile::new(self, f)) - } - - /// Take elements from this stream while the provided asynchronous predicate - /// resolves to `true`. - /// - /// This function, like `Iterator::take_while`, will take elements from the - /// stream until the predicate `f` resolves to `false`. Once one element - /// returns `false`, it will always return that the stream is done. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10); - /// - /// let stream = stream.take_while(|x| future::ready(*x <= 5)); - /// - /// assert_eq!(vec![1, 2, 3, 4, 5], stream.collect::>().await); - /// # }); - /// ``` - fn take_while(self, f: F) -> TakeWhile - where - F: FnMut(&Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_stream::(TakeWhile::new(self, f)) - } - - /// Take elements from this stream until the provided future resolves. - /// - /// This function will take elements from the stream until the provided - /// stopping future `fut` resolves. Once the `fut` future becomes ready, - /// this stream combinator will always return that the stream is done. - /// - /// The stopping future may return any type. Once the stream is stopped - /// the result of the stopping future may be accessed with `TakeUntil::take_result()`. - /// The stream may also be resumed with `TakeUntil::take_future()`. - /// See the documentation of [`TakeUntil`] for more information. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// use futures::task::Poll; - /// - /// let stream = stream::iter(1..=10); - /// - /// let mut i = 0; - /// let stop_fut = future::poll_fn(|_cx| { - /// i += 1; - /// if i <= 5 { - /// Poll::Pending - /// } else { - /// Poll::Ready(()) - /// } - /// }); - /// - /// let stream = stream.take_until(stop_fut); - /// - /// assert_eq!(vec![1, 2, 3, 4, 5], stream.collect::>().await); - /// # }); - /// ``` - fn take_until(self, fut: Fut) -> TakeUntil - where - Fut: Future, - Self: Sized, - { - assert_stream::(TakeUntil::new(self, fut)) - } - - /// Runs this stream to completion, executing the provided asynchronous - /// closure for each element on the stream. - /// - /// The closure provided will be called for each item this stream produces, - /// yielding a future. That future will then be executed to completion - /// before moving on to the next item. - /// - /// The returned value is a `Future` where the `Output` type is `()`; it is - /// executed entirely for its side effects. - /// - /// To process each item in the stream and produce another stream instead - /// of a single future, use `then` instead. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// - /// let mut x = 0; - /// - /// { - /// let fut = stream::repeat(1).take(3).for_each(|item| { - /// x += item; - /// future::ready(()) - /// }); - /// fut.await; - /// } - /// - /// assert_eq!(x, 3); - /// # }); - /// ``` - fn for_each(self, f: F) -> ForEach - where - F: FnMut(Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::<(), _>(ForEach::new(self, f)) - } - - /// Runs this stream to completion, executing the provided asynchronous - /// closure for each element on the stream concurrently as elements become - /// available. - /// - /// This is similar to [`StreamExt::for_each`], but the futures - /// produced by the closure are run concurrently (but not in parallel-- - /// this combinator does not introduce any threads). - /// - /// The closure provided will be called for each item this stream produces, - /// yielding a future. That future will then be executed to completion - /// concurrently with the other futures produced by the closure. - /// - /// The first argument is an optional limit on the number of concurrent - /// futures. If this limit is not `None`, no more than `limit` futures - /// will be run concurrently. The `limit` argument is of type - /// `Into>`, and so can be provided as either `None`, - /// `Some(10)`, or just `10`. Note: a limit of zero is interpreted as - /// no limit at all, and will have the same result as passing in `None`. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures::stream::{self, StreamExt}; - /// - /// let (tx1, rx1) = oneshot::channel(); - /// let (tx2, rx2) = oneshot::channel(); - /// let (tx3, rx3) = oneshot::channel(); - /// - /// let fut = stream::iter(vec![rx1, rx2, rx3]).for_each_concurrent( - /// /* limit */ 2, - /// |rx| async move { - /// rx.await.unwrap(); - /// } - /// ); - /// tx1.send(()).unwrap(); - /// tx2.send(()).unwrap(); - /// tx3.send(()).unwrap(); - /// fut.await; - /// # }) - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn for_each_concurrent( - self, - limit: impl Into>, - f: F, - ) -> ForEachConcurrent - where - F: FnMut(Self::Item) -> Fut, - Fut: Future, - Self: Sized, - { - assert_future::<(), _>(ForEachConcurrent::new(self, limit.into(), f)) - } - - /// Attempt to execute an accumulating asynchronous computation over a - /// stream, collecting all the values into one final result. - /// - /// This combinator will accumulate all values returned by this stream - /// according to the closure provided. The initial state is also provided to - /// this method and then is returned again by each execution of the closure. - /// Once the entire stream has been exhausted the returned future will - /// resolve to this value. - /// - /// This method is similar to [`fold`](crate::stream::StreamExt::fold), but - /// will exit early if an error is encountered in the provided closure. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let number_stream = stream::iter(vec![1, 2]); - /// let sum = number_stream.try_fold(0, |acc, x| async move { Ok::(acc + x) }); - /// assert_eq!(sum.await, Ok(3)); - /// - /// let number_stream_with_err = stream::iter(vec![Ok::(1), Err(2), Ok(1)]); - /// let sum = number_stream_with_err.try_fold(0, |acc, x| async move { Ok(acc + x?) }); - /// assert_eq!(sum.await, Err(2)); - /// # }) - /// ``` - fn try_fold(self, init: T, f: F) -> TryFold - where - F: FnMut(T, Self::Item) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_future::, _>(TryFold::new(self, f, init)) - } - - /// Attempts to run this stream to completion, executing the provided - /// asynchronous closure for each element on the stream. - /// - /// The provided closure will be called for each item this stream produces, - /// yielding a future. That future will then be executed to completion - /// before moving on to the next item. - /// - /// The returned value is a [`Future`](futures_core::future::Future) where - /// the [`Output`](futures_core::future::Future::Output) type is - /// `Result<(), Fut::Error>`. If any of the intermediate futures returns - /// an error, this future will return immediately with an error. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// - /// let mut x = 0i32; - /// - /// { - /// let fut = stream::repeat(1).try_for_each(|item| { - /// x += item; - /// future::ready(if x == 3 { Err(()) } else { Ok(()) }) - /// }); - /// assert_eq!(fut.await, Err(())); - /// } - /// - /// assert_eq!(x, 3); - /// # }) - /// ``` - fn try_for_each(self, f: F) -> TryForEach - where - F: FnMut(Self::Item) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_future::, _>(TryForEach::new(self, f)) - } - - /// Attempts to run this stream to completion, executing the provided asynchronous - /// closure for each element on the stream concurrently as elements become - /// available, exiting as soon as an error occurs. - /// - /// This is similar to - /// [`StreamExt::for_each_concurrent`](crate::stream::StreamExt::for_each_concurrent), - /// but will resolve to an error immediately if the provided closure returns - /// an error. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures::stream::{self, StreamExt}; - /// - /// let (tx1, rx1) = oneshot::channel(); - /// let (tx2, rx2) = oneshot::channel(); - /// let (_tx3, rx3) = oneshot::channel(); - /// - /// let stream = stream::iter(vec![rx1, rx2, rx3]); - /// let fut = stream.try_for_each_concurrent( - /// /* limit */ 2, - /// |rx| async move { - /// let res: Result<(), oneshot::Canceled> = rx.await; - /// res - /// } - /// ); - /// - /// tx1.send(()).unwrap(); - /// // Drop the second sender so that `rx2` resolves to `Canceled`. - /// drop(tx2); - /// - /// // The final result is an error because the second future - /// // resulted in an error. - /// assert_eq!(Err(oneshot::Canceled), fut.await); - /// # }) - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn try_for_each_concurrent( - self, - limit: impl Into>, - f: F, - ) -> TryForEachConcurrent - where - F: FnMut(Self::Item) -> Fut, - Fut: Future>, - Self: Sized, - { - assert_future::, _>(TryForEachConcurrent::new(self, limit.into(), f)) - } - - /// Creates a new stream of at most `n` items of the underlying stream. - /// - /// Once `n` items have been yielded from this stream then it will always - /// return that the stream is done. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10).take(3); - /// - /// assert_eq!(vec![1, 2, 3], stream.collect::>().await); - /// # }); - /// ``` - fn take(self, n: usize) -> Take - where - Self: Sized, - { - assert_stream::(Take::new(self, n)) - } - - /// Creates a new stream which skips `n` items of the underlying stream. - /// - /// Once `n` items have been skipped from this stream then it will always - /// return the remaining items on this stream. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(1..=10).skip(5); - /// - /// assert_eq!(vec![6, 7, 8, 9, 10], stream.collect::>().await); - /// # }); - /// ``` - fn skip(self, n: usize) -> Skip - where - Self: Sized, - { - assert_stream::(Skip::new(self, n)) - } - - /// Fuse a stream such that [`poll_next`](Stream::poll_next) will never - /// again be called once it has finished. This method can be used to turn - /// any `Stream` into a `FusedStream`. - /// - /// Normally, once a stream has returned [`None`] from - /// [`poll_next`](Stream::poll_next) any further calls could exhibit bad - /// behavior such as block forever, panic, never return, etc. If it is known - /// that [`poll_next`](Stream::poll_next) may be called after stream - /// has already finished, then this method can be used to ensure that it has - /// defined semantics. - /// - /// The [`poll_next`](Stream::poll_next) method of a `fuse`d stream - /// is guaranteed to return [`None`] after the underlying stream has - /// finished. - /// - /// # Examples - /// - /// ``` - /// use futures::executor::block_on_stream; - /// use futures::stream::{self, StreamExt}; - /// use futures::task::Poll; - /// - /// let mut x = 0; - /// let stream = stream::poll_fn(|_| { - /// x += 1; - /// match x { - /// 0..=2 => Poll::Ready(Some(x)), - /// 3 => Poll::Ready(None), - /// _ => panic!("should not happen") - /// } - /// }).fuse(); - /// - /// let mut iter = block_on_stream(stream); - /// assert_eq!(Some(1), iter.next()); - /// assert_eq!(Some(2), iter.next()); - /// assert_eq!(None, iter.next()); - /// assert_eq!(None, iter.next()); - /// // ... - /// ``` - fn fuse(self) -> Fuse - where - Self: Sized, - { - assert_stream::(Fuse::new(self)) - } - - /// Borrows a stream, rather than consuming it. - /// - /// This is useful to allow applying stream adaptors while still retaining - /// ownership of the original stream. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let mut stream = stream::iter(1..5); - /// - /// let sum = stream.by_ref() - /// .take(2) - /// .fold(0, |a, b| async move { a + b }) - /// .await; - /// assert_eq!(sum, 3); - /// - /// // You can use the stream again - /// let sum = stream.take(2) - /// .fold(0, |a, b| async move { a + b }) - /// .await; - /// assert_eq!(sum, 7); - /// # }); - /// ``` - fn by_ref(&mut self) -> &mut Self { - self - } - - /// Catches unwinding panics while polling the stream. - /// - /// Caught panic (if any) will be the last element of the resulting stream. - /// - /// In general, panics within a stream can propagate all the way out to the - /// task level. This combinator makes it possible to halt unwinding within - /// the stream itself. It's most commonly used within task executors. This - /// method should not be used for error handling. - /// - /// Note that this method requires the `UnwindSafe` bound from the standard - /// library. This isn't always applied automatically, and the standard - /// library provides an `AssertUnwindSafe` wrapper type to apply it - /// after-the fact. To assist using this method, the [`Stream`] trait is - /// also implemented for `AssertUnwindSafe` where `St` implements - /// [`Stream`]. - /// - /// This method is only available when the `std` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream = stream::iter(vec![Some(10), None, Some(11)]); - /// // Panic on second element - /// let stream_panicking = stream.map(|o| o.unwrap()); - /// // Collect all the results - /// let stream = stream_panicking.catch_unwind(); - /// - /// let results: Vec> = stream.collect().await; - /// match results[0] { - /// Ok(10) => {} - /// _ => panic!("unexpected result!"), - /// } - /// assert!(results[1].is_err()); - /// assert_eq!(results.len(), 2); - /// # }); - /// ``` - #[cfg(feature = "std")] - fn catch_unwind(self) -> CatchUnwind - where - Self: Sized + std::panic::UnwindSafe, - { - assert_stream(CatchUnwind::new(self)) - } - - /// Wrap the stream in a Box, pinning it. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "alloc")] - fn boxed<'a>(self) -> BoxStream<'a, Self::Item> - where - Self: Sized + Send + 'a, - { - assert_stream::(Box::pin(self)) - } - - /// Wrap the stream in a Box, pinning it. - /// - /// Similar to `boxed`, but without the `Send` requirement. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "alloc")] - fn boxed_local<'a>(self) -> LocalBoxStream<'a, Self::Item> - where - Self: Sized + 'a, - { - assert_stream::(Box::pin(self)) - } - - /// An adaptor for creating a buffered list of pending futures. - /// - /// If this stream's item can be converted into a future, then this adaptor - /// will buffer up to at most `n` futures and then return the outputs in the - /// same order as the underlying stream. No more than `n` futures will be - /// buffered at any point in time, and less than `n` may also be buffered - /// depending on the state of each future. - /// - /// The limit argument is of type `Into>`, and so can be - /// provided as either `None`, `Some(10)`, or just `10`. Note: a limit of zero is - /// interpreted as no limit at all, and will have the same result as passing in `None`. - /// - /// The returned stream will be a stream of each future's output. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn buffered(self, n: impl Into>) -> Buffered - where - Self::Item: Future, - Self: Sized, - { - assert_stream::<::Output, _>(Buffered::new(self, n.into())) - } - - /// An adaptor for creating a buffered list of pending futures (unordered). - /// - /// If this stream's item can be converted into a future, then this adaptor - /// will buffer up to `n` futures and then return the outputs in the order - /// in which they complete. No more than `n` futures will be buffered at - /// any point in time, and less than `n` may also be buffered depending on - /// the state of each future. - /// - /// The limit argument is of type `Into>`, and so can be - /// provided as either `None`, `Some(10)`, or just `10`. Note: a limit of zero is - /// interpreted as no limit at all, and will have the same result as passing in `None`. - /// - /// The returned stream will be a stream of each future's output. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures::stream::{self, StreamExt}; - /// - /// let (send_one, recv_one) = oneshot::channel(); - /// let (send_two, recv_two) = oneshot::channel(); - /// - /// let stream_of_futures = stream::iter(vec![recv_one, recv_two]); - /// let mut buffered = stream_of_futures.buffer_unordered(10); - /// - /// send_two.send(2i32)?; - /// assert_eq!(buffered.next().await, Some(Ok(2i32))); - /// - /// send_one.send(1i32)?; - /// assert_eq!(buffered.next().await, Some(Ok(1i32))); - /// - /// assert_eq!(buffered.next().await, None); - /// # Ok::<(), i32>(()) }).unwrap(); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn buffer_unordered(self, n: impl Into>) -> BufferUnordered - where - Self::Item: Future, - Self: Sized, - { - assert_stream::<::Output, _>(BufferUnordered::new(self, n.into())) - } - - /// An adapter for zipping two streams together. - /// - /// The zipped stream waits for both streams to produce an item, and then - /// returns that pair. If either stream ends then the zipped stream will - /// also end. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream1 = stream::iter(1..=3); - /// let stream2 = stream::iter(5..=10); - /// - /// let vec = stream1.zip(stream2) - /// .collect::>() - /// .await; - /// assert_eq!(vec![(1, 5), (2, 6), (3, 7)], vec); - /// # }); - /// ``` - /// - fn zip(self, other: St) -> Zip - where - St: Stream, - Self: Sized, - { - assert_stream::<(Self::Item, St::Item), _>(Zip::new(self, other)) - } - - /// Adapter for chaining two streams. - /// - /// The resulting stream emits elements from the first stream, and when - /// first stream reaches the end, emits the elements from the second stream. - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt}; - /// - /// let stream1 = stream::iter(vec![Ok(10), Err(false)]); - /// let stream2 = stream::iter(vec![Err(true), Ok(20)]); - /// - /// let stream = stream1.chain(stream2); - /// - /// let result: Vec<_> = stream.collect().await; - /// assert_eq!(result, vec![ - /// Ok(10), - /// Err(false), - /// Err(true), - /// Ok(20), - /// ]); - /// # }); - /// ``` - fn chain(self, other: St) -> Chain - where - St: Stream, - Self: Sized, - { - assert_stream::(Chain::new(self, other)) - } - - /// Creates a new stream which exposes a `peek` method. - /// - /// Calling `peek` returns a reference to the next item in the stream. - fn peekable(self) -> Peekable - where - Self: Sized, - { - assert_stream::(Peekable::new(self)) - } - - /// An adaptor for chunking up items of the stream inside a vector. - /// - /// This combinator will attempt to pull items from this stream and buffer - /// them into a local vector. At most `capacity` items will get buffered - /// before they're yielded from the returned stream. - /// - /// Note that the vectors returned from this iterator may not always have - /// `capacity` elements. If the underlying stream ended and only a partial - /// vector was created, it'll be returned. Additionally if an error happens - /// from the underlying stream then the currently buffered items will be - /// yielded. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Panics - /// - /// This method will panic if `capacity` is zero. - #[cfg(feature = "alloc")] - fn chunks(self, capacity: usize) -> Chunks - where - Self: Sized, - { - assert_stream::, _>(Chunks::new(self, capacity)) - } - - /// An adaptor for chunking up ready items of the stream inside a vector. - /// - /// This combinator will attempt to pull ready items from this stream and - /// buffer them into a local vector. At most `capacity` items will get - /// buffered before they're yielded from the returned stream. If underlying - /// stream returns `Poll::Pending`, and collected chunk is not empty, it will - /// be immediately returned. - /// - /// If the underlying stream ended and only a partial vector was created, - /// it will be returned. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Panics - /// - /// This method will panic if `capacity` is zero. - #[cfg(feature = "alloc")] - fn ready_chunks(self, capacity: usize) -> ReadyChunks - where - Self: Sized, - { - assert_stream::, _>(ReadyChunks::new(self, capacity)) - } - - /// A future that completes after the given stream has been fully processed - /// into the sink and the sink has been flushed and closed. - /// - /// This future will drive the stream to keep producing items until it is - /// exhausted, sending each item to the sink. It will complete once the - /// stream is exhausted, the sink has received and flushed all items, and - /// the sink is closed. Note that neither the original stream nor provided - /// sink will be output by this future. Pass the sink by `Pin<&mut S>` - /// (for example, via `forward(&mut sink)` inside an `async` fn/block) in - /// order to preserve access to the `Sink`. - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - fn forward(self, sink: S) -> Forward - where - S: Sink, - Self: Sized, - { - assert_future::, _>(Forward::new(self, sink)) - } - - /// Splits this `Stream + Sink` object into separate `Sink` and `Stream` - /// objects. - /// - /// This can be useful when you want to split ownership between tasks, or - /// allow direct interaction between the two objects (e.g. via - /// `Sink::send_all`). - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn split(self) -> (SplitSink, SplitStream) - where - Self: Sink + Sized, - { - let (sink, stream) = split::split(self); - ( - crate::sink::assert_sink::(sink), - assert_stream::(stream), - ) - } - - /// Do something with each item of this stream, afterwards passing it on. - /// - /// This is similar to the `Iterator::inspect` method in the standard - /// library where it allows easily inspecting each value as it passes - /// through the stream, for example to debug what's going on. - fn inspect(self, f: F) -> Inspect - where - F: FnMut(&Self::Item), - Self: Sized, - { - assert_stream::(Inspect::new(self, f)) - } - - /// Wrap this stream in an `Either` stream, making it the left-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `right_stream` method to write `if` - /// statements that evaluate to different streams in different branches. - fn left_stream(self) -> Either - where - B: Stream, - Self: Sized, - { - assert_stream::(Either::Left(self)) - } - - /// Wrap this stream in an `Either` stream, making it the right-hand variant - /// of that `Either`. - /// - /// This can be used in combination with the `left_stream` method to write `if` - /// statements that evaluate to different streams in different branches. - fn right_stream(self) -> Either - where - B: Stream, - Self: Sized, - { - assert_stream::(Either::Right(self)) - } - - /// A convenience method for calling [`Stream::poll_next`] on [`Unpin`] - /// stream types. - fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll> - where - Self: Unpin, - { - Pin::new(self).poll_next(cx) - } - - /// Returns a [`Future`] that resolves when the next item in this stream is - /// ready. - /// - /// This is similar to the [`next`][StreamExt::next] method, but it won't - /// resolve to [`None`] if used on an empty [`Stream`]. Instead, the - /// returned future type will return `true` from - /// [`FusedFuture::is_terminated`][] when the [`Stream`] is empty, allowing - /// [`select_next_some`][StreamExt::select_next_some] to be easily used with - /// the [`select!`] macro. - /// - /// If the future is polled after this [`Stream`] is empty it will panic. - /// Using the future with a [`FusedFuture`][]-aware primitive like the - /// [`select!`] macro will prevent this. - /// - /// [`FusedFuture`]: futures_core::future::FusedFuture - /// [`FusedFuture::is_terminated`]: futures_core::future::FusedFuture::is_terminated - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::{future, select}; - /// use futures::stream::{StreamExt, FuturesUnordered}; - /// - /// let mut fut = future::ready(1); - /// let mut async_tasks = FuturesUnordered::new(); - /// let mut total = 0; - /// loop { - /// select! { - /// num = fut => { - /// // First, the `ready` future completes. - /// total += num; - /// // Then we spawn a new task onto `async_tasks`, - /// async_tasks.push(async { 5 }); - /// }, - /// // On the next iteration of the loop, the task we spawned - /// // completes. - /// num = async_tasks.select_next_some() => { - /// total += num; - /// } - /// // Finally, both the `ready` future and `async_tasks` have - /// // finished, so we enter the `complete` branch. - /// complete => break, - /// } - /// } - /// assert_eq!(total, 6); - /// # }); - /// ``` - /// - /// [`select!`]: crate::select - fn select_next_some(&mut self) -> SelectNextSome<'_, Self> - where - Self: Unpin + FusedStream, - { - assert_future::(SelectNextSome::new(self)) - } -} diff --git a/futures-util/src/stream/stream/next.rs b/futures-util/src/stream/stream/next.rs deleted file mode 100644 index 8d8347aa03..0000000000 --- a/futures-util/src/stream/stream/next.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::stream::StreamExt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`next`](super::StreamExt::next) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Next<'a, St: ?Sized> { - stream: &'a mut St, -} - -impl Unpin for Next<'_, St> {} - -impl<'a, St: ?Sized + Stream + Unpin> Next<'a, St> { - pub(super) fn new(stream: &'a mut St) -> Self { - Self { stream } - } -} - -impl FusedFuture for Next<'_, St> { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for Next<'_, St> { - type Output = Option; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.stream.poll_next_unpin(cx) - } -} diff --git a/futures-util/src/stream/stream/peek.rs b/futures-util/src/stream/stream/peek.rs deleted file mode 100644 index 140a30b6e4..0000000000 --- a/futures-util/src/stream/stream/peek.rs +++ /dev/null @@ -1,439 +0,0 @@ -use crate::fns::FnOnce1; -use crate::stream::{Fuse, StreamExt}; -use core::fmt; -use core::marker::PhantomData; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// A `Stream` that implements a `peek` method. - /// - /// The `peek` method can be used to retrieve a reference - /// to the next `Stream::Item` if available. A subsequent - /// call to `poll` will return the owned item. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Peekable { - #[pin] - stream: Fuse, - peeked: Option, - } -} - -impl Peekable { - pub(super) fn new(stream: St) -> Self { - Self { stream: stream.fuse(), peeked: None } - } - - delegate_access_inner!(stream, St, (.)); - - /// Produces a future which retrieves a reference to the next item - /// in the stream, or `None` if the underlying stream terminates. - pub fn peek(self: Pin<&mut Self>) -> Peek<'_, St> { - Peek { inner: Some(self) } - } - - /// Peek retrieves a reference to the next item in the stream. - /// - /// This method polls the underlying stream and return either a reference - /// to the next item if the stream is ready or passes through any errors. - pub fn poll_peek(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if this.peeked.is_some() { - break this.peeked.as_ref(); - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - *this.peeked = Some(item); - } else { - break None; - } - }) - } - - /// Produces a future which retrieves a mutable reference to the next item - /// in the stream, or `None` if the underlying stream terminates. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use core::pin::pin; - /// - /// use futures::stream; - /// use futures::stream::StreamExt; - /// - /// let stream = stream::iter(vec![1, 2, 3]).peekable(); - /// 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)); - /// - /// // Peek into the stream and modify the value which will be returned next - /// if let Some(p) = stream.as_mut().peek_mut().await { - /// if *p == 2 { - /// *p = 5; - /// } - /// } - /// - /// assert_eq!(stream.collect::>().await, vec![5, 3]); - /// # }); - /// ``` - pub fn peek_mut(self: Pin<&mut Self>) -> PeekMut<'_, St> { - PeekMut { inner: Some(self) } - } - - /// Peek retrieves a mutable reference to the next item in the stream. - pub fn poll_peek_mut( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if this.peeked.is_some() { - break this.peeked.as_mut(); - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - *this.peeked = Some(item); - } else { - break None; - } - }) - } - - /// Creates a future which will consume and return the next value of this - /// stream if a condition is true. - /// - /// If `func` returns `true` for the next value of this stream, consume and - /// return it. Otherwise, return `None`. - /// - /// # Examples - /// - /// Consume a number if it's equal to 0. - /// - /// ``` - /// # futures::executor::block_on(async { - /// use core::pin::pin; - /// - /// use futures::stream; - /// use futures::stream::StreamExt; - /// - /// let stream = stream::iter(0..5).peekable(); - /// 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`. - /// assert_eq!(stream.as_mut().next_if(|&x| x == 0).await, None); - /// // `next_if` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(stream.next().await, Some(1)); - /// # }); - /// ``` - /// - /// Consume any number less than 10. - /// - /// ``` - /// # futures::executor::block_on(async { - /// use core::pin::pin; - /// - /// use futures::stream; - /// use futures::stream::StreamExt; - /// - /// let stream = stream::iter(1..20).peekable(); - /// 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 - /// assert_eq!(stream.next().await, Some(10)); - /// # }); - /// ``` - pub fn next_if(self: Pin<&mut Self>, func: F) -> NextIf<'_, St, F> - where - F: FnOnce(&St::Item) -> bool, - { - NextIf { inner: Some((self, func)) } - } - - /// Creates a future which will consume and return the next item if it is - /// equal to `expected`. - /// - /// # Example - /// - /// Consume a number if it's equal to 0. - /// - /// ``` - /// # futures::executor::block_on(async { - /// use core::pin::pin; - /// - /// use futures::stream; - /// use futures::stream::StreamExt; - /// - /// let stream = stream::iter(0..5).peekable(); - /// 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`. - /// assert_eq!(stream.as_mut().next_if_eq(&0).await, None); - /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(stream.next().await, Some(1)); - /// # }); - /// ``` - pub fn next_if_eq<'a, T>(self: Pin<&'a mut Self>, expected: &'a T) -> NextIfEq<'a, St, T> - where - T: ?Sized, - St::Item: PartialEq, - { - NextIfEq { - inner: NextIf { inner: Some((self, NextIfEqFn { expected, _next: PhantomData })) }, - } - } -} - -impl FusedStream for Peekable { - fn is_terminated(&self) -> bool { - self.peeked.is_none() && self.stream.is_terminated() - } -} - -impl Stream for Peekable { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - if let Some(item) = this.peeked.take() { - return Poll::Ready(Some(item)); - } - this.stream.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - let peek_len = usize::from(self.peeked.is_some()); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(peek_len); - let upper = match upper { - Some(x) => x.checked_add(peek_len), - None => None, - }; - (lower, upper) - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Peekable -where - S: Sink + Stream, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} - -pin_project! { - /// Future for the [`Peekable::peek`](self::Peekable::peek) method. - #[must_use = "futures do nothing unless polled"] - pub struct Peek<'a, St: Stream> { - inner: Option>>, - } -} - -impl fmt::Debug for Peek<'_, St> -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Peek").field("inner", &self.inner).finish() - } -} - -impl FusedFuture for Peek<'_, St> { - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl<'a, St> Future for Peek<'a, St> -where - St: Stream, -{ - type Output = Option<&'a St::Item>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let inner = self.project().inner; - if let Some(peekable) = inner { - ready!(peekable.as_mut().poll_peek(cx)); - - inner.take().unwrap().poll_peek(cx) - } else { - panic!("Peek polled after completion") - } - } -} - -pin_project! { - /// Future for the [`Peekable::peek_mut`](self::Peekable::peek_mut) method. - #[must_use = "futures do nothing unless polled"] - pub struct PeekMut<'a, St: Stream> { - inner: Option>>, - } -} - -impl fmt::Debug for PeekMut<'_, St> -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PeekMut").field("inner", &self.inner).finish() - } -} - -impl FusedFuture for PeekMut<'_, St> { - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl<'a, St> Future for PeekMut<'a, St> -where - St: Stream, -{ - type Output = Option<&'a mut St::Item>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let inner = self.project().inner; - if let Some(peekable) = inner { - ready!(peekable.as_mut().poll_peek_mut(cx)); - - inner.take().unwrap().poll_peek_mut(cx) - } else { - panic!("PeekMut polled after completion") - } - } -} - -pin_project! { - /// Future for the [`Peekable::next_if`](self::Peekable::next_if) method. - #[must_use = "futures do nothing unless polled"] - pub struct NextIf<'a, St: Stream, F> { - inner: Option<(Pin<&'a mut Peekable>, F)>, - } -} - -impl fmt::Debug for NextIf<'_, St, F> -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("NextIf").field("inner", &self.inner.as_ref().map(|(s, _f)| s)).finish() - } -} - -impl FusedFuture for NextIf<'_, St, F> -where - St: Stream, - F: for<'a> FnOnce1<&'a St::Item, Output = bool>, -{ - fn is_terminated(&self) -> bool { - self.inner.is_none() - } -} - -impl Future for NextIf<'_, St, F> -where - St: Stream, - F: for<'a> FnOnce1<&'a St::Item, Output = bool>, -{ - type Output = Option; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let inner = self.project().inner; - if let Some((peekable, _)) = inner { - let res = ready!(peekable.as_mut().poll_next(cx)); - - let (peekable, func) = inner.take().unwrap(); - match res { - Some(ref matched) if func.call_once(matched) => Poll::Ready(res), - other => { - let peekable = peekable.project(); - // Since we called `self.next()`, we consumed `self.peeked`. - assert!(peekable.peeked.is_none()); - *peekable.peeked = other; - Poll::Ready(None) - } - } - } else { - panic!("NextIf polled after completion") - } - } -} - -pin_project! { - /// Future for the [`Peekable::next_if_eq`](self::Peekable::next_if_eq) method. - #[must_use = "futures do nothing unless polled"] - pub struct NextIfEq<'a, St: Stream, T: ?Sized> { - #[pin] - inner: NextIf<'a, St, NextIfEqFn<'a, T, St::Item>>, - } -} - -impl fmt::Debug for NextIfEq<'_, St, T> -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - T: ?Sized, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("NextIfEq") - .field("inner", &self.inner.inner.as_ref().map(|(s, _f)| s)) - .finish() - } -} - -impl FusedFuture for NextIfEq<'_, St, T> -where - St: Stream, - T: ?Sized, - St::Item: PartialEq, -{ - fn is_terminated(&self) -> bool { - self.inner.is_terminated() - } -} - -impl Future for NextIfEq<'_, St, T> -where - St: Stream, - T: ?Sized, - St::Item: PartialEq, -{ - type Output = Option; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().inner.poll(cx) - } -} - -struct NextIfEqFn<'a, T: ?Sized, Item> { - expected: &'a T, - _next: PhantomData, -} - -impl FnOnce1<&Item> for NextIfEqFn<'_, T, Item> -where - T: ?Sized, - Item: PartialEq, -{ - type Output = bool; - - fn call_once(self, next: &Item) -> Self::Output { - next == self.expected - } -} diff --git a/futures-util/src/stream/stream/ready_chunks.rs b/futures-util/src/stream/stream/ready_chunks.rs deleted file mode 100644 index 192054c4ae..0000000000 --- a/futures-util/src/stream/stream/ready_chunks.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::stream::{Fuse, StreamExt}; -use alloc::vec::Vec; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`ready_chunks`](super::StreamExt::ready_chunks) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct ReadyChunks { - #[pin] - stream: Fuse, - cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 - } -} - -impl ReadyChunks { - pub(super) fn new(stream: St, capacity: usize) -> Self { - assert!(capacity > 0); - - Self { stream: stream.fuse(), cap: capacity } - } - - delegate_access_inner!(stream, St, (.)); -} - -impl Stream for ReadyChunks { - type Item = Vec; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - let mut items: Vec = Vec::new(); - - loop { - match this.stream.as_mut().poll_next(cx) { - // Flush all collected data if underlying stream doesn't contain - // more ready values - Poll::Pending => { - return if items.is_empty() { Poll::Pending } else { Poll::Ready(Some(items)) } - } - - // Push the ready item into the buffer and check whether it is full. - // If so, replace our buffer with a new and empty one and return - // the full one. - Poll::Ready(Some(item)) => { - if items.is_empty() { - items.reserve(*this.cap); - } - items.push(item); - if items.len() >= *this.cap { - return Poll::Ready(Some(items)); - } - } - - // Since the underlying stream ran out of values, return what we - // have buffered, if we have anything. - Poll::Ready(None) => { - let last = if items.is_empty() { None } else { Some(items) }; - - return Poll::Ready(last); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.stream.size_hint(); - let lower = lower / self.cap; - (lower, upper) - } -} - -impl FusedStream for ReadyChunks { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for ReadyChunks -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/scan.rs b/futures-util/src/stream/stream/scan.rs deleted file mode 100644 index c5cf035c55..0000000000 --- a/futures-util/src/stream/stream/scan.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::unfold_state::UnfoldState; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`scan`](super::StreamExt::scan) method. - #[must_use = "streams do nothing unless polled"] - pub struct Scan { - #[pin] - stream: St, - f: F, - #[pin] - state: UnfoldState, - } -} - -impl fmt::Debug for Scan -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - S: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Scan") - .field("stream", &self.stream) - .field("state", &self.state) - .field("done_taking", &self.is_done_taking()) - .finish() - } -} - -impl Scan { - /// Checks if internal state is `None`. - fn is_done_taking(&self) -> bool { - self.state.is_empty() - } -} - -impl Scan -where - St: Stream, - F: FnMut(S, St::Item) -> Fut, - Fut: Future>, -{ - pub(super) fn new(stream: St, initial_state: S, f: F) -> Self { - Self { stream, f, state: UnfoldState::Value { value: initial_state } } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for Scan -where - St: Stream, - F: FnMut(S, St::Item) -> Fut, - Fut: Future>, -{ - type Item = B; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.is_done_taking() { - return Poll::Ready(None); - } - - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.state.as_mut().project_future() { - match ready!(fut.poll(cx)) { - None => { - this.state.set(UnfoldState::Empty); - break None; - } - Some((state, item)) => { - this.state.set(UnfoldState::Value { value: state }); - break Some(item); - } - } - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - let state = this.state.as_mut().take_value().unwrap(); - this.state.set(UnfoldState::Future { future: (this.f)(state, item) }) - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_done_taking() { - (0, Some(0)) - } else { - self.stream.size_hint() // can't know a lower bound, due to the predicate - } - } -} - -impl FusedStream for Scan -where - St: FusedStream, - F: FnMut(S, St::Item) -> Fut, - Fut: Future>, -{ - fn is_terminated(&self) -> bool { - self.is_done_taking() || !self.state.is_future() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Scan -where - St: Stream + Sink, -{ - type Error = St::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/select_next_some.rs b/futures-util/src/stream/stream/select_next_some.rs deleted file mode 100644 index 3115e14d9a..0000000000 --- a/futures-util/src/stream/stream/select_next_some.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::stream::StreamExt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::FusedStream; -use futures_core::task::{Context, Poll}; - -/// Future for the [`select_next_some`](super::StreamExt::select_next_some) -/// method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct SelectNextSome<'a, St: ?Sized> { - stream: &'a mut St, -} - -impl<'a, St: ?Sized> SelectNextSome<'a, St> { - pub(super) fn new(stream: &'a mut St) -> Self { - Self { stream } - } -} - -impl FusedFuture for SelectNextSome<'_, St> { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for SelectNextSome<'_, St> { - type Output = St::Item; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - assert!(!self.stream.is_terminated(), "SelectNextSome polled after terminated"); - - if let Some(item) = ready!(self.stream.poll_next_unpin(cx)) { - Poll::Ready(item) - } else { - debug_assert!(self.stream.is_terminated()); - cx.waker().wake_by_ref(); - Poll::Pending - } - } -} diff --git a/futures-util/src/stream/stream/skip.rs b/futures-util/src/stream/stream/skip.rs deleted file mode 100644 index f495779521..0000000000 --- a/futures-util/src/stream/stream/skip.rs +++ /dev/null @@ -1,70 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`skip`](super::StreamExt::skip) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Skip { - #[pin] - stream: St, - remaining: usize, - } -} - -impl Skip { - pub(super) fn new(stream: St, n: usize) -> Self { - Self { stream, remaining: n } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Skip { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Stream for Skip { - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - while *this.remaining > 0 { - if ready!(this.stream.as_mut().poll_next(cx)).is_some() { - *this.remaining -= 1; - } else { - return Poll::Ready(None); - } - } - - this.stream.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.stream.size_hint(); - - let lower = lower.saturating_sub(self.remaining); - let upper = upper.map(|x| x.saturating_sub(self.remaining)); - - (lower, upper) - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Skip -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/skip_while.rs b/futures-util/src/stream/stream/skip_while.rs deleted file mode 100644 index dabd5eefae..0000000000 --- a/futures-util/src/stream/stream/skip_while.rs +++ /dev/null @@ -1,124 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`skip_while`](super::StreamExt::skip_while) method. - #[must_use = "streams do nothing unless polled"] - pub struct SkipWhile where St: Stream { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - done_skipping: bool, - } -} - -impl fmt::Debug for SkipWhile -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SkipWhile") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .field("done_skipping", &self.done_skipping) - .finish() - } -} - -impl SkipWhile -where - St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None, done_skipping: false } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for SkipWhile -where - St: FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.pending_item.is_none() && self.stream.is_terminated() - } -} - -impl Stream for SkipWhile -where - St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if *this.done_skipping { - return this.stream.poll_next(cx); - } - - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let skipped = ready!(fut.poll(cx)); - let item = this.pending_item.take(); - this.pending_fut.set(None); - if !skipped { - *this.done_skipping = true; - break item; - } - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - this.pending_fut.set(Some((this.f)(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - if self.done_skipping { - self.stream.size_hint() - } else { - let pending_len = usize::from(self.pending_item.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for SkipWhile -where - S: Stream + Sink, - F: FnMut(&S::Item) -> Fut, - Fut: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/split.rs b/futures-util/src/stream/stream/split.rs deleted file mode 100644 index e192f8a92d..0000000000 --- a/futures-util/src/stream/stream/split.rs +++ /dev/null @@ -1,224 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; - -use crate::lock::BiLock; - -/// A `Stream` part of the split pair -#[derive(Debug)] -#[must_use = "streams do nothing unless polled"] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub struct SplitStream(BiLock); - -impl Unpin for SplitStream {} - -impl SplitStream { - /// Returns `true` if the `SplitStream` and `SplitSink` originate from the same call to `StreamExt::split`. - pub fn is_pair_of(&self, other: &SplitSink) -> bool { - other.is_pair_of(&self) - } -} - -impl SplitStream { - /// Attempts to put the two "halves" of a split `Stream + Sink` back - /// together. Succeeds only if the `SplitStream` and `SplitSink` are - /// a matching pair originating from the same call to `StreamExt::split`. - pub fn reunite(self, other: SplitSink) -> Result> - where - S: Sink, - { - other.reunite(self) - } -} - -impl Stream for SplitStream { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ready!(self.0.poll_lock(cx)).as_pin_mut().poll_next(cx) - } -} - -#[allow(non_snake_case)] -fn SplitSink, Item>(lock: BiLock) -> SplitSink { - SplitSink { lock, slot: None } -} - -/// A `Sink` part of the split pair -#[derive(Debug)] -#[must_use = "sinks do nothing unless polled"] -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub struct SplitSink { - lock: BiLock, - slot: Option, -} - -impl Unpin for SplitSink {} - -impl + Unpin, Item> SplitSink { - /// Attempts to put the two "halves" of a split `Stream + Sink` back - /// together. Succeeds only if the `SplitStream` and `SplitSink` are - /// a matching pair originating from the same call to `StreamExt::split`. - pub fn reunite(self, other: SplitStream) -> Result> { - self.lock.reunite(other.0).map_err(|err| ReuniteError(SplitSink(err.0), SplitStream(err.1))) - } -} - -impl SplitSink { - /// Returns `true` if the `SplitStream` and `SplitSink` originate from the same call to `StreamExt::split`. - pub fn is_pair_of(&self, other: &SplitStream) -> bool { - self.lock.is_pair_of(&other.0) - } -} - -impl, Item> SplitSink { - fn poll_flush_slot( - mut inner: Pin<&mut S>, - slot: &mut Option, - cx: &mut Context<'_>, - ) -> Poll> { - if slot.is_some() { - ready!(inner.as_mut().poll_ready(cx))?; - Poll::Ready(inner.start_send(slot.take().unwrap())) - } else { - Poll::Ready(Ok(())) - } - } - - fn poll_lock_and_flush_slot( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - let this = &mut *self; - let mut inner = ready!(this.lock.poll_lock(cx)); - Self::poll_flush_slot(inner.as_pin_mut(), &mut this.slot, cx) - } -} - -impl, Item> Sink for SplitSink { - type Error = S::Error; - - fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - if self.slot.is_none() { - return Poll::Ready(Ok(())); - } - ready!(self.as_mut().poll_lock_and_flush_slot(cx))?; - } - } - - fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), S::Error> { - self.slot = Some(item); - Ok(()) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let mut inner = ready!(this.lock.poll_lock(cx)); - ready!(Self::poll_flush_slot(inner.as_pin_mut(), &mut this.slot, cx))?; - inner.as_pin_mut().poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let mut inner = ready!(this.lock.poll_lock(cx)); - ready!(Self::poll_flush_slot(inner.as_pin_mut(), &mut this.slot, cx))?; - inner.as_pin_mut().poll_close(cx) - } -} - -pub(super) fn split, Item>(s: S) -> (SplitSink, SplitStream) { - let (a, b) = BiLock::new(s); - let read = SplitStream(a); - let write = SplitSink(b); - (write, read) -} - -/// Error indicating a `SplitSink` and `SplitStream` were not two halves -/// of a `Stream + Split`, and thus could not be `reunite`d. -#[cfg_attr(docsrs, doc(cfg(feature = "sink")))] -pub struct ReuniteError(pub SplitSink, pub SplitStream); - -impl fmt::Debug for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ReuniteError").field(&"...").finish() - } -} - -impl fmt::Display for ReuniteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "tried to reunite a SplitStream and SplitSink that don't form a pair") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ReuniteError {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::stream::StreamExt; - use core::marker::PhantomData; - - struct NopStream { - phantom: PhantomData, - } - - impl Stream for NopStream { - type Item = Item; - - fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - todo!() - } - } - - impl Sink for NopStream { - type Error = (); - - fn poll_ready( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll> { - todo!() - } - - fn start_send(self: Pin<&mut Self>, _item: Item) -> Result<(), Self::Error> { - todo!() - } - - fn poll_flush( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll> { - todo!() - } - - fn poll_close( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll> { - todo!() - } - } - - #[test] - fn test_pairing() { - let s1 = NopStream::<()> { phantom: PhantomData }; - let (sink1, stream1) = s1.split(); - assert!(sink1.is_pair_of(&stream1)); - assert!(stream1.is_pair_of(&sink1)); - - let s2 = NopStream::<()> { phantom: PhantomData }; - let (sink2, stream2) = s2.split(); - assert!(sink2.is_pair_of(&stream2)); - assert!(stream2.is_pair_of(&sink2)); - - assert!(!sink1.is_pair_of(&stream2)); - assert!(!stream1.is_pair_of(&sink2)); - assert!(!sink2.is_pair_of(&stream1)); - assert!(!stream2.is_pair_of(&sink1)); - } -} diff --git a/futures-util/src/stream/stream/take.rs b/futures-util/src/stream/stream/take.rs deleted file mode 100644 index 29d6c39ee3..0000000000 --- a/futures-util/src/stream/stream/take.rs +++ /dev/null @@ -1,86 +0,0 @@ -use core::cmp; -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`take`](super::StreamExt::take) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Take { - #[pin] - stream: St, - remaining: usize, - } -} - -impl Take { - pub(super) fn new(stream: St, n: usize) -> Self { - Self { stream, remaining: n } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for Take -where - St: Stream, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.remaining == 0 { - Poll::Ready(None) - } else { - let this = self.project(); - let next = ready!(this.stream.poll_next(cx)); - if next.is_some() { - *this.remaining -= 1; - } else { - *this.remaining = 0; - } - Poll::Ready(next) - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.remaining == 0 { - return (0, Some(0)); - } - - let (lower, upper) = self.stream.size_hint(); - - let lower = cmp::min(lower, self.remaining); - - let upper = match upper { - Some(x) if x < self.remaining => Some(x), - _ => Some(self.remaining), - }; - - (lower, upper) - } -} - -impl FusedStream for Take -where - St: FusedStream, -{ - fn is_terminated(&self) -> bool { - self.remaining == 0 || self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Take -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/take_until.rs b/futures-util/src/stream/stream/take_until.rs deleted file mode 100644 index d14f9ce100..0000000000 --- a/futures-util/src/stream/stream/take_until.rs +++ /dev/null @@ -1,170 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -// FIXME: docs, tests - -pin_project! { - /// Stream for the [`take_until`](super::StreamExt::take_until) method. - #[must_use = "streams do nothing unless polled"] - pub struct TakeUntil { - #[pin] - stream: St, - // Contains the inner Future on start and None once the inner Future is resolved - // or taken out by the user. - #[pin] - fut: Option, - // Contains fut's return value once fut is resolved - fut_result: Option, - // Whether the future was taken out by the user. - free: bool, - } -} - -impl fmt::Debug for TakeUntil -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - Fut: Future + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TakeUntil").field("stream", &self.stream).field("fut", &self.fut).finish() - } -} - -impl TakeUntil -where - St: Stream, - Fut: Future, -{ - pub(super) fn new(stream: St, fut: Fut) -> Self { - Self { stream, fut: Some(fut), fut_result: None, free: false } - } - - delegate_access_inner!(stream, St, ()); - - /// Extract the stopping future out of the combinator. - /// The future is returned only if it isn't resolved yet, ie. if the stream isn't stopped yet. - /// Taking out the future means the combinator will be yielding - /// elements from the wrapped stream without ever stopping it. - pub fn take_future(&mut self) -> Option { - if self.fut.is_some() { - self.free = true; - } - - self.fut.take() - } - - /// Once the stopping future is resolved, this method can be used - /// to extract the value returned by the stopping future. - /// - /// This may be used to retrieve arbitrary data from the stopping - /// future, for example a reason why the stream was stopped. - /// - /// This method will return `None` if the future isn't resolved yet, - /// or if the result was already taken out. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt}; - /// use futures::task::Poll; - /// - /// let stream = stream::iter(1..=10); - /// - /// let mut i = 0; - /// let stop_fut = future::poll_fn(|_cx| { - /// i += 1; - /// if i <= 5 { - /// Poll::Pending - /// } else { - /// Poll::Ready("reason") - /// } - /// }); - /// - /// let mut stream = stream.take_until(stop_fut); - /// let _ = stream.by_ref().collect::>().await; - /// - /// let result = stream.take_result().unwrap(); - /// assert_eq!(result, "reason"); - /// # }); - /// ``` - pub fn take_result(&mut self) -> Option { - self.fut_result.take() - } - - /// Whether the stream was stopped yet by the stopping future - /// being resolved. - pub fn is_stopped(&self) -> bool { - !self.free && self.fut.is_none() - } -} - -impl Stream for TakeUntil -where - St: Stream, - Fut: Future, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if let Some(f) = this.fut.as_mut().as_pin_mut() { - if let Poll::Ready(result) = f.poll(cx) { - this.fut.set(None); - *this.fut_result = Some(result); - } - } - - if !*this.free && this.fut.is_none() { - // Future resolved, inner stream stopped - Poll::Ready(None) - } else { - // Future either not resolved yet or taken out by the user - let item = ready!(this.stream.poll_next(cx)); - if item.is_none() { - this.fut.set(None); - } - Poll::Ready(item) - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_stopped() { - return (0, Some(0)); - } - - self.stream.size_hint() - } -} - -impl FusedStream for TakeUntil -where - St: Stream, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.is_stopped() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TakeUntil -where - S: Stream + Sink, - Fut: Future, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/take_while.rs b/futures-util/src/stream/stream/take_while.rs deleted file mode 100644 index 9256943010..0000000000 --- a/futures-util/src/stream/stream/take_while.rs +++ /dev/null @@ -1,124 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`take_while`](super::StreamExt::take_while) method. - #[must_use = "streams do nothing unless polled"] - pub struct TakeWhile { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - done_taking: bool, - } -} - -impl fmt::Debug for TakeWhile -where - St: Stream + fmt::Debug, - St::Item: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TakeWhile") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .field("done_taking", &self.done_taking) - .finish() - } -} - -impl TakeWhile -where - St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None, done_taking: false } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for TakeWhile -where - St: Stream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - type Item = St::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.done_taking { - return Poll::Ready(None); - } - - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let take = ready!(fut.poll(cx)); - let item = this.pending_item.take(); - this.pending_fut.set(None); - if take { - break item; - } else { - *this.done_taking = true; - break None; - } - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - this.pending_fut.set(Some((this.f)(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - if self.done_taking { - return (0, Some(0)); - } - - let pending_len = usize::from(self.pending_item.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -impl FusedStream for TakeWhile -where - St: FusedStream, - F: FnMut(&St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.done_taking || self.pending_item.is_none() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TakeWhile -where - S: Stream + Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/then.rs b/futures-util/src/stream/stream/then.rs deleted file mode 100644 index 9192c0b0cf..0000000000 --- a/futures-util/src/stream/stream/then.rs +++ /dev/null @@ -1,101 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`then`](super::StreamExt::then) method. - #[must_use = "streams do nothing unless polled"] - pub struct Then { - #[pin] - stream: St, - #[pin] - future: Option, - f: F, - } -} - -impl fmt::Debug for Then -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Then").field("stream", &self.stream).field("future", &self.future).finish() - } -} - -impl Then -where - St: Stream, - F: FnMut(St::Item) -> Fut, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, future: None, f } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for Then -where - St: FusedStream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.future.is_none() && self.stream.is_terminated() - } -} - -impl Stream for Then -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future, -{ - type Item = Fut::Output; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - let item = ready!(fut.poll(cx)); - this.future.set(None); - break Some(item); - } else if let Some(item) = ready!(this.stream.as_mut().poll_next(cx)) { - this.future.set(Some((this.f)(item))); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let future_len = usize::from(self.future.is_some()); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(future_len); - let upper = match upper { - Some(x) => x.checked_add(future_len), - None => None, - }; - (lower, upper) - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for Then -where - S: Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/stream/try_fold.rs b/futures-util/src/stream/stream/try_fold.rs deleted file mode 100644 index fcbc0aef24..0000000000 --- a/futures-util/src/stream/stream/try_fold.rs +++ /dev/null @@ -1,92 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future, TryFuture}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_fold`](super::TryStreamExt::try_fold) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryFold { - #[pin] - stream: St, - f: F, - accum: Option, - #[pin] - future: Option, - } -} - -impl fmt::Debug for TryFold -where - St: fmt::Debug, - Fut: fmt::Debug, - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryFold") - .field("stream", &self.stream) - .field("accum", &self.accum) - .field("future", &self.future) - .finish() - } -} - -impl TryFold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F, t: T) -> Self { - Self { stream, f, accum: Some(t), future: None } - } -} - -impl FusedFuture for TryFold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: TryFuture, -{ - fn is_terminated(&self) -> bool { - self.accum.is_none() && self.future.is_none() - } -} - -impl Future for TryFold -where - St: Stream, - F: FnMut(T, St::Item) -> Fut, - Fut: TryFuture, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new accum value - let res = ready!(fut.try_poll(cx)); - this.future.set(None); - match res { - Ok(a) => *this.accum = Some(a), - Err(e) => break Err(e), - } - } else if this.accum.is_some() { - // we're waiting on a new item from the stream - let res = ready!(this.stream.as_mut().poll_next(cx)); - let a = this.accum.take().unwrap(); - match res { - Some(item) => this.future.set(Some((this.f)(a, item))), - None => break Ok(a), - } - } else { - panic!("Fold polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/stream/try_for_each.rs b/futures-util/src/stream/stream/try_for_each.rs deleted file mode 100644 index c892eb83c7..0000000000 --- a/futures-util/src/stream/stream/try_for_each.rs +++ /dev/null @@ -1,68 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{Future, TryFuture}; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_for_each`](super::StreamExt::try_for_each) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryForEach { - #[pin] - stream: St, - f: F, - #[pin] - future: Option, - } -} - -impl fmt::Debug for TryForEach -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryForEach") - .field("stream", &self.stream) - .field("future", &self.future) - .finish() - } -} - -impl TryForEach -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, future: None } - } -} - -impl Future for TryForEach -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: TryFuture, -{ - type Output = Result<(), Fut::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - ready!(fut.try_poll(cx))?; - this.future.set(None); - } else { - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(e) => this.future.set(Some((this.f)(e))), - None => break, - } - } - } - Poll::Ready(Ok(())) - } -} diff --git a/futures-util/src/stream/stream/try_for_each_concurrent.rs b/futures-util/src/stream/stream/try_for_each_concurrent.rs deleted file mode 100644 index f74c9c5718..0000000000 --- a/futures-util/src/stream/stream/try_for_each_concurrent.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::stream::{FuturesUnordered, StreamExt}; -use core::fmt; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the - /// [`try_for_each_concurrent`](super::TryStreamExt::try_for_each_concurrent) - /// method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryForEachConcurrent { - #[pin] - stream: Option, - f: F, - futures: FuturesUnordered, - limit: Option, - } -} - -impl fmt::Debug for TryForEachConcurrent -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryForEachConcurrent") - .field("stream", &self.stream) - .field("futures", &self.futures) - .field("limit", &self.limit) - .finish() - } -} - -impl FusedFuture for TryForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future>, -{ - fn is_terminated(&self) -> bool { - self.stream.is_none() && self.futures.is_empty() - } -} - -impl TryForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future>, -{ - pub(super) fn new(stream: St, limit: Option, f: F) -> Self { - Self { - stream: Some(stream), - // Note: `limit` = 0 gets ignored. - limit: limit.and_then(NonZeroUsize::new), - f, - futures: FuturesUnordered::new(), - } - } -} - -impl Future for TryForEachConcurrent -where - St: Stream, - F: FnMut(St::Item) -> Fut, - Fut: Future>, -{ - type Output = Result<(), E>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - loop { - let mut made_progress_this_iter = false; - - // Check if we've already created a number of futures greater than `limit` - if this.limit.map(|limit| limit.get() > this.futures.len()).unwrap_or(true) { - let poll_res = match this.stream.as_mut().as_pin_mut() { - Some(stream) => stream.poll_next(cx), - None => Poll::Ready(None), - }; - - let elem = match poll_res { - Poll::Ready(Some(elem)) => { - made_progress_this_iter = true; - Some(elem) - } - Poll::Ready(None) => { - this.stream.set(None); - None - } - Poll::Pending => None, - }; - - if let Some(elem) = elem { - this.futures.push((this.f)(elem)); - } - } - - match this.futures.poll_next_unpin(cx) { - Poll::Ready(Some(Ok(()))) => made_progress_this_iter = true, - Poll::Ready(None) => { - if this.stream.is_none() { - return Poll::Ready(Ok(())); - } - } - Poll::Pending => {} - Poll::Ready(Some(Err(e))) => { - // Empty the stream and futures so that we know - // the future has completed. - this.stream.set(None); - drop(core::mem::take(this.futures)); - return Poll::Ready(Err(e)); - } - } - - if !made_progress_this_iter { - return Poll::Pending; - } - } - } -} diff --git a/futures-util/src/stream/stream/unzip.rs b/futures-util/src/stream/stream/unzip.rs deleted file mode 100644 index a88cf03266..0000000000 --- a/futures-util/src/stream/stream/unzip.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::mem; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`unzip`](super::StreamExt::unzip) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct Unzip { - #[pin] - stream: St, - left: FromA, - right: FromB, - } -} - -impl Unzip { - fn finish(self: Pin<&mut Self>) -> (FromA, FromB) { - let this = self.project(); - (mem::take(this.left), mem::take(this.right)) - } - - pub(super) fn new(stream: St) -> Self { - Self { stream, left: Default::default(), right: Default::default() } - } -} - -impl FusedFuture for Unzip -where - St: FusedStream, - FromA: Default + Extend, - FromB: Default + Extend, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for Unzip -where - St: Stream, - FromA: Default + Extend, - FromB: Default + Extend, -{ - type Output = (FromA, FromB); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<(FromA, FromB)> { - let mut this = self.as_mut().project(); - loop { - match ready!(this.stream.as_mut().poll_next(cx)) { - Some(e) => { - this.left.extend(Some(e.0)); - this.right.extend(Some(e.1)); - } - None => return Poll::Ready(self.finish()), - } - } - } -} diff --git a/futures-util/src/stream/stream/zip.rs b/futures-util/src/stream/stream/zip.rs deleted file mode 100644 index 25a47e96be..0000000000 --- a/futures-util/src/stream/stream/zip.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::stream::{Fuse, StreamExt}; -use core::cmp; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`zip`](super::StreamExt::zip) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct Zip { - #[pin] - stream1: Fuse, - #[pin] - stream2: Fuse, - queued1: Option, - queued2: Option, - } -} - -impl Zip { - pub(super) fn new(stream1: St1, stream2: St2) -> Self { - Self { stream1: stream1.fuse(), stream2: stream2.fuse(), queued1: None, queued2: None } - } - - /// Acquires a reference to the underlying streams that this combinator is - /// pulling from. - pub fn get_ref(&self) -> (&St1, &St2) { - (self.stream1.get_ref(), self.stream2.get_ref()) - } - - /// Acquires a mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_mut(&mut self) -> (&mut St1, &mut St2) { - (self.stream1.get_mut(), self.stream2.get_mut()) - } - - /// Acquires a pinned mutable reference to the underlying streams that this - /// combinator is pulling from. - /// - /// Note that care must be taken to avoid tampering with the state of the - /// stream which may otherwise confuse this combinator. - pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut St1>, Pin<&mut St2>) { - let this = self.project(); - (this.stream1.get_pin_mut(), this.stream2.get_pin_mut()) - } - - /// Consumes this combinator, returning the underlying streams. - /// - /// Note that this may discard intermediate state of this combinator, so - /// care should be taken to avoid losing resources when this is called. - pub fn into_inner(self) -> (St1, St2) { - (self.stream1.into_inner(), self.stream2.into_inner()) - } -} - -impl FusedStream for Zip -where - St1: Stream, - St2: Stream, -{ - fn is_terminated(&self) -> bool { - self.stream1.is_terminated() && self.stream2.is_terminated() - } -} - -impl Stream for Zip -where - St1: Stream, - St2: Stream, -{ - type Item = (St1::Item, St2::Item); - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if this.queued1.is_none() { - match this.stream1.as_mut().poll_next(cx) { - Poll::Ready(Some(item1)) => *this.queued1 = Some(item1), - Poll::Ready(None) | Poll::Pending => {} - } - } - if this.queued2.is_none() { - match this.stream2.as_mut().poll_next(cx) { - Poll::Ready(Some(item2)) => *this.queued2 = Some(item2), - Poll::Ready(None) | Poll::Pending => {} - } - } - - if this.queued1.is_some() && this.queued2.is_some() { - let pair = (this.queued1.take().unwrap(), this.queued2.take().unwrap()); - Poll::Ready(Some(pair)) - } else if this.stream1.is_done() || this.stream2.is_done() { - Poll::Ready(None) - } else { - Poll::Pending - } - } - - fn size_hint(&self) -> (usize, Option) { - let queued1_len = usize::from(self.queued1.is_some()); - let queued2_len = usize::from(self.queued2.is_some()); - let (stream1_lower, stream1_upper) = self.stream1.size_hint(); - let (stream2_lower, stream2_upper) = self.stream2.size_hint(); - - let stream1_lower = stream1_lower.saturating_add(queued1_len); - let stream2_lower = stream2_lower.saturating_add(queued2_len); - - let lower = cmp::min(stream1_lower, stream2_lower); - - let upper = match (stream1_upper, stream2_upper) { - (Some(x), Some(y)) => { - let x = x.saturating_add(queued1_len); - let y = y.saturating_add(queued2_len); - Some(cmp::min(x, y)) - } - (Some(x), None) => x.checked_add(queued1_len), - (None, Some(y)) => y.checked_add(queued2_len), - (None, None) => None, - }; - - (lower, upper) - } -} diff --git a/futures-util/src/stream/try_stream/and_then.rs b/futures-util/src/stream/try_stream/and_then.rs deleted file mode 100644 index 2f8b6f2589..0000000000 --- a/futures-util/src/stream/try_stream/and_then.rs +++ /dev/null @@ -1,105 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`and_then`](super::TryStreamExt::and_then) method. - #[must_use = "streams do nothing unless polled"] - pub struct AndThen { - #[pin] - stream: St, - #[pin] - future: Option, - f: F, - } -} - -impl fmt::Debug for AndThen -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AndThen") - .field("stream", &self.stream) - .field("future", &self.future) - .finish() - } -} - -impl AndThen -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, future: None, f } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for AndThen -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - let item = ready!(fut.try_poll(cx)); - this.future.set(None); - break Some(item); - } else if let Some(item) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - this.future.set(Some((this.f)(item))); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let future_len = usize::from(self.future.is_some()); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(future_len); - let upper = match upper { - Some(x) => x.checked_add(future_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for AndThen -where - St: TryStream + FusedStream, - F: FnMut(St::Ok) -> Fut, - Fut: TryFuture, -{ - fn is_terminated(&self) -> bool { - self.future.is_none() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for AndThen -where - S: Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/into_async_read.rs b/futures-util/src/stream/try_stream/into_async_read.rs deleted file mode 100644 index ffbfc7eae9..0000000000 --- a/futures-util/src/stream/try_stream/into_async_read.rs +++ /dev/null @@ -1,166 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::TryStream; -use futures_core::task::{Context, Poll}; -use futures_io::{AsyncBufRead, AsyncRead, AsyncWrite}; -use pin_project_lite::pin_project; -use std::cmp; -use std::io::{Error, Result}; - -pin_project! { - /// Reader for the [`into_async_read`](super::TryStreamExt::into_async_read) method. - #[derive(Debug)] - #[must_use = "readers do nothing unless polled"] - #[cfg_attr(docsrs, doc(cfg(feature = "io")))] - pub struct IntoAsyncRead - where - St: TryStream, - St::Ok: AsRef<[u8]>, - { - #[pin] - stream: St, - state: ReadState, - } -} - -#[derive(Debug)] -enum ReadState> { - Ready { chunk: T, chunk_start: usize }, - PendingChunk, - Eof, -} - -impl IntoAsyncRead -where - St: TryStream, - St::Ok: AsRef<[u8]>, -{ - pub(super) fn new(stream: St) -> Self { - Self { stream, state: ReadState::PendingChunk } - } -} - -impl AsyncRead for IntoAsyncRead -where - St: TryStream, - St::Ok: AsRef<[u8]>, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let mut this = self.project(); - - loop { - match this.state { - ReadState::Ready { chunk, chunk_start } => { - let chunk = chunk.as_ref(); - let len = cmp::min(buf.len(), chunk.len() - *chunk_start); - - buf[..len].copy_from_slice(&chunk[*chunk_start..*chunk_start + len]); - *chunk_start += len; - - if chunk.len() == *chunk_start { - *this.state = ReadState::PendingChunk; - } - - return Poll::Ready(Ok(len)); - } - ReadState::PendingChunk => match ready!(this.stream.as_mut().try_poll_next(cx)) { - Some(Ok(chunk)) => { - if !chunk.as_ref().is_empty() { - *this.state = ReadState::Ready { chunk, chunk_start: 0 }; - } - } - Some(Err(err)) => { - *this.state = ReadState::Eof; - return Poll::Ready(Err(err)); - } - None => { - *this.state = ReadState::Eof; - return Poll::Ready(Ok(0)); - } - }, - ReadState::Eof => { - return Poll::Ready(Ok(0)); - } - } - } - } -} - -impl AsyncWrite for IntoAsyncRead -where - St: TryStream + AsyncWrite, - St::Ok: AsRef<[u8]>, -{ - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - let this = self.project(); - this.stream.poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - this.stream.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - this.stream.poll_close(cx) - } -} - -impl AsyncBufRead for IntoAsyncRead -where - St: TryStream, - St::Ok: AsRef<[u8]>, -{ - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - while let ReadState::PendingChunk = this.state { - match ready!(this.stream.as_mut().try_poll_next(cx)) { - Some(Ok(chunk)) => { - if !chunk.as_ref().is_empty() { - *this.state = ReadState::Ready { chunk, chunk_start: 0 }; - } - } - Some(Err(err)) => { - *this.state = ReadState::Eof; - return Poll::Ready(Err(err)); - } - None => { - *this.state = ReadState::Eof; - return Poll::Ready(Ok(&[])); - } - } - } - - if let &mut ReadState::Ready { ref chunk, chunk_start } = this.state { - let chunk = chunk.as_ref(); - return Poll::Ready(Ok(&chunk[chunk_start..])); - } - - // To get to this point we must be in ReadState::Eof - Poll::Ready(Ok(&[])) - } - - fn consume(self: Pin<&mut Self>, amount: usize) { - let this = self.project(); - - // https://github.com/rust-lang/futures-rs/pull/1556#discussion_r281644295 - if amount == 0 { - return; - } - if let ReadState::Ready { chunk, chunk_start } = this.state { - *chunk_start += amount; - debug_assert!(*chunk_start <= chunk.as_ref().len()); - if *chunk_start >= chunk.as_ref().len() { - *this.state = ReadState::PendingChunk; - } - } else { - debug_assert!(false, "Attempted to consume from IntoAsyncRead without chunk"); - } - } -} diff --git a/futures-util/src/stream/try_stream/into_stream.rs b/futures-util/src/stream/try_stream/into_stream.rs deleted file mode 100644 index 2126258af7..0000000000 --- a/futures-util/src/stream/try_stream/into_stream.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`into_stream`](super::TryStreamExt::into_stream) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct IntoStream { - #[pin] - stream: St, - } -} - -impl IntoStream { - #[inline] - pub(super) fn new(stream: St) -> Self { - Self { stream } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for IntoStream { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Stream for IntoStream { - type Item = Result; - - #[inline] - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().stream.try_poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option) { - self.stream.size_hint() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl, Item> Sink for IntoStream { - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/mod.rs b/futures-util/src/stream/try_stream/mod.rs deleted file mode 100644 index 7ffd8e54e9..0000000000 --- a/futures-util/src/stream/try_stream/mod.rs +++ /dev/null @@ -1,1123 +0,0 @@ -//! Streams -//! -//! This module contains a number of functions for working with `Streams`s -//! that return `Result`s, allowing for short-circuiting computations. - -#[cfg(feature = "compat")] -use crate::compat::Compat; -use crate::fns::{ - inspect_err_fn, inspect_ok_fn, into_fn, map_err_fn, map_ok_fn, InspectErrFn, InspectOkFn, - IntoFn, MapErrFn, MapOkFn, -}; -use crate::future::assert_future; -use crate::stream::{assert_stream, Inspect, Map}; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -use core::pin::Pin; - -use futures_core::{ - future::{Future, TryFuture}, - stream::TryStream, - task::{Context, Poll}, -}; -#[cfg(feature = "sink")] -use futures_sink::Sink; - -mod and_then; -pub use self::and_then::AndThen; - -delegate_all!( - /// Stream for the [`err_into`](super::TryStreamExt::err_into) method. - ErrInto( - MapErr> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (.)] + New[|x: St| MapErr::new(x, into_fn())] -); - -delegate_all!( - /// Stream for the [`inspect_ok`](super::TryStreamExt::inspect_ok) method. - InspectOk( - Inspect, InspectOkFn> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, f: F| Inspect::new(IntoStream::new(x), inspect_ok_fn(f))] -); - -delegate_all!( - /// Stream for the [`inspect_err`](super::TryStreamExt::inspect_err) method. - InspectErr( - Inspect, InspectErrFn> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, f: F| Inspect::new(IntoStream::new(x), inspect_err_fn(f))] -); - -mod into_stream; -pub use self::into_stream::IntoStream; - -delegate_all!( - /// Stream for the [`map_ok`](super::TryStreamExt::map_ok) method. - MapOk( - Map, MapOkFn> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, f: F| Map::new(IntoStream::new(x), map_ok_fn(f))] -); - -delegate_all!( - /// Stream for the [`map_err`](super::TryStreamExt::map_err) method. - MapErr( - Map, MapErrFn> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] + New[|x: St, f: F| Map::new(IntoStream::new(x), map_err_fn(f))] -); - -mod or_else; -pub use self::or_else::OrElse; - -mod try_next; -pub use self::try_next::TryNext; - -mod try_filter; -pub use self::try_filter::TryFilter; - -#[cfg(feature = "sink")] -mod try_forward; - -#[cfg(feature = "sink")] -delegate_all!( - /// Future for the [`try_forward`](super::TryStreamExt::try_forward) method. - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - TryForward( - try_forward::TryForward - ): Debug + Future + FusedFuture + New[|x: St, y: Si| try_forward::TryForward::new(x, y)] - where St: TryStream -); - -mod try_filter_map; -pub use self::try_filter_map::TryFilterMap; - -mod try_flatten; -pub use self::try_flatten::TryFlatten; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod try_flatten_unordered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::try_flatten_unordered::TryFlattenUnordered; - -mod try_collect; -pub use self::try_collect::TryCollect; - -mod try_concat; -pub use self::try_concat::TryConcat; - -#[cfg(feature = "alloc")] -mod try_chunks; -#[cfg(feature = "alloc")] -pub use self::try_chunks::{TryChunks, TryChunksError}; - -#[cfg(feature = "alloc")] -mod try_ready_chunks; -#[cfg(feature = "alloc")] -pub use self::try_ready_chunks::{TryReadyChunks, TryReadyChunksError}; - -mod try_unfold; -pub use self::try_unfold::{try_unfold, TryUnfold}; - -mod try_skip_while; -pub use self::try_skip_while::TrySkipWhile; - -mod try_take_while; -pub use self::try_take_while::TryTakeWhile; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod try_buffer_unordered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::try_buffer_unordered::TryBufferUnordered; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -mod try_buffered; -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use self::try_buffered::TryBuffered; - -#[cfg(feature = "io")] -#[cfg(feature = "std")] -mod into_async_read; -#[cfg(feature = "io")] -#[cfg_attr(docsrs, doc(cfg(feature = "io")))] -#[cfg(feature = "std")] -pub use self::into_async_read::IntoAsyncRead; - -mod try_all; -pub use self::try_all::TryAll; - -mod try_any; -pub use self::try_any::TryAny; - -impl TryStreamExt for S {} - -/// Adapters specific to `Result`-returning streams -pub trait TryStreamExt: TryStream { - /// Wraps the current stream in a new stream which converts the error type - /// into the one provided. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryStreamExt}; - /// - /// let mut stream = - /// stream::iter(vec![Ok(()), Err(5i32)]) - /// .err_into::(); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(()))); - /// assert_eq!(stream.try_next().await, Err(5i64)); - /// # }) - /// ``` - fn err_into(self) -> ErrInto - where - Self: Sized, - Self::Error: Into, - { - assert_stream::, _>(ErrInto::new(self)) - } - - /// Wraps the current stream in a new stream which maps the success value - /// using the provided closure. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryStreamExt}; - /// - /// let mut stream = - /// stream::iter(vec![Ok(5), Err(0)]) - /// .map_ok(|x| x + 2); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(7))); - /// assert_eq!(stream.try_next().await, Err(0)); - /// # }) - /// ``` - fn map_ok(self, f: F) -> MapOk - where - Self: Sized, - F: FnMut(Self::Ok) -> T, - { - assert_stream::, _>(MapOk::new(self, f)) - } - - /// Wraps the current stream in a new stream which maps the error value - /// using the provided closure. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryStreamExt}; - /// - /// let mut stream = - /// stream::iter(vec![Ok(5), Err(0)]) - /// .map_err(|x| x + 2); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(5))); - /// assert_eq!(stream.try_next().await, Err(2)); - /// # }) - /// ``` - fn map_err(self, f: F) -> MapErr - where - Self: Sized, - F: FnMut(Self::Error) -> E, - { - assert_stream::, _>(MapErr::new(self, f)) - } - - /// Chain on a computation for when a value is ready, passing the successful - /// results to the provided closure `f`. - /// - /// This function can be used to run a unit of work when the next successful - /// value on a stream is ready. The closure provided will be yielded a value - /// when ready, and the returned future will then be run to completion to - /// produce the next value on this stream. - /// - /// Any errors produced by this stream will not be passed to the closure, - /// and will be passed through. - /// - /// The returned value of the closure must implement the `TryFuture` trait - /// and can represent some more work to be done before the composed stream - /// is finished. - /// - /// Note that this function consumes the receiving stream and returns a - /// wrapped version of it. - /// - /// To process the entire stream and return a single future representing - /// success or error, use `try_for_each` instead. - /// - /// # Examples - /// - /// ``` - /// use futures::channel::mpsc; - /// use futures::future; - /// use futures::stream::TryStreamExt; - /// - /// let (_tx, rx) = mpsc::channel::>(1); - /// - /// let rx = rx.and_then(|result| { - /// future::ok(if result % 2 == 0 { - /// Some(result) - /// } else { - /// None - /// }) - /// }); - /// ``` - fn and_then(self, f: F) -> AndThen - where - F: FnMut(Self::Ok) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_stream::, _>(AndThen::new(self, f)) - } - - /// Chain on a computation for when an error happens, passing the - /// erroneous result to the provided closure `f`. - /// - /// This function can be used to run a unit of work and attempt to recover from - /// an error if one happens. The closure provided will be yielded an error - /// when one appears, and the returned future will then be run to completion - /// to produce the next value on this stream. - /// - /// Any successful values produced by this stream will not be passed to the - /// closure, and will be passed through. - /// - /// The returned value of the closure must implement the [`TryFuture`](futures_core::future::TryFuture) trait - /// and can represent some more work to be done before the composed stream - /// is finished. - /// - /// Note that this function consumes the receiving stream and returns a - /// wrapped version of it. - fn or_else(self, f: F) -> OrElse - where - F: FnMut(Self::Error) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_stream::, _>(OrElse::new(self, f)) - } - - /// A future that completes after the given stream has been fully processed - /// into the sink and the sink has been flushed and closed. - /// - /// This future will drive the stream to keep producing items until it is - /// exhausted, sending each item to the sink. It will complete once the - /// stream is exhausted, the sink has received and flushed all items, and - /// the sink is closed. Note that neither the original stream nor provided - /// sink will be output by this future. Pass the sink by `Pin<&mut S>` - /// (for example, via `try_forward(&mut sink)` inside an `async` fn/block) in - /// order to preserve access to the `Sink`. If the stream produces an error, - /// that error will be returned by this future without flushing/closing the sink. - #[cfg(feature = "sink")] - #[cfg_attr(docsrs, doc(cfg(feature = "sink")))] - fn try_forward(self, sink: S) -> TryForward - where - S: Sink, - Self: Sized, - { - assert_future::, _>(TryForward::new(self, sink)) - } - - /// Do something with the success value of this stream, afterwards passing - /// it on. - /// - /// This is similar to the `StreamExt::inspect` method where it allows - /// easily inspecting the success value as it passes through the stream, for - /// example to debug what's going on. - fn inspect_ok(self, f: F) -> InspectOk - where - F: FnMut(&Self::Ok), - Self: Sized, - { - assert_stream::, _>(InspectOk::new(self, f)) - } - - /// Do something with the error value of this stream, afterwards passing it on. - /// - /// This is similar to the `StreamExt::inspect` method where it allows - /// easily inspecting the error value as it passes through the stream, for - /// example to debug what's going on. - fn inspect_err(self, f: F) -> InspectErr - where - F: FnMut(&Self::Error), - Self: Sized, - { - assert_stream::, _>(InspectErr::new(self, f)) - } - - /// Wraps a [`TryStream`] into a type that implements - /// [`Stream`](futures_core::stream::Stream) - /// - /// [`TryStream`]s currently do not implement the - /// [`Stream`](futures_core::stream::Stream) trait because of limitations - /// of the compiler. - /// - /// # Examples - /// - /// ``` - /// use futures::stream::{Stream, TryStream, TryStreamExt}; - /// - /// # type T = i32; - /// # type E = (); - /// fn make_try_stream() -> impl TryStream { // ... } - /// # futures::stream::empty() - /// # } - /// fn take_stream(stream: impl Stream>) { /* ... */ } - /// - /// take_stream(make_try_stream().into_stream()); - /// ``` - fn into_stream(self) -> IntoStream - where - Self: Sized, - { - assert_stream::, _>(IntoStream::new(self)) - } - - /// Creates a future that attempts to resolve the next item in the stream. - /// If an error is encountered before the next item, the error is returned - /// instead. - /// - /// This is similar to the `Stream::next` combinator, but returns a - /// `Result, E>` rather than an `Option>`, making - /// for easy use with the `?` operator. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryStreamExt}; - /// - /// let mut stream = stream::iter(vec![Ok(()), Err(())]); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(()))); - /// assert_eq!(stream.try_next().await, Err(())); - /// # }) - /// ``` - fn try_next(&mut self) -> TryNext<'_, Self> - where - Self: Unpin, - { - assert_future::, Self::Error>, _>(TryNext::new(self)) - } - - /// Skip elements on this stream while the provided asynchronous predicate - /// resolves to `true`. - /// - /// This function is similar to - /// [`StreamExt::skip_while`](crate::stream::StreamExt::skip_while) but exits - /// early if an error occurs. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, TryStreamExt}; - /// - /// let stream = stream::iter(vec![Ok::(1), Ok(3), Ok(2)]); - /// let stream = stream.try_skip_while(|x| future::ready(Ok(*x < 3))); - /// - /// let output: Result, i32> = stream.try_collect().await; - /// assert_eq!(output, Ok(vec![3, 2])); - /// # }) - /// ``` - fn try_skip_while(self, f: F) -> TrySkipWhile - where - F: FnMut(&Self::Ok) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_stream::, _>(TrySkipWhile::new(self, f)) - } - - /// Take elements on this stream while the provided asynchronous predicate - /// resolves to `true`. - /// - /// This function is similar to - /// [`StreamExt::take_while`](crate::stream::StreamExt::take_while) but exits - /// early if an error occurs. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, TryStreamExt}; - /// - /// let stream = stream::iter(vec![Ok::(1), Ok(2), Ok(3), Ok(2)]); - /// let stream = stream.try_take_while(|x| future::ready(Ok(*x < 3))); - /// - /// let output: Result, i32> = stream.try_collect().await; - /// assert_eq!(output, Ok(vec![1, 2])); - /// # }) - /// ``` - fn try_take_while(self, f: F) -> TryTakeWhile - where - F: FnMut(&Self::Ok) -> Fut, - Fut: TryFuture, - Self: Sized, - { - assert_stream::, _>(TryTakeWhile::new(self, f)) - } - - /// Attempt to transform a stream into a collection, - /// returning a future representing the result of that computation. - /// - /// This combinator will collect all successful results of this stream and - /// collect them into the specified collection type. If an error happens then all - /// collected elements will be dropped and the error will be returned. - /// - /// The returned future will be resolved when the stream terminates. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::TryStreamExt; - /// use std::thread; - /// - /// let (tx, rx) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// for i in 1..=5 { - /// tx.unbounded_send(Ok(i)).unwrap(); - /// } - /// tx.unbounded_send(Err(6)).unwrap(); - /// }); - /// - /// let output: Result, i32> = rx.try_collect().await; - /// assert_eq!(output, Err(6)); - /// # }) - /// ``` - fn try_collect>(self) -> TryCollect - where - Self: Sized, - { - assert_future::, _>(TryCollect::new(self)) - } - - /// An adaptor for chunking up successful items of the stream inside a vector. - /// - /// This combinator will attempt to pull successful items from this stream and buffer - /// them into a local vector. At most `capacity` items will get buffered - /// before they're yielded from the returned stream. - /// - /// Note that the vectors returned from this iterator may not always have - /// `capacity` elements. If the underlying stream ended and only a partial - /// vector was created, it'll be returned. Additionally if an error happens - /// from the underlying stream then the currently buffered items will be - /// yielded. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// This function is similar to - /// [`StreamExt::chunks`](crate::stream::StreamExt::chunks) but exits - /// early if an error occurs. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryChunksError, TryStreamExt}; - /// - /// let stream = stream::iter(vec![Ok::(1), Ok(2), Ok(3), Err(4), Ok(5), Ok(6)]); - /// let mut stream = stream.try_chunks(2); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(vec![1, 2]))); - /// assert_eq!(stream.try_next().await, Err(TryChunksError(vec![3], 4))); - /// assert_eq!(stream.try_next().await, Ok(Some(vec![5, 6]))); - /// # }) - /// ``` - /// - /// # Panics - /// - /// This method will panic if `capacity` is zero. - #[cfg(feature = "alloc")] - fn try_chunks(self, capacity: usize) -> TryChunks - where - Self: Sized, - { - assert_stream::, TryChunksError>, _>( - TryChunks::new(self, capacity), - ) - } - - /// An adaptor for chunking up successful, ready items of the stream inside a vector. - /// - /// This combinator will attempt to pull successful items from this stream and buffer - /// them into a local vector. At most `capacity` items will get buffered - /// before they're yielded from the returned stream. If the underlying stream - /// returns `Poll::Pending`, and the collected chunk is not empty, it will - /// be immediately returned. - /// - /// Note that the vectors returned from this iterator may not always have - /// `capacity` elements. If the underlying stream ended and only a partial - /// vector was created, it'll be returned. Additionally if an error happens - /// from the underlying stream then the currently buffered items will be - /// yielded. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// This function is similar to - /// [`StreamExt::ready_chunks`](crate::stream::StreamExt::ready_chunks) but exits - /// early if an error occurs. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryReadyChunksError, TryStreamExt}; - /// - /// let stream = stream::iter(vec![Ok::(1), Ok(2), Ok(3), Err(4), Ok(5), Ok(6)]); - /// let mut stream = stream.try_ready_chunks(2); - /// - /// assert_eq!(stream.try_next().await, Ok(Some(vec![1, 2]))); - /// assert_eq!(stream.try_next().await, Err(TryReadyChunksError(vec![3], 4))); - /// assert_eq!(stream.try_next().await, Ok(Some(vec![5, 6]))); - /// # }) - /// ``` - /// - /// # Panics - /// - /// This method will panic if `capacity` is zero. - #[cfg(feature = "alloc")] - fn try_ready_chunks(self, capacity: usize) -> TryReadyChunks - where - Self: Sized, - { - assert_stream::, TryReadyChunksError>, _>( - TryReadyChunks::new(self, capacity), - ) - } - - /// Attempt to filter the values produced by this stream according to the - /// provided asynchronous closure. - /// - /// As values of this stream are made available, the provided predicate `f` - /// will be run on them. If the predicate returns a `Future` which resolves - /// to `true`, then the stream will yield the value, but if the predicate - /// return a `Future` which resolves to `false`, then the value will be - /// discarded and the next value will be produced. - /// - /// All errors are passed through without filtering in this combinator. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `filter` methods in - /// the standard library. - /// - /// # Examples - /// ``` - /// # futures::executor::block_on(async { - /// use futures::future; - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// - /// let stream = stream::iter(vec![Ok(1i32), Ok(2i32), Ok(3i32), Err("error")]); - /// let mut evens = stream.try_filter(|x| { - /// future::ready(x % 2 == 0) - /// }); - /// - /// assert_eq!(evens.next().await, Some(Ok(2))); - /// assert_eq!(evens.next().await, Some(Err("error"))); - /// # }) - /// ``` - fn try_filter(self, f: F) -> TryFilter - where - Fut: Future, - F: FnMut(&Self::Ok) -> Fut, - Self: Sized, - { - assert_stream::, _>(TryFilter::new(self, f)) - } - - /// Attempt to filter the values produced by this stream while - /// simultaneously mapping them to a different type according to the - /// provided asynchronous closure. - /// - /// As values of this stream are made available, the provided function will - /// be run on them. If the future returned by the predicate `f` resolves to - /// [`Some(item)`](Some) then the stream will yield the value `item`, but if - /// it resolves to [`None`] then the next value will be produced. - /// - /// All errors are passed through without filtering in this combinator. - /// - /// Note that this function consumes the stream passed into it and returns a - /// wrapped version of it, similar to the existing `filter_map` methods in - /// the standard library. - /// - /// # Examples - /// ``` - /// # futures::executor::block_on(async { - /// 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 { - /// let ret = if x % 2 == 0 { Some(x / 2) } else { None }; - /// Ok(ret) - /// }); - /// - /// let mut halves = pin!(halves); - /// assert_eq!(halves.next().await, Some(Ok(3))); - /// assert_eq!(halves.next().await, Some(Err("error"))); - /// # }) - /// ``` - fn try_filter_map(self, f: F) -> TryFilterMap - where - Fut: TryFuture, Error = Self::Error>, - F: FnMut(Self::Ok) -> Fut, - Self: Sized, - { - assert_stream::, _>(TryFilterMap::new(self, f)) - } - - /// Flattens a stream of streams into just one continuous stream. Produced streams - /// will be polled concurrently and any errors will be passed through without looking at them. - /// If the underlying base stream returns an error, it will be **immediately** propagated. - /// - /// The only argument is an optional limit on the number of concurrently - /// polled streams. If this limit is not `None`, no more than `limit` streams - /// will be polled at the same time. The `limit` argument is of type - /// `Into>`, and so can be provided as either `None`, - /// `Some(10)`, or just `10`. Note: a limit of zero is interpreted as - /// no limit at all, and will have the same result as passing in `None`. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::{StreamExt, TryStreamExt}; - /// use std::thread; - /// - /// let (tx1, rx1) = mpsc::unbounded(); - /// let (tx2, rx2) = mpsc::unbounded(); - /// let (tx3, rx3) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// tx1.unbounded_send(Ok(1)).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx2.unbounded_send(Ok(2)).unwrap(); - /// tx2.unbounded_send(Err(3)).unwrap(); - /// tx2.unbounded_send(Ok(4)).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx3.unbounded_send(Ok(rx1)).unwrap(); - /// tx3.unbounded_send(Ok(rx2)).unwrap(); - /// tx3.unbounded_send(Err(5)).unwrap(); - /// }); - /// - /// let stream = rx3.try_flatten_unordered(None); - /// let mut values: Vec<_> = stream.collect().await; - /// values.sort(); - /// - /// assert_eq!(values, vec![Ok(1), Ok(2), Ok(4), Err(3), Err(5)]); - /// # }); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn try_flatten_unordered(self, limit: impl Into>) -> TryFlattenUnordered - where - Self::Ok: TryStream + Unpin, - ::Error: From, - Self: Sized, - { - assert_stream::::Ok, ::Error>, _>( - TryFlattenUnordered::new(self, limit), - ) - } - - /// Flattens a stream of streams into just one continuous stream. - /// - /// If this stream's elements are themselves streams then this combinator - /// will flatten out the entire stream to one long chain of elements. Any - /// errors are passed through without looking at them, but otherwise each - /// individual stream will get exhausted before moving on to the next. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::{StreamExt, TryStreamExt}; - /// use std::thread; - /// - /// let (tx1, rx1) = mpsc::unbounded(); - /// let (tx2, rx2) = mpsc::unbounded(); - /// let (tx3, rx3) = mpsc::unbounded(); - /// - /// thread::spawn(move || { - /// tx1.unbounded_send(Ok(1)).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx2.unbounded_send(Ok(2)).unwrap(); - /// tx2.unbounded_send(Err(3)).unwrap(); - /// tx2.unbounded_send(Ok(4)).unwrap(); - /// }); - /// thread::spawn(move || { - /// tx3.unbounded_send(Ok(rx1)).unwrap(); - /// tx3.unbounded_send(Ok(rx2)).unwrap(); - /// tx3.unbounded_send(Err(5)).unwrap(); - /// }); - /// - /// let mut stream = rx3.try_flatten(); - /// assert_eq!(stream.next().await, Some(Ok(1))); - /// assert_eq!(stream.next().await, Some(Ok(2))); - /// assert_eq!(stream.next().await, Some(Err(3))); - /// assert_eq!(stream.next().await, Some(Ok(4))); - /// assert_eq!(stream.next().await, Some(Err(5))); - /// assert_eq!(stream.next().await, None); - /// # }); - /// ``` - fn try_flatten(self) -> TryFlatten - where - Self::Ok: TryStream, - ::Error: From, - Self: Sized, - { - assert_stream::::Ok, ::Error>, _>( - TryFlatten::new(self), - ) - } - - /// Attempt to concatenate all items of a stream into a single - /// extendable destination, returning a future representing the end result. - /// - /// This combinator will extend the first item with the contents of all - /// the subsequent successful results of the stream. If the stream is empty, - /// the default value will be returned. - /// - /// Works with all collections that implement the [`Extend`](std::iter::Extend) trait. - /// - /// This method is similar to [`concat`](crate::stream::StreamExt::concat), but will - /// exit early if an error is encountered in the stream. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::TryStreamExt; - /// use std::thread; - /// - /// let (tx, rx) = mpsc::unbounded::, ()>>(); - /// - /// thread::spawn(move || { - /// for i in (0..3).rev() { - /// let n = i * 3; - /// tx.unbounded_send(Ok(vec![n + 1, n + 2, n + 3])).unwrap(); - /// } - /// }); - /// - /// let result = rx.try_concat().await; - /// - /// assert_eq!(result, Ok(vec![7, 8, 9, 4, 5, 6, 1, 2, 3])); - /// # }); - /// ``` - fn try_concat(self) -> TryConcat - where - Self: Sized, - Self::Ok: Extend<<::Ok as IntoIterator>::Item> + IntoIterator + Default, - { - assert_future::, _>(TryConcat::new(self)) - } - - /// Attempt to execute several futures from a stream concurrently (unordered). - /// - /// This stream's `Ok` type must be a [`TryFuture`](futures_core::future::TryFuture) with an `Error` type - /// that matches the stream's `Error` type. - /// - /// This adaptor will buffer up to `n` futures and then return their - /// outputs in the order in which they complete. If the underlying stream - /// returns an error, it will be immediately propagated. - /// - /// The limit argument is of type `Into>`, and so can be - /// provided as either `None`, `Some(10)`, or just `10`. Note: a limit of zero is - /// interpreted as no limit at all, and will have the same result as passing in `None`. - /// - /// The returned stream will be a stream of results, each containing either - /// an error or a future's output. An error can be produced either by the - /// underlying stream itself or by one of the futures it yielded. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// Results are returned in the order of completion: - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// - /// let (send_one, recv_one) = oneshot::channel(); - /// let (send_two, recv_two) = oneshot::channel(); - /// - /// let stream_of_futures = stream::iter(vec![Ok(recv_one), Ok(recv_two)]); - /// - /// let mut buffered = stream_of_futures.try_buffer_unordered(10); - /// - /// send_two.send(2i32)?; - /// assert_eq!(buffered.next().await, Some(Ok(2i32))); - /// - /// send_one.send(1i32)?; - /// assert_eq!(buffered.next().await, Some(Ok(1i32))); - /// - /// assert_eq!(buffered.next().await, None); - /// # Ok::<(), i32>(()) }).unwrap(); - /// ``` - /// - /// Errors from the underlying stream itself are propagated: - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::{StreamExt, TryStreamExt}; - /// - /// let (sink, stream_of_futures) = mpsc::unbounded(); - /// let mut buffered = stream_of_futures.try_buffer_unordered(10); - /// - /// sink.unbounded_send(Ok(async { Ok(7i32) }))?; - /// assert_eq!(buffered.next().await, Some(Ok(7i32))); - /// - /// sink.unbounded_send(Err("error in the stream"))?; - /// assert_eq!(buffered.next().await, Some(Err("error in the stream"))); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn try_buffer_unordered(self, n: impl Into>) -> TryBufferUnordered - where - Self::Ok: TryFuture, - Self: Sized, - { - assert_stream::::Ok, Self::Error>, _>( - TryBufferUnordered::new(self, n.into()), - ) - } - - /// Attempt to execute several futures from a stream concurrently. - /// - /// This stream's `Ok` type must be a [`TryFuture`](futures_core::future::TryFuture) with an `Error` type - /// that matches the stream's `Error` type. - /// - /// This adaptor will buffer up to `n` futures and then return their - /// outputs in the same order as the underlying stream. If the underlying stream returns an error, it will - /// be immediately propagated. - /// - /// The limit argument is of type `Into>`, and so can be - /// provided as either `None`, `Some(10)`, or just `10`. Note: a limit of zero is - /// interpreted as no limit at all, and will have the same result as passing in `None`. - /// - /// The returned stream will be a stream of results, each containing either - /// an error or a future's output. An error can be produced either by the - /// underlying stream itself or by one of the futures it yielded. - /// - /// This method is only available when the `std` or `alloc` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// Results are returned in the order of addition: - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::oneshot; - /// use futures::future::lazy; - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// - /// let (send_one, recv_one) = oneshot::channel(); - /// let (send_two, recv_two) = oneshot::channel(); - /// - /// let mut buffered = lazy(move |cx| { - /// let stream_of_futures = stream::iter(vec![Ok(recv_one), Ok(recv_two)]); - /// - /// let mut buffered = stream_of_futures.try_buffered(10); - /// - /// assert!(buffered.try_poll_next_unpin(cx).is_pending()); - /// - /// send_two.send(2i32)?; - /// assert!(buffered.try_poll_next_unpin(cx).is_pending()); - /// Ok::<_, i32>(buffered) - /// }).await?; - /// - /// send_one.send(1i32)?; - /// assert_eq!(buffered.next().await, Some(Ok(1i32))); - /// assert_eq!(buffered.next().await, Some(Ok(2i32))); - /// - /// assert_eq!(buffered.next().await, None); - /// # Ok::<(), i32>(()) }).unwrap(); - /// ``` - /// - /// Errors from the underlying stream itself are propagated: - /// ``` - /// # futures::executor::block_on(async { - /// use futures::channel::mpsc; - /// use futures::stream::{StreamExt, TryStreamExt}; - /// - /// let (sink, stream_of_futures) = mpsc::unbounded(); - /// let mut buffered = stream_of_futures.try_buffered(10); - /// - /// sink.unbounded_send(Ok(async { Ok(7i32) }))?; - /// assert_eq!(buffered.next().await, Some(Ok(7i32))); - /// - /// sink.unbounded_send(Err("error in the stream"))?; - /// assert_eq!(buffered.next().await, Some(Err("error in the stream"))); - /// # Ok::<(), Box>(()) }).unwrap(); - /// ``` - #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] - #[cfg(feature = "alloc")] - fn try_buffered(self, n: impl Into>) -> TryBuffered - where - Self::Ok: TryFuture, - Self: Sized, - { - assert_stream::::Ok, Self::Error>, _>(TryBuffered::new( - self, - n.into(), - )) - } - - // TODO: false positive warning from rustdoc. Verify once #43466 settles - // - /// A convenience method for calling [`TryStream::try_poll_next`] on [`Unpin`] - /// stream types. - fn try_poll_next_unpin( - &mut self, - cx: &mut Context<'_>, - ) -> Poll>> - where - Self: Unpin, - { - Pin::new(self).try_poll_next(cx) - } - - /// Wraps a [`TryStream`] into a stream compatible with libraries using - /// futures 0.1 `Stream`. Requires the `compat` feature to be enabled. - /// ``` - /// # if cfg!(miri) { return; } // Miri does not support epoll - /// use futures::future::{FutureExt, TryFutureExt}; - /// # let (tx, rx) = futures::channel::oneshot::channel(); - /// - /// let future03 = async { - /// println!("Running on the pool"); - /// tx.send(42).unwrap(); - /// }; - /// - /// let future01 = future03 - /// .unit_error() // Make it a TryFuture - /// .boxed() // Make it Unpin - /// .compat(); - /// - /// tokio::run(future01); - /// # assert_eq!(42, futures::executor::block_on(rx).unwrap()); - /// ``` - #[cfg(feature = "compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "compat")))] - fn compat(self) -> Compat - where - Self: Sized + Unpin, - { - Compat::new(self) - } - - /// Adapter that converts this stream into an [`AsyncBufRead`](crate::io::AsyncBufRead). - /// - /// This method is only available when the `std` feature of this - /// library is activated, and it is activated by default. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, TryStreamExt}; - /// use futures::io::AsyncReadExt; - /// - /// let stream = stream::iter([Ok(vec![1, 2, 3]), Ok(vec![4, 5])]); - /// let mut reader = stream.into_async_read(); - /// - /// let mut buf = Vec::new(); - /// reader.read_to_end(&mut buf).await.unwrap(); - /// assert_eq!(buf, [1, 2, 3, 4, 5]); - /// # }) - /// ``` - #[cfg(feature = "io")] - #[cfg_attr(docsrs, doc(cfg(feature = "io")))] - #[cfg(feature = "std")] - fn into_async_read(self) -> IntoAsyncRead - where - Self: Sized + TryStreamExt, - Self::Ok: AsRef<[u8]>, - { - crate::io::assert_read(IntoAsyncRead::new(self)) - } - - /// Attempt to execute a predicate over an asynchronous stream and evaluate if all items - /// satisfy the predicate. Exits early if an `Err` is encountered or if an `Ok` item is found - /// that does not satisfy the predicate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// use std::convert::Infallible; - /// - /// let number_stream = stream::iter(1..10).map(Ok::<_, Infallible>); - /// let positive = number_stream.try_all(|i| async move { i > 0 }); - /// assert_eq!(positive.await, Ok(true)); - /// - /// let stream_with_errors = stream::iter([Ok(1), Err("err"), Ok(3)]); - /// let positive = stream_with_errors.try_all(|i| async move { i > 0 }); - /// assert_eq!(positive.await, Err("err")); - /// # }); - /// ``` - fn try_all(self, f: F) -> TryAll - where - Self: Sized, - F: FnMut(Self::Ok) -> Fut, - Fut: Future, - { - assert_future::, _>(TryAll::new(self, f)) - } - - /// Attempt to execute a predicate over an asynchronous stream and evaluate if any items - /// satisfy the predicate. Exits early if an `Err` is encountered or if an `Ok` item is found - /// that satisfies the predicate. - /// - /// # Examples - /// - /// ``` - /// # futures::executor::block_on(async { - /// use futures::stream::{self, StreamExt, TryStreamExt}; - /// use std::convert::Infallible; - /// - /// let number_stream = stream::iter(0..10).map(Ok::<_, Infallible>); - /// let contain_three = number_stream.try_any(|i| async move { i == 3 }); - /// assert_eq!(contain_three.await, Ok(true)); - /// - /// let stream_with_errors = stream::iter([Ok(1), Err("err"), Ok(3)]); - /// let contain_three = stream_with_errors.try_any(|i| async move { i == 3 }); - /// assert_eq!(contain_three.await, Err("err")); - /// # }); - /// ``` - fn try_any(self, f: F) -> TryAny - where - Self: Sized, - F: FnMut(Self::Ok) -> Fut, - Fut: Future, - { - assert_future::, _>(TryAny::new(self, f)) - } -} diff --git a/futures-util/src/stream/try_stream/or_else.rs b/futures-util/src/stream/try_stream/or_else.rs deleted file mode 100644 index 53aceb8e64..0000000000 --- a/futures-util/src/stream/try_stream/or_else.rs +++ /dev/null @@ -1,109 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`or_else`](super::TryStreamExt::or_else) method. - #[must_use = "streams do nothing unless polled"] - pub struct OrElse { - #[pin] - stream: St, - #[pin] - future: Option, - f: F, - } -} - -impl fmt::Debug for OrElse -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OrElse") - .field("stream", &self.stream) - .field("future", &self.future) - .finish() - } -} - -impl OrElse -where - St: TryStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, future: None, f } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for OrElse -where - St: TryStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - let item = ready!(fut.try_poll(cx)); - this.future.set(None); - break Some(item); - } else { - match ready!(this.stream.as_mut().try_poll_next(cx)) { - Some(Ok(item)) => break Some(Ok(item)), - Some(Err(e)) => { - this.future.set(Some((this.f)(e))); - } - None => break None, - } - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let future_len = usize::from(self.future.is_some()); - let (lower, upper) = self.stream.size_hint(); - let lower = lower.saturating_add(future_len); - let upper = match upper { - Some(x) => x.checked_add(future_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for OrElse -where - St: TryStream + FusedStream, - F: FnMut(St::Error) -> Fut, - Fut: TryFuture, -{ - fn is_terminated(&self) -> bool { - self.future.is_none() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for OrElse -where - S: Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_all.rs b/futures-util/src/stream/try_stream/try_all.rs deleted file mode 100644 index 8179f86afc..0000000000 --- a/futures-util/src/stream/try_stream/try_all.rs +++ /dev/null @@ -1,98 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::TryStream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_all`](super::TryStreamExt::try_all) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryAll { - #[pin] - stream: St, - f: F, - done: bool, - #[pin] - future: Option, - } -} - -impl fmt::Debug for TryAll -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryAll") - .field("stream", &self.stream) - .field("done", &self.done) - .field("future", &self.future) - .finish() - } -} - -impl TryAll -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, done: false, future: None } - } -} - -impl FusedFuture for TryAll -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.done && self.future.is_none() - } -} - -impl Future for TryAll -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new value - let acc = ready!(fut.poll(cx)); - this.future.set(None); - if !acc { - *this.done = true; - break Ok(false); - } // early exit - } else if !*this.done { - // we're waiting on a new item from the stream - match ready!(this.stream.as_mut().try_poll_next(cx)) { - Some(Ok(item)) => { - this.future.set(Some((this.f)(item))); - } - Some(Err(err)) => { - *this.done = true; - break Err(err); - } - None => { - *this.done = true; - break Ok(true); - } - } - } else { - panic!("TryAll polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/try_stream/try_any.rs b/futures-util/src/stream/try_stream/try_any.rs deleted file mode 100644 index 55e876be05..0000000000 --- a/futures-util/src/stream/try_stream/try_any.rs +++ /dev/null @@ -1,98 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::TryStream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_any`](super::TryStreamExt::try_any) method. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryAny { - #[pin] - stream: St, - f: F, - done: bool, - #[pin] - future: Option, - } -} - -impl fmt::Debug for TryAny -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryAny") - .field("stream", &self.stream) - .field("done", &self.done) - .field("future", &self.future) - .finish() - } -} - -impl TryAny -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, done: false, future: None } - } -} - -impl FusedFuture for TryAny -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.done && self.future.is_none() - } -} - -impl Future for TryAny -where - St: TryStream, - F: FnMut(St::Ok) -> Fut, - Fut: Future, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.future.as_mut().as_pin_mut() { - // we're currently processing a future to produce a new value - let acc = ready!(fut.poll(cx)); - this.future.set(None); - if acc { - *this.done = true; - break Ok(true); - } // early exit - } else if !*this.done { - // we're waiting on a new item from the stream - match ready!(this.stream.as_mut().try_poll_next(cx)) { - Some(Ok(item)) => { - this.future.set(Some((this.f)(item))); - } - Some(Err(err)) => { - *this.done = true; - break Err(err); - } - None => { - *this.done = true; - break Ok(false); - } - } - } else { - panic!("TryAny polled after completion") - } - }) - } -} diff --git a/futures-util/src/stream/try_stream/try_buffer_unordered.rs b/futures-util/src/stream/try_stream/try_buffer_unordered.rs deleted file mode 100644 index 21b00b20ac..0000000000 --- a/futures-util/src/stream/try_stream/try_buffer_unordered.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::future::{IntoFuture, TryFutureExt}; -use crate::stream::{Fuse, FuturesUnordered, IntoStream, StreamExt}; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::stream::{Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the - /// [`try_buffer_unordered`](super::TryStreamExt::try_buffer_unordered) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct TryBufferUnordered - where St: TryStream - { - #[pin] - stream: Fuse>, - in_progress_queue: FuturesUnordered>, - max: Option, - } -} - -impl TryBufferUnordered -where - St: TryStream, - St::Ok: TryFuture, -{ - pub(super) fn new(stream: St, n: Option) -> Self { - Self { - stream: IntoStream::new(stream).fuse(), - in_progress_queue: FuturesUnordered::new(), - max: n.and_then(NonZeroUsize::new), - } - } - - delegate_access_inner!(stream, St, (. .)); -} - -impl Stream for TryBufferUnordered -where - St: TryStream, - St::Ok: TryFuture, -{ - type Item = Result<::Ok, St::Error>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - // First up, try to spawn off as many futures as possible by filling up - // our queue of futures. Propagate errors from the stream immediately. - while this.max.map(|max| this.in_progress_queue.len() < max.get()).unwrap_or(true) { - match this.stream.as_mut().poll_next(cx)? { - Poll::Ready(Some(fut)) => this.in_progress_queue.push(fut.into_future()), - Poll::Ready(None) | Poll::Pending => break, - } - } - - // Attempt to pull the next value from the in_progress_queue - match this.in_progress_queue.poll_next_unpin(cx) { - x @ Poll::Pending | x @ Poll::Ready(Some(_)) => return x, - Poll::Ready(None) => {} - } - - // If more values are still coming from the stream, we're not done yet - if this.stream.is_done() { - Poll::Ready(None) - } else { - Poll::Pending - } - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryBufferUnordered -where - S: TryStream + Sink, - S::Ok: TryFuture, -{ - type Error = E; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_buffered.rs b/futures-util/src/stream/try_stream/try_buffered.rs deleted file mode 100644 index 83e9093fbc..0000000000 --- a/futures-util/src/stream/try_stream/try_buffered.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::future::{IntoFuture, TryFutureExt}; -use crate::stream::{Fuse, FuturesOrdered, IntoStream, StreamExt}; -use core::num::NonZeroUsize; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::stream::{Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_buffered`](super::TryStreamExt::try_buffered) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct TryBuffered - where - St: TryStream, - St::Ok: TryFuture, - { - #[pin] - stream: Fuse>, - in_progress_queue: FuturesOrdered>, - max: Option, - } -} - -impl TryBuffered -where - St: TryStream, - St::Ok: TryFuture, -{ - pub(super) fn new(stream: St, n: Option) -> Self { - Self { - stream: IntoStream::new(stream).fuse(), - in_progress_queue: FuturesOrdered::new(), - max: n.and_then(NonZeroUsize::new), - } - } - - delegate_access_inner!(stream, St, (. .)); -} - -impl Stream for TryBuffered -where - St: TryStream, - St::Ok: TryFuture, -{ - type Item = Result<::Ok, St::Error>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - // First up, try to spawn off as many futures as possible by filling up - // our queue of futures. Propagate errors from the stream immediately. - while this.max.map(|max| this.in_progress_queue.len() < max.get()).unwrap_or(true) { - match this.stream.as_mut().poll_next(cx)? { - Poll::Ready(Some(fut)) => this.in_progress_queue.push_back(fut.into_future()), - Poll::Ready(None) | Poll::Pending => break, - } - } - - // Attempt to pull the next value from the in_progress_queue - match this.in_progress_queue.poll_next_unpin(cx) { - x @ Poll::Pending | x @ Poll::Ready(Some(_)) => return x, - Poll::Ready(None) => {} - } - - // If more values are still coming from the stream, we're not done yet - if this.stream.is_done() { - Poll::Ready(None) - } else { - Poll::Pending - } - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryBuffered -where - S: TryStream + Sink, - S::Ok: TryFuture, -{ - type Error = E; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_chunks.rs b/futures-util/src/stream/try_stream/try_chunks.rs deleted file mode 100644 index ec53f4bd11..0000000000 --- a/futures-util/src/stream/try_stream/try_chunks.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::stream::{Fuse, IntoStream, StreamExt}; - -use alloc::vec::Vec; -use core::pin::Pin; -use core::{fmt, mem}; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_chunks`](super::TryStreamExt::try_chunks) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct TryChunks { - #[pin] - stream: Fuse>, - items: Vec, - cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 - } -} - -impl TryChunks { - pub(super) fn new(stream: St, capacity: usize) -> Self { - assert!(capacity > 0); - - Self { - stream: IntoStream::new(stream).fuse(), - items: Vec::with_capacity(capacity), - cap: capacity, - } - } - - fn take(self: Pin<&mut Self>) -> Vec { - let cap = self.cap; - mem::replace(self.project().items, Vec::with_capacity(cap)) - } - - delegate_access_inner!(stream, St, (. .)); -} - -type TryChunksStreamError = TryChunksError<::Ok, ::Error>; - -impl Stream for TryChunks { - type Item = Result, TryChunksStreamError>; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.as_mut().project(); - loop { - match ready!(this.stream.as_mut().try_poll_next(cx)) { - // Push the item into the buffer and check whether it is full. - // If so, replace our buffer with a new and empty one and return - // the full one. - Some(item) => match item { - Ok(item) => { - this.items.push(item); - if this.items.len() >= *this.cap { - return Poll::Ready(Some(Ok(self.take()))); - } - } - Err(e) => { - return Poll::Ready(Some(Err(TryChunksError(self.take(), e)))); - } - }, - - // Since the underlying stream ran out of values, return what we - // have buffered, if we have anything. - None => { - let last = if this.items.is_empty() { - None - } else { - let full_buf = mem::take(this.items); - Some(full_buf) - }; - - return Poll::Ready(last.map(Ok)); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let chunk_len = usize::from(!self.items.is_empty()); - let (lower, upper) = self.stream.size_hint(); - let lower = (lower / self.cap).saturating_add(chunk_len); - let upper = match upper { - Some(x) => x.checked_add(chunk_len), - None => None, - }; - (lower, upper) - } -} - -impl FusedStream for TryChunks { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() && self.items.is_empty() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryChunks -where - S: TryStream + Sink, -{ - type Error = >::Error; - - delegate_sink!(stream, Item); -} - -/// Error indicating, that while chunk was collected inner stream produced an error. -/// -/// Contains all items that were collected before an error occurred, and the stream error itself. -#[derive(PartialEq, Eq)] -pub struct TryChunksError(pub Vec, pub E); - -impl fmt::Debug for TryChunksError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.1.fmt(f) - } -} - -impl fmt::Display for TryChunksError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.1.fmt(f) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for TryChunksError {} diff --git a/futures-util/src/stream/try_stream/try_collect.rs b/futures-util/src/stream/try_stream/try_collect.rs deleted file mode 100644 index 3e5963f033..0000000000 --- a/futures-util/src/stream/try_stream/try_collect.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::mem; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::stream::{FusedStream, TryStream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_collect`](super::TryStreamExt::try_collect) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryCollect { - #[pin] - stream: St, - items: C, - } -} - -impl TryCollect { - pub(super) fn new(s: St) -> Self { - Self { stream: s, items: Default::default() } - } -} - -impl FusedFuture for TryCollect -where - St: TryStream + FusedStream, - C: Default + Extend, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for TryCollect -where - St: TryStream, - C: Default + Extend, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - Poll::Ready(Ok(loop { - match ready!(this.stream.as_mut().try_poll_next(cx)?) { - Some(x) => this.items.extend(Some(x)), - None => break mem::take(this.items), - } - })) - } -} diff --git a/futures-util/src/stream/try_stream/try_concat.rs b/futures-util/src/stream/try_stream/try_concat.rs deleted file mode 100644 index 58fb6a5413..0000000000 --- a/futures-util/src/stream/try_stream/try_concat.rs +++ /dev/null @@ -1,51 +0,0 @@ -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::TryStream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_concat`](super::TryStreamExt::try_concat) method. - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryConcat { - #[pin] - stream: St, - accum: Option, - } -} - -impl TryConcat -where - St: TryStream, - St::Ok: Extend<::Item> + IntoIterator + Default, -{ - pub(super) fn new(stream: St) -> Self { - Self { stream, accum: None } - } -} - -impl Future for TryConcat -where - St: TryStream, - St::Ok: Extend<::Item> + IntoIterator + Default, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - - Poll::Ready(Ok(loop { - if let Some(x) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - if let Some(a) = this.accum { - a.extend(x) - } else { - *this.accum = Some(x) - } - } else { - break this.accum.take().unwrap_or_default(); - } - })) - } -} diff --git a/futures-util/src/stream/try_stream/try_filter.rs b/futures-util/src/stream/try_stream/try_filter.rs deleted file mode 100644 index 11d58243fd..0000000000 --- a/futures-util/src/stream/try_stream/try_filter.rs +++ /dev/null @@ -1,112 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_filter`](super::TryStreamExt::try_filter) - /// method. - #[must_use = "streams do nothing unless polled"] - pub struct TryFilter - where St: TryStream - { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - } -} - -impl fmt::Debug for TryFilter -where - St: TryStream + fmt::Debug, - St::Ok: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryFilter") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .finish() - } -} - -impl TryFilter -where - St: TryStream, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for TryFilter -where - St: TryStream + FusedStream, - F: FnMut(&St::Ok) -> Fut, - Fut: Future, -{ - fn is_terminated(&self) -> bool { - self.pending_fut.is_none() && self.stream.is_terminated() - } -} - -impl Stream for TryFilter -where - St: TryStream, - Fut: Future, - F: FnMut(&St::Ok) -> Fut, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let res = ready!(fut.poll(cx)); - this.pending_fut.set(None); - if res { - break this.pending_item.take().map(Ok); - } - *this.pending_item = None; - } else if let Some(item) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - this.pending_fut.set(Some((this.f)(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let pending_len = usize::from(self.pending_fut.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryFilter -where - S: TryStream + Sink, -{ - type Error = E; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_filter_map.rs b/futures-util/src/stream/try_stream/try_filter_map.rs deleted file mode 100644 index ed1201732b..0000000000 --- a/futures-util/src/stream/try_stream/try_filter_map.rs +++ /dev/null @@ -1,106 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_filter_map`](super::TryStreamExt::try_filter_map) - /// method. - #[must_use = "streams do nothing unless polled"] - pub struct TryFilterMap { - #[pin] - stream: St, - f: F, - #[pin] - pending: Option, - } -} - -impl fmt::Debug for TryFilterMap -where - St: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryFilterMap") - .field("stream", &self.stream) - .field("pending", &self.pending) - .finish() - } -} - -impl TryFilterMap { - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for TryFilterMap -where - St: TryStream + FusedStream, - Fut: TryFuture, Error = St::Error>, - F: FnMut(St::Ok) -> Fut, -{ - fn is_terminated(&self) -> bool { - self.pending.is_none() && self.stream.is_terminated() - } -} - -impl Stream for TryFilterMap -where - St: TryStream, - Fut: TryFuture, Error = St::Error>, - F: FnMut(St::Ok) -> Fut, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(p) = this.pending.as_mut().as_pin_mut() { - // We have an item in progress, poll that until it's done - let res = ready!(p.try_poll(cx)); - this.pending.set(None); - let item = res?; - if item.is_some() { - break item.map(Ok); - } - } else if let Some(item) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - // No item in progress, but the stream is still going - this.pending.set(Some((this.f)(item))); - } else { - // The stream is done - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let pending_len = usize::from(self.pending.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryFilterMap -where - S: Sink, -{ - type Error = S::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_flatten.rs b/futures-util/src/stream/try_stream/try_flatten.rs deleted file mode 100644 index 4fc04a07bb..0000000000 --- a/futures-util/src/stream/try_stream/try_flatten.rs +++ /dev/null @@ -1,84 +0,0 @@ -use core::pin::Pin; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_flatten`](super::TryStreamExt::try_flatten) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct TryFlatten - where - St: TryStream, - { - #[pin] - stream: St, - #[pin] - next: Option, - } -} - -impl TryFlatten -where - St: TryStream, - St::Ok: TryStream, - ::Error: From, -{ - pub(super) fn new(stream: St) -> Self { - Self { stream, next: None } - } - - delegate_access_inner!(stream, St, ()); -} - -impl FusedStream for TryFlatten -where - St: TryStream + FusedStream, - St::Ok: TryStream, - ::Error: From, -{ - fn is_terminated(&self) -> bool { - self.next.is_none() && self.stream.is_terminated() - } -} - -impl Stream for TryFlatten -where - St: TryStream, - St::Ok: TryStream, - ::Error: From, -{ - type Item = Result<::Ok, ::Error>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - Poll::Ready(loop { - if let Some(s) = this.next.as_mut().as_pin_mut() { - if let Some(item) = ready!(s.try_poll_next(cx)?) { - break Some(Ok(item)); - } else { - this.next.set(None); - } - } else if let Some(s) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - this.next.set(Some(s)); - } else { - break None; - } - }) - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryFlatten -where - S: TryStream + Sink, -{ - type Error = >::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_flatten_unordered.rs b/futures-util/src/stream/try_stream/try_flatten_unordered.rs deleted file mode 100644 index a74dfc451d..0000000000 --- a/futures-util/src/stream/try_stream/try_flatten_unordered.rs +++ /dev/null @@ -1,176 +0,0 @@ -use core::marker::PhantomData; -use core::pin::Pin; - -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; - -use pin_project_lite::pin_project; - -use crate::future::Either; -use crate::stream::stream::flatten_unordered::{ - FlattenUnorderedWithFlowController, FlowController, FlowStep, -}; -use crate::stream::IntoStream; -use crate::TryStreamExt; - -delegate_all!( - /// Stream for the [`try_flatten_unordered`](super::TryStreamExt::try_flatten_unordered) method. - TryFlattenUnordered( - FlattenUnorderedWithFlowController, PropagateBaseStreamError> - ): Debug + Sink + Stream + FusedStream + AccessInner[St, (. .)] - + New[ - |stream: St, limit: impl Into>| - FlattenUnorderedWithFlowController::new( - NestedTryStreamIntoEitherTryStream::new(stream), - limit.into() - ) - ] - where - St: TryStream, - St::Ok: TryStream, - St::Ok: Unpin, - ::Error: From -); - -pin_project! { - /// Emits either successful streams or single-item streams containing the underlying errors. - /// This's a wrapper for `FlattenUnordered` to reuse its logic over `TryStream`. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct NestedTryStreamIntoEitherTryStream - where - St: TryStream, - St::Ok: TryStream, - St::Ok: Unpin, - ::Error: From - { - #[pin] - stream: St - } -} - -impl NestedTryStreamIntoEitherTryStream -where - St: TryStream, - St::Ok: TryStream + Unpin, - ::Error: From, -{ - fn new(stream: St) -> Self { - Self { stream } - } - - delegate_access_inner!(stream, St, ()); -} - -/// Emits a single item immediately, then stream will be terminated. -#[derive(Debug, Clone)] -pub struct Single(Option); - -impl Single { - /// Constructs new `Single` with the given value. - fn new(val: T) -> Self { - Self(Some(val)) - } - - /// Attempts to take inner item immediately. Will always succeed if the stream isn't terminated. - fn next_immediate(&mut self) -> Option { - self.0.take() - } -} - -impl Unpin for Single {} - -impl Stream for Single { - type Item = T; - - fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(self.0.take()) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.as_ref().map_or((0, Some(0)), |_| (1, Some(1))) - } -} - -/// Immediately propagates errors occurred in the base stream. -#[derive(Debug, Clone, Copy)] -pub struct PropagateBaseStreamError(PhantomData); - -type BaseStreamItem = as Stream>::Item; -type InnerStreamItem = as Stream>::Item; - -impl FlowController, InnerStreamItem> for PropagateBaseStreamError -where - St: TryStream, - St::Ok: TryStream + Unpin, - ::Error: From, -{ - fn next_step(item: BaseStreamItem) -> FlowStep, InnerStreamItem> { - match item { - // A new successful inner stream received - st @ Either::Left(_) => FlowStep::Continue(st), - // An error encountered - Either::Right(mut err) => FlowStep::Return(err.next_immediate().unwrap()), - } - } -} - -type SingleStreamResult = Single::Ok, ::Error>>; - -impl Stream for NestedTryStreamIntoEitherTryStream -where - St: TryStream, - St::Ok: TryStream + Unpin, - ::Error: From, -{ - // Item is either an inner stream or a stream containing a single error. - // This will allow using `Either`'s `Stream` implementation as both branches are actually streams of `Result`'s. - type Item = Either, SingleStreamResult>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let item = ready!(self.project().stream.try_poll_next(cx)); - - let out = match item { - Some(res) => match res { - // Emit successful inner stream as is - Ok(stream) => Either::Left(stream.into_stream()), - // Wrap an error into a stream containing a single item - err @ Err(_) => { - let res = err.map(|_: St::Ok| unreachable!()).map_err(Into::into); - - Either::Right(Single::new(res)) - } - }, - None => return Poll::Ready(None), - }; - - Poll::Ready(Some(out)) - } -} - -impl FusedStream for NestedTryStreamIntoEitherTryStream -where - St: TryStream + FusedStream, - St::Ok: TryStream + Unpin, - ::Error: From, -{ - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for NestedTryStreamIntoEitherTryStream -where - St: TryStream + Sink, - St::Ok: TryStream + Unpin, - ::Error: From<::Error>, -{ - type Error = >::Error; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_forward.rs b/futures-util/src/stream/try_stream/try_forward.rs deleted file mode 100644 index 52c28afa34..0000000000 --- a/futures-util/src/stream/try_stream/try_forward.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::stream::{Fuse, IntoStream, Stream, TryStream}; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::ready; -use futures_core::task::{Context, Poll}; -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Future for the [`try_forward`](super::TryStreamExt::try_forward) method. - #[project = TryForwardProj] - #[derive(Debug)] - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct TryForward { - #[pin] - sink: Option, - #[pin] - stream: Fuse>, - buffered_item: Option, - } -} - -impl TryForward { - pub(crate) fn new(stream: St, sink: Si) -> Self { - Self { sink: Some(sink), stream: Fuse::new(IntoStream::new(stream)), buffered_item: None } - } -} - -impl FusedFuture for TryForward -where - Si: Sink, - St: TryStream, -{ - fn is_terminated(&self) -> bool { - self.sink.is_none() - } -} - -impl Future for TryForward -where - Si: Sink, - St: TryStream, -{ - type Output = Result<(), E>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let TryForwardProj { mut sink, mut stream, buffered_item } = self.project(); - let mut si = sink.as_mut().as_pin_mut().expect("polled `TryForward` after completion"); - - loop { - // If we've got an item buffered already, we need to write it to the - // sink before we can do anything else - if buffered_item.is_some() { - ready!(si.as_mut().poll_ready(cx))?; - si.as_mut().start_send(buffered_item.take().unwrap())?; - } - - match stream.as_mut().poll_next(cx)? { - Poll::Ready(Some(item)) => { - *buffered_item = Some(item); - } - Poll::Ready(None) => { - ready!(si.poll_close(cx))?; - sink.set(None); - return Poll::Ready(Ok(())); - } - Poll::Pending => { - ready!(si.poll_flush(cx))?; - return Poll::Pending; - } - } - } - } -} diff --git a/futures-util/src/stream/try_stream/try_next.rs b/futures-util/src/stream/try_stream/try_next.rs deleted file mode 100644 index 13fcf80cae..0000000000 --- a/futures-util/src/stream/try_stream/try_next.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::stream::TryStreamExt; -use core::pin::Pin; -use futures_core::future::{FusedFuture, Future}; -use futures_core::stream::{FusedStream, TryStream}; -use futures_core::task::{Context, Poll}; - -/// Future for the [`try_next`](super::TryStreamExt::try_next) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct TryNext<'a, St: ?Sized> { - stream: &'a mut St, -} - -impl Unpin for TryNext<'_, St> {} - -impl<'a, St: ?Sized + TryStream + Unpin> TryNext<'a, St> { - pub(super) fn new(stream: &'a mut St) -> Self { - Self { stream } - } -} - -impl FusedFuture for TryNext<'_, St> { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -impl Future for TryNext<'_, St> { - type Output = Result, St::Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.stream.try_poll_next_unpin(cx)?.map(Ok) - } -} diff --git a/futures-util/src/stream/try_stream/try_ready_chunks.rs b/futures-util/src/stream/try_stream/try_ready_chunks.rs deleted file mode 100644 index 8b1470ea26..0000000000 --- a/futures-util/src/stream/try_stream/try_ready_chunks.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::stream::{Fuse, IntoStream, StreamExt}; - -use alloc::vec::Vec; -use core::fmt; -use core::pin::Pin; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_ready_chunks`](super::TryStreamExt::try_ready_chunks) method. - #[derive(Debug)] - #[must_use = "streams do nothing unless polled"] - pub struct TryReadyChunks { - #[pin] - stream: Fuse>, - cap: usize, // https://github.com/rust-lang/futures-rs/issues/1475 - } -} - -impl TryReadyChunks { - pub(super) fn new(stream: St, capacity: usize) -> Self { - assert!(capacity > 0); - - Self { stream: IntoStream::new(stream).fuse(), cap: capacity } - } - - delegate_access_inner!(stream, St, (. .)); -} - -type TryReadyChunksStreamError = - TryReadyChunksError<::Ok, ::Error>; - -impl Stream for TryReadyChunks { - type Item = Result, TryReadyChunksStreamError>; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.as_mut().project(); - - let mut items: Vec = Vec::new(); - - loop { - match this.stream.as_mut().poll_next(cx) { - // Flush all the collected data if the underlying stream doesn't - // contain more ready values - Poll::Pending => { - return if items.is_empty() { - Poll::Pending - } else { - Poll::Ready(Some(Ok(items))) - } - } - - // Push the ready item into the buffer and check whether it is full. - // If so, return the buffer. - Poll::Ready(Some(Ok(item))) => { - if items.is_empty() { - items.reserve_exact(*this.cap); - } - items.push(item); - if items.len() >= *this.cap { - return Poll::Ready(Some(Ok(items))); - } - } - - // Return the already collected items and the error. - Poll::Ready(Some(Err(e))) => { - return Poll::Ready(Some(Err(TryReadyChunksError(items, e)))); - } - - // Since the underlying stream ran out of values, return what we - // have buffered, if we have anything. - Poll::Ready(None) => { - let last = if items.is_empty() { None } else { Some(Ok(items)) }; - return Poll::Ready(last); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.stream.size_hint(); - let lower = lower / self.cap; - (lower, upper) - } -} - -impl FusedStream for TryReadyChunks { - fn is_terminated(&self) -> bool { - self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryReadyChunks -where - S: TryStream + Sink, -{ - type Error = >::Error; - - delegate_sink!(stream, Item); -} - -/// Error indicating, that while chunk was collected inner stream produced an error. -/// -/// Contains all items that were collected before an error occurred, and the stream error itself. -#[derive(PartialEq, Eq)] -pub struct TryReadyChunksError(pub Vec, pub E); - -impl fmt::Debug for TryReadyChunksError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.1.fmt(f) - } -} - -impl fmt::Display for TryReadyChunksError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.1.fmt(f) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for TryReadyChunksError {} diff --git a/futures-util/src/stream/try_stream/try_skip_while.rs b/futures-util/src/stream/try_stream/try_skip_while.rs deleted file mode 100644 index 52aa2d478b..0000000000 --- a/futures-util/src/stream/try_stream/try_skip_while.rs +++ /dev/null @@ -1,120 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_skip_while`](super::TryStreamExt::try_skip_while) - /// method. - #[must_use = "streams do nothing unless polled"] - pub struct TrySkipWhile where St: TryStream { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - done_skipping: bool, - } -} - -impl fmt::Debug for TrySkipWhile -where - St: TryStream + fmt::Debug, - St::Ok: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TrySkipWhile") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .field("done_skipping", &self.done_skipping) - .finish() - } -} - -impl TrySkipWhile -where - St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None, done_skipping: false } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for TrySkipWhile -where - St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if *this.done_skipping { - return this.stream.try_poll_next(cx); - } - - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let res = ready!(fut.try_poll(cx)); - this.pending_fut.set(None); - let skipped = res?; - let item = this.pending_item.take(); - if !skipped { - *this.done_skipping = true; - break item.map(Ok); - } - } else if let Some(item) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - this.pending_fut.set(Some((this.f)(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - let pending_len = usize::from(self.pending_item.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -impl FusedStream for TrySkipWhile -where - St: TryStream + FusedStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - fn is_terminated(&self) -> bool { - self.pending_item.is_none() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TrySkipWhile -where - S: TryStream + Sink, -{ - type Error = E; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_take_while.rs b/futures-util/src/stream/try_stream/try_take_while.rs deleted file mode 100644 index 4b5ff1ad38..0000000000 --- a/futures-util/src/stream/try_stream/try_take_while.rs +++ /dev/null @@ -1,129 +0,0 @@ -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream, TryStream}; -use futures_core::task::{Context, Poll}; -#[cfg(feature = "sink")] -use futures_sink::Sink; -use pin_project_lite::pin_project; - -pin_project! { - /// Stream for the [`try_take_while`](super::TryStreamExt::try_take_while) - /// method. - #[must_use = "streams do nothing unless polled"] - pub struct TryTakeWhile - where - St: TryStream, - { - #[pin] - stream: St, - f: F, - #[pin] - pending_fut: Option, - pending_item: Option, - done_taking: bool, - } -} - -impl fmt::Debug for TryTakeWhile -where - St: TryStream + fmt::Debug, - St::Ok: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryTakeWhile") - .field("stream", &self.stream) - .field("pending_fut", &self.pending_fut) - .field("pending_item", &self.pending_item) - .field("done_taking", &self.done_taking) - .finish() - } -} - -impl TryTakeWhile -where - St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - pub(super) fn new(stream: St, f: F) -> Self { - Self { stream, f, pending_fut: None, pending_item: None, done_taking: false } - } - - delegate_access_inner!(stream, St, ()); -} - -impl Stream for TryTakeWhile -where - St: TryStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if *this.done_taking { - return Poll::Ready(None); - } - - Poll::Ready(loop { - if let Some(fut) = this.pending_fut.as_mut().as_pin_mut() { - let res = ready!(fut.try_poll(cx)); - this.pending_fut.set(None); - let take = res?; - let item = this.pending_item.take(); - if take { - break item.map(Ok); - } else { - *this.done_taking = true; - break None; - } - } else if let Some(item) = ready!(this.stream.as_mut().try_poll_next(cx)?) { - this.pending_fut.set(Some((this.f)(&item))); - *this.pending_item = Some(item); - } else { - break None; - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - if self.done_taking { - return (0, Some(0)); - } - - let pending_len = usize::from(self.pending_item.is_some()); - let (_, upper) = self.stream.size_hint(); - let upper = match upper { - Some(x) => x.checked_add(pending_len), - None => None, - }; - (0, upper) // can't know a lower bound, due to the predicate - } -} - -impl FusedStream for TryTakeWhile -where - St: TryStream + FusedStream, - F: FnMut(&St::Ok) -> Fut, - Fut: TryFuture, -{ - fn is_terminated(&self) -> bool { - self.done_taking || self.pending_item.is_none() && self.stream.is_terminated() - } -} - -// Forwarding impl of Sink from the underlying stream -#[cfg(feature = "sink")] -impl Sink for TryTakeWhile -where - S: TryStream + Sink, -{ - type Error = E; - - delegate_sink!(stream, Item); -} diff --git a/futures-util/src/stream/try_stream/try_unfold.rs b/futures-util/src/stream/try_stream/try_unfold.rs deleted file mode 100644 index fd9cdf1d8c..0000000000 --- a/futures-util/src/stream/try_stream/try_unfold.rs +++ /dev/null @@ -1,122 +0,0 @@ -use super::assert_stream; -use core::fmt; -use core::pin::Pin; -use futures_core::future::TryFuture; -use futures_core::ready; -use futures_core::stream::Stream; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -/// Creates a `TryStream` from a seed and a closure returning a `TryFuture`. -/// -/// This function is the dual for the `TryStream::try_fold()` adapter: while -/// `TryStream::try_fold()` reduces a `TryStream` to one single value, -/// `try_unfold()` creates a `TryStream` from a seed value. -/// -/// `try_unfold()` will call the provided closure with the provided seed, then -/// wait for the returned `TryFuture` to complete with `(a, b)`. It will then -/// yield the value `a`, and use `b` as the next internal state. -/// -/// If the closure returns `None` instead of `Some(TryFuture)`, then the -/// `try_unfold()` will stop producing items and return `Poll::Ready(None)` in -/// future calls to `poll()`. -/// -/// In case of error generated by the returned `TryFuture`, the error will be -/// returned by the `TryStream`. The `TryStream` will then yield -/// `Poll::Ready(None)` in future calls to `poll()`. -/// -/// This function can typically be used when wanting to go from the "world of -/// futures" to the "world of streams": the provided closure can build a -/// `TryFuture` using other library functions working on futures, and -/// `try_unfold()` will turn it into a `TryStream` by repeating the operation. -/// -/// # Example -/// -/// ``` -/// # #[derive(Debug, PartialEq)] -/// # struct SomeError; -/// # futures::executor::block_on(async { -/// use futures::stream::{self, TryStreamExt}; -/// -/// let stream = stream::try_unfold(0, |state| async move { -/// if state < 0 { -/// return Err(SomeError); -/// } -/// -/// if state <= 2 { -/// let next_state = state + 1; -/// let yielded = state * 2; -/// Ok(Some((yielded, next_state))) -/// } else { -/// Ok(None) -/// } -/// }); -/// -/// let result: Result, _> = stream.try_collect().await; -/// assert_eq!(result, Ok(vec![0, 2, 4])); -/// # }); -/// ``` -pub fn try_unfold(init: T, f: F) -> TryUnfold -where - F: FnMut(T) -> Fut, - Fut: TryFuture>, -{ - assert_stream::, _>(TryUnfold { f, state: Some(init), fut: None }) -} - -pin_project! { - /// Stream for the [`try_unfold`] function. - #[must_use = "streams do nothing unless polled"] - pub struct TryUnfold { - f: F, - state: Option, - #[pin] - fut: Option, - } -} - -impl fmt::Debug for TryUnfold -where - T: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TryUnfold").field("state", &self.state).field("fut", &self.fut).finish() - } -} - -impl Stream for TryUnfold -where - F: FnMut(T) -> Fut, - Fut: TryFuture>, -{ - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if let Some(state) = this.state.take() { - this.fut.set(Some((this.f)(state))); - } - - match this.fut.as_mut().as_pin_mut() { - None => { - // The future previously errored - Poll::Ready(None) - } - Some(future) => { - let step = ready!(future.try_poll(cx)); - this.fut.set(None); - - match step { - Ok(Some((item, next_state))) => { - *this.state = Some(next_state); - Poll::Ready(Some(Ok(item))) - } - Ok(None) => Poll::Ready(None), - Err(e) => Poll::Ready(Some(Err(e))), - } - } - } - } -} diff --git a/futures-util/src/stream/unfold.rs b/futures-util/src/stream/unfold.rs deleted file mode 100644 index f78aa45a05..0000000000 --- a/futures-util/src/stream/unfold.rs +++ /dev/null @@ -1,115 +0,0 @@ -use super::assert_stream; -use crate::unfold_state::UnfoldState; -use core::fmt; -use core::pin::Pin; -use futures_core::future::Future; -use futures_core::ready; -use futures_core::stream::{FusedStream, Stream}; -use futures_core::task::{Context, Poll}; -use pin_project_lite::pin_project; - -/// Creates a `Stream` from a seed and a closure returning a `Future`. -/// -/// This function is the dual for the `Stream::fold()` adapter: while -/// `Stream::fold()` reduces a `Stream` to one single value, `unfold()` creates a -/// `Stream` from a seed value. -/// -/// `unfold()` will call the provided closure with the provided seed, then wait -/// for the returned `Future` to complete with `(a, b)`. It will then yield the -/// value `a`, and use `b` as the next internal state. -/// -/// If the closure returns `None` instead of `Some(Future)`, then the `unfold()` -/// will stop producing items and return `Poll::Ready(None)` in future -/// calls to `poll()`. -/// -/// This function can typically be used when wanting to go from the "world of -/// futures" to the "world of streams": the provided closure can build a -/// `Future` using other library functions working on futures, and `unfold()` -/// will turn it into a `Stream` by repeating the operation. -/// -/// # Example -/// -/// ``` -/// # futures::executor::block_on(async { -/// use futures::stream::{self, StreamExt}; -/// -/// let stream = stream::unfold(0, |state| async move { -/// if state <= 2 { -/// let next_state = state + 1; -/// let yielded = state * 2; -/// Some((yielded, next_state)) -/// } else { -/// None -/// } -/// }); -/// -/// let result = stream.collect::>().await; -/// assert_eq!(result, vec![0, 2, 4]); -/// # }); -/// ``` -pub fn unfold(init: T, f: F) -> Unfold -where - F: FnMut(T) -> Fut, - Fut: Future>, -{ - assert_stream::(Unfold { f, state: UnfoldState::Value { value: init } }) -} - -pin_project! { - /// Stream for the [`unfold`] function. - #[must_use = "streams do nothing unless polled"] - pub struct Unfold { - f: F, - #[pin] - state: UnfoldState, - } -} - -impl fmt::Debug for Unfold -where - T: fmt::Debug, - Fut: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Unfold").field("state", &self.state).finish() - } -} - -impl FusedStream for Unfold -where - F: FnMut(T) -> Fut, - Fut: Future>, -{ - fn is_terminated(&self) -> bool { - matches!(self.state, UnfoldState::Empty) - } -} - -impl Stream for Unfold -where - F: FnMut(T) -> Fut, - Fut: Future>, -{ - type Item = Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut this = self.project(); - - if let Some(state) = this.state.as_mut().take_value() { - this.state.set(UnfoldState::Future { future: (this.f)(state) }); - } - - let step = match this.state.as_mut().project_future() { - Some(fut) => ready!(fut.poll(cx)), - None => panic!("Unfold must not be polled after it returned `Poll::Ready(None)`"), - }; - - if let Some((item, next_state)) = step { - this.state.set(UnfoldState::Value { value: next_state }); - Poll::Ready(Some(item)) - } else { - this.state.set(UnfoldState::Empty); - Poll::Ready(None) - } - } -} diff --git a/futures-util/src/task/mod.rs b/futures-util/src/task/mod.rs deleted file mode 100644 index 7a9e993e5e..0000000000 --- a/futures-util/src/task/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Tools for working with tasks. -//! -//! This module contains: -//! -//! - [`Spawn`], a trait for spawning new tasks. -//! - [`Context`], a context of an asynchronous task, -//! including a handle for waking up the task. -//! - [`Waker`], a handle for waking up a task. -//! -//! The remaining types and traits in the module are used for implementing -//! executors or dealing with synchronization issues around task wakeup. - -#[doc(no_inline)] -pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; - -pub use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError, UnsafeFutureObj}; - -pub use futures_task::noop_waker; -pub use futures_task::noop_waker_ref; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use futures_task::ArcWake; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use futures_task::waker; - -#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))] -#[cfg(feature = "alloc")] -pub use futures_task::{waker_ref, WakerRef}; - -#[cfg_attr( - target_os = "none", - cfg(any(target_has_atomic = "ptr", feature = "portable-atomic")) -)] -pub use futures_core::task::__internal::AtomicWaker; - -mod spawn; -pub use self::spawn::{LocalSpawnExt, SpawnExt}; diff --git a/futures-util/src/task/spawn.rs b/futures-util/src/task/spawn.rs deleted file mode 100644 index d9e9985309..0000000000 --- a/futures-util/src/task/spawn.rs +++ /dev/null @@ -1,169 +0,0 @@ -use futures_task::{LocalSpawn, Spawn}; - -#[cfg(feature = "compat")] -use crate::compat::Compat; - -#[cfg(feature = "channel")] -#[cfg(feature = "std")] -use crate::future::{FutureExt, RemoteHandle}; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; -#[cfg(feature = "alloc")] -use futures_core::future::Future; -#[cfg(feature = "alloc")] -use futures_task::{FutureObj, LocalFutureObj, SpawnError}; - -impl SpawnExt for Sp where Sp: Spawn {} -impl LocalSpawnExt for Sp where Sp: LocalSpawn {} - -/// Extension trait for `Spawn`. -pub trait SpawnExt: Spawn { - /// Spawns a task that polls the given future with output `()` to - /// completion. - /// - /// This method returns a [`Result`] that contains a [`SpawnError`] if - /// spawning fails. - /// - /// You can use [`spawn_with_handle`](SpawnExt::spawn_with_handle) if - /// you want to spawn a future with output other than `()` or if you want - /// to be able to await its completion. - /// - /// Note this method will eventually be replaced with the upcoming - /// `Spawn::spawn` method which will take a `dyn Future` as input. - /// Technical limitations prevent `Spawn::spawn` from being implemented - /// today. Feel free to use this method in the meantime. - /// - /// ``` - /// # { - /// use futures::executor::ThreadPool; - /// use futures::task::SpawnExt; - /// - /// let executor = ThreadPool::new().unwrap(); - /// - /// let future = async { /* ... */ }; - /// executor.spawn(future).unwrap(); - /// # } - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - #[cfg(feature = "alloc")] - fn spawn(&self, future: Fut) -> Result<(), SpawnError> - where - Fut: Future + Send + 'static, - { - self.spawn_obj(FutureObj::new(Box::new(future))) - } - - /// Spawns a task that polls the given future to completion and returns a - /// future that resolves to the spawned future's output. - /// - /// This method returns a [`Result`] that contains a [`RemoteHandle`](crate::future::RemoteHandle), or, if - /// spawning fails, a [`SpawnError`]. [`RemoteHandle`](crate::future::RemoteHandle) is a future that - /// resolves to the output of the spawned future. - /// - /// ``` - /// # { - /// use futures::executor::{block_on, ThreadPool}; - /// use futures::future; - /// use futures::task::SpawnExt; - /// - /// let executor = ThreadPool::new().unwrap(); - /// - /// let future = future::ready(1); - /// let join_handle_fut = executor.spawn_with_handle(future).unwrap(); - /// assert_eq!(block_on(join_handle_fut), 1); - /// # } - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - #[cfg(feature = "channel")] - #[cfg_attr(docsrs, doc(cfg(feature = "channel")))] - #[cfg(feature = "std")] - fn spawn_with_handle(&self, future: Fut) -> Result, SpawnError> - where - Fut: Future + Send + 'static, - Fut::Output: Send, - { - let (future, handle) = future.remote_handle(); - self.spawn(future)?; - Ok(handle) - } - - /// Wraps a [`Spawn`] and makes it usable as a futures 0.1 `Executor`. - /// Requires the `compat` feature to enable. - #[cfg(feature = "compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "compat")))] - fn compat(self) -> Compat - where - Self: Sized, - { - Compat::new(self) - } -} - -/// Extension trait for `LocalSpawn`. -pub trait LocalSpawnExt: LocalSpawn { - /// Spawns a task that polls the given future with output `()` to - /// completion. - /// - /// This method returns a [`Result`] that contains a [`SpawnError`] if - /// spawning fails. - /// - /// You can use [`spawn_with_handle`](SpawnExt::spawn_with_handle) if - /// you want to spawn a future with output other than `()` or if you want - /// to be able to await its completion. - /// - /// Note this method will eventually be replaced with the upcoming - /// `Spawn::spawn` method which will take a `dyn Future` as input. - /// Technical limitations prevent `Spawn::spawn` from being implemented - /// today. Feel free to use this method in the meantime. - /// - /// ``` - /// use futures::executor::LocalPool; - /// use futures::task::LocalSpawnExt; - /// - /// let executor = LocalPool::new(); - /// let spawner = executor.spawner(); - /// - /// let future = async { /* ... */ }; - /// spawner.spawn_local(future).unwrap(); - /// ``` - #[cfg(feature = "alloc")] - fn spawn_local(&self, future: Fut) -> Result<(), SpawnError> - where - Fut: Future + 'static, - { - self.spawn_local_obj(LocalFutureObj::new(Box::new(future))) - } - - /// Spawns a task that polls the given future to completion and returns a - /// future that resolves to the spawned future's output. - /// - /// This method returns a [`Result`] that contains a [`RemoteHandle`](crate::future::RemoteHandle), or, if - /// spawning fails, a [`SpawnError`]. [`RemoteHandle`](crate::future::RemoteHandle) is a future that - /// resolves to the output of the spawned future. - /// - /// ``` - /// use futures::executor::LocalPool; - /// use futures::task::LocalSpawnExt; - /// - /// let mut executor = LocalPool::new(); - /// let spawner = executor.spawner(); - /// - /// let future = async { 1 }; - /// let join_handle_fut = spawner.spawn_local_with_handle(future).unwrap(); - /// assert_eq!(executor.run_until(join_handle_fut), 1); - /// ``` - #[cfg(feature = "channel")] - #[cfg_attr(docsrs, doc(cfg(feature = "channel")))] - #[cfg(feature = "std")] - fn spawn_local_with_handle( - &self, - future: Fut, - ) -> Result, SpawnError> - where - Fut: Future + 'static, - { - let (future, handle) = future.remote_handle(); - self.spawn_local(future)?; - Ok(handle) - } -} diff --git a/futures-util/src/unfold_state.rs b/futures-util/src/unfold_state.rs deleted file mode 100644 index 20cd37846e..0000000000 --- a/futures-util/src/unfold_state.rs +++ /dev/null @@ -1,47 +0,0 @@ -use core::pin::Pin; - -use pin_project_lite::pin_project; - -pin_project! { - /// UnfoldState used for stream and sink unfolds - #[project = UnfoldStateProj] - #[project_replace = UnfoldStateProjReplace] - #[derive(Debug)] - pub(crate) enum UnfoldState { - Value { - value: T, - }, - Future { - #[pin] - future: Fut, - }, - Empty, - } -} - -impl UnfoldState { - pub(crate) fn is_empty(&self) -> bool { - matches!(self, Self::Empty) - } - - pub(crate) fn is_future(&self) -> bool { - matches!(self, Self::Future { .. }) - } - - pub(crate) fn project_future(self: Pin<&mut Self>) -> Option> { - match self.project() { - UnfoldStateProj::Future { future } => Some(future), - _ => None, - } - } - - pub(crate) fn take_value(self: Pin<&mut Self>) -> Option { - match &*self { - Self::Value { .. } => match self.project_replace(Self::Empty) { - UnfoldStateProjReplace::Value { value } => Some(value), - _ => unreachable!(), - }, - _ => None, - } - } -} diff --git a/futures/Cargo.toml b/futures/Cargo.toml deleted file mode 100644 index d8111b7413..0000000000 --- a/futures/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "futures" -version = "0.4.0-alpha.0" -edition = "2018" -rust-version = "1.68" -license = "MIT OR Apache-2.0" -readme = "../README.md" -keywords = ["futures", "async", "future"] -repository = "https://github.com/rust-lang/futures-rs" -homepage = "https://rust-lang.github.io/futures-rs" -description = """ -An implementation of futures and streams featuring zero allocations, -composability, and iterator-like interfaces. -""" -categories = ["asynchronous"] - -[dependencies] -futures-core = { path = "../futures-core", version = "=1.0.0-alpha.0", default-features = false } -futures-task = { path = "../futures-task", version = "=0.4.0-alpha.0", default-features = false } -futures-channel = { path = "../futures-channel", version = "=0.4.0-alpha.0", default-features = false, features = ["sink"] } -futures-executor = { path = "../futures-executor", version = "=0.4.0-alpha.0", default-features = false, optional = true } -futures-io = { path = "../futures-io", version = "0.3.31", default-features = false } -futures-sink = { path = "../futures-sink", version = "=0.4.0-alpha.0", default-features = false } -futures-util = { path = "../futures-util", version = "=0.4.0-alpha.0", default-features = false, features = ["sink"] } - -[dev-dependencies] -futures-executor = { path = "../futures-executor", features = ["thread-pool"] } -futures-test = { path = "../futures-test" } -assert_matches = "1.3.0" -pin-project = "1.0.11" -static_assertions = "1" -tokio = "0.1.11" - -[features] -default = ["std", "async-await", "executor"] -std = ["alloc", "futures-core/std", "futures-task/std", "futures-io/std", "futures-sink/std", "futures-util/std", "futures-util/io", "futures-util/channel"] -alloc = ["futures-core/alloc", "futures-task/alloc", "futures-sink/alloc", "futures-channel/alloc", "futures-util/alloc"] -async-await = ["futures-util/async-await", "futures-util/async-await-macro"] -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 -# `unstable` feature as an explicit opt-in to unstable API. -unstable = ["futures-io/unstable", "futures-util/unstable"] -bilock = ["futures-util/bilock"] -write-all-vectored = ["futures-util/write-all-vectored"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[package.metadata.playground] -features = ["std", "async-await", "compat", "io-compat", "executor", "thread-pool"] - -[lints] -workspace = true diff --git a/futures/LICENSE-APACHE b/futures/LICENSE-APACHE deleted file mode 120000 index 965b606f33..0000000000 --- a/futures/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/futures/LICENSE-MIT b/futures/LICENSE-MIT deleted file mode 120000 index 76219eb72e..0000000000 --- a/futures/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/futures/src/lib.rs b/futures/src/lib.rs deleted file mode 100644 index 2c31e76d29..0000000000 --- a/futures/src/lib.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Abstractions for asynchronous programming. -//! -//! This crate provides a number of core abstractions for writing asynchronous -//! code: -//! -//! - [Futures](crate::future) are single eventual values produced by -//! asynchronous computations. Some programming languages (e.g. JavaScript) -//! call this concept "promise". -//! - [Streams](crate::stream) represent a series of values -//! produced asynchronously. -//! - [Sinks](crate::sink) provide support for asynchronous writing of -//! data. -//! - [Executors](crate::executor) are responsible for running asynchronous -//! tasks. -//! -//! The crate also contains abstractions for [asynchronous I/O](crate::io) and -//! [cross-task communication](crate::channel). -//! -//! Underlying all of this is the *task system*, which is a form of lightweight -//! threading. Large asynchronous computations are built up using futures, -//! streams and sinks, and then spawned as independent tasks that are run to -//! completion, but *do not block* the thread running them. -//! -//! The following example describes how the task system context is built and used -//! within macros and keywords such as async and await!. -//! -//! ```rust -//! # use futures::channel::mpsc; -//! # use futures::executor; ///standard executors to provide a context for futures and streams -//! # use futures::executor::ThreadPool; -//! # use futures::StreamExt; -//! # -//! fn main() { -//! # { -//! let pool = ThreadPool::new().expect("Failed to build pool"); -//! let (tx, rx) = mpsc::unbounded::(); -//! -//! // Create a future by an async block, where async is responsible for an -//! // implementation of Future. At this point no executor has been provided -//! // to this future, so it will not be running. -//! let fut_values = async { -//! // Create another async block, again where the Future implementation -//! // is generated by async. Since this is inside of a parent async block, -//! // it will be provided with the executor of the parent block when the parent -//! // block is executed. -//! // -//! // This executor chaining is done by Future::poll whose second argument -//! // is a std::task::Context. This represents our executor, and the Future -//! // implemented by this async block can be polled using the parent async -//! // block's executor. -//! let fut_tx_result = async move { -//! (0..100).for_each(|v| { -//! tx.unbounded_send(v).expect("Failed to send"); -//! }) -//! }; -//! -//! // Use the provided thread pool to spawn the generated future -//! // responsible for transmission -//! pool.spawn_ok(fut_tx_result); -//! -//! let fut_values = rx -//! .map(|v| v * 2) -//! .collect(); -//! -//! // Use the executor provided to this async block to wait for the -//! // future to complete. -//! fut_values.await -//! }; -//! -//! // Actually execute the above future, which will invoke Future::poll and -//! // subsequently chain appropriate Future::poll and methods needing executors -//! // to drive all futures. Eventually fut_values will be driven to completion. -//! let values: Vec = executor::block_on(fut_values); -//! -//! println!("Values={:?}", values); -//! # } -//! # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -//! } -//! ``` -//! -//! The majority of examples and code snippets in this crate assume that they are -//! inside an async block as written above. - -#![no_std] -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms, single_use_lifetimes), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, unsafe_op_in_unsafe_fn)] -#![cfg_attr(docsrs, feature(doc_cfg))] - -#[cfg(all(feature = "bilock", not(feature = "unstable")))] -compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features"); - -#[doc(no_inline)] -pub use futures_core::future::{Future, TryFuture}; -#[doc(no_inline)] -pub use futures_util::future::{FutureExt, TryFutureExt}; - -#[doc(no_inline)] -pub use futures_core::stream::{Stream, TryStream}; -#[doc(no_inline)] -pub use futures_util::stream::{StreamExt, TryStreamExt}; - -#[doc(no_inline)] -pub use futures_sink::Sink; -#[doc(no_inline)] -pub use futures_util::sink::SinkExt; - -#[cfg(feature = "std")] -#[doc(no_inline)] -pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; -#[cfg(feature = "std")] -#[doc(no_inline)] -pub use futures_util::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; - -// Macro reexports -pub use futures_core::ready; // Readiness propagation -#[cfg(feature = "std")] -#[cfg(feature = "async-await")] -pub use futures_util::select; -#[cfg(feature = "async-await")] -pub use futures_util::{join, pending, poll, select_biased, try_join}; // Async-await - -// Module reexports -#[doc(inline)] -pub use futures_util::{future, sink, stream, task}; - -#[cfg(feature = "std")] -#[cfg(feature = "async-await")] -pub use futures_util::stream_select; - -#[cfg(feature = "alloc")] -#[doc(inline)] -pub use futures_channel as channel; -#[cfg(feature = "alloc")] -#[doc(inline)] -pub use futures_util::lock; - -#[cfg(feature = "std")] -#[doc(inline)] -pub use futures_util::io; - -#[cfg(feature = "executor")] -#[cfg_attr(docsrs, doc(cfg(feature = "executor")))] -pub mod executor { - //! Built-in executors and related tools. - //! - //! All asynchronous computation occurs within an executor, which is - //! capable of spawning futures as tasks. This module provides several - //! built-in executors, as well as tools for building your own. - //! - //! - //! This module is only available when the `executor` feature of this - //! library is activated. - //! - //! # Using a thread pool (M:N task scheduling) - //! - //! Most of the time tasks should be executed on a [thread pool](ThreadPool). - //! A small set of worker threads can handle a very large set of spawned tasks - //! (which are much lighter weight than threads). Tasks spawned onto the pool - //! with the [`spawn_ok`](ThreadPool::spawn_ok) function will run ambiently on - //! the created threads. - //! - //! # Spawning additional tasks - //! - //! Tasks can be spawned onto a spawner by calling its [`spawn_obj`] method - //! directly. In the case of `!Send` futures, [`spawn_local_obj`] can be used - //! instead. - //! - //! # Single-threaded execution - //! - //! In addition to thread pools, it's possible to run a task (and the tasks - //! it spawns) entirely within a single thread via the [`LocalPool`] executor. - //! Aside from cutting down on synchronization costs, this executor also makes - //! it possible to spawn non-`Send` tasks, via [`spawn_local_obj`]. The - //! [`LocalPool`] is best suited for running I/O-bound tasks that do relatively - //! little work between I/O operations. - //! - //! There is also a convenience function [`block_on`] for simply running a - //! future to completion on the current thread. - //! - //! [`spawn_obj`]: https://docs.rs/futures/0.3/futures/task/trait.Spawn.html#tymethod.spawn_obj - //! [`spawn_local_obj`]: https://docs.rs/futures/0.3/futures/task/trait.LocalSpawn.html#tymethod.spawn_local_obj - - pub use futures_executor::{ - block_on, block_on_stream, enter, BlockingStream, Enter, EnterError, LocalPool, - LocalSpawner, - }; - - #[cfg(feature = "thread-pool")] - #[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] - pub use futures_executor::{ThreadPool, ThreadPoolBuilder}; -} - -#[cfg(feature = "compat")] -#[cfg_attr(docsrs, doc(cfg(feature = "compat")))] -pub mod compat { - //! Interop between `futures` 0.1 and 0.3. - //! - //! This module is only available when the `compat` feature of this - //! library is activated. - - pub use futures_util::compat::{ - Compat, Compat01As03, Compat01As03Sink, CompatSink, Executor01As03, Executor01CompatExt, - Executor01Future, Future01CompatExt, Sink01CompatExt, Stream01CompatExt, - }; - - #[cfg(feature = "io-compat")] - #[cfg_attr(docsrs, doc(cfg(feature = "io-compat")))] - pub use futures_util::compat::{AsyncRead01CompatExt, AsyncWrite01CompatExt}; -} - -pub mod prelude { - //! A "prelude" for crates using the `futures` crate. - //! - //! This prelude is similar to the standard library's prelude in that you'll - //! almost always want to import its entire contents, but unlike the - //! standard library's prelude you'll have to do so manually: - //! - //! ``` - //! # #[allow(unused_imports)] - //! use futures::prelude::*; - //! ``` - //! - //! The prelude may grow over time as additional items see ubiquitous use. - - pub use crate::future::{self, Future, TryFuture}; - pub use crate::sink::{self, Sink}; - pub use crate::stream::{self, Stream, TryStream}; - - #[doc(no_inline)] - pub use crate::future::{FutureExt as _, TryFutureExt as _}; - #[doc(no_inline)] - pub use crate::sink::SinkExt as _; - #[doc(no_inline)] - pub use crate::stream::{StreamExt as _, TryStreamExt as _}; - - #[cfg(feature = "std")] - pub use crate::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; - - #[cfg(feature = "std")] - #[doc(no_inline)] - pub use crate::io::{ - AsyncBufReadExt as _, AsyncReadExt as _, AsyncSeekExt as _, AsyncWriteExt as _, - }; -} diff --git a/futures/tests/_require_features.rs b/futures/tests/_require_features.rs deleted file mode 100644 index 8046cc99a4..0000000000 --- a/futures/tests/_require_features.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg(not(all( - feature = "std", - feature = "alloc", - feature = "async-await", - feature = "compat", - feature = "io-compat", - feature = "executor", - feature = "thread-pool", -)))] -compile_error!( - "`futures` tests must have all stable features activated: \ - use `--all-features` or `--features default,thread-pool,io-compat`" -); diff --git a/futures/tests/async_await_macros.rs b/futures/tests/async_await_macros.rs deleted file mode 100644 index 60498c5836..0000000000 --- a/futures/tests/async_await_macros.rs +++ /dev/null @@ -1,403 +0,0 @@ -use futures::channel::{mpsc, oneshot}; -use futures::executor::block_on; -use futures::future::{self, poll_fn, FutureExt}; -use futures::sink::SinkExt; -use futures::stream::StreamExt; -use futures::task::{Context, Poll}; -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 { - let mut pending_once = pin!(pending_once); - assert_eq!(Poll::Pending, poll!(&mut pending_once)); - assert_eq!(Poll::Ready(()), poll!(&mut pending_once)); - }); -} - -#[test] -fn join() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = oneshot::channel::(); - - let fut = async { - let res = join!(rx1, rx2); - assert_eq!((Ok(1), Ok(2)), res); - }; - - block_on(async { - let mut fut = pin!(fut); - assert_eq!(Poll::Pending, poll!(&mut fut)); - tx1.send(1).unwrap(); - assert_eq!(Poll::Pending, poll!(&mut fut)); - tx2.send(2).unwrap(); - assert_eq!(Poll::Ready(()), poll!(&mut fut)); - }); -} - -#[test] -fn select() { - let (tx1, rx1) = oneshot::channel::(); - let (_tx2, rx2) = oneshot::channel::(); - tx1.send(1).unwrap(); - let mut ran = false; - block_on(async { - select! { - res = rx1.fuse() => { - assert_eq!(Ok(1), res); - ran = true; - }, - _ = rx2.fuse() => unreachable!(), - } - }); - assert!(ran); -} - -#[test] -fn select_grammar() { - // Parsing after `=>` using Expr::parse would parse `{}() = future::ready(())` - // as one expression. - block_on(async { - select! { - () = future::pending::<()>() => {} - () = future::ready(()) => {} - } - }); -} - -#[test] -fn select_biased() { - let (tx1, rx1) = oneshot::channel::(); - let (_tx2, rx2) = oneshot::channel::(); - tx1.send(1).unwrap(); - let mut ran = false; - block_on(async { - select_biased! { - res = rx1.fuse() => { - assert_eq!(Ok(1), res); - ran = true; - }, - _ = rx2.fuse() => unreachable!(), - } - }); - assert!(ran); -} - -#[test] -fn select_streams() { - let (mut tx1, rx1) = mpsc::channel::(1); - let (mut tx2, rx2) = mpsc::channel::(1); - let mut rx1 = rx1.fuse(); - let mut rx2 = rx2.fuse(); - let mut ran = false; - let mut total = 0; - block_on(async { - let mut tx1_opt; - let mut tx2_opt; - select! { - _ = rx1.next() => panic!(), - _ = rx2.next() => panic!(), - default => { - tx1.send(2).await.unwrap(); - tx2.send(3).await.unwrap(); - tx1_opt = Some(tx1); - tx2_opt = Some(tx2); - } - complete => panic!(), - } - loop { - select! { - // runs first and again after default - x = rx1.next() => if let Some(x) = x { total += x; }, - // runs second and again after default - x = rx2.next() => if let Some(x) = x { total += x; }, - // runs third - default => { - assert_eq!(total, 5); - ran = true; - drop(tx1_opt.take().unwrap()); - drop(tx2_opt.take().unwrap()); - }, - // runs last - complete => break, - }; - } - }); - assert!(ran); -} - -#[test] -fn select_can_move_uncompleted_futures() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = oneshot::channel::(); - tx1.send(1).unwrap(); - tx2.send(2).unwrap(); - let mut ran = false; - let mut rx1 = rx1.fuse(); - let mut rx2 = rx2.fuse(); - block_on(async { - select! { - res = rx1 => { - assert_eq!(Ok(1), res); - assert_eq!(Ok(2), rx2.await); - ran = true; - }, - res = rx2 => { - assert_eq!(Ok(2), res); - assert_eq!(Ok(1), rx1.await); - ran = true; - }, - } - }); - assert!(ran); -} - -#[test] -fn select_nested() { - let mut outer_fut = future::ready(1); - let mut inner_fut = future::ready(2); - let res = block_on(async { - select! { - x = outer_fut => { - select! { - y = inner_fut => x + y, - } - } - } - }); - assert_eq!(res, 3); -} - -#[cfg_attr(not(target_pointer_width = "64"), ignore)] -#[test] -fn select_size() { - let fut = async { - let mut ready = future::ready(0i32); - select! { - _ = ready => {}, - } - }; - assert_eq!(mem::size_of_val(&fut), 24); - - let fut = async { - let mut ready1 = future::ready(0i32); - let mut ready2 = future::ready(0i32); - select! { - _ = ready1 => {}, - _ = ready2 => {}, - } - }; - assert_eq!(mem::size_of_val(&fut), 40); -} - -#[test] -fn select_on_non_unpin_expressions() { - // The returned Future is !Unpin - let make_non_unpin_fut = || async { 5 }; - - let res = block_on(async { - let select_res; - select! { - value_1 = make_non_unpin_fut().fuse() => select_res = value_1, - value_2 = make_non_unpin_fut().fuse() => select_res = value_2, - }; - select_res - }); - assert_eq!(res, 5); -} - -#[test] -fn select_on_non_unpin_expressions_with_default() { - // The returned Future is !Unpin - let make_non_unpin_fut = || async { 5 }; - - let res = block_on(async { - let select_res; - select! { - value_1 = make_non_unpin_fut().fuse() => select_res = value_1, - value_2 = make_non_unpin_fut().fuse() => select_res = value_2, - default => select_res = 7, - }; - select_res - }); - assert_eq!(res, 5); -} - -#[cfg_attr(not(target_pointer_width = "64"), ignore)] -#[test] -fn select_on_non_unpin_size() { - // The returned Future is !Unpin - let make_non_unpin_fut = || async { 5 }; - - let fut = async { - let select_res; - select! { - value_1 = make_non_unpin_fut().fuse() => select_res = value_1, - value_2 = make_non_unpin_fut().fuse() => select_res = value_2, - }; - select_res - }; - - assert_eq!(32, mem::size_of_val(&fut)); -} - -#[test] -fn select_can_be_used_as_expression() { - block_on(async { - let res = select! { - x = future::ready(7) => x, - y = future::ready(3) => y + 1, - }; - assert!(res == 7 || res == 4); - }); -} - -#[test] -fn select_with_default_can_be_used_as_expression() { - fn poll_always_pending(_cx: &mut Context<'_>) -> Poll { - Poll::Pending - } - - block_on(async { - let res = select! { - x = poll_fn(poll_always_pending::).fuse() => x, - y = poll_fn(poll_always_pending::).fuse() => y + 1, - default => 99, - }; - assert_eq!(res, 99); - }); -} - -#[test] -fn select_with_complete_can_be_used_as_expression() { - block_on(async { - let res = select! { - x = future::pending::() => x, - y = future::pending::() => y + 1, - default => 99, - complete => 237, - }; - assert_eq!(res, 237); - }); -} - -#[test] -#[allow(unused_assignments)] -fn select_on_mutable_borrowing_future_with_same_borrow_in_block() { - async fn require_mutable(_: &mut i32) {} - async fn async_noop() {} - - block_on(async { - let mut value = 234; - select! { - _ = require_mutable(&mut value).fuse() => { }, - _ = async_noop().fuse() => { - value += 5; - }, - } - }); -} - -#[test] -#[allow(unused_assignments)] -fn select_on_mutable_borrowing_future_with_same_borrow_in_block_and_default() { - async fn require_mutable(_: &mut i32) {} - async fn async_noop() {} - - block_on(async { - let mut value = 234; - select! { - _ = require_mutable(&mut value).fuse() => { }, - _ = async_noop().fuse() => { - value += 5; - }, - default => { - value += 27; - }, - } - }); -} - -#[test] -#[allow(unused_assignments)] -fn stream_select() { - // stream_select! macro - block_on(async { - let endless_ints = |i| stream::iter(vec![i].into_iter().cycle()); - - let mut endless_ones = stream_select!(endless_ints(1i32), stream::pending()); - assert_eq!(endless_ones.next().await, Some(1)); - assert_eq!(endless_ones.next().await, Some(1)); - - let mut finite_list = stream_select!(stream::iter(vec![1]), stream::iter(vec![1])); - assert_eq!(finite_list.next().await, Some(1)); - assert_eq!(finite_list.next().await, Some(1)); - assert_eq!(finite_list.next().await, None); - - let endless_mixed = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3)); - // Take 1000, and assert a somewhat even distribution of values. - // The fairness is randomized, but over 1000 samples we should be pretty close to even. - // This test may be a bit flaky. Feel free to adjust the margins as you see fit. - let mut count = 0; - let results = endless_mixed - .take_while(move |_| { - count += 1; - let ret = count < 1000; - async move { ret } - }) - .collect::>() - .await; - assert!(results.iter().filter(|x| **x == 1).count() >= 299); - assert!(results.iter().filter(|x| **x == 2).count() >= 299); - assert!(results.iter().filter(|x| **x == 3).count() >= 299); - }); -} - -#[cfg_attr(not(target_pointer_width = "64"), ignore)] -#[test] -fn join_size() { - let fut = async { - let ready = future::ready(0i32); - join!(ready) - }; - assert_eq!(mem::size_of_val(&fut), 24); - - let fut = async { - let ready1 = future::ready(0i32); - let ready2 = future::ready(0i32); - join!(ready1, ready2) - }; - assert_eq!(mem::size_of_val(&fut), 40); -} - -#[cfg_attr(not(target_pointer_width = "64"), ignore)] -#[test] -fn try_join_size() { - let fut = async { - let ready = future::ready(Ok::(0)); - try_join!(ready) - }; - assert_eq!(mem::size_of_val(&fut), 24); - - let fut = async { - let ready1 = future::ready(Ok::(0)); - let ready2 = future::ready(Ok::(0)); - try_join!(ready1, ready2) - }; - assert_eq!(mem::size_of_val(&fut), 48); -} - -#[allow(clippy::let_underscore_future)] -#[test] -fn join_doesnt_require_unpin() { - let _ = async { join!(async {}, async {}) }; -} - -#[allow(clippy::let_underscore_future)] -#[test] -fn try_join_doesnt_require_unpin() { - let _ = async { try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) },) }; -} diff --git a/futures/tests/auto_traits.rs b/futures/tests/auto_traits.rs deleted file mode 100644 index 8d15fa28ef..0000000000 --- a/futures/tests/auto_traits.rs +++ /dev/null @@ -1,1911 +0,0 @@ -#![cfg(feature = "compat")] -#![allow(dead_code)] - -//! Assert Send/Sync/Unpin for all public types. - -use futures::{ - future::Future, - sink::Sink, - stream::Stream, - task::{Context, Poll}, -}; -use static_assertions::{assert_impl_all as assert_impl, assert_not_impl_all as assert_not_impl}; -use std::marker::PhantomPinned; -use std::{marker::PhantomData, pin::Pin}; - -type LocalFuture = Pin>>; -type LocalTryFuture = LocalFuture>; -type SendFuture = Pin + Send>>; -type SendTryFuture = SendFuture>; -type SyncFuture = Pin + Sync>>; -type SyncTryFuture = SyncFuture>; -type SendSyncFuture = Pin + Send + Sync>>; -type SendSyncTryFuture = SendSyncFuture>; -type UnpinFuture = LocalFuture; -type UnpinTryFuture = UnpinFuture>; -struct PinnedFuture(PhantomPinned, PhantomData); -impl Future for PinnedFuture { - type Output = T; - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { - unimplemented!() - } -} -type PinnedTryFuture = PinnedFuture>; - -type LocalStream = Pin>>; -type LocalTryStream = LocalStream>; -type SendStream = Pin + Send>>; -type SendTryStream = SendStream>; -type SyncStream = Pin + Sync>>; -type SyncTryStream = SyncStream>; -type SendSyncStream = Pin + Send + Sync>>; -type SendSyncTryStream = SendSyncStream>; -type UnpinStream = LocalStream; -type UnpinTryStream = UnpinStream>; -struct PinnedStream(PhantomPinned, PhantomData); -impl Stream for PinnedStream { - type Item = T; - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - unimplemented!() - } -} -type PinnedTryStream = PinnedStream>; - -type LocalSink = Pin>>; -type SendSink = Pin + Send>>; -type SyncSink = Pin + Sync>>; -type UnpinSink = LocalSink; -struct PinnedSink(PhantomPinned, PhantomData<(T, E)>); -impl Sink for PinnedSink { - type Error = E; - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - unimplemented!() - } - fn start_send(self: Pin<&mut Self>, _: T) -> Result<(), Self::Error> { - unimplemented!() - } - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - unimplemented!() - } - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - unimplemented!() - } -} - -/// Assert Send/Sync/Unpin for all public types in `futures::channel`. -mod channel { - use super::*; - use futures::channel::*; - - assert_impl!(mpsc::Receiver<()>: Send); - assert_not_impl!(mpsc::Receiver<*const ()>: Send); - assert_impl!(mpsc::Receiver<()>: Sync); - assert_not_impl!(mpsc::Receiver<*const ()>: Sync); - assert_impl!(mpsc::Receiver: Unpin); - - assert_impl!(mpsc::SendError: Send); - assert_impl!(mpsc::SendError: Sync); - assert_impl!(mpsc::SendError: Unpin); - - assert_impl!(mpsc::Sender<()>: Send); - assert_not_impl!(mpsc::Sender<*const ()>: Send); - assert_impl!(mpsc::Sender<()>: Sync); - assert_not_impl!(mpsc::Sender<*const ()>: Sync); - assert_impl!(mpsc::Sender: Unpin); - - assert_impl!(mpsc::TryRecvError: Send); - assert_impl!(mpsc::TryRecvError: Sync); - assert_impl!(mpsc::TryRecvError: Unpin); - - assert_impl!(mpsc::TrySendError<()>: Send); - assert_not_impl!(mpsc::TrySendError<*const ()>: Send); - assert_impl!(mpsc::TrySendError<()>: Sync); - assert_not_impl!(mpsc::TrySendError<*const ()>: Sync); - assert_impl!(mpsc::TrySendError<()>: Unpin); - assert_not_impl!(mpsc::TrySendError: Unpin); - - assert_impl!(mpsc::UnboundedReceiver<()>: Send); - assert_not_impl!(mpsc::UnboundedReceiver<*const ()>: Send); - assert_impl!(mpsc::UnboundedReceiver<()>: Sync); - assert_not_impl!(mpsc::UnboundedReceiver<*const ()>: Sync); - assert_impl!(mpsc::UnboundedReceiver: Unpin); - - assert_impl!(mpsc::UnboundedReceiver<()>: Send); - assert_not_impl!(mpsc::UnboundedReceiver<*const ()>: Send); - assert_impl!(mpsc::UnboundedReceiver<()>: Sync); - assert_not_impl!(mpsc::UnboundedReceiver<*const ()>: Sync); - assert_impl!(mpsc::UnboundedReceiver: Unpin); - - assert_impl!(oneshot::Canceled: Send); - assert_impl!(oneshot::Canceled: Sync); - assert_impl!(oneshot::Canceled: Unpin); - - assert_impl!(oneshot::Cancellation<'_, ()>: Send); - assert_not_impl!(oneshot::Cancellation<'_, *const ()>: Send); - assert_impl!(oneshot::Cancellation<'_, ()>: Sync); - assert_not_impl!(oneshot::Cancellation<'_, *const ()>: Sync); - assert_impl!(oneshot::Cancellation<'_, PhantomPinned>: Unpin); - - assert_impl!(oneshot::Receiver<()>: Send); - assert_not_impl!(oneshot::Receiver<*const ()>: Send); - assert_impl!(oneshot::Receiver<()>: Sync); - assert_not_impl!(oneshot::Receiver<*const ()>: Sync); - assert_impl!(oneshot::Receiver: Unpin); - - assert_impl!(oneshot::Sender<()>: Send); - assert_not_impl!(oneshot::Sender<*const ()>: Send); - assert_impl!(oneshot::Sender<()>: Sync); - assert_not_impl!(oneshot::Sender<*const ()>: Sync); - assert_impl!(oneshot::Sender: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::compat`. -mod compat { - use super::*; - use futures::compat::*; - - assert_impl!(Compat<()>: Send); - assert_not_impl!(Compat<*const ()>: Send); - assert_impl!(Compat<()>: Sync); - assert_not_impl!(Compat<*const ()>: Sync); - assert_impl!(Compat<()>: Unpin); - assert_not_impl!(Compat: Unpin); - - assert_impl!(Compat01As03<()>: Send); - assert_not_impl!(Compat01As03<*const ()>: Send); - assert_not_impl!(Compat01As03<()>: Sync); - assert_impl!(Compat01As03: Unpin); - - assert_impl!(Compat01As03Sink<(), ()>: Send); - assert_not_impl!(Compat01As03Sink<(), *const ()>: Send); - assert_not_impl!(Compat01As03Sink<*const (), ()>: Send); - assert_not_impl!(Compat01As03Sink<(), ()>: Sync); - assert_impl!(Compat01As03Sink: Unpin); - - assert_impl!(CompatSink<(), *const ()>: Send); - assert_not_impl!(CompatSink<*const (), ()>: Send); - assert_impl!(CompatSink<(), *const ()>: Sync); - assert_not_impl!(CompatSink<*const (), ()>: Sync); - assert_impl!(CompatSink<(), PhantomPinned>: Unpin); - assert_not_impl!(CompatSink: Unpin); - - assert_impl!(Executor01As03<()>: Send); - assert_not_impl!(Executor01As03<*const ()>: Send); - assert_impl!(Executor01As03<()>: Sync); - assert_not_impl!(Executor01As03<*const ()>: Sync); - assert_impl!(Executor01As03<()>: Unpin); - assert_not_impl!(Executor01As03: Unpin); - - assert_impl!(Executor01Future: Send); - assert_not_impl!(Executor01Future: Sync); - assert_impl!(Executor01Future: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::executor`. -mod executor { - use super::*; - use futures::executor::*; - - assert_impl!(BlockingStream: Send); - assert_not_impl!(BlockingStream: Send); - assert_impl!(BlockingStream: Sync); - assert_not_impl!(BlockingStream: Sync); - assert_impl!(BlockingStream: Unpin); - // BlockingStream requires `S: Unpin` - // assert_not_impl!(BlockingStream: Unpin); - - assert_impl!(Enter: Send); - assert_impl!(Enter: Sync); - assert_impl!(Enter: Unpin); - - assert_impl!(EnterError: Send); - assert_impl!(EnterError: Sync); - assert_impl!(EnterError: Unpin); - - assert_not_impl!(LocalPool: Send); - assert_not_impl!(LocalPool: Sync); - assert_impl!(LocalPool: Unpin); - - assert_not_impl!(LocalSpawner: Send); - assert_not_impl!(LocalSpawner: Sync); - assert_impl!(LocalSpawner: Unpin); - - assert_impl!(ThreadPool: Send); - assert_impl!(ThreadPool: Sync); - assert_impl!(ThreadPool: Unpin); - - assert_impl!(ThreadPoolBuilder: Send); - assert_impl!(ThreadPoolBuilder: Sync); - assert_impl!(ThreadPoolBuilder: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::future`. -mod future { - use super::*; - use futures::future::*; - - assert_impl!(AbortHandle: Send); - assert_impl!(AbortHandle: Sync); - assert_impl!(AbortHandle: Unpin); - - assert_impl!(AbortRegistration: Send); - assert_impl!(AbortRegistration: Sync); - assert_impl!(AbortRegistration: Unpin); - - assert_impl!(Abortable: Send); - assert_not_impl!(Abortable: Send); - assert_impl!(Abortable: Sync); - assert_not_impl!(Abortable: Sync); - assert_impl!(Abortable: Unpin); - assert_not_impl!(Abortable: Unpin); - - assert_impl!(Aborted: Send); - assert_impl!(Aborted: Sync); - assert_impl!(Aborted: Unpin); - - assert_impl!(AndThen: Send); - assert_not_impl!(AndThen: Send); - assert_not_impl!(AndThen: Send); - assert_not_impl!(AndThen: Send); - assert_impl!(AndThen: Sync); - assert_not_impl!(AndThen: Sync); - assert_not_impl!(AndThen: Sync); - assert_not_impl!(AndThen: Sync); - assert_impl!(AndThen: Unpin); - assert_not_impl!(AndThen: Unpin); - assert_not_impl!(AndThen: Unpin); - - assert_impl!(CatchUnwind: Send); - assert_not_impl!(CatchUnwind: Send); - assert_impl!(CatchUnwind: Sync); - assert_not_impl!(CatchUnwind: Sync); - assert_impl!(CatchUnwind: Unpin); - assert_not_impl!(CatchUnwind: Unpin); - - assert_impl!(ErrInto: Send); - assert_not_impl!(ErrInto: Send); - assert_impl!(ErrInto: Sync); - assert_not_impl!(ErrInto: Sync); - assert_impl!(ErrInto: Unpin); - assert_not_impl!(ErrInto: Unpin); - - assert_impl!(Flatten>: Send); - assert_not_impl!(Flatten: Send); - assert_not_impl!(Flatten: Send); - assert_impl!(Flatten>: Sync); - assert_not_impl!(Flatten: Sync); - assert_not_impl!(Flatten: Sync); - assert_impl!(Flatten>: Unpin); - assert_not_impl!(Flatten: Unpin); - assert_not_impl!(Flatten: Unpin); - - assert_impl!(FlattenSink: Send); - assert_not_impl!(FlattenSink: Send); - assert_not_impl!(FlattenSink: Send); - assert_impl!(FlattenSink: Sync); - assert_not_impl!(FlattenSink: Sync); - assert_not_impl!(FlattenSink: Sync); - assert_impl!(FlattenSink: Unpin); - assert_not_impl!(FlattenSink: Unpin); - assert_not_impl!(FlattenSink: Unpin); - - assert_impl!(FlattenStream>: Send); - assert_not_impl!(FlattenStream: Send); - assert_not_impl!(FlattenStream: Send); - assert_impl!(FlattenStream>: Sync); - assert_not_impl!(FlattenStream: Sync); - assert_not_impl!(FlattenStream: Sync); - assert_impl!(FlattenStream>: Unpin); - assert_not_impl!(FlattenStream: Unpin); - assert_not_impl!(FlattenStream: Unpin); - - assert_impl!(Fuse: Send); - assert_not_impl!(Fuse: Send); - assert_impl!(Fuse: Sync); - assert_not_impl!(Fuse: Sync); - assert_impl!(Fuse: Unpin); - assert_not_impl!(Fuse: Unpin); - - assert_impl!(FutureObj<'_, *const ()>: Send); - assert_not_impl!(FutureObj<'_, ()>: Sync); - assert_impl!(FutureObj<'_, PhantomPinned>: Unpin); - - assert_impl!(Inspect: Send); - assert_not_impl!(Inspect: Send); - assert_not_impl!(Inspect: Send); - assert_impl!(Inspect: Sync); - assert_not_impl!(Inspect: Sync); - assert_not_impl!(Inspect: Sync); - assert_impl!(Inspect: Unpin); - assert_not_impl!(Inspect: Unpin); - - assert_impl!(InspectErr: Send); - assert_not_impl!(InspectErr: Send); - assert_not_impl!(InspectErr: Send); - assert_impl!(InspectErr: Sync); - assert_not_impl!(InspectErr: Sync); - assert_not_impl!(InspectErr: Sync); - assert_impl!(InspectErr: Unpin); - assert_not_impl!(InspectErr: Unpin); - - assert_impl!(InspectOk: Send); - assert_not_impl!(InspectOk: Send); - assert_not_impl!(InspectOk: Send); - assert_impl!(InspectOk: Sync); - assert_not_impl!(InspectOk: Sync); - assert_not_impl!(InspectOk: Sync); - assert_impl!(InspectOk: Unpin); - assert_not_impl!(InspectOk: Unpin); - - assert_impl!(IntoFuture: Send); - assert_not_impl!(IntoFuture: Send); - assert_impl!(IntoFuture: Sync); - assert_not_impl!(IntoFuture: Sync); - assert_impl!(IntoFuture: Unpin); - assert_not_impl!(IntoFuture: Unpin); - - assert_impl!(IntoStream: Send); - assert_not_impl!(IntoStream: Send); - assert_impl!(IntoStream: Sync); - assert_not_impl!(IntoStream: Sync); - assert_impl!(IntoStream: Unpin); - assert_not_impl!(IntoStream: Unpin); - - assert_impl!(Join, SendFuture<()>>: Send); - assert_not_impl!(Join, SendFuture>: Send); - assert_not_impl!(Join>: Send); - assert_not_impl!(Join: Send); - assert_not_impl!(Join: Send); - assert_impl!(Join, SyncFuture<()>>: Sync); - assert_not_impl!(Join, SyncFuture>: Sync); - assert_not_impl!(Join>: Sync); - assert_not_impl!(Join: Sync); - assert_not_impl!(Join: Sync); - assert_impl!(Join: Unpin); - assert_not_impl!(Join: Unpin); - assert_not_impl!(Join: Unpin); - - // Join3, Join4, Join5 are the same as Join - - assert_impl!(JoinAll>: Send); - assert_not_impl!(JoinAll: Send); - assert_not_impl!(JoinAll: Send); - assert_impl!(JoinAll>: Sync); - assert_not_impl!(JoinAll>: Sync); - assert_not_impl!(JoinAll>: Sync); - assert_not_impl!(JoinAll: Sync); - assert_impl!(JoinAll: Unpin); - - assert_impl!(Lazy<()>: Send); - assert_not_impl!(Lazy<*const ()>: Send); - assert_impl!(Lazy<()>: Sync); - assert_not_impl!(Lazy<*const ()>: Sync); - assert_impl!(Lazy: Unpin); - - assert_not_impl!(LocalFutureObj<'_, ()>: Send); - assert_not_impl!(LocalFutureObj<'_, ()>: Sync); - assert_impl!(LocalFutureObj<'_, PhantomPinned>: Unpin); - - assert_impl!(Map: Send); - assert_not_impl!(Map: Send); - assert_not_impl!(Map: Send); - assert_impl!(Map: Sync); - assert_not_impl!(Map: Sync); - assert_not_impl!(Map: Sync); - assert_impl!(Map: Unpin); - assert_not_impl!(Map: Unpin); - - assert_impl!(MapErr: Send); - assert_not_impl!(MapErr: Send); - assert_not_impl!(MapErr: Send); - assert_impl!(MapErr: Sync); - assert_not_impl!(MapErr: Sync); - assert_not_impl!(MapErr: Sync); - assert_impl!(MapErr: Unpin); - assert_not_impl!(MapErr: Unpin); - - assert_impl!(MapInto: Send); - assert_not_impl!(MapInto: Send); - assert_impl!(MapInto: Sync); - assert_not_impl!(MapInto: Sync); - assert_impl!(MapInto: Unpin); - assert_not_impl!(MapInto: Unpin); - - assert_impl!(MapOk: Send); - assert_not_impl!(MapOk: Send); - assert_not_impl!(MapOk: Send); - assert_impl!(MapOk: Sync); - assert_not_impl!(MapOk: Sync); - assert_not_impl!(MapOk: Sync); - assert_impl!(MapOk: Unpin); - assert_not_impl!(MapOk: Unpin); - - assert_impl!(MapOkOrElse: Send); - assert_not_impl!(MapOkOrElse: Send); - assert_not_impl!(MapOkOrElse: Send); - assert_not_impl!(MapOkOrElse: Send); - assert_impl!(MapOkOrElse: Sync); - assert_not_impl!(MapOkOrElse: Sync); - assert_not_impl!(MapOkOrElse: Sync); - assert_not_impl!(MapOkOrElse: Sync); - assert_impl!(MapOkOrElse: Unpin); - assert_not_impl!(MapOkOrElse: Unpin); - - assert_impl!(NeverError: Send); - assert_not_impl!(NeverError: Send); - assert_impl!(NeverError: Sync); - assert_not_impl!(NeverError: Sync); - assert_impl!(NeverError: Unpin); - assert_not_impl!(NeverError: Unpin); - - assert_impl!(OkInto: Send); - assert_not_impl!(OkInto: Send); - assert_impl!(OkInto: Sync); - assert_not_impl!(OkInto: Sync); - assert_impl!(OkInto: Unpin); - assert_not_impl!(OkInto: Unpin); - - assert_impl!(OptionFuture: Send); - assert_not_impl!(OptionFuture: Send); - assert_impl!(OptionFuture: Sync); - assert_not_impl!(OptionFuture: Sync); - assert_impl!(OptionFuture: Unpin); - assert_not_impl!(OptionFuture: Unpin); - - assert_impl!(OrElse: Send); - assert_not_impl!(OrElse: Send); - assert_not_impl!(OrElse: Send); - assert_not_impl!(OrElse: Send); - assert_impl!(OrElse: Sync); - assert_not_impl!(OrElse: Sync); - assert_not_impl!(OrElse: Sync); - assert_not_impl!(OrElse: Sync); - assert_impl!(OrElse: Unpin); - assert_not_impl!(OrElse: Unpin); - assert_not_impl!(OrElse: Unpin); - - assert_impl!(Pending<()>: Send); - assert_not_impl!(Pending<*const ()>: Send); - assert_impl!(Pending<()>: Sync); - assert_not_impl!(Pending<*const ()>: Sync); - assert_impl!(Pending: Unpin); - - assert_impl!(PollFn<()>: Send); - assert_not_impl!(PollFn<*const ()>: Send); - assert_impl!(PollFn<()>: Sync); - assert_not_impl!(PollFn<*const ()>: Sync); - assert_impl!(PollFn: Unpin); - - assert_impl!(PollImmediate: Send); - assert_not_impl!(PollImmediate>: Send); - assert_impl!(PollImmediate: Sync); - assert_not_impl!(PollImmediate>: Sync); - assert_impl!(PollImmediate: Unpin); - assert_not_impl!(PollImmediate: Unpin); - - assert_impl!(Ready<()>: Send); - assert_not_impl!(Ready<*const ()>: Send); - assert_impl!(Ready<()>: Sync); - assert_not_impl!(Ready<*const ()>: Sync); - assert_impl!(Ready: Unpin); - - assert_impl!(Remote>: Send); - assert_not_impl!(Remote: Send); - assert_not_impl!(Remote: Send); - assert_impl!(Remote>: Sync); - assert_not_impl!(Remote: Sync); - assert_not_impl!(Remote: Sync); - assert_impl!(Remote: Unpin); - assert_not_impl!(Remote: Unpin); - - assert_impl!(RemoteHandle<()>: Send); - assert_not_impl!(RemoteHandle<*const ()>: Send); - assert_impl!(RemoteHandle<()>: Sync); - assert_not_impl!(RemoteHandle<*const ()>: Sync); - assert_impl!(RemoteHandle: Unpin); - - assert_impl!(Select: Send); - assert_not_impl!(Select: Send); - assert_not_impl!(Select: Send); - assert_impl!(Select: Sync); - assert_not_impl!(Select: Sync); - assert_not_impl!(Select: Sync); - assert_impl!(Select: Unpin); - assert_not_impl!(Select: Unpin); - assert_not_impl!(Select: Unpin); - - assert_impl!(SelectAll: Send); - assert_not_impl!(SelectAll: Send); - assert_impl!(SelectAll: Sync); - assert_not_impl!(SelectAll: Sync); - assert_impl!(SelectAll: Unpin); - assert_not_impl!(SelectAll: Unpin); - - assert_impl!(SelectOk: Send); - assert_not_impl!(SelectOk: Send); - assert_impl!(SelectOk: Sync); - assert_not_impl!(SelectOk: Sync); - assert_impl!(SelectOk: Unpin); - assert_not_impl!(SelectOk: Unpin); - - assert_impl!(Shared>: Send); - assert_not_impl!(Shared: Send); - assert_not_impl!(Shared: Send); - assert_not_impl!(Shared>: Sync); - assert_impl!(Shared: Unpin); - - assert_impl!(Then: Send); - assert_not_impl!(Then: Send); - assert_not_impl!(Then: Send); - assert_not_impl!(Then: Send); - assert_impl!(Then: Sync); - assert_not_impl!(Then: Sync); - assert_not_impl!(Then: Sync); - assert_not_impl!(Then: Sync); - assert_impl!(Then: Unpin); - assert_not_impl!(Then: Unpin); - assert_not_impl!(Then: Unpin); - - assert_impl!(TryFlatten, ()>: Send); - assert_not_impl!(TryFlatten: Send); - assert_not_impl!(TryFlatten: Send); - assert_impl!(TryFlatten, ()>: Sync); - assert_not_impl!(TryFlatten: Sync); - assert_not_impl!(TryFlatten: Sync); - assert_impl!(TryFlatten, ()>: Unpin); - assert_not_impl!(TryFlatten: Unpin); - assert_not_impl!(TryFlatten: Unpin); - - assert_impl!(TryFlattenStream>: Send); - assert_not_impl!(TryFlattenStream: Send); - assert_not_impl!(TryFlattenStream: Send); - assert_impl!(TryFlattenStream>: Sync); - assert_not_impl!(TryFlattenStream: Sync); - assert_not_impl!(TryFlattenStream: Sync); - assert_impl!(TryFlattenStream>: Unpin); - assert_not_impl!(TryFlattenStream: Unpin); - assert_not_impl!(TryFlattenStream: Unpin); - - assert_impl!(TryJoin, SendTryFuture<()>>: Send); - assert_not_impl!(TryJoin, SendTryFuture>: Send); - assert_not_impl!(TryJoin>: Send); - assert_not_impl!(TryJoin: Send); - assert_not_impl!(TryJoin: Send); - assert_impl!(TryJoin, SyncTryFuture<()>>: Sync); - assert_not_impl!(TryJoin, SyncTryFuture>: Sync); - assert_not_impl!(TryJoin>: Sync); - assert_not_impl!(TryJoin: Sync); - assert_not_impl!(TryJoin: Sync); - assert_impl!(TryJoin: Unpin); - assert_not_impl!(TryJoin: Unpin); - assert_not_impl!(TryJoin: Unpin); - - // TryJoin3, TryJoin4, TryJoin5 are the same as TryJoin - - assert_impl!(TryJoinAll>: Send); - assert_not_impl!(TryJoinAll: Send); - assert_not_impl!(TryJoinAll: Send); - assert_impl!(TryJoinAll>: Sync); - assert_not_impl!(TryJoinAll>: Sync); - assert_not_impl!(TryJoinAll>: Sync); - assert_not_impl!(TryJoinAll: Sync); - assert_impl!(TryJoinAll: Unpin); - - assert_impl!(TrySelect: Send); - assert_not_impl!(TrySelect: Send); - assert_not_impl!(TrySelect: Send); - assert_impl!(TrySelect: Sync); - assert_not_impl!(TrySelect: Sync); - assert_not_impl!(TrySelect: Sync); - assert_impl!(TrySelect: Unpin); - assert_not_impl!(TrySelect: Unpin); - assert_not_impl!(TrySelect: Unpin); - - assert_impl!(UnitError: Send); - assert_not_impl!(UnitError: Send); - assert_impl!(UnitError: Sync); - assert_not_impl!(UnitError: Sync); - assert_impl!(UnitError: Unpin); - assert_not_impl!(UnitError: Unpin); - - assert_impl!(UnwrapOrElse: Send); - assert_not_impl!(UnwrapOrElse: Send); - assert_not_impl!(UnwrapOrElse: Send); - assert_impl!(UnwrapOrElse: Sync); - assert_not_impl!(UnwrapOrElse: Sync); - assert_not_impl!(UnwrapOrElse: Sync); - assert_impl!(UnwrapOrElse: Unpin); - assert_not_impl!(UnwrapOrElse: Unpin); - - assert_impl!(WeakShared>: Send); - assert_not_impl!(WeakShared: Send); - assert_not_impl!(WeakShared: Send); - assert_not_impl!(WeakShared>: Sync); - assert_impl!(WeakShared: Unpin); - - assert_impl!(Either: Send); - assert_not_impl!(Either: Send); - assert_not_impl!(Either: Send); - assert_impl!(Either: Sync); - assert_not_impl!(Either: Sync); - assert_not_impl!(Either: Sync); - assert_impl!(Either: Unpin); - assert_not_impl!(Either: Unpin); - assert_not_impl!(Either: Unpin); - - assert_impl!(MaybeDone>: Send); - assert_not_impl!(MaybeDone: Send); - assert_not_impl!(MaybeDone: Send); - assert_impl!(MaybeDone>: Sync); - assert_not_impl!(MaybeDone: Sync); - assert_not_impl!(MaybeDone: Sync); - assert_impl!(MaybeDone: Unpin); - assert_not_impl!(MaybeDone: Unpin); - - assert_impl!(TryMaybeDone>: Send); - assert_not_impl!(TryMaybeDone: Send); - assert_not_impl!(TryMaybeDone: Send); - assert_impl!(TryMaybeDone>: Sync); - assert_not_impl!(TryMaybeDone: Sync); - assert_not_impl!(TryMaybeDone: Sync); - assert_impl!(TryMaybeDone: Unpin); - assert_not_impl!(TryMaybeDone: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::io`. -mod io { - use super::*; - use futures::io::{Sink, *}; - - assert_impl!(AllowStdIo<()>: Send); - assert_not_impl!(AllowStdIo<*const ()>: Send); - assert_impl!(AllowStdIo<()>: Sync); - assert_not_impl!(AllowStdIo<*const ()>: Sync); - assert_impl!(AllowStdIo: Unpin); - - assert_impl!(BufReader<()>: Send); - assert_not_impl!(BufReader<*const ()>: Send); - assert_impl!(BufReader<()>: Sync); - assert_not_impl!(BufReader<*const ()>: Sync); - assert_impl!(BufReader<()>: Unpin); - assert_not_impl!(BufReader: Unpin); - - assert_impl!(BufWriter<()>: Send); - assert_not_impl!(BufWriter<*const ()>: Send); - assert_impl!(BufWriter<()>: Sync); - assert_not_impl!(BufWriter<*const ()>: Sync); - assert_impl!(BufWriter<()>: Unpin); - assert_not_impl!(BufWriter: Unpin); - - assert_impl!(Chain<(), ()>: Send); - assert_not_impl!(Chain<(), *const ()>: Send); - assert_not_impl!(Chain<*const (), ()>: Send); - assert_impl!(Chain<(), ()>: Sync); - assert_not_impl!(Chain<(), *const ()>: Sync); - assert_not_impl!(Chain<*const (), ()>: Sync); - assert_impl!(Chain<(), ()>: Unpin); - assert_not_impl!(Chain<(), PhantomPinned>: Unpin); - assert_not_impl!(Chain: Unpin); - - assert_impl!(Close<'_, ()>: Send); - assert_not_impl!(Close<'_, *const ()>: Send); - assert_impl!(Close<'_, ()>: Sync); - assert_not_impl!(Close<'_, *const ()>: Sync); - assert_impl!(Close<'_, ()>: Unpin); - assert_not_impl!(Close<'_, PhantomPinned>: Unpin); - - assert_impl!(Copy<'_, (), ()>: Send); - assert_not_impl!(Copy<'_, (), *const ()>: Send); - assert_not_impl!(Copy<'_, *const (), ()>: Send); - assert_impl!(Copy<'_, (), ()>: Sync); - assert_not_impl!(Copy<'_, (), *const ()>: Sync); - assert_not_impl!(Copy<'_, *const (), ()>: Sync); - assert_impl!(Copy<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(Copy<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(CopyBuf<'_, (), ()>: Send); - assert_not_impl!(CopyBuf<'_, (), *const ()>: Send); - assert_not_impl!(CopyBuf<'_, *const (), ()>: Send); - assert_impl!(CopyBuf<'_, (), ()>: Sync); - assert_not_impl!(CopyBuf<'_, (), *const ()>: Sync); - assert_not_impl!(CopyBuf<'_, *const (), ()>: Sync); - assert_impl!(CopyBuf<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(CopyBuf<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(Cursor<()>: Send); - assert_not_impl!(Cursor<*const ()>: Send); - assert_impl!(Cursor<()>: Sync); - assert_not_impl!(Cursor<*const ()>: Sync); - assert_impl!(Cursor<()>: Unpin); - assert_not_impl!(Cursor: Unpin); - - assert_impl!(Empty: Send); - assert_impl!(Empty: Sync); - assert_impl!(Empty: Unpin); - - assert_impl!(FillBuf<'_, ()>: Send); - assert_not_impl!(FillBuf<'_, *const ()>: Send); - assert_impl!(FillBuf<'_, ()>: Sync); - assert_not_impl!(FillBuf<'_, *const ()>: Sync); - assert_impl!(FillBuf<'_, PhantomPinned>: Unpin); - - assert_impl!(Flush<'_, ()>: Send); - assert_not_impl!(Flush<'_, *const ()>: Send); - assert_impl!(Flush<'_, ()>: Sync); - assert_not_impl!(Flush<'_, *const ()>: Sync); - assert_impl!(Flush<'_, ()>: Unpin); - assert_not_impl!(Flush<'_, PhantomPinned>: Unpin); - - assert_impl!(IntoSink<(), ()>: Send); - assert_not_impl!(IntoSink<(), *const ()>: Send); - assert_not_impl!(IntoSink<*const (), ()>: Send); - assert_impl!(IntoSink<(), ()>: Sync); - assert_not_impl!(IntoSink<(), *const ()>: Sync); - assert_not_impl!(IntoSink<*const (), ()>: Sync); - assert_impl!(IntoSink<(), PhantomPinned>: Unpin); - assert_not_impl!(IntoSink: Unpin); - - assert_impl!(Lines<()>: Send); - assert_not_impl!(Lines<*const ()>: Send); - assert_impl!(Lines<()>: Sync); - assert_not_impl!(Lines<*const ()>: Sync); - assert_impl!(Lines<()>: Unpin); - assert_not_impl!(Lines: Unpin); - - assert_impl!(Read<'_, ()>: Send); - assert_not_impl!(Read<'_, *const ()>: Send); - assert_impl!(Read<'_, ()>: Sync); - assert_not_impl!(Read<'_, *const ()>: Sync); - assert_impl!(Read<'_, ()>: Unpin); - assert_not_impl!(Read<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadExact<'_, ()>: Send); - assert_not_impl!(ReadExact<'_, *const ()>: Send); - assert_impl!(ReadExact<'_, ()>: Sync); - assert_not_impl!(ReadExact<'_, *const ()>: Sync); - assert_impl!(ReadExact<'_, ()>: Unpin); - assert_not_impl!(ReadExact<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadHalf<()>: Send); - assert_not_impl!(ReadHalf<*const ()>: Send); - assert_impl!(ReadHalf<()>: Sync); - assert_not_impl!(ReadHalf<*const ()>: Sync); - assert_impl!(ReadHalf: Unpin); - - assert_impl!(ReadLine<'_, ()>: Send); - assert_not_impl!(ReadLine<'_, *const ()>: Send); - assert_impl!(ReadLine<'_, ()>: Sync); - assert_not_impl!(ReadLine<'_, *const ()>: Sync); - assert_impl!(ReadLine<'_, ()>: Unpin); - assert_not_impl!(ReadLine<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadToEnd<'_, ()>: Send); - assert_not_impl!(ReadToEnd<'_, *const ()>: Send); - assert_impl!(ReadToEnd<'_, ()>: Sync); - assert_not_impl!(ReadToEnd<'_, *const ()>: Sync); - assert_impl!(ReadToEnd<'_, ()>: Unpin); - assert_not_impl!(ReadToEnd<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadToString<'_, ()>: Send); - assert_not_impl!(ReadToString<'_, *const ()>: Send); - assert_impl!(ReadToString<'_, ()>: Sync); - assert_not_impl!(ReadToString<'_, *const ()>: Sync); - assert_impl!(ReadToString<'_, ()>: Unpin); - assert_not_impl!(ReadToString<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadUntil<'_, ()>: Send); - assert_not_impl!(ReadUntil<'_, *const ()>: Send); - assert_impl!(ReadUntil<'_, ()>: Sync); - assert_not_impl!(ReadUntil<'_, *const ()>: Sync); - assert_impl!(ReadUntil<'_, ()>: Unpin); - assert_not_impl!(ReadUntil<'_, PhantomPinned>: Unpin); - - assert_impl!(ReadVectored<'_, '_, ()>: Send); - assert_not_impl!(ReadVectored<'_, '_, *const ()>: Send); - assert_impl!(ReadVectored<'_, '_, ()>: Sync); - assert_not_impl!(ReadVectored<'_, '_, *const ()>: Sync); - assert_impl!(ReadVectored<'_, '_, ()>: Unpin); - assert_not_impl!(ReadVectored<'_, '_, PhantomPinned>: Unpin); - - assert_impl!(Repeat: Send); - assert_impl!(Repeat: Sync); - assert_impl!(Repeat: Unpin); - - assert_impl!(ReuniteError<()>: Send); - assert_not_impl!(ReuniteError<*const ()>: Send); - assert_impl!(ReuniteError<()>: Sync); - assert_not_impl!(ReuniteError<*const ()>: Sync); - assert_impl!(ReuniteError: Unpin); - - assert_impl!(Seek<'_, ()>: Send); - assert_not_impl!(Seek<'_, *const ()>: Send); - assert_impl!(Seek<'_, ()>: Sync); - assert_not_impl!(Seek<'_, *const ()>: Sync); - assert_impl!(Seek<'_, ()>: Unpin); - assert_not_impl!(Seek<'_, PhantomPinned>: Unpin); - - assert_impl!(SeekRelative<'_, ()>: Send); - assert_not_impl!(SeekRelative<'_, *const ()>: Send); - assert_impl!(SeekRelative<'_, ()>: Sync); - assert_not_impl!(SeekRelative<'_, *const ()>: Sync); - assert_impl!(SeekRelative<'_, PhantomPinned>: Unpin); - - assert_impl!(Sink: Send); - assert_impl!(Sink: Sync); - assert_impl!(Sink: Unpin); - - assert_impl!(Take<()>: Send); - assert_not_impl!(Take<*const ()>: Send); - assert_impl!(Take<()>: Sync); - assert_not_impl!(Take<*const ()>: Sync); - assert_impl!(Take<()>: Unpin); - assert_not_impl!(Take: Unpin); - - assert_impl!(Window<()>: Send); - assert_not_impl!(Window<*const ()>: Send); - assert_impl!(Window<()>: Sync); - assert_not_impl!(Window<*const ()>: Sync); - assert_impl!(Window<()>: Unpin); - assert_not_impl!(Window: Unpin); - - assert_impl!(Write<'_, ()>: Send); - assert_not_impl!(Write<'_, *const ()>: Send); - assert_impl!(Write<'_, ()>: Sync); - assert_not_impl!(Write<'_, *const ()>: Sync); - assert_impl!(Write<'_, ()>: Unpin); - assert_not_impl!(Write<'_, PhantomPinned>: Unpin); - - assert_impl!(WriteAll<'_, ()>: Send); - assert_not_impl!(WriteAll<'_, *const ()>: Send); - assert_impl!(WriteAll<'_, ()>: Sync); - assert_not_impl!(WriteAll<'_, *const ()>: Sync); - assert_impl!(WriteAll<'_, ()>: Unpin); - assert_not_impl!(WriteAll<'_, PhantomPinned>: Unpin); - - #[cfg(feature = "write-all-vectored")] - assert_impl!(WriteAllVectored<'_, '_, ()>: Send); - #[cfg(feature = "write-all-vectored")] - assert_not_impl!(WriteAllVectored<'_, '_, *const ()>: Send); - #[cfg(feature = "write-all-vectored")] - assert_impl!(WriteAllVectored<'_, '_, ()>: Sync); - #[cfg(feature = "write-all-vectored")] - assert_not_impl!(WriteAllVectored<'_, '_, *const ()>: Sync); - #[cfg(feature = "write-all-vectored")] - assert_impl!(WriteAllVectored<'_, '_, ()>: Unpin); - // WriteAllVectored requires `W: Unpin` - // #[cfg(feature = "write-all-vectored")] - // assert_not_impl!(WriteAllVectored<'_, PhantomPinned>: Unpin); - - assert_impl!(WriteHalf<()>: Send); - assert_not_impl!(WriteHalf<*const ()>: Send); - assert_impl!(WriteHalf<()>: Sync); - assert_not_impl!(WriteHalf<*const ()>: Sync); - assert_impl!(WriteHalf: Unpin); - - assert_impl!(WriteVectored<'_, '_, ()>: Send); - assert_not_impl!(WriteVectored<'_, '_, *const ()>: Send); - assert_impl!(WriteVectored<'_, '_, ()>: Sync); - assert_not_impl!(WriteVectored<'_, '_, *const ()>: Sync); - assert_impl!(WriteVectored<'_, '_, ()>: Unpin); - assert_not_impl!(WriteVectored<'_, '_, PhantomPinned>: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::lock`. -mod lock { - use super::*; - use futures::lock::*; - - #[cfg(feature = "bilock")] - assert_impl!(BiLock<()>: Send); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLock<*const ()>: Send); - #[cfg(feature = "bilock")] - assert_impl!(BiLock<()>: Sync); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLock<*const ()>: Sync); - #[cfg(feature = "bilock")] - assert_impl!(BiLock: Unpin); - - #[cfg(feature = "bilock")] - assert_impl!(BiLockAcquire<'_, ()>: Send); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLockAcquire<'_, *const ()>: Send); - #[cfg(feature = "bilock")] - assert_impl!(BiLockAcquire<'_, ()>: Sync); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLockAcquire<'_, *const ()>: Sync); - #[cfg(feature = "bilock")] - assert_impl!(BiLockAcquire<'_, PhantomPinned>: Unpin); - - #[cfg(feature = "bilock")] - assert_impl!(BiLockGuard<'_, ()>: Send); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLockGuard<'_, *const ()>: Send); - #[cfg(feature = "bilock")] - assert_impl!(BiLockGuard<'_, ()>: Sync); - #[cfg(feature = "bilock")] - assert_not_impl!(BiLockGuard<'_, *const ()>: Sync); - #[cfg(feature = "bilock")] - assert_impl!(BiLockGuard<'_, PhantomPinned>: Unpin); - - assert_impl!(MappedMutexGuard<'_, (), ()>: Send); - assert_not_impl!(MappedMutexGuard<'_, (), *const ()>: Send); - assert_not_impl!(MappedMutexGuard<'_, *const (), ()>: Send); - assert_impl!(MappedMutexGuard<'_, (), ()>: Sync); - assert_not_impl!(MappedMutexGuard<'_, (), *const ()>: Sync); - assert_not_impl!(MappedMutexGuard<'_, *const (), ()>: Sync); - assert_impl!(MappedMutexGuard<'_, PhantomPinned, PhantomPinned>: Unpin); - - assert_impl!(Mutex<()>: Send); - assert_not_impl!(Mutex<*const ()>: Send); - assert_impl!(Mutex<()>: Sync); - assert_not_impl!(Mutex<*const ()>: Sync); - assert_impl!(Mutex<()>: Unpin); - assert_not_impl!(Mutex: Unpin); - - assert_impl!(MutexGuard<'_, ()>: Send); - assert_not_impl!(MutexGuard<'_, *const ()>: Send); - assert_impl!(MutexGuard<'_, ()>: Sync); - assert_not_impl!(MutexGuard<'_, *const ()>: Sync); - assert_impl!(MutexGuard<'_, PhantomPinned>: Unpin); - - assert_impl!(MutexLockFuture<'_, ()>: Send); - assert_not_impl!(MutexLockFuture<'_, *const ()>: Send); - assert_impl!(MutexLockFuture<'_, *const ()>: Sync); - assert_impl!(MutexLockFuture<'_, PhantomPinned>: Unpin); - - #[cfg(feature = "bilock")] - assert_impl!(ReuniteError<()>: Send); - #[cfg(feature = "bilock")] - assert_not_impl!(ReuniteError<*const ()>: Send); - #[cfg(feature = "bilock")] - assert_impl!(ReuniteError<()>: Sync); - #[cfg(feature = "bilock")] - assert_not_impl!(ReuniteError<*const ()>: Sync); - #[cfg(feature = "bilock")] - assert_impl!(ReuniteError: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::sink`. -mod sink { - use super::*; - use futures::sink::{self, *}; - use std::marker::Send; - - assert_impl!(Buffer<(), ()>: Send); - assert_not_impl!(Buffer<(), *const ()>: Send); - assert_not_impl!(Buffer<*const (), ()>: Send); - assert_impl!(Buffer<(), ()>: Sync); - assert_not_impl!(Buffer<(), *const ()>: Sync); - assert_not_impl!(Buffer<*const (), ()>: Sync); - assert_impl!(Buffer<(), PhantomPinned>: Unpin); - assert_not_impl!(Buffer: Unpin); - - assert_impl!(Close<'_, (), *const ()>: Send); - assert_not_impl!(Close<'_, *const (), ()>: Send); - assert_impl!(Close<'_, (), *const ()>: Sync); - assert_not_impl!(Close<'_, *const (), ()>: Sync); - assert_impl!(Close<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(Close<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(Drain<()>: Send); - assert_not_impl!(Drain<*const ()>: Send); - assert_impl!(Drain<()>: Sync); - assert_not_impl!(Drain<*const ()>: Sync); - assert_impl!(Drain: Unpin); - - assert_impl!(Fanout<(), ()>: Send); - assert_not_impl!(Fanout<(), *const ()>: Send); - assert_not_impl!(Fanout<*const (), ()>: Send); - assert_impl!(Fanout<(), ()>: Sync); - assert_not_impl!(Fanout<(), *const ()>: Sync); - assert_not_impl!(Fanout<*const (), ()>: Sync); - assert_impl!(Fanout<(), ()>: Unpin); - assert_not_impl!(Fanout<(), PhantomPinned>: Unpin); - assert_not_impl!(Fanout: Unpin); - - assert_impl!(Feed<'_, (), ()>: Send); - assert_not_impl!(Feed<'_, (), *const ()>: Send); - assert_not_impl!(Feed<'_, *const (), ()>: Send); - assert_impl!(Feed<'_, (), ()>: Sync); - assert_not_impl!(Feed<'_, (), *const ()>: Sync); - assert_not_impl!(Feed<'_, *const (), ()>: Sync); - assert_impl!(Feed<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(Feed<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(Flush<'_, (), *const ()>: Send); - assert_not_impl!(Flush<'_, *const (), ()>: Send); - assert_impl!(Flush<'_, (), *const ()>: Sync); - assert_not_impl!(Flush<'_, *const (), ()>: Sync); - assert_impl!(Flush<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(Flush<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(sink::Send<'_, (), ()>: Send); - assert_not_impl!(sink::Send<'_, (), *const ()>: Send); - assert_not_impl!(sink::Send<'_, *const (), ()>: Send); - assert_impl!(sink::Send<'_, (), ()>: Sync); - assert_not_impl!(sink::Send<'_, (), *const ()>: Sync); - assert_not_impl!(sink::Send<'_, *const (), ()>: Sync); - assert_impl!(sink::Send<'_, (), PhantomPinned>: Unpin); - assert_not_impl!(sink::Send<'_, PhantomPinned, ()>: Unpin); - - assert_impl!(SendAll<'_, (), SendTryStream<()>>: Send); - assert_not_impl!(SendAll<'_, (), SendTryStream>: Send); - assert_not_impl!(SendAll<'_, (), LocalTryStream>: Send); - assert_not_impl!(SendAll<'_, *const (), SendTryStream<()>>: Send); - assert_impl!(SendAll<'_, (), SyncTryStream<()>>: Sync); - assert_not_impl!(SendAll<'_, (), SyncTryStream>: Sync); - assert_not_impl!(SendAll<'_, (), LocalTryStream>: Sync); - assert_not_impl!(SendAll<'_, *const (), SyncTryStream<()>>: Sync); - assert_impl!(SendAll<'_, (), UnpinTryStream>: Unpin); - assert_impl!(SendAll<'_, PhantomPinned, UnpinTryStream>: Unpin); - assert_not_impl!(SendAll<'_, (), PinnedTryStream>: Unpin); - - assert_impl!(SinkErrInto: Send); - assert_not_impl!(SinkErrInto, (), ()>: Send); - assert_impl!(SinkErrInto: Sync); - assert_not_impl!(SinkErrInto, (), ()>: Sync); - assert_impl!(SinkErrInto: Unpin); - assert_not_impl!(SinkErrInto, (), ()>: Unpin); - - assert_impl!(SinkMapErr: Send); - assert_not_impl!(SinkMapErr: Send); - assert_not_impl!(SinkMapErr, ()>: Send); - assert_impl!(SinkMapErr: Sync); - assert_not_impl!(SinkMapErr: Sync); - assert_not_impl!(SinkMapErr, ()>: Sync); - assert_impl!(SinkMapErr: Unpin); - assert_not_impl!(SinkMapErr, ()>: Unpin); - - assert_impl!(Unfold<(), (), ()>: Send); - assert_not_impl!(Unfold<*const (), (), ()>: Send); - assert_not_impl!(Unfold<(), *const (), ()>: Send); - assert_not_impl!(Unfold<(), (), *const ()>: Send); - assert_impl!(Unfold<(), (), ()>: Sync); - assert_not_impl!(Unfold<*const (), (), ()>: Sync); - assert_not_impl!(Unfold<(), *const (), ()>: Sync); - assert_not_impl!(Unfold<(), (), *const ()>: Sync); - assert_impl!(Unfold: Unpin); - assert_not_impl!(Unfold, (), PhantomPinned>: Unpin); - - assert_impl!(With<(), *const (), *const (), (), ()>: Send); - assert_not_impl!(With<*const (), (), (), (), ()>: Send); - assert_not_impl!(With<(), (), (), *const (), ()>: Send); - assert_not_impl!(With<(), (), (), (), *const ()>: Send); - assert_impl!(With<(), *const (), *const (), (), ()>: Sync); - assert_not_impl!(With<*const (), (), (), (), ()>: Sync); - assert_not_impl!(With<(), (), (), *const (), ()>: Sync); - assert_not_impl!(With<(), (), (), (), *const ()>: Sync); - assert_impl!(With<(), PhantomPinned, PhantomPinned, (), PhantomPinned>: Unpin); - assert_not_impl!(With: Unpin); - assert_not_impl!(With<(), (), (), PhantomPinned, ()>: Unpin); - - assert_impl!(WithFlatMap<(), (), *const (), (), ()>: Send); - assert_not_impl!(WithFlatMap<*const (), (), (), (), ()>: Send); - assert_not_impl!(WithFlatMap<(), *const (), (), (), ()>: Send); - assert_not_impl!(WithFlatMap<(), (), (), *const (), ()>: Send); - assert_not_impl!(WithFlatMap<(), (), (), (), *const ()>: Send); - assert_impl!(WithFlatMap<(), (), *const (), (), ()>: Sync); - assert_not_impl!(WithFlatMap<*const (), (), (), (), ()>: Sync); - assert_not_impl!(WithFlatMap<(), *const (), (), (), ()>: Sync); - assert_not_impl!(WithFlatMap<(), (), (), *const (), ()>: Sync); - assert_not_impl!(WithFlatMap<(), (), (), (), *const ()>: Sync); - assert_impl!(WithFlatMap<(), PhantomPinned, PhantomPinned, (), PhantomPinned>: Unpin); - assert_not_impl!(WithFlatMap: Unpin); - assert_not_impl!(WithFlatMap<(), (), (), PhantomPinned, ()>: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::stream`. -mod stream { - use super::*; - use futures::{io, stream::*}; - - assert_impl!(AndThen<(), (), ()>: Send); - assert_not_impl!(AndThen<*const (), (), ()>: Send); - assert_not_impl!(AndThen<(), *const (), ()>: Send); - assert_not_impl!(AndThen<(), (), *const ()>: Send); - assert_impl!(AndThen<(), (), ()>: Sync); - assert_not_impl!(AndThen<*const (), (), ()>: Sync); - assert_not_impl!(AndThen<(), *const (), ()>: Sync); - assert_not_impl!(AndThen<(), (), *const ()>: Sync); - assert_impl!(AndThen<(), (), PhantomPinned>: Unpin); - assert_not_impl!(AndThen: Unpin); - assert_not_impl!(AndThen<(), PhantomPinned, ()>: Unpin); - - assert_impl!(BufferUnordered>: Send); - assert_not_impl!(BufferUnordered: Send); - assert_not_impl!(BufferUnordered: Send); - assert_impl!(BufferUnordered>: Sync); - assert_not_impl!(BufferUnordered: Sync); - assert_not_impl!(BufferUnordered: Sync); - assert_impl!(BufferUnordered: Unpin); - assert_not_impl!(BufferUnordered: Unpin); - - assert_impl!(Buffered>>: Send); - assert_not_impl!(Buffered>: Send); - assert_not_impl!(Buffered>: Send); - assert_not_impl!(Buffered>>: Send); - assert_impl!(Buffered>>: Sync); - assert_not_impl!(Buffered>>: Sync); - assert_not_impl!(Buffered>>: Sync); - assert_impl!(Buffered>: Unpin); - assert_not_impl!(Buffered>: Unpin); - - assert_impl!(CatchUnwind: Send); - assert_not_impl!(CatchUnwind: Send); - assert_impl!(CatchUnwind: Sync); - assert_not_impl!(CatchUnwind: Sync); - assert_impl!(CatchUnwind: Unpin); - assert_not_impl!(CatchUnwind: Unpin); - - assert_impl!(Chain<(), ()>: Send); - assert_not_impl!(Chain<(), *const ()>: Send); - assert_not_impl!(Chain<*const (), ()>: Send); - assert_impl!(Chain<(), ()>: Sync); - assert_not_impl!(Chain<(), *const ()>: Sync); - assert_not_impl!(Chain<*const (), ()>: Sync); - assert_impl!(Chain<(), ()>: Unpin); - assert_not_impl!(Chain<(), PhantomPinned>: Unpin); - assert_not_impl!(Chain: Unpin); - - assert_impl!(Chunks>: Send); - assert_not_impl!(Chunks: Send); - assert_not_impl!(Chunks: Send); - assert_impl!(Chunks>: Sync); - assert_not_impl!(Chunks: Sync); - assert_not_impl!(Chunks: Sync); - assert_impl!(Chunks: Unpin); - assert_not_impl!(Chunks: Unpin); - - assert_impl!(Collect<(), ()>: Send); - assert_not_impl!(Collect<*const (), ()>: Send); - assert_not_impl!(Collect<(), *const ()>: Send); - assert_impl!(Collect<(), ()>: Sync); - assert_not_impl!(Collect<*const (), ()>: Sync); - assert_not_impl!(Collect<(), *const ()>: Sync); - assert_impl!(Collect<(), PhantomPinned>: Unpin); - assert_not_impl!(Collect: Unpin); - - assert_impl!(Concat>: Send); - assert_not_impl!(Concat: Send); - assert_not_impl!(Concat: Send); - assert_impl!(Concat>: Sync); - assert_not_impl!(Concat: Sync); - assert_not_impl!(Concat: Sync); - assert_impl!(Concat: Unpin); - assert_not_impl!(Concat: Unpin); - - assert_impl!(Cycle<()>: Send); - assert_not_impl!(Cycle<*const ()>: Send); - assert_impl!(Cycle<()>: Sync); - assert_not_impl!(Cycle<*const ()>: Sync); - assert_impl!(Cycle<()>: Unpin); - assert_not_impl!(Cycle: Unpin); - - assert_impl!(Empty<()>: Send); - assert_not_impl!(Empty<*const ()>: Send); - assert_impl!(Empty<()>: Sync); - assert_not_impl!(Empty<*const ()>: Sync); - assert_impl!(Empty: Unpin); - - assert_impl!(Enumerate<()>: Send); - assert_not_impl!(Enumerate<*const ()>: Send); - assert_impl!(Enumerate<()>: Sync); - assert_not_impl!(Enumerate<*const ()>: Sync); - assert_impl!(Enumerate<()>: Unpin); - assert_not_impl!(Enumerate: Unpin); - - assert_impl!(ErrInto<(), *const ()>: Send); - assert_not_impl!(ErrInto<*const (), ()>: Send); - assert_impl!(ErrInto<(), *const ()>: Sync); - assert_not_impl!(ErrInto<*const (), ()>: Sync); - assert_impl!(ErrInto<(), PhantomPinned>: Unpin); - assert_not_impl!(ErrInto: Unpin); - - assert_impl!(Filter, (), ()>: Send); - assert_not_impl!(Filter, (), ()>: Send); - assert_not_impl!(Filter: Send); - assert_not_impl!(Filter, *const (), ()>: Send); - assert_not_impl!(Filter, (), *const ()>: Send); - assert_impl!(Filter, (), ()>: Sync); - assert_not_impl!(Filter, (), ()>: Sync); - assert_not_impl!(Filter: Sync); - assert_not_impl!(Filter, *const (), ()>: Sync); - assert_not_impl!(Filter, (), *const ()>: Sync); - assert_impl!(Filter: Unpin); - assert_not_impl!(Filter: Unpin); - assert_not_impl!(Filter: Unpin); - - assert_impl!(FilterMap<(), (), ()>: Send); - assert_not_impl!(FilterMap<*const (), (), ()>: Send); - assert_not_impl!(FilterMap<(), *const (), ()>: Send); - assert_not_impl!(FilterMap<(), (), *const ()>: Send); - assert_impl!(FilterMap<(), (), ()>: Sync); - assert_not_impl!(FilterMap<*const (), (), ()>: Sync); - assert_not_impl!(FilterMap<(), *const (), ()>: Sync); - assert_not_impl!(FilterMap<(), (), *const ()>: Sync); - assert_impl!(FilterMap<(), (), PhantomPinned>: Unpin); - assert_not_impl!(FilterMap: Unpin); - assert_not_impl!(FilterMap<(), PhantomPinned, ()>: Unpin); - - assert_impl!(FlatMap<(), (), ()>: Send); - assert_not_impl!(FlatMap<*const (), (), ()>: Send); - assert_not_impl!(FlatMap<(), *const (), ()>: Send); - assert_not_impl!(FlatMap<(), (), *const ()>: Send); - assert_impl!(FlatMap<(), (), ()>: Sync); - assert_not_impl!(FlatMap<*const (), (), ()>: Sync); - assert_not_impl!(FlatMap<(), *const (), ()>: Sync); - assert_not_impl!(FlatMap<(), (), *const ()>: Sync); - assert_impl!(FlatMap<(), (), PhantomPinned>: Unpin); - assert_not_impl!(FlatMap: Unpin); - assert_not_impl!(FlatMap<(), PhantomPinned, ()>: Unpin); - - assert_impl!(Flatten>: Send); - assert_not_impl!(Flatten: Send); - assert_not_impl!(Flatten: Send); - assert_impl!(Flatten>: Sync); - assert_not_impl!(Flatten>: Sync); - assert_not_impl!(Flatten>: Sync); - assert_impl!(Flatten>: Unpin); - assert_not_impl!(Flatten: Unpin); - assert_not_impl!(Flatten: Unpin); - - assert_impl!(Fold<(), (), (), ()>: Send); - assert_not_impl!(Fold<*const (), (), (), ()>: Send); - assert_not_impl!(Fold<(), *const (), (), ()>: Send); - assert_not_impl!(Fold<(), (), *const (), ()>: Send); - assert_not_impl!(Fold<(), (), (), *const ()>: Send); - assert_impl!(Fold<(), (), (), ()>: Sync); - assert_not_impl!(Fold<*const (), (), (), ()>: Sync); - assert_not_impl!(Fold<(), *const (), (), ()>: Sync); - assert_not_impl!(Fold<(), (), *const (), ()>: Sync); - assert_not_impl!(Fold<(), (), (), *const ()>: Sync); - assert_impl!(Fold<(), (), PhantomPinned, PhantomPinned>: Unpin); - assert_not_impl!(Fold: Unpin); - assert_not_impl!(Fold<(), PhantomPinned, (), ()>: Unpin); - - assert_impl!(ForEach<(), (), ()>: Send); - assert_not_impl!(ForEach<*const (), (), ()>: Send); - assert_not_impl!(ForEach<(), *const (), ()>: Send); - assert_not_impl!(ForEach<(), (), *const ()>: Send); - assert_impl!(ForEach<(), (), ()>: Sync); - assert_not_impl!(ForEach<*const (), (), ()>: Sync); - assert_not_impl!(ForEach<(), *const (), ()>: Sync); - assert_not_impl!(ForEach<(), (), *const ()>: Sync); - assert_impl!(ForEach<(), (), PhantomPinned>: Unpin); - assert_not_impl!(ForEach: Unpin); - assert_not_impl!(ForEach<(), PhantomPinned, ()>: Unpin); - - assert_impl!(ForEachConcurrent<(), (), ()>: Send); - assert_not_impl!(ForEachConcurrent<*const (), (), ()>: Send); - assert_not_impl!(ForEachConcurrent<(), *const (), ()>: Send); - assert_not_impl!(ForEachConcurrent<(), (), *const ()>: Send); - assert_impl!(ForEachConcurrent<(), (), ()>: Sync); - assert_not_impl!(ForEachConcurrent<*const (), (), ()>: Sync); - assert_not_impl!(ForEachConcurrent<(), *const (), ()>: Sync); - assert_not_impl!(ForEachConcurrent<(), (), *const ()>: Sync); - assert_impl!(ForEachConcurrent<(), PhantomPinned, PhantomPinned>: Unpin); - assert_not_impl!(ForEachConcurrent: Unpin); - - assert_impl!(Forward, ()>: Send); - assert_not_impl!(Forward: Send); - assert_not_impl!(Forward, *const ()>: Send); - assert_not_impl!(Forward: Send); - assert_impl!(Forward, ()>: Sync); - assert_not_impl!(Forward: Sync); - assert_not_impl!(Forward, *const ()>: Sync); - assert_not_impl!(Forward: Sync); - assert_impl!(Forward: Unpin); - assert_not_impl!(Forward: Unpin); - assert_not_impl!(Forward: Unpin); - - assert_impl!(TryForward, ()>: Send); - assert_not_impl!(TryForward: Send); - assert_not_impl!(TryForward, *const ()>: Send); - assert_not_impl!(TryForward: Send); - assert_impl!(TryForward, ()>: Sync); - assert_not_impl!(TryForward: Sync); - assert_not_impl!(TryForward, *const ()>: Sync); - assert_not_impl!(TryForward: Sync); - assert_impl!(TryForward: Unpin); - assert_not_impl!(TryForward: Unpin); - assert_not_impl!(TryForward: Unpin); - - assert_impl!(Fuse<()>: Send); - assert_not_impl!(Fuse<*const ()>: Send); - assert_impl!(Fuse<()>: Sync); - assert_not_impl!(Fuse<*const ()>: Sync); - assert_impl!(Fuse<()>: Unpin); - assert_not_impl!(Fuse: Unpin); - - assert_impl!(FuturesOrdered>: Send); - assert_not_impl!(FuturesOrdered: Send); - assert_not_impl!(FuturesOrdered: Send); - assert_impl!(FuturesOrdered>: Sync); - assert_not_impl!(FuturesOrdered>: Sync); - assert_not_impl!(FuturesOrdered>: Sync); - assert_not_impl!(FuturesOrdered: Sync); - assert_impl!(FuturesOrdered: Unpin); - - assert_impl!(FuturesUnordered<()>: Send); - assert_not_impl!(FuturesUnordered<*const ()>: Send); - assert_impl!(FuturesUnordered<()>: Sync); - assert_not_impl!(FuturesUnordered<*const ()>: Sync); - assert_impl!(FuturesUnordered: Unpin); - - assert_impl!(Inspect<(), ()>: Send); - assert_not_impl!(Inspect<*const (), ()>: Send); - assert_not_impl!(Inspect<(), *const ()>: Send); - assert_impl!(Inspect<(), ()>: Sync); - assert_not_impl!(Inspect<*const (), ()>: Sync); - assert_not_impl!(Inspect<(), *const ()>: Sync); - assert_impl!(Inspect<(), PhantomPinned>: Unpin); - assert_not_impl!(Inspect: Unpin); - - assert_impl!(InspectErr<(), ()>: Send); - assert_not_impl!(InspectErr<*const (), ()>: Send); - assert_not_impl!(InspectErr<(), *const ()>: Send); - assert_impl!(InspectErr<(), ()>: Sync); - assert_not_impl!(InspectErr<*const (), ()>: Sync); - assert_not_impl!(InspectErr<(), *const ()>: Sync); - assert_impl!(InspectErr<(), PhantomPinned>: Unpin); - assert_not_impl!(InspectErr: Unpin); - - assert_impl!(InspectOk<(), ()>: Send); - assert_not_impl!(InspectOk<*const (), ()>: Send); - assert_not_impl!(InspectOk<(), *const ()>: Send); - assert_impl!(InspectOk<(), ()>: Sync); - assert_not_impl!(InspectOk<*const (), ()>: Sync); - assert_not_impl!(InspectOk<(), *const ()>: Sync); - assert_impl!(InspectOk<(), PhantomPinned>: Unpin); - assert_not_impl!(InspectOk: Unpin); - - assert_impl!(IntoAsyncRead, io::Error>>: Send); - assert_not_impl!(IntoAsyncRead, io::Error>>: Send); - assert_impl!(IntoAsyncRead, io::Error>>: Sync); - assert_not_impl!(IntoAsyncRead, io::Error>>: Sync); - assert_impl!(IntoAsyncRead, io::Error>>: Unpin); - // IntoAsyncRead requires `St: Unpin` - // assert_not_impl!(IntoAsyncRead, io::Error>>: Unpin); - - assert_impl!(IntoStream<()>: Send); - assert_not_impl!(IntoStream<*const ()>: Send); - assert_impl!(IntoStream<()>: Sync); - assert_not_impl!(IntoStream<*const ()>: Sync); - assert_impl!(IntoStream<()>: Unpin); - assert_not_impl!(IntoStream: Unpin); - - assert_impl!(Iter<()>: Send); - assert_not_impl!(Iter<*const ()>: Send); - assert_impl!(Iter<()>: Sync); - assert_not_impl!(Iter<*const ()>: Sync); - assert_impl!(Iter: Unpin); - - assert_impl!(Map<(), ()>: Send); - assert_not_impl!(Map<*const (), ()>: Send); - assert_not_impl!(Map<(), *const ()>: Send); - assert_impl!(Map<(), ()>: Sync); - assert_not_impl!(Map<*const (), ()>: Sync); - assert_not_impl!(Map<(), *const ()>: Sync); - assert_impl!(Map<(), PhantomPinned>: Unpin); - assert_not_impl!(Map: Unpin); - - assert_impl!(MapErr<(), ()>: Send); - assert_not_impl!(MapErr<*const (), ()>: Send); - assert_not_impl!(MapErr<(), *const ()>: Send); - assert_impl!(MapErr<(), ()>: Sync); - assert_not_impl!(MapErr<*const (), ()>: Sync); - assert_not_impl!(MapErr<(), *const ()>: Sync); - assert_impl!(MapErr<(), PhantomPinned>: Unpin); - assert_not_impl!(MapErr: Unpin); - - assert_impl!(MapOk<(), ()>: Send); - assert_not_impl!(MapOk<*const (), ()>: Send); - assert_not_impl!(MapOk<(), *const ()>: Send); - assert_impl!(MapOk<(), ()>: Sync); - assert_not_impl!(MapOk<*const (), ()>: Sync); - assert_not_impl!(MapOk<(), *const ()>: Sync); - assert_impl!(MapOk<(), PhantomPinned>: Unpin); - assert_not_impl!(MapOk: Unpin); - - assert_impl!(Next<'_, ()>: Send); - assert_not_impl!(Next<'_, *const ()>: Send); - assert_impl!(Next<'_, ()>: Sync); - assert_not_impl!(Next<'_, *const ()>: Sync); - assert_impl!(Next<'_, ()>: Unpin); - assert_not_impl!(Next<'_, PhantomPinned>: Unpin); - - assert_impl!(NextIf<'_, SendStream<()>, ()>: Send); - assert_not_impl!(NextIf<'_, SendStream<()>, *const ()>: Send); - assert_not_impl!(NextIf<'_, SendStream, ()>: Send); - assert_not_impl!(NextIf<'_, LocalStream<()>, ()>: Send); - assert_impl!(NextIf<'_, SyncStream<()>, ()>: Sync); - assert_not_impl!(NextIf<'_, SyncStream<()>, *const ()>: Sync); - assert_not_impl!(NextIf<'_, SyncStream, ()>: Sync); - assert_not_impl!(NextIf<'_, LocalStream<()>, ()>: Send); - assert_impl!(NextIf<'_, PinnedStream, PhantomPinned>: Unpin); - - assert_impl!(NextIfEq<'_, SendStream<()>, ()>: Send); - assert_not_impl!(NextIfEq<'_, SendStream<()>, *const ()>: Send); - assert_not_impl!(NextIfEq<'_, SendStream, ()>: Send); - assert_not_impl!(NextIfEq<'_, LocalStream<()>, ()>: Send); - assert_impl!(NextIfEq<'_, SyncStream<()>, ()>: Sync); - assert_not_impl!(NextIfEq<'_, SyncStream<()>, *const ()>: Sync); - assert_not_impl!(NextIfEq<'_, SyncStream, ()>: Sync); - assert_not_impl!(NextIfEq<'_, LocalStream<()>, ()>: Send); - assert_impl!(NextIfEq<'_, PinnedStream, PhantomPinned>: Unpin); - - assert_impl!(Once<()>: Send); - assert_not_impl!(Once<*const ()>: Send); - assert_impl!(Once<()>: Sync); - assert_not_impl!(Once<*const ()>: Sync); - assert_impl!(Once<()>: Unpin); - assert_not_impl!(Once: Unpin); - - assert_impl!(OrElse<(), (), ()>: Send); - assert_not_impl!(OrElse<*const (), (), ()>: Send); - assert_not_impl!(OrElse<(), *const (), ()>: Send); - assert_not_impl!(OrElse<(), (), *const ()>: Send); - assert_impl!(OrElse<(), (), ()>: Sync); - assert_not_impl!(OrElse<*const (), (), ()>: Sync); - assert_not_impl!(OrElse<(), *const (), ()>: Sync); - assert_not_impl!(OrElse<(), (), *const ()>: Sync); - assert_impl!(OrElse<(), (), PhantomPinned>: Unpin); - assert_not_impl!(OrElse: Unpin); - assert_not_impl!(OrElse<(), PhantomPinned, ()>: Unpin); - - assert_impl!(Peek<'_, SendStream<()>>: Send); - assert_not_impl!(Peek<'_, SendStream>: Send); - assert_not_impl!(Peek<'_, LocalStream<()>>: Send); - assert_impl!(Peek<'_, SyncStream<()>>: Sync); - assert_not_impl!(Peek<'_, SyncStream>: Sync); - assert_not_impl!(Peek<'_, LocalStream<()>>: Sync); - assert_impl!(Peek<'_, PinnedStream>: Unpin); - - assert_impl!(PeekMut<'_, SendStream<()>>: Send); - assert_not_impl!(PeekMut<'_, SendStream>: Send); - assert_not_impl!(PeekMut<'_, LocalStream<()>>: Send); - assert_impl!(PeekMut<'_, SyncStream<()>>: Sync); - assert_not_impl!(PeekMut<'_, SyncStream>: Sync); - assert_not_impl!(PeekMut<'_, LocalStream<()>>: Sync); - assert_impl!(PeekMut<'_, PinnedStream>: Unpin); - - assert_impl!(Peekable>: Send); - assert_not_impl!(Peekable: Send); - assert_not_impl!(Peekable: Send); - assert_impl!(Peekable>: Sync); - assert_not_impl!(Peekable: Sync); - assert_not_impl!(Peekable: Sync); - assert_impl!(Peekable: Unpin); - assert_not_impl!(Peekable: Unpin); - - assert_impl!(Pending<()>: Send); - assert_not_impl!(Pending<*const ()>: Send); - assert_impl!(Pending<()>: Sync); - assert_not_impl!(Pending<*const ()>: Sync); - assert_impl!(Pending: Unpin); - - assert_impl!(PollFn<()>: Send); - assert_not_impl!(PollFn<*const ()>: Send); - assert_impl!(PollFn<()>: Sync); - assert_not_impl!(PollFn<*const ()>: Sync); - assert_impl!(PollFn: Unpin); - - assert_impl!(PollImmediate: Send); - assert_not_impl!(PollImmediate>: Send); - assert_impl!(PollImmediate: Sync); - assert_not_impl!(PollImmediate>: Sync); - assert_impl!(PollImmediate: Unpin); - assert_not_impl!(PollImmediate: Unpin); - - assert_impl!(ReadyChunks>: Send); - assert_impl!(ReadyChunks: Send); - assert_not_impl!(ReadyChunks: Send); - assert_impl!(ReadyChunks>: Sync); - assert_impl!(ReadyChunks: Sync); - assert_not_impl!(ReadyChunks: Sync); - assert_impl!(ReadyChunks: Unpin); - assert_not_impl!(ReadyChunks: Unpin); - - assert_impl!(Repeat<()>: Send); - assert_not_impl!(Repeat<*const ()>: Send); - assert_impl!(Repeat<()>: Sync); - assert_not_impl!(Repeat<*const ()>: Sync); - assert_impl!(Repeat: Unpin); - - assert_impl!(RepeatWith<()>: Send); - assert_not_impl!(RepeatWith<*const ()>: Send); - assert_impl!(RepeatWith<()>: Sync); - assert_not_impl!(RepeatWith<*const ()>: Sync); - // RepeatWith requires `F: FnMut() -> A` - assert_impl!(RepeatWith ()>: Unpin); - // assert_impl!(RepeatWith: Unpin); - - assert_impl!(ReuniteError<(), ()>: Send); - assert_not_impl!(ReuniteError<*const (), ()>: Send); - assert_not_impl!(ReuniteError<(), *const ()>: Send); - assert_impl!(ReuniteError<(), ()>: Sync); - assert_not_impl!(ReuniteError<*const (), ()>: Sync); - assert_not_impl!(ReuniteError<(), *const ()>: Sync); - assert_impl!(ReuniteError: Unpin); - - assert_impl!(Scan: Send); - assert_not_impl!(Scan, (), (), ()>: Send); - assert_not_impl!(Scan, *const (), (), ()>: Send); - assert_not_impl!(Scan, (), *const (), ()>: Send); - assert_not_impl!(Scan, (), (), *const ()>: Send); - assert_impl!(Scan: Sync); - assert_not_impl!(Scan, (), (), ()>: Sync); - assert_not_impl!(Scan, *const (), (), ()>: Sync); - assert_not_impl!(Scan, (), *const (), ()>: Sync); - assert_not_impl!(Scan, (), (), *const ()>: Sync); - assert_impl!(Scan: Unpin); - assert_not_impl!(Scan: Unpin); - assert_not_impl!(Scan: Unpin); - - assert_impl!(Select<(), ()>: Send); - assert_not_impl!(Select<*const (), ()>: Send); - assert_not_impl!(Select<(), *const ()>: Send); - assert_impl!(Select<(), ()>: Sync); - assert_not_impl!(Select<*const (), ()>: Sync); - assert_not_impl!(Select<(), *const ()>: Sync); - assert_impl!(Select<(), ()>: Unpin); - assert_not_impl!(Select: Unpin); - assert_not_impl!(Select<(), PhantomPinned>: Unpin); - - assert_impl!(SelectAll<()>: Send); - assert_not_impl!(SelectAll<*const ()>: Send); - assert_impl!(SelectAll<()>: Sync); - assert_not_impl!(SelectAll<*const ()>: Sync); - assert_impl!(SelectAll: Unpin); - - assert_impl!(SelectNextSome<'_, ()>: Send); - assert_not_impl!(SelectNextSome<'_, *const ()>: Send); - assert_impl!(SelectNextSome<'_, ()>: Sync); - assert_not_impl!(SelectNextSome<'_, *const ()>: Sync); - assert_impl!(SelectNextSome<'_, PhantomPinned>: Unpin); - - assert_impl!(Skip<()>: Send); - assert_not_impl!(Skip<*const ()>: Send); - assert_impl!(Skip<()>: Sync); - assert_not_impl!(Skip<*const ()>: Sync); - assert_impl!(Skip<()>: Unpin); - assert_not_impl!(Skip: Unpin); - - assert_impl!(SkipWhile, (), ()>: Send); - assert_not_impl!(SkipWhile, (), ()>: Send); - assert_not_impl!(SkipWhile: Send); - assert_not_impl!(SkipWhile, *const (), ()>: Send); - assert_not_impl!(SkipWhile, (), *const ()>: Send); - assert_impl!(SkipWhile, (), ()>: Sync); - assert_not_impl!(SkipWhile, (), ()>: Sync); - assert_not_impl!(SkipWhile: Sync); - assert_not_impl!(SkipWhile, *const (), ()>: Sync); - assert_not_impl!(SkipWhile, (), *const ()>: Sync); - assert_impl!(SkipWhile: Unpin); - assert_not_impl!(SkipWhile: Unpin); - assert_not_impl!(SkipWhile: Unpin); - - assert_impl!(SplitSink<(), ()>: Send); - assert_not_impl!(SplitSink<*const (), ()>: Send); - assert_not_impl!(SplitSink<(), *const ()>: Send); - assert_impl!(SplitSink<(), ()>: Sync); - assert_not_impl!(SplitSink<*const (), ()>: Sync); - assert_not_impl!(SplitSink<(), *const ()>: Sync); - assert_impl!(SplitSink: Unpin); - - assert_impl!(SplitStream<()>: Send); - assert_not_impl!(SplitStream<*const ()>: Send); - assert_impl!(SplitStream<()>: Sync); - assert_not_impl!(SplitStream<*const ()>: Sync); - assert_impl!(SplitStream: Unpin); - - assert_impl!(StreamFuture<()>: Send); - assert_not_impl!(StreamFuture<*const ()>: Send); - assert_impl!(StreamFuture<()>: Sync); - assert_not_impl!(StreamFuture<*const ()>: Sync); - assert_impl!(StreamFuture<()>: Unpin); - assert_not_impl!(StreamFuture: Unpin); - - assert_impl!(Take<()>: Send); - assert_not_impl!(Take<*const ()>: Send); - assert_impl!(Take<()>: Sync); - assert_not_impl!(Take<*const ()>: Sync); - assert_impl!(Take<()>: Unpin); - assert_not_impl!(Take: Unpin); - - assert_impl!(TakeUntil>: Send); - assert_not_impl!(TakeUntil: Send); - assert_not_impl!(TakeUntil>: Send); - assert_not_impl!(TakeUntil>: Send); - assert_impl!(TakeUntil>: Sync); - assert_not_impl!(TakeUntil: Sync); - assert_not_impl!(TakeUntil>: Sync); - assert_not_impl!(TakeUntil>: Sync); - assert_impl!(TakeUntil: Unpin); - assert_not_impl!(TakeUntil: Unpin); - assert_not_impl!(TakeUntil: Unpin); - - assert_impl!(TakeWhile, (), ()>: Send); - assert_not_impl!(TakeWhile, (), ()>: Send); - assert_not_impl!(TakeWhile: Send); - assert_not_impl!(TakeWhile, *const (), ()>: Send); - assert_not_impl!(TakeWhile, (), *const ()>: Send); - assert_impl!(TakeWhile, (), ()>: Sync); - assert_not_impl!(TakeWhile, (), ()>: Sync); - assert_not_impl!(TakeWhile: Sync); - assert_not_impl!(TakeWhile, *const (), ()>: Sync); - assert_not_impl!(TakeWhile, (), *const ()>: Sync); - assert_impl!(TakeWhile: Unpin); - assert_not_impl!(TakeWhile: Unpin); - assert_not_impl!(TakeWhile: Unpin); - - assert_impl!(Then: Send); - assert_not_impl!(Then, (), ()>: Send); - assert_not_impl!(Then, *const (), ()>: Send); - assert_not_impl!(Then, (), *const ()>: Send); - assert_impl!(Then: Sync); - assert_not_impl!(Then, (), ()>: Sync); - assert_not_impl!(Then, *const (), ()>: Sync); - assert_not_impl!(Then, (), *const ()>: Sync); - assert_impl!(Then: Unpin); - assert_not_impl!(Then: Unpin); - assert_not_impl!(Then: Unpin); - - assert_impl!(TryBufferUnordered>: Send); - assert_not_impl!(TryBufferUnordered: Send); - assert_not_impl!(TryBufferUnordered: Send); - assert_impl!(TryBufferUnordered>: Sync); - assert_not_impl!(TryBufferUnordered: Sync); - assert_not_impl!(TryBufferUnordered: Sync); - assert_impl!(TryBufferUnordered: Unpin); - assert_not_impl!(TryBufferUnordered: Unpin); - - assert_impl!(TryBuffered>>: Send); - assert_not_impl!(TryBuffered>>: Send); - assert_not_impl!(TryBuffered>>: Send); - assert_not_impl!(TryBuffered>>: Send); - assert_not_impl!(TryBuffered>>: Send); - assert_impl!(TryBuffered>>: Sync); - assert_not_impl!(TryBuffered>>: Sync); - assert_not_impl!(TryBuffered>>: Sync); - assert_not_impl!(TryBuffered>>: Sync); - assert_not_impl!(TryBuffered>>: Sync); - assert_not_impl!(TryBuffered>>: Sync); - assert_impl!(TryBuffered>: Unpin); - assert_not_impl!(TryBuffered>: Unpin); - - assert_impl!(TryCollect<(), ()>: Send); - assert_not_impl!(TryCollect<*const (), ()>: Send); - assert_not_impl!(TryCollect<(), *const ()>: Send); - assert_impl!(TryCollect<(), ()>: Sync); - assert_not_impl!(TryCollect<*const (), ()>: Sync); - assert_not_impl!(TryCollect<(), *const ()>: Sync); - assert_impl!(TryCollect<(), PhantomPinned>: Unpin); - assert_not_impl!(TryCollect: Unpin); - - assert_impl!(TryConcat>: Send); - assert_not_impl!(TryConcat: Send); - assert_not_impl!(TryConcat: Send); - assert_impl!(TryConcat>: Sync); - assert_not_impl!(TryConcat: Sync); - assert_not_impl!(TryConcat: Sync); - assert_impl!(TryConcat: Unpin); - assert_not_impl!(TryConcat: Unpin); - - assert_impl!(TryFilter, (), ()>: Send); - assert_not_impl!(TryFilter, (), ()>: Send); - assert_not_impl!(TryFilter: Send); - assert_not_impl!(TryFilter, *const (), ()>: Send); - assert_not_impl!(TryFilter, (), *const ()>: Send); - assert_impl!(TryFilter, (), ()>: Sync); - assert_not_impl!(TryFilter, (), ()>: Sync); - assert_not_impl!(TryFilter: Sync); - assert_not_impl!(TryFilter, *const (), ()>: Sync); - assert_not_impl!(TryFilter, (), *const ()>: Sync); - assert_impl!(TryFilter: Unpin); - assert_not_impl!(TryFilter: Unpin); - assert_not_impl!(TryFilter: Unpin); - - assert_impl!(TryFilterMap<(), (), ()>: Send); - assert_not_impl!(TryFilterMap<*const (), (), ()>: Send); - assert_not_impl!(TryFilterMap<(), *const (), ()>: Send); - assert_not_impl!(TryFilterMap<(), (), *const ()>: Send); - assert_impl!(TryFilterMap<(), (), ()>: Sync); - assert_not_impl!(TryFilterMap<*const (), (), ()>: Sync); - assert_not_impl!(TryFilterMap<(), *const (), ()>: Sync); - assert_not_impl!(TryFilterMap<(), (), *const ()>: Sync); - assert_impl!(TryFilterMap<(), (), PhantomPinned>: Unpin); - assert_not_impl!(TryFilterMap: Unpin); - assert_not_impl!(TryFilterMap<(), PhantomPinned, ()>: Unpin); - - assert_impl!(TryFlatten>: Send); - assert_not_impl!(TryFlatten: Send); - assert_not_impl!(TryFlatten: Send); - assert_impl!(TryFlatten>: Sync); - assert_not_impl!(TryFlatten>: Sync); - assert_not_impl!(TryFlatten>: Sync); - assert_impl!(TryFlatten>: Unpin); - assert_not_impl!(TryFlatten: Unpin); - assert_not_impl!(TryFlatten: Unpin); - - assert_impl!(TryFold<(), (), (), ()>: Send); - assert_not_impl!(TryFold<*const (), (), (), ()>: Send); - assert_not_impl!(TryFold<(), *const (), (), ()>: Send); - assert_not_impl!(TryFold<(), (), *const (), ()>: Send); - assert_not_impl!(TryFold<(), (), (), *const ()>: Send); - assert_impl!(TryFold<(), (), (), ()>: Sync); - assert_not_impl!(TryFold<*const (), (), (), ()>: Sync); - assert_not_impl!(TryFold<(), *const (), (), ()>: Sync); - assert_not_impl!(TryFold<(), (), *const (), ()>: Sync); - assert_not_impl!(TryFold<(), (), (), *const ()>: Sync); - assert_impl!(TryFold<(), (), PhantomPinned, PhantomPinned>: Unpin); - assert_not_impl!(TryFold: Unpin); - assert_not_impl!(TryFold<(), PhantomPinned, (), ()>: Unpin); - - assert_impl!(TryForEach<(), (), ()>: Send); - assert_not_impl!(TryForEach<*const (), (), ()>: Send); - assert_not_impl!(TryForEach<(), *const (), ()>: Send); - assert_not_impl!(TryForEach<(), (), *const ()>: Send); - assert_impl!(TryForEach<(), (), ()>: Sync); - assert_not_impl!(TryForEach<*const (), (), ()>: Sync); - assert_not_impl!(TryForEach<(), *const (), ()>: Sync); - assert_not_impl!(TryForEach<(), (), *const ()>: Sync); - assert_impl!(TryForEach<(), (), PhantomPinned>: Unpin); - assert_not_impl!(TryForEach: Unpin); - assert_not_impl!(TryForEach<(), PhantomPinned, ()>: Unpin); - - assert_impl!(TryForEachConcurrent<(), (), ()>: Send); - assert_not_impl!(TryForEachConcurrent<*const (), (), ()>: Send); - assert_not_impl!(TryForEachConcurrent<(), *const (), ()>: Send); - assert_not_impl!(TryForEachConcurrent<(), (), *const ()>: Send); - assert_impl!(TryForEachConcurrent<(), (), ()>: Sync); - assert_not_impl!(TryForEachConcurrent<*const (), (), ()>: Sync); - assert_not_impl!(TryForEachConcurrent<(), *const (), ()>: Sync); - assert_not_impl!(TryForEachConcurrent<(), (), *const ()>: Sync); - assert_impl!(TryForEachConcurrent<(), PhantomPinned, PhantomPinned>: Unpin); - assert_not_impl!(TryForEachConcurrent: Unpin); - - assert_impl!(TryNext<'_, ()>: Send); - assert_not_impl!(TryNext<'_, *const ()>: Send); - assert_impl!(TryNext<'_, ()>: Sync); - assert_not_impl!(TryNext<'_, *const ()>: Sync); - assert_impl!(TryNext<'_, ()>: Unpin); - assert_not_impl!(TryNext<'_, PhantomPinned>: Unpin); - - assert_impl!(TrySkipWhile, (), ()>: Send); - assert_not_impl!(TrySkipWhile, (), ()>: Send); - assert_not_impl!(TrySkipWhile: Send); - assert_not_impl!(TrySkipWhile, *const (), ()>: Send); - assert_not_impl!(TrySkipWhile, (), *const ()>: Send); - assert_impl!(TrySkipWhile, (), ()>: Sync); - assert_not_impl!(TrySkipWhile, (), ()>: Sync); - assert_not_impl!(TrySkipWhile: Sync); - assert_not_impl!(TrySkipWhile, *const (), ()>: Sync); - assert_not_impl!(TrySkipWhile, (), *const ()>: Sync); - assert_impl!(TrySkipWhile: Unpin); - assert_not_impl!(TrySkipWhile: Unpin); - assert_not_impl!(TrySkipWhile: Unpin); - - assert_impl!(TryTakeWhile, (), ()>: Send); - assert_not_impl!(TryTakeWhile, (), ()>: Send); - assert_not_impl!(TryTakeWhile: Send); - assert_not_impl!(TryTakeWhile, *const (), ()>: Send); - assert_not_impl!(TryTakeWhile, (), *const ()>: Send); - assert_impl!(TryTakeWhile, (), ()>: Sync); - assert_not_impl!(TryTakeWhile, (), ()>: Sync); - assert_not_impl!(TryTakeWhile: Sync); - assert_not_impl!(TryTakeWhile, *const (), ()>: Sync); - assert_not_impl!(TryTakeWhile, (), *const ()>: Sync); - assert_impl!(TryTakeWhile: Unpin); - assert_not_impl!(TryTakeWhile: Unpin); - assert_not_impl!(TryTakeWhile: Unpin); - - assert_impl!(TryUnfold<(), (), ()>: Send); - assert_not_impl!(TryUnfold<*const (), (), ()>: Send); - assert_not_impl!(TryUnfold<(), *const (), ()>: Send); - assert_not_impl!(TryUnfold<(), (), *const ()>: Send); - assert_impl!(TryUnfold<(), (), ()>: Sync); - assert_not_impl!(TryUnfold<*const (), (), ()>: Sync); - assert_not_impl!(TryUnfold<(), *const (), ()>: Sync); - assert_not_impl!(TryUnfold<(), (), *const ()>: Sync); - assert_impl!(TryUnfold: Unpin); - assert_not_impl!(TryUnfold<(), (), PhantomPinned>: Unpin); - - assert_impl!(Unfold<(), (), ()>: Send); - assert_not_impl!(Unfold<*const (), (), ()>: Send); - assert_not_impl!(Unfold<(), *const (), ()>: Send); - assert_not_impl!(Unfold<(), (), *const ()>: Send); - assert_impl!(Unfold<(), (), ()>: Sync); - assert_not_impl!(Unfold<*const (), (), ()>: Sync); - assert_not_impl!(Unfold<(), *const (), ()>: Sync); - assert_not_impl!(Unfold<(), (), *const ()>: Sync); - assert_impl!(Unfold: Unpin); - assert_not_impl!(Unfold<(), (), PhantomPinned>: Unpin); - - assert_impl!(Unzip<(), (), ()>: Send); - assert_not_impl!(Unzip<*const (), (), ()>: Send); - assert_not_impl!(Unzip<(), *const (), ()>: Send); - assert_not_impl!(Unzip<(), (), *const ()>: Send); - assert_impl!(Unzip<(), (), ()>: Sync); - assert_not_impl!(Unzip<*const (), (), ()>: Sync); - assert_not_impl!(Unzip<(), *const (), ()>: Sync); - assert_not_impl!(Unzip<(), (), *const ()>: Sync); - assert_impl!(Unzip<(), PhantomPinned, PhantomPinned>: Unpin); - assert_not_impl!(Unzip: Unpin); - - assert_impl!(Zip, SendStream<()>>: Send); - assert_not_impl!(Zip>: Send); - assert_not_impl!(Zip, SendStream>: Send); - assert_not_impl!(Zip>: Send); - assert_not_impl!(Zip, LocalStream>: Send); - assert_impl!(Zip, SyncStream<()>>: Sync); - assert_not_impl!(Zip>: Sync); - assert_not_impl!(Zip, SyncStream>: Sync); - assert_not_impl!(Zip>: Sync); - assert_not_impl!(Zip, LocalStream>: Sync); - assert_impl!(Zip: Unpin); - assert_not_impl!(Zip: Unpin); - assert_not_impl!(Zip: Unpin); - - assert_impl!(futures_unordered::Iter<'_, ()>: Send); - assert_not_impl!(futures_unordered::Iter<'_, *const ()>: Send); - assert_impl!(futures_unordered::Iter<'_, ()>: Sync); - assert_not_impl!(futures_unordered::Iter<'_, *const ()>: Sync); - assert_impl!(futures_unordered::Iter<'_, ()>: Unpin); - // The definition of futures_unordered::Iter has `Fut: Unpin` bounds. - // assert_not_impl!(futures_unordered::Iter<'_, PhantomPinned>: Unpin); - - assert_impl!(futures_unordered::IterMut<'_, ()>: Send); - assert_not_impl!(futures_unordered::IterMut<'_, *const ()>: Send); - assert_impl!(futures_unordered::IterMut<'_, ()>: Sync); - assert_not_impl!(futures_unordered::IterMut<'_, *const ()>: Sync); - assert_impl!(futures_unordered::IterMut<'_, ()>: Unpin); - // The definition of futures_unordered::IterMut has `Fut: Unpin` bounds. - // assert_not_impl!(futures_unordered::IterMut<'_, PhantomPinned>: Unpin); - - assert_impl!(futures_unordered::IterPinMut<'_, ()>: Send); - assert_not_impl!(futures_unordered::IterPinMut<'_, *const ()>: Send); - assert_impl!(futures_unordered::IterPinMut<'_, ()>: Sync); - assert_not_impl!(futures_unordered::IterPinMut<'_, *const ()>: Sync); - assert_impl!(futures_unordered::IterPinMut<'_, PhantomPinned>: Unpin); - - assert_impl!(futures_unordered::IterPinRef<'_, ()>: Send); - assert_not_impl!(futures_unordered::IterPinRef<'_, *const ()>: Send); - assert_impl!(futures_unordered::IterPinRef<'_, ()>: Sync); - assert_not_impl!(futures_unordered::IterPinRef<'_, *const ()>: Sync); - assert_impl!(futures_unordered::IterPinRef<'_, PhantomPinned>: Unpin); - - assert_impl!(futures_unordered::IntoIter<()>: Send); - assert_not_impl!(futures_unordered::IntoIter<*const ()>: Send); - assert_impl!(futures_unordered::IntoIter<()>: Sync); - assert_not_impl!(futures_unordered::IntoIter<*const ()>: Sync); - // The definition of futures_unordered::IntoIter has `Fut: Unpin` bounds. - // assert_not_impl!(futures_unordered::IntoIter: Unpin); -} - -/// Assert Send/Sync/Unpin for all public types in `futures::task`. -mod task { - use super::*; - use futures::task::*; - - assert_impl!(AtomicWaker: Send); - assert_impl!(AtomicWaker: Sync); - assert_impl!(AtomicWaker: Unpin); - - assert_impl!(FutureObj<'_, *const ()>: Send); - assert_not_impl!(FutureObj<'_, ()>: Sync); - assert_impl!(FutureObj<'_, PhantomPinned>: Unpin); - - assert_not_impl!(LocalFutureObj<'_, ()>: Send); - assert_not_impl!(LocalFutureObj<'_, ()>: Sync); - assert_impl!(LocalFutureObj<'_, PhantomPinned>: Unpin); - - assert_impl!(SpawnError: Send); - assert_impl!(SpawnError: Sync); - assert_impl!(SpawnError: Unpin); - - assert_impl!(WakerRef<'_>: Send); - assert_impl!(WakerRef<'_>: Sync); - assert_impl!(WakerRef<'_>: Unpin); -} diff --git a/futures/tests/bilock.rs b/futures/tests/bilock.rs deleted file mode 100644 index b103487849..0000000000 --- a/futures/tests/bilock.rs +++ /dev/null @@ -1,104 +0,0 @@ -#![cfg(feature = "bilock")] - -use futures::executor::block_on; -use futures::future; -use futures::stream; -use futures::task::{Context, Poll}; -use futures::Future; -use futures::StreamExt; -use futures_test::task::noop_context; -use futures_util::lock::BiLock; -use std::pin::Pin; -use std::thread; - -#[test] -fn smoke() { - let future = future::lazy(|cx| { - let (a, b) = BiLock::new(1); - - { - let mut lock = match a.poll_lock(cx) { - Poll::Ready(l) => l, - Poll::Pending => panic!("poll not ready"), - }; - assert_eq!(*lock, 1); - *lock = 2; - - assert!(b.poll_lock(cx).is_pending()); - assert!(a.poll_lock(cx).is_pending()); - } - - assert!(b.poll_lock(cx).is_ready()); - assert!(a.poll_lock(cx).is_ready()); - - { - let lock = match b.poll_lock(cx) { - Poll::Ready(l) => l, - Poll::Pending => panic!("poll not ready"), - }; - assert_eq!(*lock, 2); - } - - assert_eq!(a.reunite(b).expect("bilock/smoke: reunite error"), 2); - - Ok::<(), ()>(()) - }); - - assert_eq!(block_on(future), Ok(())); -} - -#[test] -fn concurrent() { - const N: usize = 10000; - let mut cx = noop_context(); - let (a, b) = BiLock::new(0); - - let a = Increment { a: Some(a), remaining: N }; - let b = stream::iter(0..N).fold(b, |b, _n| async { - let mut g = b.lock().await; - *g += 1; - drop(g); - b - }); - - let t1 = thread::spawn(move || block_on(a)); - let b = block_on(b); - let a = t1.join().unwrap(); - - match a.poll_lock(&mut cx) { - Poll::Ready(l) => assert_eq!(*l, 2 * N), - Poll::Pending => panic!("poll not ready"), - } - match b.poll_lock(&mut cx) { - Poll::Ready(l) => assert_eq!(*l, 2 * N), - Poll::Pending => panic!("poll not ready"), - } - - assert_eq!(a.reunite(b).expect("bilock/concurrent: reunite error"), 2 * N); - - struct Increment { - remaining: usize, - a: Option>, - } - - impl Future for Increment { - type Output = BiLock; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - if self.remaining == 0 { - return self.a.take().unwrap().into(); - } - - let a = self.a.as_mut().unwrap(); - let mut a = match a.poll_lock(cx) { - Poll::Ready(l) => l, - Poll::Pending => return Poll::Pending, - }; - *a += 1; - drop(a); - self.remaining -= 1; - } - } - } -} diff --git a/futures/tests/compat.rs b/futures/tests/compat.rs deleted file mode 100644 index 44e02e9a21..0000000000 --- a/futures/tests/compat.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![cfg(feature = "compat")] -#![cfg(not(miri))] // Miri does not support epoll - -use futures::compat::Future01CompatExt; -use futures::prelude::*; -use std::time::Instant; -use tokio::runtime::Runtime; -use tokio::timer::Delay; - -#[test] -fn can_use_01_futures_in_a_03_future_running_on_a_01_executor() { - let f = Delay::new(Instant::now()).compat(); - - let mut runtime = Runtime::new().unwrap(); - runtime.block_on(f.boxed().compat()).unwrap(); -} diff --git a/futures/tests/eager_drop.rs b/futures/tests/eager_drop.rs deleted file mode 100644 index 992507774c..0000000000 --- a/futures/tests/eager_drop.rs +++ /dev/null @@ -1,121 +0,0 @@ -use futures::channel::oneshot; -use futures::future::{self, Future, FutureExt, TryFutureExt}; -use futures::task::{Context, Poll}; -use futures_test::future::FutureTestExt; -use pin_project::pin_project; -use std::pin::Pin; -use std::sync::mpsc; - -#[test] -fn map_ok() { - // The closure given to `map_ok` should have been dropped by the time `map` - // runs. - let (tx1, rx1) = mpsc::channel::<()>(); - let (tx2, rx2) = mpsc::channel::<()>(); - - future::ready::>(Err(1)) - .map_ok(move |_| { - let _tx1 = tx1; - panic!("should not run"); - }) - .map(move |_| { - assert!(rx1.recv().is_err()); - tx2.send(()).unwrap() - }) - .run_in_background(); - - rx2.recv().unwrap(); -} - -#[test] -fn map_err() { - // The closure given to `map_err` should have been dropped by the time `map` - // runs. - let (tx1, rx1) = mpsc::channel::<()>(); - let (tx2, rx2) = mpsc::channel::<()>(); - - future::ready::>(Ok(1)) - .map_err(move |_| { - let _tx1 = tx1; - panic!("should not run"); - }) - .map(move |_| { - assert!(rx1.recv().is_err()); - tx2.send(()).unwrap() - }) - .run_in_background(); - - rx2.recv().unwrap(); -} - -#[pin_project] -struct FutureData { - _data: T, - #[pin] - future: F, -} - -impl Future for FutureData { - type Output = F::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().future.poll(cx) - } -} - -#[test] -fn then_drops_eagerly() { - let (tx0, rx0) = oneshot::channel::<()>(); - let (tx1, rx1) = mpsc::channel::<()>(); - let (tx2, rx2) = mpsc::channel::<()>(); - - FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } - .then(move |_| { - assert!(rx1.recv().is_err()); // tx1 should have been dropped - tx2.send(()).unwrap(); - future::ready(()) - }) - .run_in_background(); - - assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); - tx0.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn and_then_drops_eagerly() { - let (tx0, rx0) = oneshot::channel::>(); - let (tx1, rx1) = mpsc::channel::<()>(); - let (tx2, rx2) = mpsc::channel::<()>(); - - FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } - .and_then(move |_| { - assert!(rx1.recv().is_err()); // tx1 should have been dropped - tx2.send(()).unwrap(); - future::ready(Ok(())) - }) - .run_in_background(); - - assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); - tx0.send(Ok(())).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn or_else_drops_eagerly() { - let (tx0, rx0) = oneshot::channel::>(); - let (tx1, rx1) = mpsc::channel::<()>(); - let (tx2, rx2) = mpsc::channel::<()>(); - - FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| panic!()) } - .or_else(move |_| { - assert!(rx1.recv().is_err()); // tx1 should have been dropped - tx2.send(()).unwrap(); - future::ready::>(Ok(())) - }) - .run_in_background(); - - assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv()); - tx0.send(Err(())).unwrap(); - rx2.recv().unwrap(); -} diff --git a/futures/tests/eventual.rs b/futures/tests/eventual.rs deleted file mode 100644 index 57a49b2417..0000000000 --- a/futures/tests/eventual.rs +++ /dev/null @@ -1,179 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::ThreadPool; -use futures::future::{self, ok, Future, FutureExt, TryFutureExt}; -use futures::task::SpawnExt; -use std::sync::mpsc; -use std::thread; - -fn run(future: F) { - let tp = ThreadPool::new().unwrap(); - tp.spawn(future.map(drop)).unwrap(); -} - -#[test] -fn join1() { - let (tx, rx) = mpsc::channel(); - run(future::try_join(ok::(1), ok(2)).map_ok(move |v| tx.send(v).unwrap())); - assert_eq!(rx.recv(), Ok((1, 2))); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn join2() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_join(p1, p2).map_ok(move |v| tx.send(v).unwrap())); - assert!(rx.try_recv().is_err()); - c1.send(1).unwrap(); - assert!(rx.try_recv().is_err()); - c2.send(2).unwrap(); - assert_eq!(rx.recv(), Ok((1, 2))); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn join3() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_join(p1, p2).map_err(move |_v| tx.send(1).unwrap())); - assert!(rx.try_recv().is_err()); - drop(c1); - assert_eq!(rx.recv(), Ok(1)); - assert!(rx.recv().is_err()); - drop(c2); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn join4() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_join(p1, p2).map_err(move |v| tx.send(v).unwrap())); - assert!(rx.try_recv().is_err()); - drop(c1); - assert!(rx.recv().is_ok()); - drop(c2); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn join5() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (c3, p3) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_join(future::try_join(p1, p2), p3).map_ok(move |v| tx.send(v).unwrap())); - assert!(rx.try_recv().is_err()); - c1.send(1).unwrap(); - assert!(rx.try_recv().is_err()); - c2.send(2).unwrap(); - assert!(rx.try_recv().is_err()); - c3.send(3).unwrap(); - assert_eq!(rx.recv(), Ok(((1, 2), 3))); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn select1() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_select(p1, p2).map_ok(move |v| tx.send(v).unwrap())); - assert!(rx.try_recv().is_err()); - c1.send(1).unwrap(); - let (v, p2) = rx.recv().unwrap().into_inner(); - assert_eq!(v, 1); - assert!(rx.recv().is_err()); - - let (tx, rx) = mpsc::channel(); - run(p2.map_ok(move |v| tx.send(v).unwrap())); - c2.send(2).unwrap(); - assert_eq!(rx.recv(), Ok(2)); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn select2() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_select(p1, p2).map_err(move |v| tx.send((1, v.into_inner().1)).unwrap())); - assert!(rx.try_recv().is_err()); - drop(c1); - let (v, p2) = rx.recv().unwrap(); - assert_eq!(v, 1); - assert!(rx.recv().is_err()); - - let (tx, rx) = mpsc::channel(); - run(p2.map_ok(move |v| tx.send(v).unwrap())); - c2.send(2).unwrap(); - assert_eq!(rx.recv(), Ok(2)); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn select3() { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - let (tx, rx) = mpsc::channel(); - run(future::try_select(p1, p2).map_err(move |v| tx.send((1, v.into_inner().1)).unwrap())); - assert!(rx.try_recv().is_err()); - drop(c1); - let (v, p2) = rx.recv().unwrap(); - assert_eq!(v, 1); - assert!(rx.recv().is_err()); - - let (tx, rx) = mpsc::channel(); - run(p2.map_err(move |_v| tx.send(2).unwrap())); - drop(c2); - assert_eq!(rx.recv(), Ok(2)); - assert!(rx.recv().is_err()); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} - -#[test] -fn select4() { - const N: usize = if cfg!(miri) { 100 } else { 10000 }; - - let (tx, rx) = mpsc::channel::>(); - - let t = thread::spawn(move || { - for c in rx { - c.send(1).unwrap(); - } - }); - - let (tx2, rx2) = mpsc::channel(); - for _ in 0..N { - let (c1, p1) = oneshot::channel::(); - let (c2, p2) = oneshot::channel::(); - - let tx3 = tx2.clone(); - run(future::try_select(p1, p2).map_ok(move |_| tx3.send(()).unwrap())); - tx.send(c1).unwrap(); - rx2.recv().unwrap(); - drop(c2); - } - drop(tx); - - t.join().unwrap(); - - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} diff --git a/futures/tests/future_abortable.rs b/futures/tests/future_abortable.rs deleted file mode 100644 index e119f0b719..0000000000 --- a/futures/tests/future_abortable.rs +++ /dev/null @@ -1,44 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::block_on; -use futures::future::{abortable, Aborted, FutureExt}; -use futures::task::{Context, Poll}; -use futures_test::task::new_count_waker; - -#[test] -fn abortable_works() { - let (_tx, a_rx) = oneshot::channel::<()>(); - let (abortable_rx, abort_handle) = abortable(a_rx); - - abort_handle.abort(); - assert!(abortable_rx.is_aborted()); - assert_eq!(Err(Aborted), block_on(abortable_rx)); -} - -#[test] -fn abortable_awakens() { - let (_tx, a_rx) = oneshot::channel::<()>(); - let (mut abortable_rx, abort_handle) = abortable(a_rx); - - let (waker, counter) = new_count_waker(); - let mut cx = Context::from_waker(&waker); - - assert_eq!(counter, 0); - assert_eq!(Poll::Pending, abortable_rx.poll_unpin(&mut cx)); - assert_eq!(counter, 0); - - abort_handle.abort(); - assert_eq!(counter, 1); - assert!(abortable_rx.is_aborted()); - assert_eq!(Poll::Ready(Err(Aborted)), abortable_rx.poll_unpin(&mut cx)); -} - -#[test] -fn abortable_resolves() { - let (tx, a_rx) = oneshot::channel::<()>(); - let (abortable_rx, _abort_handle) = abortable(a_rx); - - tx.send(()).unwrap(); - - assert!(!abortable_rx.is_aborted()); - assert_eq!(Ok(Ok(())), block_on(abortable_rx)); -} diff --git a/futures/tests/future_basic_combinators.rs b/futures/tests/future_basic_combinators.rs deleted file mode 100644 index 372ab48b79..0000000000 --- a/futures/tests/future_basic_combinators.rs +++ /dev/null @@ -1,104 +0,0 @@ -use futures::future::{self, FutureExt, TryFutureExt}; -use futures_test::future::FutureTestExt; -use std::sync::mpsc; - -#[test] -fn basic_future_combinators() { - let (tx1, rx) = mpsc::channel(); - let tx2 = tx1.clone(); - let tx3 = tx1.clone(); - - let fut = future::ready(1) - .then(move |x| { - tx1.send(x).unwrap(); // Send 1 - tx1.send(2).unwrap(); // Send 2 - future::ready(3) - }) - .map(move |x| { - tx2.send(x).unwrap(); // Send 3 - tx2.send(4).unwrap(); // Send 4 - 5 - }) - .map(move |x| { - tx3.send(x).unwrap(); // Send 5 - }); - - assert!(rx.try_recv().is_err()); // Not started yet - fut.run_in_background(); // Start it - for i in 1..=5 { - assert_eq!(rx.recv(), Ok(i)); - } // Check it - assert!(rx.recv().is_err()); // Should be done -} - -#[test] -fn basic_try_future_combinators() { - let (tx1, rx) = mpsc::channel(); - let tx2 = tx1.clone(); - let tx3 = tx1.clone(); - let tx4 = tx1.clone(); - let tx5 = tx1.clone(); - let tx6 = tx1.clone(); - let tx7 = tx1.clone(); - let tx8 = tx1.clone(); - let tx9 = tx1.clone(); - let tx10 = tx1.clone(); - - let fut = future::ready(Ok(1)) - .and_then(move |x: i32| { - tx1.send(x).unwrap(); // Send 1 - tx1.send(2).unwrap(); // Send 2 - future::ready(Ok(3)) - }) - .or_else(move |x: i32| { - tx2.send(x).unwrap(); // Should not run - tx2.send(-1).unwrap(); - future::ready(Ok(-1)) - }) - .map_ok(move |x: i32| { - tx3.send(x).unwrap(); // Send 3 - tx3.send(4).unwrap(); // Send 4 - 5 - }) - .map_err(move |x: i32| { - tx4.send(x).unwrap(); // Should not run - tx4.send(-1).unwrap(); - -1 - }) - .map(move |x: Result| { - tx5.send(x.unwrap()).unwrap(); // Send 5 - tx5.send(6).unwrap(); // Send 6 - Err(7) // Now return errors! - }) - .and_then(move |x: i32| { - tx6.send(x).unwrap(); // Should not run - tx6.send(-1).unwrap(); - future::ready(Err(-1)) - }) - .or_else(move |x: i32| { - tx7.send(x).unwrap(); // Send 7 - tx7.send(8).unwrap(); // Send 8 - future::ready(Err(9)) - }) - .map_ok(move |x: i32| { - tx8.send(x).unwrap(); // Should not run - tx8.send(-1).unwrap(); - -1 - }) - .map_err(move |x: i32| { - tx9.send(x).unwrap(); // Send 9 - tx9.send(10).unwrap(); // Send 10 - 11 - }) - .map(move |x: Result| { - tx10.send(x.err().unwrap()).unwrap(); // Send 11 - tx10.send(12).unwrap(); // Send 12 - }); - - assert!(rx.try_recv().is_err()); // Not started yet - fut.run_in_background(); // Start it - for i in 1..=12 { - assert_eq!(rx.recv(), Ok(i)); - } // Check it - assert!(rx.recv().is_err()); // Should be done -} diff --git a/futures/tests/future_fuse.rs b/futures/tests/future_fuse.rs deleted file mode 100644 index 83f2c1ce9e..0000000000 --- a/futures/tests/future_fuse.rs +++ /dev/null @@ -1,12 +0,0 @@ -use futures::future::{self, FutureExt}; -use futures::task::Context; -use futures_test::task::panic_waker; - -#[test] -fn fuse() { - let mut future = future::ready::(2).fuse(); - let waker = panic_waker(); - let mut cx = Context::from_waker(&waker); - assert!(future.poll_unpin(&mut cx).is_ready()); - assert!(future.poll_unpin(&mut cx).is_pending()); -} diff --git a/futures/tests/future_inspect.rs b/futures/tests/future_inspect.rs deleted file mode 100644 index eacd1f78a2..0000000000 --- a/futures/tests/future_inspect.rs +++ /dev/null @@ -1,16 +0,0 @@ -use futures::executor::block_on; -use futures::future::{self, FutureExt}; - -#[test] -fn smoke() { - let mut counter = 0; - - { - let work = future::ready::(40).inspect(|val| { - counter += *val; - }); - assert_eq!(block_on(work), 40); - } - - assert_eq!(counter, 40); -} diff --git a/futures/tests/future_join.rs b/futures/tests/future_join.rs deleted file mode 100644 index 0556a6e62c..0000000000 --- a/futures/tests/future_join.rs +++ /dev/null @@ -1,32 +0,0 @@ -use futures::executor::block_on; -use futures::future::{self, Future}; -use std::task::Poll; - -/// This tests verifies (through miri) that self-referencing -/// futures are not invalidated when joining them. -#[test] -fn futures_join_macro_self_referential() { - block_on(async { futures::join!(yield_now(), trouble()) }); -} - -async fn trouble() { - let lucky_number = 42; - let problematic_variable = &lucky_number; - - yield_now().await; - - // problematic dereference - let _ = { *problematic_variable }; -} - -fn yield_now() -> impl Future { - let mut yielded = false; - future::poll_fn(move |cx| { - if core::mem::replace(&mut yielded, true) { - Poll::Ready(()) - } else { - cx.waker().wake_by_ref(); - Poll::Pending - } - }) -} diff --git a/futures/tests/future_join_all.rs b/futures/tests/future_join_all.rs deleted file mode 100644 index f981b6553a..0000000000 --- a/futures/tests/future_join_all.rs +++ /dev/null @@ -1,40 +0,0 @@ -use futures::executor::block_on; -use futures::future::{join_all, ready, Future, JoinAll}; -use std::fmt::Debug; -use std::pin::pin; - -#[track_caller] -fn assert_done(actual_fut: impl Future, expected: T) -where - T: PartialEq + Debug, -{ - let output = block_on(pin!(actual_fut)); - assert_eq!(output, expected); -} - -#[test] -fn collect_collects() { - assert_done(join_all(vec![ready(1), ready(2)]), vec![1, 2]); - assert_done(join_all(vec![ready(1)]), vec![1]); - // REVIEW: should this be implemented? - // assert_done(join_all(Vec::::new()), vec![]); - - // TODO: needs more tests -} - -#[test] -fn join_all_iter_lifetime() { - // In futures-rs version 0.1, this function would fail to typecheck due to an overly - // conservative type parameterization of `JoinAll`. - fn sizes(bufs: Vec<&[u8]>) -> impl Future> { - let iter = bufs.into_iter().map(|b| ready::(b.len())); - join_all(iter) - } - - assert_done(sizes(vec![&[1, 2, 3], &[], &[0]]), vec![3_usize, 0, 1]); -} - -#[test] -fn join_all_from_iter() { - assert_done(vec![ready(1), ready(2)].into_iter().collect::>(), vec![1, 2]) -} diff --git a/futures/tests/future_obj.rs b/futures/tests/future_obj.rs deleted file mode 100644 index 0e5253464e..0000000000 --- a/futures/tests/future_obj.rs +++ /dev/null @@ -1,33 +0,0 @@ -use futures::future::{Future, FutureExt, FutureObj}; -use futures::task::{Context, Poll}; -use std::pin::Pin; - -#[test] -fn dropping_does_not_segfault() { - FutureObj::new(async { String::new() }.boxed()); -} - -#[test] -fn dropping_drops_the_future() { - let mut times_dropped = 0; - - struct Inc<'a>(&'a mut u32); - - impl Future for Inc<'_> { - type Output = (); - - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { - unimplemented!() - } - } - - impl Drop for Inc<'_> { - fn drop(&mut self) { - *self.0 += 1; - } - } - - FutureObj::new(Inc(&mut times_dropped).boxed()); - - assert_eq!(times_dropped, 1); -} diff --git a/futures/tests/future_select_all.rs b/futures/tests/future_select_all.rs deleted file mode 100644 index 299b479044..0000000000 --- a/futures/tests/future_select_all.rs +++ /dev/null @@ -1,25 +0,0 @@ -use futures::executor::block_on; -use futures::future::{ready, select_all}; -use std::collections::HashSet; - -#[test] -fn smoke() { - let v = vec![ready(1), ready(2), ready(3)]; - - let mut c = vec![1, 2, 3].into_iter().collect::>(); - - let (i, idx, v) = block_on(select_all(v)); - assert!(c.remove(&i)); - assert_eq!(idx, 0); - - let (i, idx, v) = block_on(select_all(v)); - assert!(c.remove(&i)); - assert_eq!(idx, 0); - - let (i, idx, v) = block_on(select_all(v)); - assert!(c.remove(&i)); - assert_eq!(idx, 0); - - assert!(c.is_empty()); - assert!(v.is_empty()); -} diff --git a/futures/tests/future_select_ok.rs b/futures/tests/future_select_ok.rs deleted file mode 100644 index 8aec00362d..0000000000 --- a/futures/tests/future_select_ok.rs +++ /dev/null @@ -1,30 +0,0 @@ -use futures::executor::block_on; -use futures::future::{err, ok, select_ok}; - -#[test] -fn ignore_err() { - let v = vec![err(1), err(2), ok(3), ok(4)]; - - let (i, v) = block_on(select_ok(v)).ok().unwrap(); - assert_eq!(i, 3); - - assert_eq!(v.len(), 1); - - let (i, v) = block_on(select_ok(v)).ok().unwrap(); - assert_eq!(i, 4); - - assert!(v.is_empty()); -} - -#[test] -fn last_err() { - let v = vec![ok(1), err(2), err(3)]; - - let (i, v) = block_on(select_ok(v)).ok().unwrap(); - assert_eq!(i, 1); - - assert_eq!(v.len(), 2); - - let i = block_on(select_ok(v)).err().unwrap(); - assert_eq!(i, 3); -} diff --git a/futures/tests/future_shared.rs b/futures/tests/future_shared.rs deleted file mode 100644 index bd69c1d7c1..0000000000 --- a/futures/tests/future_shared.rs +++ /dev/null @@ -1,273 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::{block_on, LocalPool}; -use futures::future::{self, FutureExt, LocalFutureObj, TryFutureExt}; -use futures::task::LocalSpawn; -use std::cell::{Cell, RefCell}; -use std::panic::AssertUnwindSafe; -use std::rc::Rc; -use std::task::Poll; -use std::thread; - -struct CountClone(Rc>); - -impl Clone for CountClone { - fn clone(&self) -> Self { - self.0.set(self.0.get() + 1); - Self(self.0.clone()) - } -} - -fn send_shared_oneshot_and_wait_on_multiple_threads(threads_number: u32) { - let (tx, rx) = oneshot::channel::(); - let f = rx.shared(); - let join_handles = (0..threads_number) - .map(|_| { - let cloned_future = f.clone(); - thread::spawn(move || { - assert_eq!(block_on(cloned_future).unwrap(), 6); - }) - }) - .collect::>(); - - tx.send(6).unwrap(); - - assert_eq!(block_on(f).unwrap(), 6); - for join_handle in join_handles { - join_handle.join().unwrap(); - } -} - -#[test] -fn one_thread() { - send_shared_oneshot_and_wait_on_multiple_threads(1); -} - -#[test] -fn two_threads() { - send_shared_oneshot_and_wait_on_multiple_threads(2); -} - -#[test] -fn many_threads() { - send_shared_oneshot_and_wait_on_multiple_threads(1000); -} - -#[test] -fn drop_on_one_task_ok() { - let (tx, rx) = oneshot::channel::(); - let f1 = rx.shared(); - let f2 = f1.clone(); - - let (tx2, rx2) = oneshot::channel::(); - - let t1 = thread::spawn(|| { - let f = future::try_select(f1.map_err(|_| ()), rx2.map_err(|_| ())); - drop(block_on(f)); - }); - - let (tx3, rx3) = oneshot::channel::(); - - let t2 = thread::spawn(|| { - let _ = block_on(f2.map_ok(|x| tx3.send(x).unwrap()).map_err(|_| ())); - }); - - tx2.send(11).unwrap(); // cancel `f1` - t1.join().unwrap(); - - tx.send(42).unwrap(); // Should cause `f2` and then `rx3` to get resolved. - let result = block_on(rx3).unwrap(); - assert_eq!(result, 42); - t2.join().unwrap(); -} - -#[test] -fn drop_in_poll() { - let slot1 = Rc::new(RefCell::new(None)); - let slot2 = slot1.clone(); - - let future1 = future::lazy(move |_| { - slot2.replace(None); // Drop future - 1 - }) - .shared(); - - let future2 = LocalFutureObj::new(Box::new(future1.clone())); - slot1.replace(Some(future2)); - - assert_eq!(block_on(future1), 1); -} - -#[test] -fn peek() { - let mut local_pool = LocalPool::new(); - let spawn = &mut local_pool.spawner(); - - let (tx0, rx0) = oneshot::channel::(); - let f1 = rx0.shared(); - let f2 = f1.clone(); - - // Repeated calls on the original or clone do not change the outcome. - for _ in 0..2 { - assert!(f1.peek().is_none()); - assert!(f2.peek().is_none()); - } - - // Completing the underlying future has no effect, because the value has not been `poll`ed in. - tx0.send(42).unwrap(); - for _ in 0..2 { - assert!(f1.peek().is_none()); - assert!(f2.peek().is_none()); - } - - // Once the Shared has been polled, the value is peekable on the clone. - spawn.spawn_local_obj(LocalFutureObj::new(Box::new(f1.map(|_| ())))).unwrap(); - local_pool.run(); - for _ in 0..2 { - assert_eq!(*f2.peek().unwrap(), Ok(42)); - } -} - -#[test] -fn downgrade() { - let (tx, rx) = oneshot::channel::(); - let shared = rx.shared(); - // Since there are outstanding `Shared`s, we can get a `WeakShared`. - let weak = shared.downgrade().unwrap(); - // It should upgrade fine right now. - let mut shared2 = weak.upgrade().unwrap(); - - tx.send(42).unwrap(); - assert_eq!(block_on(shared).unwrap(), 42); - - // We should still be able to get a new `WeakShared` and upgrade it - // because `shared2` is outstanding. - assert!(shared2.downgrade().is_some()); - assert!(weak.upgrade().is_some()); - - assert_eq!(block_on(&mut shared2).unwrap(), 42); - // Now that all `Shared`s have been exhausted, we should not be able - // to get a new `WeakShared` or upgrade an existing one. - assert!(weak.upgrade().is_none()); - assert!(shared2.downgrade().is_none()); -} - -#[test] -fn ptr_eq() { - use future::FusedFuture; - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; - - let (tx, rx) = oneshot::channel::(); - let shared = rx.shared(); - let mut shared2 = shared.clone(); - let mut hasher = DefaultHasher::new(); - let mut hasher2 = DefaultHasher::new(); - - // Because these two futures share the same underlying future, - // `ptr_eq` should return true. - assert!(shared.ptr_eq(&shared2)); - // Equivalence relations are symmetric - assert!(shared2.ptr_eq(&shared)); - - // If `ptr_eq` returns true, they should hash to the same value. - shared.ptr_hash(&mut hasher); - shared2.ptr_hash(&mut hasher2); - assert_eq!(hasher.finish(), hasher2.finish()); - - tx.send(42).unwrap(); - assert_eq!(block_on(&mut shared2).unwrap(), 42); - - // Now that `shared2` has completed, `ptr_eq` should return false. - assert!(shared2.is_terminated()); - assert!(!shared.ptr_eq(&shared2)); - - // `ptr_eq` should continue to work for the other `Shared`. - let shared3 = shared.clone(); - let mut hasher3 = DefaultHasher::new(); - assert!(shared.ptr_eq(&shared3)); - - shared3.ptr_hash(&mut hasher3); - assert_eq!(hasher.finish(), hasher3.finish()); - - let (_tx, rx) = oneshot::channel::(); - let shared4 = rx.shared(); - - // And `ptr_eq` should return false for two futures that don't share - // the underlying future. - assert!(!shared.ptr_eq(&shared4)); -} - -#[test] -fn dont_clone_in_single_owner_shared_future() { - let counter = CountClone(Rc::new(Cell::new(0))); - let (tx, rx) = oneshot::channel(); - - let rx = rx.shared(); - - tx.send(counter).ok().unwrap(); - - assert_eq!(block_on(rx).unwrap().0.get(), 0); -} - -#[test] -fn dont_do_unnecessary_clones_on_output() { - let counter = CountClone(Rc::new(Cell::new(0))); - let (tx, rx) = oneshot::channel(); - - let rx = rx.shared(); - - tx.send(counter).ok().unwrap(); - - assert_eq!(block_on(rx.clone()).unwrap().0.get(), 1); - assert_eq!(block_on(rx.clone()).unwrap().0.get(), 2); - assert_eq!(block_on(rx).unwrap().0.get(), 2); -} - -#[test] -fn shared_future_that_wakes_itself_until_pending_is_returned() { - let proceed = Cell::new(false); - let fut = futures::future::poll_fn(|cx| { - if proceed.get() { - Poll::Ready(()) - } else { - cx.waker().wake_by_ref(); - Poll::Pending - } - }) - .shared(); - - // The join future can only complete if the second future gets a chance to run after the first - // has returned pending - assert_eq!(block_on(futures::future::join(fut, async { proceed.set(true) })), ((), ())); -} - -#[test] -#[should_panic(expected = "inner future panicked during poll")] -fn panic_while_poll() { - let fut = futures::future::poll_fn::(|_cx| panic!("test")).shared(); - - let fut_captured = fut.clone(); - std::panic::catch_unwind(AssertUnwindSafe(|| { - block_on(fut_captured); - })) - .unwrap_err(); - - block_on(fut); -} - -#[test] -#[should_panic(expected = "test_marker")] -fn poll_while_panic() { - struct S; - - impl Drop for S { - fn drop(&mut self) { - let fut = futures::future::ready(1).shared(); - assert_eq!(block_on(fut.clone()), 1); - assert_eq!(block_on(fut), 1); - } - } - - let _s = S {}; - panic!("test_marker"); -} diff --git a/futures/tests/future_try_flatten_stream.rs b/futures/tests/future_try_flatten_stream.rs deleted file mode 100644 index 82ae1baf2c..0000000000 --- a/futures/tests/future_try_flatten_stream.rs +++ /dev/null @@ -1,83 +0,0 @@ -use futures::executor::block_on_stream; -use futures::future::{err, ok, TryFutureExt}; -use futures::sink::Sink; -use futures::stream::Stream; -use futures::stream::{self, StreamExt}; -use futures::task::{Context, Poll}; -use std::marker::PhantomData; -use std::pin::Pin; - -#[test] -fn successful_future() { - let stream_items = vec![17, 19]; - let future_of_a_stream = ok::<_, bool>(stream::iter(stream_items).map(Ok)); - - let stream = future_of_a_stream.try_flatten_stream(); - - let mut iter = block_on_stream(stream); - assert_eq!(Ok(17), iter.next().unwrap()); - assert_eq!(Ok(19), iter.next().unwrap()); - assert_eq!(None, iter.next()); -} - -#[test] -fn failed_future() { - struct PanickingStream { - _marker: PhantomData<(T, E)>, - } - - impl Stream for PanickingStream { - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - panic!() - } - } - - let future_of_a_stream = err::, _>(10); - let stream = future_of_a_stream.try_flatten_stream(); - let mut iter = block_on_stream(stream); - assert_eq!(Err(10), iter.next().unwrap()); - assert_eq!(None, iter.next()); -} - -#[test] -fn assert_impls() { - struct StreamSink(PhantomData<(T, E, Item)>); - - impl Stream for StreamSink { - type Item = Result; - fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - panic!() - } - } - - impl Sink for StreamSink { - type Error = E; - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - panic!() - } - fn start_send(self: Pin<&mut Self>, _: Item) -> Result<(), Self::Error> { - panic!() - } - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - panic!() - } - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - panic!() - } - } - - fn assert_stream(_: &S) {} - fn assert_sink, Item>(_: &S) {} - fn assert_stream_sink, Item>(_: &S) {} - - let s = ok(StreamSink::<(), (), ()>(PhantomData)).try_flatten_stream(); - assert_stream(&s); - assert_sink(&s); - assert_stream_sink(&s); - let s = ok(StreamSink::<(), (), ()>(PhantomData)).flatten_sink(); - assert_stream(&s); - assert_sink(&s); - assert_stream_sink(&s); -} diff --git a/futures/tests/future_try_join_all.rs b/futures/tests/future_try_join_all.rs deleted file mode 100644 index 52dd117381..0000000000 --- a/futures/tests/future_try_join_all.rs +++ /dev/null @@ -1,44 +0,0 @@ -use futures::executor::block_on; -use futures::future::{err, ok, try_join_all, Future, TryJoinAll}; -use std::fmt::Debug; -use std::pin::pin; - -#[track_caller] -fn assert_done(actual_fut: impl Future, expected: T) -where - T: PartialEq + Debug, -{ - let output = block_on(pin!(actual_fut)); - assert_eq!(output, expected); -} - -#[test] -fn collect_collects() { - assert_done(try_join_all(vec![ok(1), ok(2)]), Ok::<_, usize>(vec![1, 2])); - assert_done(try_join_all(vec![ok(1), err(2)]), Err(2)); - assert_done(try_join_all(vec![ok(1)]), Ok::<_, usize>(vec![1])); - // REVIEW: should this be implemented? - // assert_done(try_join_all(Vec::::new()), Ok(vec![])); - - // TODO: needs more tests -} - -#[test] -fn try_join_all_iter_lifetime() { - // In futures-rs version 0.1, this function would fail to typecheck due to an overly - // conservative type parameterization of `TryJoinAll`. - fn sizes(bufs: Vec<&[u8]>) -> impl Future, ()>> { - let iter = bufs.into_iter().map(|b| ok::(b.len())); - try_join_all(iter) - } - - assert_done(sizes(vec![&[1, 2, 3], &[], &[0]]), Ok(vec![3_usize, 0, 1])); -} - -#[test] -fn try_join_all_from_iter() { - assert_done( - vec![ok(1), ok(2)].into_iter().collect::>(), - Ok::<_, usize>(vec![1, 2]), - ) -} diff --git a/futures/tests/io_buf_reader.rs b/futures/tests/io_buf_reader.rs deleted file mode 100644 index 7861d6d46e..0000000000 --- a/futures/tests/io_buf_reader.rs +++ /dev/null @@ -1,431 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{ - AllowStdIo, AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, - BufReader, SeekFrom, -}; -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, Pin}; - -// helper for maybe_pending_* tests -fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } -} - -// https://github.com/rust-lang/futures-rs/pull/2489#discussion_r697865719 -#[pin_project(!Unpin)] -struct Cursor { - #[pin] - inner: futures::io::Cursor, -} - -impl Cursor { - fn new(inner: T) -> Self { - Self { inner: futures::io::Cursor::new(inner) } - } -} - -impl AsyncRead for Cursor<&[u8]> { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.project().inner.poll_read(cx, buf) - } -} - -impl AsyncBufRead for Cursor<&[u8]> { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().inner.poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.project().inner.consume(amt) - } -} - -impl AsyncSeek for Cursor<&[u8]> { - fn poll_seek( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - self.project().inner.poll_seek(cx, pos) - } -} - -struct MaybePending<'a> { - inner: &'a [u8], - ready_read: bool, - ready_fill_buf: bool, -} - -impl<'a> MaybePending<'a> { - fn new(inner: &'a [u8]) -> Self { - Self { inner, ready_read: false, ready_fill_buf: false } - } -} - -impl AsyncRead for MaybePending<'_> { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - if self.ready_read { - self.ready_read = false; - Pin::new(&mut self.inner).poll_read(cx, buf) - } else { - self.ready_read = true; - Poll::Pending - } - } -} - -impl AsyncBufRead for MaybePending<'_> { - fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - if self.ready_fill_buf { - self.ready_fill_buf = false; - if self.inner.is_empty() { - return Poll::Ready(Ok(&[])); - } - let len = cmp::min(2, self.inner.len()); - Poll::Ready(Ok(&self.inner[0..len])) - } else { - self.ready_fill_buf = true; - Poll::Pending - } - } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - self.inner = &self.inner[amt..]; - } -} - -#[test] -fn test_buffered_reader() { - block_on(async { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf).await.unwrap(); - assert_eq!(nread, 3); - assert_eq!(buf, [5, 6, 7]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf).await.unwrap(); - assert_eq!(nread, 2); - assert_eq!(buf, [0, 1]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0]; - let nread = reader.read(&mut buf).await.unwrap(); - assert_eq!(nread, 1); - assert_eq!(buf, [2]); - assert_eq!(reader.buffer(), [3]); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf).await.unwrap(); - assert_eq!(nread, 1); - assert_eq!(buf, [3, 0, 0]); - assert_eq!(reader.buffer(), []); - - let nread = reader.read(&mut buf).await.unwrap(); - assert_eq!(nread, 1); - assert_eq!(buf, [4, 0, 0]); - assert_eq!(reader.buffer(), []); - - assert_eq!(reader.read(&mut buf).await.unwrap(), 0); - }); -} - -#[test] -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)); - 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][..]); - assert!(reader.seek(SeekFrom::Current(i64::MIN)).await.is_err()); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1][..]); - assert_eq!(reader.seek(SeekFrom::Current(1)).await.unwrap(), 4); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[1, 2][..]); - reader.as_mut().consume(1); - assert_eq!(reader.seek(SeekFrom::Current(-2)).await.unwrap(), 3); - }); -} - -#[test] -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)); - 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][..]); - assert!(reader.as_mut().seek_relative(0).await.is_ok()); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1][..]); - assert!(reader.as_mut().seek_relative(1).await.is_ok()); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[1][..]); - assert!(reader.as_mut().seek_relative(-1).await.is_ok()); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[0, 1][..]); - assert!(reader.as_mut().seek_relative(2).await.is_ok()); - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[2, 3][..]); - }); -} - -#[test] -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)); - let mut reader = pin!(reader); - - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[5, 6, 7][..]); - reader.as_mut().consume(3); - - let mut buffer = [0, 0, 0, 0, 0]; - assert_eq!(reader.read(&mut buffer).await.unwrap(), 5); - assert_eq!(buffer, [0, 1, 2, 3, 4]); - - assert!(reader.as_mut().seek_relative(-2).await.is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).await.unwrap(), 2); - assert_eq!(buffer, [3, 4]); - }); -} - -#[test] -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)); - let mut reader = pin!(reader); - - assert_eq!(reader.as_mut().fill_buf().await.unwrap(), &[5, 6, 7][..]); - reader.as_mut().consume(3); - - assert!(reader.seek(SeekFrom::Current(5)).await.is_ok()); - - assert!(reader.as_mut().seek_relative(-2).await.is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).await.unwrap(), 2); - assert_eq!(buffer, [3, 4]); - }); -} - -#[test] -fn test_buffered_reader_seek_underflow() { - // gimmick reader that yields its position modulo 256 for each byte - struct PositionReader { - pos: u64, - } - impl io::Read for PositionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = buf.len(); - for x in buf { - *x = self.pos as u8; - self.pos = self.pos.wrapping_add(1); - } - Ok(len) - } - } - impl io::Seek for PositionReader { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - match pos { - SeekFrom::Start(n) => { - self.pos = n; - } - SeekFrom::Current(n) => { - self.pos = self.pos.wrapping_add(n as u64); - } - SeekFrom::End(n) => { - self.pos = u64::MAX.wrapping_add(n as u64); - } - } - Ok(self.pos) - } - } - - block_on(async { - let reader = BufReader::with_capacity(5, AllowStdIo::new(PositionReader { pos: 0 })); - 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); - // the following seek will require two underlying seeks - let expected = 9_223_372_036_854_775_802; - assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).await.unwrap(), expected); - assert_eq!(reader.as_mut().fill_buf().await.unwrap().len(), 5); - // seeking to 0 should empty the buffer. - assert_eq!(reader.seek(SeekFrom::Current(0)).await.unwrap(), expected); - assert_eq!(reader.get_ref().get_ref().pos, expected); - }); -} - -#[test] -fn test_short_reads() { - /// A dummy reader intended at testing short-reads propagation. - struct ShortReader { - lengths: Vec, - } - - impl io::Read for ShortReader { - fn read(&mut self, _: &mut [u8]) -> io::Result { - if self.lengths.is_empty() { - Ok(0) - } else { - Ok(self.lengths.remove(0)) - } - } - } - - block_on(async { - let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; - let mut reader = BufReader::new(AllowStdIo::new(inner)); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf).await.unwrap(), 0); - assert_eq!(reader.read(&mut buf).await.unwrap(), 1); - assert_eq!(reader.read(&mut buf).await.unwrap(), 2); - assert_eq!(reader.read(&mut buf).await.unwrap(), 0); - assert_eq!(reader.read(&mut buf).await.unwrap(), 1); - assert_eq!(reader.read(&mut buf).await.unwrap(), 0); - assert_eq!(reader.read(&mut buf).await.unwrap(), 0); - }); -} - -#[test] -fn maybe_pending() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, MaybePending::new(inner)); - - let mut buf = [0, 0, 0]; - let nread = run(reader.read(&mut buf)); - assert_eq!(nread.unwrap(), 3); - assert_eq!(buf, [5, 6, 7]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0, 0]; - let nread = run(reader.read(&mut buf)); - assert_eq!(nread.unwrap(), 2); - assert_eq!(buf, [0, 1]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0]; - let nread = run(reader.read(&mut buf)); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [2]); - assert_eq!(reader.buffer(), [3]); - - let mut buf = [0, 0, 0]; - let nread = run(reader.read(&mut buf)); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [3, 0, 0]); - assert_eq!(reader.buffer(), []); - - let nread = run(reader.read(&mut buf)); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [4, 0, 0]); - assert_eq!(reader.buffer(), []); - - assert_eq!(run(reader.read(&mut buf)).unwrap(), 0); -} - -#[test] -fn maybe_pending_buf_read() { - let inner = MaybePending::new(&[0, 1, 2, 3, 1, 0]); - let mut reader = BufReader::with_capacity(2, inner); - let mut v = Vec::new(); - run(reader.read_until(3, &mut v)).unwrap(); - assert_eq!(v, [0, 1, 2, 3]); - v.clear(); - run(reader.read_until(1, &mut v)).unwrap(); - assert_eq!(v, [1]); - v.clear(); - run(reader.read_until(8, &mut v)).unwrap(); - assert_eq!(v, [0]); - v.clear(); - run(reader.read_until(9, &mut v)).unwrap(); - assert_eq!(v, []); -} - -// https://github.com/rust-lang/futures-rs/pull/1573#discussion_r281162309 -#[test] -fn maybe_pending_seek() { - #[pin_project] - struct MaybePendingSeek<'a> { - #[pin] - inner: Cursor<&'a [u8]>, - ready: bool, - } - - impl<'a> MaybePendingSeek<'a> { - fn new(inner: &'a [u8]) -> Self { - Self { inner: Cursor::new(inner), ready: true } - } - } - - impl AsyncRead for MaybePendingSeek<'_> { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.project().inner.poll_read(cx, buf) - } - } - - impl AsyncBufRead for MaybePendingSeek<'_> { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().inner.poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.project().inner.consume(amt) - } - } - - impl AsyncSeek for MaybePendingSeek<'_> { - fn poll_seek( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - if self.ready { - *self.as_mut().project().ready = false; - self.project().inner.poll_seek(cx, pos) - } else { - *self.project().ready = true; - Poll::Pending - } - } - } - - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let reader = BufReader::with_capacity(2, MaybePendingSeek::new(inner)); - 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][..])); - assert_eq!(run(reader.seek(SeekFrom::Current(i64::MIN))).ok(), None); - assert_eq!(run(reader.as_mut().fill_buf()).ok(), Some(&[0, 1][..])); - assert_eq!(run(reader.seek(SeekFrom::Current(1))).ok(), Some(4)); - assert_eq!(run(reader.as_mut().fill_buf()).ok(), Some(&[1, 2][..])); - Pin::new(&mut reader).consume(1); - assert_eq!(run(reader.seek(SeekFrom::Current(-2))).ok(), Some(3)); -} diff --git a/futures/tests/io_buf_writer.rs b/futures/tests/io_buf_writer.rs deleted file mode 100644 index b264cd54c2..0000000000 --- a/futures/tests/io_buf_writer.rs +++ /dev/null @@ -1,239 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{ - AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt, BufWriter, Cursor, SeekFrom, -}; -use futures::task::{Context, Poll}; -use futures_test::task::noop_context; -use std::io; -use std::pin::Pin; - -struct MaybePending { - inner: Vec, - ready: bool, -} - -impl MaybePending { - fn new(inner: Vec) -> Self { - Self { inner, ready: false } - } -} - -impl AsyncWrite for MaybePending { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - if self.ready { - self.ready = false; - Pin::new(&mut self.inner).poll_write(cx, buf) - } else { - self.ready = true; - Poll::Pending - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.inner).poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.inner).poll_close(cx) - } -} - -fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } -} - -#[test] -fn buf_writer() { - let mut writer = BufWriter::with_capacity(2, Vec::new()); - - block_on(writer.write(&[0, 1])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1]); - - block_on(writer.write(&[2])).unwrap(); - assert_eq!(writer.buffer(), [2]); - assert_eq!(*writer.get_ref(), [0, 1]); - - block_on(writer.write(&[3])).unwrap(); - assert_eq!(writer.buffer(), [2, 3]); - assert_eq!(*writer.get_ref(), [0, 1]); - - block_on(writer.flush()).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - block_on(writer.write(&[4])).unwrap(); - block_on(writer.write(&[5])).unwrap(); - assert_eq!(writer.buffer(), [4, 5]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - block_on(writer.write(&[6])).unwrap(); - assert_eq!(writer.buffer(), [6]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); - - block_on(writer.write(&[7, 8])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); - - block_on(writer.write(&[9, 10, 11])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - block_on(writer.flush()).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); -} - -#[test] -fn buf_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, Vec::new()); - block_on(w.write(&[0, 1])).unwrap(); - assert_eq!(*w.get_ref(), []); - block_on(w.flush()).unwrap(); - let w = w.into_inner(); - assert_eq!(w, [0, 1]); -} - -#[test] -fn buf_writer_seek() { - // FIXME: when https://github.com/rust-lang/futures-rs/issues/1510 fixed, - // use `Vec::new` instead of `vec![0; 8]`. - let mut w = BufWriter::with_capacity(3, Cursor::new(vec![0; 8])); - block_on(w.write_all(&[0, 1, 2, 3, 4, 5])).unwrap(); - block_on(w.write_all(&[6, 7])).unwrap(); - assert_eq!(block_on(w.seek(SeekFrom::Current(0))).ok(), Some(8)); - assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(block_on(w.seek(SeekFrom::Start(2))).ok(), Some(2)); - block_on(w.write_all(&[8, 9])).unwrap(); - block_on(w.flush()).unwrap(); - assert_eq!(&w.into_inner().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); -} - -#[test] -fn maybe_pending_buf_writer() { - let mut writer = BufWriter::with_capacity(2, MaybePending::new(Vec::new())); - - run(writer.write(&[0, 1])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(&writer.get_ref().inner, &[0, 1]); - - run(writer.write(&[2])).unwrap(); - assert_eq!(writer.buffer(), [2]); - assert_eq!(&writer.get_ref().inner, &[0, 1]); - - run(writer.write(&[3])).unwrap(); - assert_eq!(writer.buffer(), [2, 3]); - assert_eq!(&writer.get_ref().inner, &[0, 1]); - - run(writer.flush()).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(&writer.get_ref().inner, &[0, 1, 2, 3]); - - run(writer.write(&[4])).unwrap(); - run(writer.write(&[5])).unwrap(); - assert_eq!(writer.buffer(), [4, 5]); - assert_eq!(&writer.get_ref().inner, &[0, 1, 2, 3]); - - run(writer.write(&[6])).unwrap(); - assert_eq!(writer.buffer(), [6]); - assert_eq!(writer.get_ref().inner, &[0, 1, 2, 3, 4, 5]); - - run(writer.write(&[7, 8])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref().inner, &[0, 1, 2, 3, 4, 5, 6, 7, 8]); - - run(writer.write(&[9, 10, 11])).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref().inner, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - run(writer.flush()).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(&writer.get_ref().inner, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); -} - -#[test] -fn maybe_pending_buf_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, MaybePending::new(Vec::new())); - run(w.write(&[0, 1])).unwrap(); - assert_eq!(&w.get_ref().inner, &[]); - run(w.flush()).unwrap(); - let w = w.into_inner().inner; - assert_eq!(w, [0, 1]); -} - -#[test] -fn maybe_pending_buf_writer_seek() { - struct MaybePendingSeek { - inner: Cursor>, - ready_write: bool, - ready_seek: bool, - } - - impl MaybePendingSeek { - fn new(inner: Vec) -> Self { - Self { inner: Cursor::new(inner), ready_write: false, ready_seek: false } - } - } - - impl AsyncWrite for MaybePendingSeek { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - if self.ready_write { - self.ready_write = false; - Pin::new(&mut self.inner).poll_write(cx, buf) - } else { - self.ready_write = true; - Poll::Pending - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.inner).poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.inner).poll_close(cx) - } - } - - impl AsyncSeek for MaybePendingSeek { - fn poll_seek( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - pos: SeekFrom, - ) -> Poll> { - if self.ready_seek { - self.ready_seek = false; - Pin::new(&mut self.inner).poll_seek(cx, pos) - } else { - self.ready_seek = true; - Poll::Pending - } - } - } - - // FIXME: when https://github.com/rust-lang/futures-rs/issues/1510 fixed, - // use `Vec::new` instead of `vec![0; 8]`. - let mut w = BufWriter::with_capacity(3, MaybePendingSeek::new(vec![0; 8])); - run(w.write_all(&[0, 1, 2, 3, 4, 5])).unwrap(); - run(w.write_all(&[6, 7])).unwrap(); - assert_eq!(run(w.seek(SeekFrom::Current(0))).ok(), Some(8)); - assert_eq!(&w.get_ref().inner.get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(run(w.seek(SeekFrom::Start(2))).ok(), Some(2)); - run(w.write_all(&[8, 9])).unwrap(); - run(w.flush()).unwrap(); - assert_eq!(&w.into_inner().inner.into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); -} diff --git a/futures/tests/io_cursor.rs b/futures/tests/io_cursor.rs deleted file mode 100644 index 435ea5a155..0000000000 --- a/futures/tests/io_cursor.rs +++ /dev/null @@ -1,30 +0,0 @@ -use assert_matches::assert_matches; -use futures::executor::block_on; -use futures::future::lazy; -use futures::io::{AsyncWrite, Cursor}; -use futures::task::Poll; -use std::pin::Pin; - -#[test] -fn cursor_asyncwrite_vec() { - let mut cursor = Cursor::new(vec![0; 5]); - block_on(lazy(|cx| { - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(2))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(2))); - })); - assert_eq!(cursor.into_inner(), [1, 2, 3, 4, 5, 6, 6, 7]); -} - -#[test] -fn cursor_asyncwrite_box() { - let mut cursor = Cursor::new(vec![0; 5].into_boxed_slice()); - block_on(lazy(|cx| { - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(1))); - assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(0))); - })); - assert_eq!(&*cursor.into_inner(), [1, 2, 3, 4, 5]); -} diff --git a/futures/tests/io_line_writer.rs b/futures/tests/io_line_writer.rs deleted file mode 100644 index b483e0ff77..0000000000 --- a/futures/tests/io_line_writer.rs +++ /dev/null @@ -1,73 +0,0 @@ -use futures::executor::block_on; -use futures::io::{AsyncWriteExt, LineWriter}; -use std::io; - -#[test] -fn line_writer() { - let mut writer = LineWriter::new(Vec::new()); - - block_on(writer.write(&[0])).unwrap(); - assert_eq!(*writer.get_ref(), []); - - block_on(writer.write(&[1])).unwrap(); - assert_eq!(*writer.get_ref(), []); - - block_on(writer.flush()).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - block_on(writer.write(&[0, b'\n', 1, b'\n', 2])).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); - - block_on(writer.flush()).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); - - block_on(writer.write(&[3, b'\n'])).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); -} - -#[test] -fn line_vectored() { - let mut line_writer = LineWriter::new(Vec::new()); - assert_eq!( - block_on(line_writer.write_vectored(&[ - io::IoSlice::new(&[]), - io::IoSlice::new(b"\n"), - io::IoSlice::new(&[]), - io::IoSlice::new(b"a"), - ])) - .unwrap(), - 2 - ); - assert_eq!(line_writer.get_ref(), b"\n"); - - assert_eq!( - block_on(line_writer.write_vectored(&[ - io::IoSlice::new(&[]), - io::IoSlice::new(b"b"), - io::IoSlice::new(&[]), - io::IoSlice::new(b"a"), - io::IoSlice::new(&[]), - io::IoSlice::new(b"c"), - ])) - .unwrap(), - 3 - ); - assert_eq!(line_writer.get_ref(), b"\n"); - block_on(line_writer.flush()).unwrap(); - assert_eq!(line_writer.get_ref(), b"\nabac"); - assert_eq!(block_on(line_writer.write_vectored(&[])).unwrap(), 0); - - assert_eq!( - block_on(line_writer.write_vectored(&[ - io::IoSlice::new(&[]), - io::IoSlice::new(&[]), - io::IoSlice::new(&[]), - io::IoSlice::new(&[]), - ])) - .unwrap(), - 0 - ); - - assert_eq!(block_on(line_writer.write_vectored(&[io::IoSlice::new(b"a\nb")])).unwrap(), 3); - assert_eq!(line_writer.get_ref(), b"\nabaca\nb"); -} diff --git a/futures/tests/io_lines.rs b/futures/tests/io_lines.rs deleted file mode 100644 index 62afef326a..0000000000 --- a/futures/tests/io_lines.rs +++ /dev/null @@ -1,84 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{AsyncBufReadExt, AsyncRead, Cursor}; -use futures::stream::{self, StreamExt, TryStreamExt}; -use futures::task::Poll; -use futures_test::io::AsyncReadTestExt; -use futures_test::task::noop_context; - -fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } -} - -macro_rules! block_on_next { - ($expr:expr) => { - block_on($expr.next()).unwrap().unwrap() - }; -} - -macro_rules! run_next { - ($expr:expr) => { - run($expr.next()).unwrap().unwrap() - }; -} - -struct IOErrorRead(bool); - -impl AsyncRead for IOErrorRead { - fn poll_read( - mut self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - b: &mut [u8], - ) -> Poll> { - if self.0 { - Poll::Ready(Err(std::io::ErrorKind::InvalidInput.into())) - } else { - self.0 = true; - b[..16].fill(b'x'); - Ok(16).into() - } - } -} - -#[test] -fn lines() { - let buf = Cursor::new(&b"12\r"[..]); - let mut s = buf.lines(); - assert_eq!(block_on_next!(s), "12\r".to_string()); - assert!(block_on(s.next()).is_none()); - - let buf = Cursor::new(&b"12\r\n\n"[..]); - let mut s = buf.lines(); - assert_eq!(block_on_next!(s), "12".to_string()); - assert_eq!(block_on_next!(s), "".to_string()); - assert!(block_on(s.next()).is_none()); -} - -#[test] -fn maybe_pending() { - let buf = - stream::iter(vec![&b"12"[..], &b"\r"[..]]).map(Ok).into_async_read().interleave_pending(); - let mut s = buf.lines(); - assert_eq!(run_next!(s), "12\r".to_string()); - assert!(run(s.next()).is_none()); - - let buf = stream::iter(vec![&b"12"[..], &b"\r\n"[..], &b"\n"[..]]) - .map(Ok) - .into_async_read() - .interleave_pending(); - let mut s = buf.lines(); - assert_eq!(run_next!(s), "12".to_string()); - assert_eq!(run_next!(s), "".to_string()); - assert!(run(s.next()).is_none()); -} - -#[test] -fn issue2862() { - let mut lines = futures::io::BufReader::new(IOErrorRead(false)).lines(); - assert!(block_on(lines.next()).unwrap().is_err()) -} diff --git a/futures/tests/io_read.rs b/futures/tests/io_read.rs deleted file mode 100644 index 77f894c9b1..0000000000 --- a/futures/tests/io_read.rs +++ /dev/null @@ -1,66 +0,0 @@ -use futures::io::AsyncRead; -use futures_test::task::panic_context; -use std::io; -use std::pin::Pin; -use std::task::{Context, Poll}; - -type MockReaderFun = Box Poll>>; - -struct MockReader { - fun: MockReaderFun, -} - -impl MockReader { - fn new(fun: impl FnMut(&mut [u8]) -> Poll> + 'static) -> Self { - Self { fun: Box::new(fun) } - } -} - -impl AsyncRead for MockReader { - fn poll_read( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - (self.get_mut().fun)(buf) - } -} - -/// Verifies that the default implementation of `poll_read_vectored` -/// calls `poll_read` with an empty slice if no buffers are provided. -#[test] -fn read_vectored_no_buffers() { - let mut reader = MockReader::new(|buf| { - assert_eq!(buf, b""); - Err(io::ErrorKind::BrokenPipe.into()).into() - }); - let cx = &mut panic_context(); - let bufs = &mut []; - - let res = Pin::new(&mut reader).poll_read_vectored(cx, bufs); - let res = res.map_err(|e| e.kind()); - assert_eq!(res, Poll::Ready(Err(io::ErrorKind::BrokenPipe))) -} - -/// Verifies that the default implementation of `poll_read_vectored` -/// calls `poll_read` with the first non-empty buffer. -#[test] -fn read_vectored_first_non_empty() { - let mut reader = MockReader::new(|buf| { - assert_eq!(buf.len(), 4); - buf.copy_from_slice(b"four"); - Poll::Ready(Ok(4)) - }); - let cx = &mut panic_context(); - let mut buf = [0; 4]; - let bufs = &mut [ - io::IoSliceMut::new(&mut []), - io::IoSliceMut::new(&mut []), - io::IoSliceMut::new(&mut buf), - ]; - - let res = Pin::new(&mut reader).poll_read_vectored(cx, bufs); - let res = res.map_err(|e| e.kind()); - assert_eq!(res, Poll::Ready(Ok(4))); - assert_eq!(buf, b"four"[..]); -} diff --git a/futures/tests/io_read_exact.rs b/futures/tests/io_read_exact.rs deleted file mode 100644 index 6582e50b80..0000000000 --- a/futures/tests/io_read_exact.rs +++ /dev/null @@ -1,17 +0,0 @@ -use futures::executor::block_on; -use futures::io::AsyncReadExt; - -#[test] -fn read_exact() { - let mut reader: &[u8] = &[1, 2, 3, 4, 5]; - let mut out = [0u8; 3]; - - let res = block_on(reader.read_exact(&mut out)); // read 3 bytes out - assert!(res.is_ok()); - assert_eq!(out, [1, 2, 3]); - assert_eq!(reader.len(), 2); - - let res = block_on(reader.read_exact(&mut out)); // read another 3 bytes, but only 2 bytes left - assert!(res.is_err()); - assert_eq!(reader.len(), 0); -} diff --git a/futures/tests/io_read_line.rs b/futures/tests/io_read_line.rs deleted file mode 100644 index c7559c593b..0000000000 --- a/futures/tests/io_read_line.rs +++ /dev/null @@ -1,101 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{AsyncBufReadExt, Cursor}; -use futures::stream::{self, StreamExt, TryStreamExt}; -use futures::task::Poll; -use futures::AsyncRead; -use futures_test::io::AsyncReadTestExt; -use futures_test::task::noop_context; - -fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } -} - -struct IOErrorRead(bool); - -impl AsyncRead for IOErrorRead { - fn poll_read( - mut self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - b: &mut [u8], - ) -> Poll> { - if self.0 { - Poll::Ready(Err(std::io::ErrorKind::InvalidInput.into())) - } else { - self.0 = true; - b[..16].fill(b'x'); - Ok(16).into() - } - } -} - -#[test] -fn read_line() { - let mut buf = Cursor::new(b"12"); - let mut v = String::new(); - assert_eq!(block_on(buf.read_line(&mut v)).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = Cursor::new(b"12\n\n"); - let mut v = String::new(); - assert_eq!(block_on(buf.read_line(&mut v)).unwrap(), 3); - assert_eq!(v, "12\n"); - v.clear(); - assert_eq!(block_on(buf.read_line(&mut v)).unwrap(), 1); - assert_eq!(v, "\n"); - v.clear(); - assert_eq!(block_on(buf.read_line(&mut v)).unwrap(), 0); - assert_eq!(v, ""); -} - -#[test] -fn read_line_drop() { - // string contents should be preserved if the future is dropped - let mut buf = Cursor::new(b"12\n\n"); - let mut v = String::from("abc"); - drop(buf.read_line(&mut v)); - assert_eq!(v, "abc"); -} - -#[test] -fn read_line_io_error() { - let mut r = futures::io::BufReader::new(IOErrorRead(false)); - let _ = block_on(r.read_line(&mut String::new())); -} - -#[test] -fn read_line_utf8_error() { - let mut buf = Cursor::new(b"12\xFF\n\n"); - let mut v = String::from("abc"); - let res = block_on(buf.read_line(&mut v)); - assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::InvalidData); - assert_eq!(v, "abc"); -} - -#[test] -fn maybe_pending() { - let mut buf = b"12".interleave_pending(); - let mut v = String::new(); - assert_eq!(run(buf.read_line(&mut v)).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = - stream::iter(vec![&b"12"[..], &b"\n\n"[..]]).map(Ok).into_async_read().interleave_pending(); - let mut v = String::new(); - assert_eq!(run(buf.read_line(&mut v)).unwrap(), 3); - assert_eq!(v, "12\n"); - v.clear(); - assert_eq!(run(buf.read_line(&mut v)).unwrap(), 1); - assert_eq!(v, "\n"); - v.clear(); - assert_eq!(run(buf.read_line(&mut v)).unwrap(), 0); - assert_eq!(v, ""); - v.clear(); - assert_eq!(run(buf.read_line(&mut v)).unwrap(), 0); - assert_eq!(v, ""); -} diff --git a/futures/tests/io_read_to_end.rs b/futures/tests/io_read_to_end.rs deleted file mode 100644 index 0441b3bc4f..0000000000 --- a/futures/tests/io_read_to_end.rs +++ /dev/null @@ -1,65 +0,0 @@ -use futures::{ - executor::block_on, - io::{self, AsyncRead, AsyncReadExt}, - task::{Context, Poll}, -}; -use std::pin::Pin; - -#[test] -#[should_panic(expected = "assertion failed: n <= buf.len()")] -fn issue2310() { - struct MyRead { - first: bool, - } - - impl MyRead { - fn new() -> Self { - Self { first: false } - } - } - - impl AsyncRead for MyRead { - fn poll_read( - mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, - _buf: &mut [u8], - ) -> Poll> { - Poll::Ready(if !self.first { - self.first = true; - // First iteration: return more than the buffer size - Ok(64) - } else { - // Second iteration: indicate that we are done - Ok(0) - }) - } - } - - struct VecWrapper { - inner: Vec, - } - - impl VecWrapper { - fn new() -> Self { - Self { inner: Vec::new() } - } - } - - impl Drop for VecWrapper { - fn drop(&mut self) { - // Observe uninitialized bytes - println!("{:?}", &self.inner); - // Overwrite heap contents - for b in &mut self.inner { - *b = 0x90; - } - } - } - - block_on(async { - let mut vec = VecWrapper::new(); - let mut read = MyRead::new(); - - read.read_to_end(&mut vec.inner).await.unwrap(); - }) -} diff --git a/futures/tests/io_read_to_string.rs b/futures/tests/io_read_to_string.rs deleted file mode 100644 index ae6aaa21d8..0000000000 --- a/futures/tests/io_read_to_string.rs +++ /dev/null @@ -1,44 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{AsyncReadExt, Cursor}; -use futures::stream::{self, StreamExt, TryStreamExt}; -use futures::task::Poll; -use futures_test::io::AsyncReadTestExt; -use futures_test::task::noop_context; - -#[test] -fn read_to_string() { - let mut c = Cursor::new(&b""[..]); - let mut v = String::new(); - assert_eq!(block_on(c.read_to_string(&mut v)).unwrap(), 0); - assert_eq!(v, ""); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = String::new(); - assert_eq!(block_on(c.read_to_string(&mut v)).unwrap(), 1); - assert_eq!(v, "1"); - - let mut c = Cursor::new(&b"\xff"[..]); - let mut v = String::new(); - assert!(block_on(c.read_to_string(&mut v)).is_err()); -} - -#[test] -fn interleave_pending() { - fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } - } - let mut buf = stream::iter(vec![&b"12"[..], &b"33"[..], &b"3"[..]]) - .map(Ok) - .into_async_read() - .interleave_pending(); - - let mut v = String::new(); - assert_eq!(run(buf.read_to_string(&mut v)).unwrap(), 5); - assert_eq!(v, "12333"); -} diff --git a/futures/tests/io_read_until.rs b/futures/tests/io_read_until.rs deleted file mode 100644 index 71f857f4b0..0000000000 --- a/futures/tests/io_read_until.rs +++ /dev/null @@ -1,60 +0,0 @@ -use futures::executor::block_on; -use futures::future::{Future, FutureExt}; -use futures::io::{AsyncBufReadExt, Cursor}; -use futures::stream::{self, StreamExt, TryStreamExt}; -use futures::task::Poll; -use futures_test::io::AsyncReadTestExt; -use futures_test::task::noop_context; - -fn run(mut f: F) -> F::Output { - let mut cx = noop_context(); - loop { - if let Poll::Ready(x) = f.poll_unpin(&mut cx) { - return x; - } - } -} - -#[test] -fn read_until() { - let mut buf = Cursor::new(b"12"); - let mut v = Vec::new(); - assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = Cursor::new(b"1233"); - let mut v = Vec::new(); - assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 3); - assert_eq!(v, b"123"); - v.truncate(0); - assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 1); - assert_eq!(v, b"3"); - v.truncate(0); - assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 0); - assert_eq!(v, []); -} - -#[test] -fn maybe_pending() { - let mut buf = b"12".interleave_pending(); - let mut v = Vec::new(); - assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = stream::iter(vec![&b"12"[..], &b"33"[..], &b"3"[..]]) - .map(Ok) - .into_async_read() - .interleave_pending(); - let mut v = Vec::new(); - assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 3); - assert_eq!(v, b"123"); - v.clear(); - assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1); - assert_eq!(v, b"3"); - v.clear(); - assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1); - assert_eq!(v, b"3"); - v.clear(); - assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 0); - assert_eq!(v, []); -} diff --git a/futures/tests/io_window.rs b/futures/tests/io_window.rs deleted file mode 100644 index 8f0d48bc94..0000000000 --- a/futures/tests/io_window.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![allow(clippy::reversed_empty_ranges)] // This is intentional. - -use futures::io::Window; - -#[test] -fn set() { - let mut buffer = Window::new(&[1, 2, 3]); - buffer.set(..3); - assert_eq!(buffer.as_ref(), &[1, 2, 3]); - buffer.set(3..3); - assert_eq!(buffer.as_ref(), &[]); - buffer.set(3..=2); // == 3..3 - assert_eq!(buffer.as_ref(), &[]); - buffer.set(0..2); - assert_eq!(buffer.as_ref(), &[1, 2]); -} - -#[test] -#[should_panic] -fn set_panic_out_of_bounds() { - let mut buffer = Window::new(&[1, 2, 3]); - buffer.set(2..4); -} - -#[test] -#[should_panic] -fn set_panic_start_is_greater_than_end() { - let mut buffer = Window::new(&[1, 2, 3]); - buffer.set(3..2); -} diff --git a/futures/tests/io_write.rs b/futures/tests/io_write.rs deleted file mode 100644 index 661f671a5b..0000000000 --- a/futures/tests/io_write.rs +++ /dev/null @@ -1,67 +0,0 @@ -use futures::io::AsyncWrite; -use futures_test::task::panic_context; -use std::io; -use std::pin::Pin; -use std::task::{Context, Poll}; - -type MockWriterFun = Box Poll>>; - -struct MockWriter { - fun: MockWriterFun, -} - -impl MockWriter { - fn new(fun: impl FnMut(&[u8]) -> Poll> + 'static) -> Self { - Self { fun: Box::new(fun) } - } -} - -impl AsyncWrite for MockWriter { - fn poll_write( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - (self.get_mut().fun)(buf) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - panic!() - } - - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - panic!() - } -} - -/// Verifies that the default implementation of `poll_write_vectored` -/// calls `poll_write` with an empty slice if no buffers are provided. -#[test] -fn write_vectored_no_buffers() { - let mut writer = MockWriter::new(|buf| { - assert_eq!(buf, b""); - Err(io::ErrorKind::BrokenPipe.into()).into() - }); - let cx = &mut panic_context(); - let bufs = &mut []; - - let res = Pin::new(&mut writer).poll_write_vectored(cx, bufs); - let res = res.map_err(|e| e.kind()); - assert_eq!(res, Poll::Ready(Err(io::ErrorKind::BrokenPipe))) -} - -/// Verifies that the default implementation of `poll_write_vectored` -/// calls `poll_write` with the first non-empty buffer. -#[test] -fn write_vectored_first_non_empty() { - let mut writer = MockWriter::new(|buf| { - assert_eq!(buf, b"four"); - Poll::Ready(Ok(4)) - }); - let cx = &mut panic_context(); - let bufs = &mut [io::IoSlice::new(&[]), io::IoSlice::new(&[]), io::IoSlice::new(b"four")]; - - let res = Pin::new(&mut writer).poll_write_vectored(cx, bufs); - let res = res.map_err(|e| e.kind()); - assert_eq!(res, Poll::Ready(Ok(4))); -} diff --git a/futures/tests/lock_mutex.rs b/futures/tests/lock_mutex.rs deleted file mode 100644 index c15e76bd84..0000000000 --- a/futures/tests/lock_mutex.rs +++ /dev/null @@ -1,69 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::{block_on, ThreadPool}; -use futures::future::{ready, FutureExt}; -use futures::lock::Mutex; -use futures::stream::StreamExt; -use futures::task::{Context, SpawnExt}; -use futures_test::future::FutureTestExt; -use futures_test::task::{new_count_waker, panic_context}; -use std::sync::Arc; - -#[test] -fn mutex_acquire_uncontested() { - let mutex = Mutex::new(()); - for _ in 0..10 { - assert!(mutex.lock().poll_unpin(&mut panic_context()).is_ready()); - } -} - -#[test] -fn mutex_wakes_waiters() { - let mutex = Mutex::new(()); - let (waker, counter) = new_count_waker(); - let lock = mutex.lock().poll_unpin(&mut panic_context()); - assert!(lock.is_ready()); - - let mut cx = Context::from_waker(&waker); - let mut waiter = mutex.lock(); - assert!(waiter.poll_unpin(&mut cx).is_pending()); - assert_eq!(counter, 0); - - drop(lock); - - assert_eq!(counter, 1); - assert!(waiter.poll_unpin(&mut panic_context()).is_ready()); -} - -#[test] -fn mutex_contested() { - { - let (tx, mut rx) = mpsc::unbounded(); - let pool = ThreadPool::builder().pool_size(16).create().unwrap(); - - let tx = Arc::new(tx); - let mutex = Arc::new(Mutex::new(0)); - - let num_tasks = 1000; - for _ in 0..num_tasks { - let tx = tx.clone(); - let mutex = mutex.clone(); - pool.spawn(async move { - let mut lock = mutex.lock().await; - ready(()).pending_once().await; - *lock += 1; - tx.unbounded_send(()).unwrap(); - drop(lock); - }) - .unwrap(); - } - - block_on(async { - for _ in 0..num_tasks { - rx.next().await.unwrap(); - } - let lock = mutex.lock().await; - assert_eq!(num_tasks, *lock); - }); - } - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -} diff --git a/futures/tests/macro-reexport/Cargo.toml b/futures/tests/macro-reexport/Cargo.toml deleted file mode 100644 index 8584fc1afd..0000000000 --- a/futures/tests/macro-reexport/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "macro-reexport" -version = "0.0.0" -edition = "2018" -publish = false - -[dependencies] -futures04 = { path = "../..", package = "futures" } - -[lints] -workspace = true diff --git a/futures/tests/macro-reexport/src/lib.rs b/futures/tests/macro-reexport/src/lib.rs deleted file mode 100644 index 0d6727b0e6..0000000000 --- a/futures/tests/macro-reexport/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// normal reexport -pub use futures04::{join, select, select_biased, try_join}; - -// reexport + rename -pub use futures04::{ - join as join2, select as select2, select_biased as select_biased2, try_join as try_join2, -}; diff --git a/futures/tests/macro-tests/Cargo.toml b/futures/tests/macro-tests/Cargo.toml deleted file mode 100644 index 5c248d04da..0000000000 --- a/futures/tests/macro-tests/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "macro-tests" -version = "0.0.0" -edition = "2018" -publish = false - -[dependencies] -futures04 = { path = "../..", package = "futures" } -macro-reexport = { path = "../macro-reexport" } - -[lints] -workspace = true diff --git a/futures/tests/macro-tests/src/main.rs b/futures/tests/macro-tests/src/main.rs deleted file mode 100644 index c89397ddd3..0000000000 --- a/futures/tests/macro-tests/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Check that it works even if proc-macros are reexported. - -fn main() { - use futures04::{executor::block_on, future}; - - // join! macro - block_on(async { - let _ = futures04::join!(async {}, async {}); - let _ = macro_reexport::join!(async {}, async {}); - let _ = macro_reexport::join2!(async {}, async {}); - }); - - // try_join! macro - let _ = block_on(async { - let _ = futures04::try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) }); - let _ = macro_reexport::try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) }); - let _ = macro_reexport::try_join2!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) }); - Ok::<(), ()>(()) - }); - - // select! macro - block_on(async { - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - futures04::select! { - _ = a => {}, - _ = b => unreachable!(), - }; - - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - macro_reexport::select! { - _ = a => {}, - _ = b => unreachable!(), - }; - - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - macro_reexport::select2! { - _ = a => {}, - _ = b => unreachable!(), - }; - }); - - // select_biased! macro - block_on(async { - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - futures04::select_biased! { - _ = a => {}, - _ = b => unreachable!(), - }; - - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - macro_reexport::select_biased! { - _ = a => {}, - _ = b => unreachable!(), - }; - - let mut a = future::ready(()); - let mut b = future::pending::<()>(); - macro_reexport::select_biased2! { - _ = a => {}, - _ = b => unreachable!(), - }; - }); -} diff --git a/futures/tests/macro_comma_support.rs b/futures/tests/macro_comma_support.rs deleted file mode 100644 index 85871e98be..0000000000 --- a/futures/tests/macro_comma_support.rs +++ /dev/null @@ -1,43 +0,0 @@ -use futures::{ - executor::block_on, - future::{self, FutureExt}, - join, ready, - task::Poll, - try_join, -}; - -#[test] -fn ready() { - block_on(future::poll_fn(|_| { - ready!(Poll::Ready(()),); - Poll::Ready(()) - })) -} - -#[test] -fn poll() { - use futures::poll; - - block_on(async { - let _ = poll!(async {}.boxed(),); - }) -} - -#[test] -fn join() { - block_on(async { - let future1 = async { 1 }; - let future2 = async { 2 }; - join!(future1, future2,); - }) -} - -#[test] -fn try_join() { - block_on(async { - let future1 = async { 1 }.never_error(); - let future2 = async { 2 }.never_error(); - try_join!(future1, future2,) - }) - .unwrap(); -} diff --git a/futures/tests/no-std/Cargo.toml b/futures/tests/no-std/Cargo.toml deleted file mode 100644 index ec7d4c7871..0000000000 --- a/futures/tests/no-std/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "no-std" -version = "0.0.0" -edition = "2018" -publish = false - -[features] -futures-core-alloc = ["futures-core/alloc"] -futures-task-alloc = ["futures-task/alloc"] -futures-channel-alloc = ["futures-channel/alloc"] -futures-util-alloc = ["futures-util/alloc"] -futures-util-async-await = ["futures-util/async-await"] -futures-alloc = ["futures/alloc"] -futures-async-await = ["futures/async-await"] - -[dependencies] -futures-core = { path = "../../../futures-core", optional = true, default-features = false } -futures-task = { path = "../../../futures-task", optional = true, default-features = false } -futures-channel = { path = "../../../futures-channel", optional = true, default-features = false } -futures-util = { path = "../../../futures-util", optional = true, default-features = false } -futures = { path = "../..", optional = true, default-features = false } - -[lints] -workspace = true diff --git a/futures/tests/no-std/build.rs b/futures/tests/no-std/build.rs deleted file mode 100644 index 73d2a7b52b..0000000000 --- a/futures/tests/no-std/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::{env, process::Command}; - -fn main() { - println!("cargo:rustc-check-cfg=cfg(nightly)"); - if is_nightly() { - println!("cargo:rustc-cfg=nightly"); - } -} - -fn is_nightly() -> bool { - env::var_os("RUSTC") - .and_then(|rustc| Command::new(rustc).arg("--version").output().ok()) - .and_then(|output| String::from_utf8(output.stdout).ok()) - .is_some_and(|version| version.contains("nightly") || version.contains("dev")) -} diff --git a/futures/tests/no-std/src/lib.rs b/futures/tests/no-std/src/lib.rs deleted file mode 100644 index 7209e7f6a1..0000000000 --- a/futures/tests/no-std/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![cfg(nightly)] -#![no_std] -#![allow(unused_imports)] - -#[cfg(feature = "futures-core-alloc")] -#[cfg(target_has_atomic = "ptr")] -pub use futures_core::task::__internal::AtomicWaker as _; - -#[cfg(feature = "futures-task-alloc")] -#[cfg(target_has_atomic = "ptr")] -pub use futures_task::ArcWake as _; - -#[cfg(feature = "futures-channel-alloc")] -#[cfg(target_has_atomic = "ptr")] -pub use futures_channel::oneshot as _; - -#[cfg(any(feature = "futures", feature = "futures-alloc"))] -#[cfg(target_has_atomic = "ptr")] -pub use futures::task::AtomicWaker as _; - -#[cfg(feature = "futures-alloc")] -#[cfg(target_has_atomic = "ptr")] -pub use futures::stream::FuturesOrdered as _; - -#[cfg(any(feature = "futures-util", feature = "futures-util-alloc"))] -#[cfg(target_has_atomic = "ptr")] -pub use futures_util::task::AtomicWaker as _; - -#[cfg(feature = "futures-util-alloc")] -#[cfg(target_has_atomic = "ptr")] -pub use futures_util::stream::FuturesOrdered as _; diff --git a/futures/tests/object_safety.rs b/futures/tests/object_safety.rs deleted file mode 100644 index 76d696bf4b..0000000000 --- a/futures/tests/object_safety.rs +++ /dev/null @@ -1,49 +0,0 @@ -fn assert_is_object_safe() {} - -#[test] -fn future() { - // `FutureExt`, `TryFutureExt` and `UnsafeFutureObj` are not object safe. - use futures::future::{FusedFuture, Future, TryFuture}; - - assert_is_object_safe::>(); - assert_is_object_safe::>(); - assert_is_object_safe::>>(); -} - -#[test] -fn stream() { - // `StreamExt` and `TryStreamExt` are not object safe. - use futures::stream::{FusedStream, Stream, TryStream}; - - assert_is_object_safe::>(); - assert_is_object_safe::>(); - assert_is_object_safe::>>(); -} - -#[test] -fn sink() { - // `SinkExt` is not object safe. - use futures::sink::Sink; - - assert_is_object_safe::>(); -} - -#[test] -fn io() { - // `AsyncReadExt`, `AsyncWriteExt`, `AsyncSeekExt` and `AsyncBufReadExt` are not object safe. - use futures::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite}; - - assert_is_object_safe::(); - assert_is_object_safe::(); - assert_is_object_safe::(); - assert_is_object_safe::(); -} - -#[test] -fn task() { - // `ArcWake`, `SpawnExt` and `LocalSpawnExt` are not object safe. - use futures::task::{LocalSpawn, Spawn}; - - assert_is_object_safe::(); - assert_is_object_safe::(); -} diff --git a/futures/tests/oneshot.rs b/futures/tests/oneshot.rs deleted file mode 100644 index bc005f0688..0000000000 --- a/futures/tests/oneshot.rs +++ /dev/null @@ -1,78 +0,0 @@ -use futures::channel::oneshot; -use futures::future::{FutureExt, TryFutureExt}; -use futures_test::future::FutureTestExt; -use std::sync::mpsc; -use std::thread; - -#[test] -fn oneshot_send1() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - - let t = thread::spawn(|| tx1.send(1).unwrap()); - rx1.map_ok(move |x| tx2.send(x)).run_in_background(); - assert_eq!(1, rx2.recv().unwrap()); - t.join().unwrap(); -} - -#[test] -fn oneshot_send2() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - - thread::spawn(|| tx1.send(1).unwrap()).join().unwrap(); - rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background(); - assert_eq!(1, rx2.recv().unwrap()); -} - -#[test] -fn oneshot_send3() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - - rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background(); - thread::spawn(|| tx1.send(1).unwrap()).join().unwrap(); - assert_eq!(1, rx2.recv().unwrap()); -} - -#[test] -fn oneshot_drop_tx1() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - - drop(tx1); - rx1.map(move |result| tx2.send(result).unwrap()).run_in_background(); - - assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap()); -} - -#[test] -fn oneshot_drop_tx2() { - let (tx1, rx1) = oneshot::channel::(); - let (tx2, rx2) = mpsc::channel(); - - let t = thread::spawn(|| drop(tx1)); - rx1.map(move |result| tx2.send(result).unwrap()).run_in_background(); - t.join().unwrap(); - - assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap()); -} - -#[test] -fn oneshot_drop_rx() { - let (tx, rx) = oneshot::channel::(); - drop(rx); - assert_eq!(Err(2), tx.send(2)); -} - -#[test] -fn oneshot_debug() { - let (tx, rx) = oneshot::channel::(); - assert_eq!(format!("{tx:?}"), "Sender { complete: false }"); - assert_eq!(format!("{rx:?}"), "Receiver { complete: false }"); - drop(rx); - assert_eq!(format!("{tx:?}"), "Sender { complete: true }"); - let (tx, rx) = oneshot::channel::(); - drop(tx); - assert_eq!(format!("{rx:?}"), "Receiver { complete: true }"); -} diff --git a/futures/tests/ready_queue.rs b/futures/tests/ready_queue.rs deleted file mode 100644 index c19d62593c..0000000000 --- a/futures/tests/ready_queue.rs +++ /dev/null @@ -1,148 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::{block_on, block_on_stream}; -use futures::future; -use futures::stream::{FuturesUnordered, StreamExt}; -use futures::task::Poll; -use futures_test::task::noop_context; -use std::panic::{self, AssertUnwindSafe}; -use std::sync::{Arc, Barrier}; -use std::thread; - -#[test] -fn basic_usage() { - block_on(future::lazy(move |cx| { - let mut queue = FuturesUnordered::new(); - let (tx1, rx1) = oneshot::channel(); - let (tx2, rx2) = oneshot::channel(); - let (tx3, rx3) = oneshot::channel(); - - queue.push(rx1); - queue.push(rx2); - queue.push(rx3); - - assert!(!queue.poll_next_unpin(cx).is_ready()); - - tx2.send("hello").unwrap(); - - assert_eq!(Poll::Ready(Some(Ok("hello"))), queue.poll_next_unpin(cx)); - assert!(!queue.poll_next_unpin(cx).is_ready()); - - tx1.send("world").unwrap(); - tx3.send("world2").unwrap(); - - assert_eq!(Poll::Ready(Some(Ok("world"))), queue.poll_next_unpin(cx)); - assert_eq!(Poll::Ready(Some(Ok("world2"))), queue.poll_next_unpin(cx)); - assert_eq!(Poll::Ready(None), queue.poll_next_unpin(cx)); - })); -} - -#[test] -fn resolving_errors() { - block_on(future::lazy(move |cx| { - let mut queue = FuturesUnordered::new(); - let (tx1, rx1) = oneshot::channel(); - let (tx2, rx2) = oneshot::channel(); - let (tx3, rx3) = oneshot::channel(); - - queue.push(rx1); - queue.push(rx2); - queue.push(rx3); - - assert!(!queue.poll_next_unpin(cx).is_ready()); - - drop(tx2); - - assert_eq!(Poll::Ready(Some(Err(oneshot::Canceled))), queue.poll_next_unpin(cx)); - assert!(!queue.poll_next_unpin(cx).is_ready()); - - drop(tx1); - tx3.send("world2").unwrap(); - - assert_eq!(Poll::Ready(Some(Err(oneshot::Canceled))), queue.poll_next_unpin(cx)); - assert_eq!(Poll::Ready(Some(Ok("world2"))), queue.poll_next_unpin(cx)); - assert_eq!(Poll::Ready(None), queue.poll_next_unpin(cx)); - })); -} - -#[test] -fn dropping_ready_queue() { - block_on(future::lazy(move |_| { - let queue = FuturesUnordered::new(); - let (mut tx1, rx1) = oneshot::channel::<()>(); - let (mut tx2, rx2) = oneshot::channel::<()>(); - let (mut tx3, rx3) = oneshot::channel::<()>(); - - queue.push(rx1); - queue.push(rx2); - queue.push(rx3); - - { - let cx = &mut noop_context(); - assert!(!tx1.poll_canceled(cx).is_ready()); - assert!(!tx2.poll_canceled(cx).is_ready()); - assert!(!tx3.poll_canceled(cx).is_ready()); - - drop(queue); - - assert!(tx1.poll_canceled(cx).is_ready()); - assert!(tx2.poll_canceled(cx).is_ready()); - assert!(tx3.poll_canceled(cx).is_ready()); - } - })); -} - -#[test] -fn stress() { - const ITER: usize = if cfg!(miri) { 30 } else { 300 }; - - for i in 0..ITER { - let n = (i % 10) + 1; - - let mut queue = FuturesUnordered::new(); - - for _ in 0..5 { - let barrier = Arc::new(Barrier::new(n + 1)); - - for num in 0..n { - let barrier = barrier.clone(); - let (tx, rx) = oneshot::channel(); - - queue.push(rx); - - thread::spawn(move || { - barrier.wait(); - tx.send(num).unwrap(); - }); - } - - barrier.wait(); - - let mut sync = block_on_stream(queue); - - let mut rx: Vec<_> = (&mut sync).take(n).map(|res| res.unwrap()).collect(); - - assert_eq!(rx.len(), n); - - rx.sort_unstable(); - - for (i, x) in rx.into_iter().enumerate() { - assert_eq!(i, x); - } - - queue = sync.into_inner(); - } - } -} - -#[test] -fn panicking_future_dropped() { - block_on(future::lazy(move |cx| { - let mut queue = FuturesUnordered::new(); - queue.push(future::poll_fn(|_| -> Poll> { panic!() })); - - let r = panic::catch_unwind(AssertUnwindSafe(|| queue.poll_next_unpin(cx))); - assert!(r.is_err()); - assert!(queue.is_empty()); - assert_eq!(Poll::Ready(None), queue.poll_next_unpin(cx)); - })); -} diff --git a/futures/tests/recurse.rs b/futures/tests/recurse.rs deleted file mode 100644 index d81753c9d7..0000000000 --- a/futures/tests/recurse.rs +++ /dev/null @@ -1,25 +0,0 @@ -use futures::executor::block_on; -use futures::future::{self, BoxFuture, FutureExt}; -use std::sync::mpsc; -use std::thread; - -#[test] -fn lots() { - #[cfg(not(futures_sanitizer))] - const N: i32 = 1_000; - #[cfg(futures_sanitizer)] // If N is many, asan reports stack-overflow: https://gist.github.com/taiki-e/099446d21cbec69d4acbacf7a9646136 - const N: i32 = 100; - - fn do_it(input: (i32, i32)) -> BoxFuture<'static, i32> { - let (n, x) = input; - if n == 0 { - future::ready(x).boxed() - } else { - future::ready((n - 1, x + n)).then(do_it).boxed() - } - } - - let (tx, rx) = mpsc::channel(); - thread::spawn(|| block_on(do_it((N, 0)).map(move |x| tx.send(x).unwrap()))); - assert_eq!((0..=N).sum::(), rx.recv().unwrap()); -} diff --git a/futures/tests/sink.rs b/futures/tests/sink.rs deleted file mode 100644 index ed86e88197..0000000000 --- a/futures/tests/sink.rs +++ /dev/null @@ -1,554 +0,0 @@ -use futures::channel::{mpsc, oneshot}; -use futures::executor::block_on; -use futures::future::{self, poll_fn, Future, FutureExt, TryFutureExt}; -use futures::ready; -use futures::sink::{self, Sink, SinkErrInto, SinkExt}; -use futures::stream::{self, Stream, StreamExt}; -use futures::task::{self, ArcWake, Context, Poll, Waker}; -use futures_test::task::panic_context; -use std::cell::{Cell, RefCell}; -use std::collections::VecDeque; -use std::convert::Infallible; -use std::fmt; -use std::mem; -use std::pin::{pin, Pin}; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -fn sassert_next(s: &mut S, item: S::Item) -where - S: Stream + Unpin, - S::Item: Eq + fmt::Debug, -{ - match s.poll_next_unpin(&mut panic_context()) { - Poll::Ready(None) => panic!("stream is at its end"), - Poll::Ready(Some(e)) => assert_eq!(e, item), - Poll::Pending => panic!("stream wasn't ready"), - } -} - -fn unwrap(x: Poll>) -> T { - match x { - Poll::Ready(Ok(x)) => x, - Poll::Ready(Err(_)) => panic!("Poll::Ready(Err(_))"), - Poll::Pending => panic!("Poll::Pending"), - } -} - -// An Unpark struct that records unpark events for inspection -struct Flag(AtomicBool); - -impl Flag { - fn new() -> Arc { - Arc::new(Self(AtomicBool::new(false))) - } - - fn take(&self) -> bool { - self.0.swap(false, Ordering::SeqCst) - } - - fn set(&self, v: bool) { - self.0.store(v, Ordering::SeqCst) - } -} - -impl ArcWake for Flag { - fn wake_by_ref(arc_self: &Arc) { - arc_self.set(true) - } -} - -fn flag_cx(f: F) -> R -where - F: FnOnce(Arc, &mut Context<'_>) -> R, -{ - let flag = Flag::new(); - let waker = task::waker_ref(&flag); - let cx = &mut Context::from_waker(&waker); - f(flag.clone(), cx) -} - -// Sends a value on an i32 channel sink -struct StartSendFut + Unpin, Item: Unpin>(Option, Option); - -impl + Unpin, Item: Unpin> StartSendFut { - fn new(sink: S, item: Item) -> Self { - Self(Some(sink), Some(item)) - } -} - -impl + Unpin, Item: Unpin> Future for StartSendFut { - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self(inner, item) = self.get_mut(); - { - let mut inner = inner.as_mut().unwrap(); - ready!(Pin::new(&mut inner).poll_ready(cx))?; - Pin::new(&mut inner).start_send(item.take().unwrap())?; - } - Poll::Ready(Ok(inner.take().unwrap())) - } -} - -// Immediately accepts all requests to start pushing, but completion is managed -// by manually flushing -struct ManualFlush { - data: Vec, - waiting_tasks: Vec, -} - -impl Sink> for ManualFlush { - type Error = (); - - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn start_send(mut self: Pin<&mut Self>, item: Option) -> Result<(), Self::Error> { - if let Some(item) = item { - self.data.push(item); - } else { - self.force_flush(); - } - Ok(()) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.data.is_empty() { - Poll::Ready(Ok(())) - } else { - self.waiting_tasks.push(cx.waker().clone()); - Poll::Pending - } - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } -} - -impl ManualFlush { - fn new() -> Self { - Self { data: Vec::new(), waiting_tasks: Vec::new() } - } - - fn force_flush(&mut self) -> Vec { - for task in self.waiting_tasks.drain(..) { - task.wake() - } - mem::take(&mut self.data) - } -} - -struct ManualAllow { - data: Vec, - allow: Rc, -} - -struct Allow { - flag: Cell, - tasks: RefCell>, -} - -impl Allow { - fn new() -> Self { - Self { flag: Cell::new(false), tasks: RefCell::new(Vec::new()) } - } - - fn check(&self, cx: &mut Context<'_>) -> bool { - if self.flag.get() { - true - } else { - self.tasks.borrow_mut().push(cx.waker().clone()); - false - } - } - - fn start(&self) { - self.flag.set(true); - let mut tasks = self.tasks.borrow_mut(); - for task in tasks.drain(..) { - task.wake(); - } - } -} - -impl Sink for ManualAllow { - type Error = (); - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.allow.check(cx) { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - } - - fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { - self.data.push(item); - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -fn manual_allow() -> (ManualAllow, Rc) { - let allow = Rc::new(Allow::new()); - let manual_allow = ManualAllow { data: Vec::new(), allow: allow.clone() }; - (manual_allow, allow) -} - -#[test] -fn either_sink() { - let mut s = - if true { Vec::::new().left_sink() } else { VecDeque::::new().right_sink() }; - - Pin::new(&mut s).start_send(0).unwrap(); -} - -#[test] -fn vec_sink() { - let mut v = Vec::new(); - Pin::new(&mut v).start_send(0).unwrap(); - Pin::new(&mut v).start_send(1).unwrap(); - assert_eq!(v, vec![0, 1]); - block_on(v.flush()).unwrap(); - assert_eq!(v, vec![0, 1]); -} - -#[test] -fn vecdeque_sink() { - let mut deque = VecDeque::new(); - Pin::new(&mut deque).start_send(2).unwrap(); - Pin::new(&mut deque).start_send(3).unwrap(); - - assert_eq!(deque.pop_front(), Some(2)); - assert_eq!(deque.pop_front(), Some(3)); - assert_eq!(deque.pop_front(), None); -} - -#[test] -fn send() { - let mut v = Vec::new(); - - block_on(v.send(0)).unwrap(); - assert_eq!(v, vec![0]); - - block_on(v.send(1)).unwrap(); - assert_eq!(v, vec![0, 1]); - - block_on(v.send(2)).unwrap(); - assert_eq!(v, vec![0, 1, 2]); -} - -#[test] -fn send_all() { - let mut v = Vec::new(); - - block_on(v.send_all(&mut stream::iter(vec![0, 1]).map(Ok))).unwrap(); - assert_eq!(v, vec![0, 1]); - - block_on(v.send_all(&mut stream::iter(vec![2, 3]).map(Ok))).unwrap(); - assert_eq!(v, vec![0, 1, 2, 3]); - - block_on(v.send_all(&mut stream::iter(vec![4, 5]).map(Ok))).unwrap(); - assert_eq!(v, vec![0, 1, 2, 3, 4, 5]); -} - -// Test that `start_send` on an `mpsc` channel does indeed block when the -// channel is full -#[test] -fn mpsc_blocking_start_send() { - let (mut tx, mut rx) = mpsc::channel::(0); - - block_on(future::lazy(|_| { - tx.start_send(0).unwrap(); - - flag_cx(|flag, cx| { - let mut task = StartSendFut::new(tx, 1); - - assert!(task.poll_unpin(cx).is_pending()); - assert!(!flag.take()); - sassert_next(&mut rx, 0); - assert!(flag.take()); - unwrap(task.poll_unpin(cx)); - assert!(!flag.take()); - sassert_next(&mut rx, 1); - }) - })); -} - -// test `flush` by using `with` to make the first insertion into a sink block -// until a oneshot is completed -#[test] -fn with_flush() { - let (tx, rx) = oneshot::channel(); - let mut block = rx.boxed(); - let mut sink = Vec::new().with(|elem| { - mem::replace(&mut block, future::ok(()).boxed()) - .map_ok(move |()| elem + 1) - .map_err(|_| -> Infallible { panic!() }) - }); - - assert_eq!(Pin::new(&mut sink).start_send(0).ok(), Some(())); - - flag_cx(|flag, cx| { - let mut task = sink.flush(); - assert!(task.poll_unpin(cx).is_pending()); - tx.send(()).unwrap(); - assert!(flag.take()); - - unwrap(task.poll_unpin(cx)); - - block_on(sink.send(1)).unwrap(); - assert_eq!(sink.get_ref(), &[1, 2]); - }) -} - -// test simple use of with to change data -#[test] -fn with_as_map() { - let mut sink = Vec::new().with(|item| future::ok::(item * 2)); - block_on(sink.send(0)).unwrap(); - block_on(sink.send(1)).unwrap(); - block_on(sink.send(2)).unwrap(); - assert_eq!(sink.get_ref(), &[0, 2, 4]); -} - -// test simple use of with_flat_map -#[test] -fn with_flat_map() { - let mut sink = Vec::new().with_flat_map(|item| stream::iter(vec![item; item]).map(Ok)); - block_on(sink.send(0)).unwrap(); - block_on(sink.send(1)).unwrap(); - block_on(sink.send(2)).unwrap(); - block_on(sink.send(3)).unwrap(); - assert_eq!(sink.get_ref(), &[1, 2, 2, 3, 3, 3]); -} - -// Check that `with` propagates `poll_ready` to the inner sink. -// Regression test for the issue #1834. -#[test] -fn with_propagates_poll_ready() { - let (tx, mut rx) = mpsc::channel::(0); - let mut tx = tx.with(|item: i32| future::ok::(item + 10)); - - block_on(future::lazy(|_| { - flag_cx(|flag, cx| { - let mut tx = Pin::new(&mut tx); - - // Should be ready for the first item. - assert_eq!(tx.as_mut().poll_ready(cx), Poll::Ready(Ok(()))); - assert_eq!(tx.as_mut().start_send(0), Ok(())); - - // Should be ready for the second item only after the first one is received. - assert_eq!(tx.as_mut().poll_ready(cx), Poll::Pending); - assert!(!flag.take()); - sassert_next(&mut rx, 10); - assert!(flag.take()); - assert_eq!(tx.as_mut().poll_ready(cx), Poll::Ready(Ok(()))); - assert_eq!(tx.as_mut().start_send(1), Ok(())); - }) - })); -} - -// test that the `with` sink doesn't require the underlying sink to flush, -// but doesn't claim to be flushed until the underlying sink is -#[test] -fn with_flush_propagate() { - let mut sink = ManualFlush::new().with(future::ok::, ()>); - flag_cx(|flag, cx| { - unwrap(Pin::new(&mut sink).poll_ready(cx)); - Pin::new(&mut sink).start_send(Some(0)).unwrap(); - unwrap(Pin::new(&mut sink).poll_ready(cx)); - Pin::new(&mut sink).start_send(Some(1)).unwrap(); - - { - let mut task = sink.flush(); - assert!(task.poll_unpin(cx).is_pending()); - assert!(!flag.take()); - } - assert_eq!(sink.get_mut().force_flush(), vec![0, 1]); - assert!(flag.take()); - unwrap(sink.flush().poll_unpin(cx)); - }) -} - -// test that `Clone` is implemented on `with` sinks -#[test] -fn with_implements_clone() { - let (mut tx, rx) = mpsc::channel(5); - - { - let mut is_positive = tx.clone().with(|item| future::ok::(item > 0)); - - let mut is_long = - tx.clone().with(|item: &str| future::ok::(item.len() > 5)); - - block_on(is_positive.clone().send(-1)).unwrap(); - block_on(is_long.clone().send("123456")).unwrap(); - block_on(is_long.send("123")).unwrap(); - block_on(is_positive.send(1)).unwrap(); - } - - block_on(tx.send(false)).unwrap(); - - block_on(tx.close()).unwrap(); - - assert_eq!(block_on(rx.collect::>()), vec![false, true, false, true, false]); -} - -// test that a buffer is a no-nop around a sink that always accepts sends -#[test] -fn buffer_noop() { - let mut sink = Vec::new().buffer(0); - block_on(sink.send(0)).unwrap(); - block_on(sink.send(1)).unwrap(); - assert_eq!(sink.get_ref(), &[0, 1]); - - let mut sink = Vec::new().buffer(1); - block_on(sink.send(0)).unwrap(); - block_on(sink.send(1)).unwrap(); - assert_eq!(sink.get_ref(), &[0, 1]); -} - -// test basic buffer functionality, including both filling up to capacity, -// and writing out when the underlying sink is ready -#[test] -fn buffer() { - let (sink, allow) = manual_allow::(); - let sink = sink.buffer(2); - - let sink = block_on(StartSendFut::new(sink, 0)).unwrap(); - let mut sink = block_on(StartSendFut::new(sink, 1)).unwrap(); - - flag_cx(|flag, cx| { - let mut task = sink.send(2); - assert!(task.poll_unpin(cx).is_pending()); - assert!(!flag.take()); - allow.start(); - assert!(flag.take()); - unwrap(task.poll_unpin(cx)); - assert_eq!(sink.get_ref().data, vec![0, 1, 2]); - }) -} - -#[test] -fn fanout_smoke() { - let sink1 = Vec::new(); - let sink2 = Vec::new(); - let mut sink = sink1.fanout(sink2); - block_on(sink.send_all(&mut stream::iter(vec![1, 2, 3]).map(Ok))).unwrap(); - let (sink1, sink2) = sink.into_inner(); - assert_eq!(sink1, vec![1, 2, 3]); - assert_eq!(sink2, vec![1, 2, 3]); -} - -#[test] -fn fanout_backpressure() { - let (left_send, mut left_recv) = mpsc::channel(0); - let (right_send, mut right_recv) = mpsc::channel(0); - let sink = left_send.fanout(right_send); - - let mut sink = block_on(StartSendFut::new(sink, 0)).unwrap(); - - flag_cx(|flag, cx| { - let mut task = sink.send(2); - assert!(!flag.take()); - assert!(task.poll_unpin(cx).is_pending()); - assert_eq!(block_on(left_recv.next()), Some(0)); - assert!(flag.take()); - assert!(task.poll_unpin(cx).is_pending()); - assert_eq!(block_on(right_recv.next()), Some(0)); - assert!(flag.take()); - - assert!(task.poll_unpin(cx).is_pending()); - assert_eq!(block_on(left_recv.next()), Some(2)); - assert!(flag.take()); - assert!(task.poll_unpin(cx).is_pending()); - assert_eq!(block_on(right_recv.next()), Some(2)); - assert!(flag.take()); - - unwrap(task.poll_unpin(cx)); - // make sure receivers live until end of test to prevent send errors - drop(left_recv); - drop(right_recv); - }) -} - -#[test] -fn sink_map_err() { - { - let cx = &mut panic_context(); - let (tx, _rx) = mpsc::channel(1); - let mut tx = tx.sink_map_err(|_| ()); - assert_eq!(Pin::new(&mut tx).start_send(()), Ok(())); - assert_eq!(Pin::new(&mut tx).poll_flush(cx), Poll::Ready(Ok(()))); - } - - let tx = mpsc::channel(0).0; - assert_eq!(Pin::new(&mut tx.sink_map_err(|_| ())).start_send(()), Err(())); -} - -#[test] -fn sink_unfold() { - block_on(poll_fn(|cx| { - let (tx, mut rx) = mpsc::channel(1); - let unfold = sink::unfold((), |(), i: i32| { - let mut tx = tx.clone(); - async move { - tx.send(i).await.unwrap(); - Ok::<_, String>(()) - } - }); - 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_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_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_recv().unwrap(), 3); - assert_eq!(rx.try_recv().unwrap(), 4); - - Poll::Ready(()) - })) -} - -#[test] -fn err_into() { - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - struct ErrIntoTest; - - impl From for ErrIntoTest { - fn from(_: mpsc::SendError) -> Self { - Self - } - } - - { - let cx = &mut panic_context(); - let (tx, _rx) = mpsc::channel(1); - let mut tx: SinkErrInto, _, ErrIntoTest> = tx.sink_err_into(); - assert_eq!(Pin::new(&mut tx).start_send(()), Ok(())); - assert_eq!(Pin::new(&mut tx).poll_flush(cx), Poll::Ready(Ok(()))); - } - - let tx = mpsc::channel(0).0; - assert_eq!(Pin::new(&mut tx.sink_err_into()).start_send(()), Err(ErrIntoTest)); -} diff --git a/futures/tests/sink_fanout.rs b/futures/tests/sink_fanout.rs deleted file mode 100644 index 8ce007934a..0000000000 --- a/futures/tests/sink_fanout.rs +++ /dev/null @@ -1,24 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::block_on; -use futures::join; -use futures::sink::SinkExt; -use futures::stream::{self, StreamExt}; - -#[test] -fn it_works() { - let (tx1, rx1) = mpsc::channel(1); - let (tx2, rx2) = mpsc::channel(2); - let tx = tx1.fanout(tx2).sink_map_err(|_| ()); - - let src = stream::iter((0..10).map(Ok)); - let fwd = src.forward(tx); - - let collect_fut1 = rx1.collect::>(); - let collect_fut2 = rx2.collect::>(); - let (_, vec1, vec2) = block_on(async move { join!(fwd, collect_fut1, collect_fut2) }); - - let expected = (0..10).map(Ok::<_, ()>).collect::>(); - - assert_eq!(vec1, expected); - assert_eq!(vec2, expected); -} diff --git a/futures/tests/stream.rs b/futures/tests/stream.rs deleted file mode 100644 index db74b96586..0000000000 --- a/futures/tests/stream.rs +++ /dev/null @@ -1,594 +0,0 @@ -use std::cell::Cell; -use std::iter; -use std::pin::Pin; -use std::rc::Rc; -use std::sync::Arc; -use std::task::Context; - -use futures::channel::mpsc; -use futures::executor::block_on; -use futures::future::{self, Future}; -use futures::lock::Mutex; -use futures::sink::SinkExt; -use futures::stream::{self, StreamExt}; -use futures::task::Poll; -use futures::{ready, FutureExt}; -use futures_core::Stream; -use futures_executor::ThreadPool; -use futures_test::task::noop_context; - -#[test] -fn select() { - fn select_and_compare(a: Vec, b: Vec, expected: Vec) { - let a = stream::iter(a); - let b = stream::iter(b); - let vec = block_on(stream::select(a, b).collect::>()); - assert_eq!(vec, expected); - } - - select_and_compare(vec![1, 2, 3], vec![4, 5, 6], vec![1, 4, 2, 5, 3, 6]); - select_and_compare(vec![1, 2, 3], vec![4, 5], vec![1, 4, 2, 5, 3]); - select_and_compare(vec![1, 2], vec![4, 5, 6], vec![1, 4, 2, 5, 6]); -} - -#[test] -fn flat_map() { - block_on(async { - let st = - stream::iter(vec![stream::iter(0..=4u8), stream::iter(6..=10), stream::iter(0..=2)]); - - let values: Vec<_> = - st.flat_map(|s| s.filter(|v| futures::future::ready(v % 2 == 0))).collect().await; - - assert_eq!(values, vec![0, 2, 4, 6, 8, 10, 0, 2]); - }); -} - -#[test] -fn scan() { - block_on(async { - let values = stream::iter(vec![1u8, 2, 3, 4, 6, 8, 2]) - .scan(1, |mut state, e| async move { - state += 1; - if e < state { - Some((state, e)) - } else { - None - } - }) - .collect::>() - .await; - - assert_eq!(values, vec![1u8, 2, 3, 4]); - }); - - block_on(async { - let mut state = vec![]; - let values = stream::iter(vec![1u8, 2, 3, 4, 6, 8, 2]) - .scan(&mut state, |state, e| async move { - state.push(e); - Some((state, e)) - }) - .collect::>() - .await; - - assert_eq!(values, state); - }); -} - -#[test] -fn flatten_unordered() { - use futures::executor::block_on; - use futures::stream::*; - use futures::task::*; - use std::convert::identity; - use std::pin::Pin; - use std::sync::atomic::{AtomicBool, Ordering}; - use std::thread; - use std::time::Duration; - - struct DataStream { - data: Vec, - polled: bool, - wake_immediately: bool, - } - - impl Stream for DataStream { - type Item = u8; - - fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - if !self.polled { - if !self.wake_immediately { - let waker = ctx.waker().clone(); - let sleep_time = - Duration::from_millis(*self.data.first().unwrap_or(&0) as u64 / 10); - thread::spawn(move || { - thread::sleep(sleep_time); - waker.wake_by_ref(); - }); - } else { - ctx.waker().wake_by_ref(); - } - self.polled = true; - Poll::Pending - } else { - self.polled = false; - Poll::Ready(self.data.pop()) - } - } - } - - struct Interchanger { - polled: bool, - base: u8, - wake_immediately: bool, - } - - impl Stream for Interchanger { - type Item = DataStream; - - fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - if !self.polled { - self.polled = true; - if !self.wake_immediately { - let waker = ctx.waker().clone(); - let sleep_time = Duration::from_millis(self.base as u64); - thread::spawn(move || { - thread::sleep(sleep_time); - waker.wake_by_ref(); - }); - } else { - ctx.waker().wake_by_ref(); - } - Poll::Pending - } else { - let data: Vec<_> = (0..6).rev().map(|v| v + self.base * 6).collect(); - self.base += 1; - self.polled = false; - Poll::Ready(Some(DataStream { - polled: false, - data, - wake_immediately: self.wake_immediately && self.base % 2 == 0, - })) - } - } - } - - // basic behaviour - { - block_on(async { - let st = stream::iter(vec![ - stream::iter(0..=4u8), - stream::iter(6..=10), - stream::iter(10..=12), - ]); - - let fl_unordered = st.flatten_unordered(3).collect::>().await; - - assert_eq!(fl_unordered, vec![0, 6, 10, 1, 7, 11, 2, 8, 12, 3, 9, 4, 10]); - }); - - block_on(async { - let st = stream::iter(vec![ - stream::iter(0..=4u8), - stream::iter(6..=10), - stream::iter(0..=2), - ]); - - let mut fm_unordered = st - .flat_map_unordered(1, |s| s.filter(|v| futures::future::ready(v % 2 == 0))) - .collect::>() - .await; - - fm_unordered.sort_unstable(); - - assert_eq!(fm_unordered, vec![0, 0, 2, 2, 4, 6, 8, 10]); - }); - } - - // wake up immediately - { - block_on(async { - let mut fl_unordered = Interchanger { polled: false, base: 0, wake_immediately: true } - .take(10) - .map(|s| s.map(identity)) - .flatten_unordered(10) - .collect::>() - .await; - - fl_unordered.sort_unstable(); - - assert_eq!(fl_unordered, (0..60).collect::>()); - }); - - block_on(async { - let mut fm_unordered = Interchanger { polled: false, base: 0, wake_immediately: true } - .take(10) - .flat_map_unordered(10, |s| s.map(identity)) - .collect::>() - .await; - - fm_unordered.sort_unstable(); - - assert_eq!(fm_unordered, (0..60).collect::>()); - }); - } - - // wake up after delay - { - block_on(async { - let mut fl_unordered = Interchanger { polled: false, base: 0, wake_immediately: false } - .take(10) - .map(|s| s.map(identity)) - .flatten_unordered(10) - .collect::>() - .await; - - fl_unordered.sort_unstable(); - - assert_eq!(fl_unordered, (0..60).collect::>()); - }); - - block_on(async { - let mut fm_unordered = Interchanger { polled: false, base: 0, wake_immediately: false } - .take(10) - .flat_map_unordered(10, |s| s.map(identity)) - .collect::>() - .await; - - fm_unordered.sort_unstable(); - - assert_eq!(fm_unordered, (0..60).collect::>()); - }); - - block_on(async { - let (mut fm_unordered, mut fl_unordered) = futures_util::join!( - Interchanger { polled: false, base: 0, wake_immediately: false } - .take(10) - .flat_map_unordered(10, |s| s.map(identity)) - .collect::>(), - Interchanger { polled: false, base: 0, wake_immediately: false } - .take(10) - .map(|s| s.map(identity)) - .flatten_unordered(10) - .collect::>() - ); - - fm_unordered.sort_unstable(); - fl_unordered.sort_unstable(); - - assert_eq!(fm_unordered, fl_unordered); - assert_eq!(fm_unordered, (0..60).collect::>()); - }); - } - - // waker panics - { - let stream = Arc::new(Mutex::new( - Interchanger { polled: false, base: 0, wake_immediately: true } - .take(10) - .flat_map_unordered(10, |s| s.map(identity)), - )); - - struct PanicWaker; - - impl ArcWake for PanicWaker { - fn wake_by_ref(_arc_self: &Arc) { - panic!("WAKE UP"); - } - } - - std::thread::spawn({ - let stream = stream.clone(); - move || { - let mut st = poll_fn(|cx| { - let mut lock = ready!(stream.lock().poll_unpin(cx)); - - let panic_waker = waker(Arc::new(PanicWaker)); - let mut panic_cx = Context::from_waker(&panic_waker); - let _ = ready!(lock.poll_next_unpin(&mut panic_cx)); - - Poll::Ready(Some(())) - }); - - block_on(st.next()) - } - }) - .join() - .unwrap_err(); - - block_on(async move { - let mut values: Vec<_> = stream.lock().await.by_ref().collect().await; - values.sort_unstable(); - - assert_eq!(values, (0..60).collect::>()); - }); - } - - // stream panics - { - let st = stream::iter(iter::once( - once(Box::pin(async { panic!("Polled") })).left_stream::(), - )) - .chain( - Interchanger { polled: false, base: 0, wake_immediately: true } - .map(|stream| stream.right_stream()) - .take(10), - ); - - let stream = Arc::new(Mutex::new(st.flatten_unordered(10))); - - std::thread::spawn({ - let stream = stream.clone(); - move || { - let mut st = poll_fn(|cx| { - let mut lock = ready!(stream.lock().poll_unpin(cx)); - let data = ready!(lock.poll_next_unpin(cx)); - - Poll::Ready(data) - }); - - block_on(st.next()) - } - }) - .join() - .unwrap_err(); - - block_on(async move { - let mut values: Vec<_> = stream.lock().await.by_ref().collect().await; - values.sort_unstable(); - - assert_eq!(values, (0..60).collect::>()); - }); - } - - fn timeout(time: Duration, value: I) -> impl Future { - let ready = Arc::new(AtomicBool::new(false)); - let mut spawned = false; - - future::poll_fn(move |cx| { - if !spawned { - let waker = cx.waker().clone(); - let ready = ready.clone(); - - std::thread::spawn(move || { - std::thread::sleep(time); - ready.store(true, Ordering::Release); - - waker.wake_by_ref() - }); - spawned = true; - } - - if ready.load(Ordering::Acquire) { - Poll::Ready(value.clone()) - } else { - Poll::Pending - } - }) - } - - fn build_nested_fu(st: S) -> impl Stream + Unpin - where - S::Item: Clone, - { - let inner = st - .then(|item| timeout(Duration::from_millis(50), item)) - .enumerate() - .map(|(idx, value)| { - stream::once(if idx % 2 == 0 { - future::ready(value).left_future() - } else { - timeout(Duration::from_millis(100), value).right_future() - }) - }) - .flatten_unordered(None); - - stream::once(future::ready(inner)).flatten_unordered(None) - } - - // nested `flatten_unordered` - let te = ThreadPool::new().unwrap(); - let base_handle = te - .spawn_with_handle(async move { - let fu = build_nested_fu(stream::iter(1..=10)); - - assert_eq!(fu.count().await, 10); - }) - .unwrap(); - - block_on(base_handle); - - let empty_state_move_handle = te - .spawn_with_handle(async move { - let mut fu = build_nested_fu(stream::iter(1..10)); - { - let mut cx = noop_context(); - let _ = fu.poll_next_unpin(&mut cx); - let _ = fu.poll_next_unpin(&mut cx); - } - - assert_eq!(fu.count().await, 9); - }) - .unwrap(); - - block_on(empty_state_move_handle); -} - -#[test] -fn take_until() { - fn make_stop_fut(stop_on: u32) -> impl Future { - let mut i = 0; - future::poll_fn(move |_cx| { - i += 1; - if i <= stop_on { - Poll::Pending - } else { - Poll::Ready(()) - } - }) - } - - block_on(async { - // Verify stopping works: - let stream = stream::iter(1u32..=10); - let stop_fut = make_stop_fut(5); - - let stream = stream.take_until(stop_fut); - let last = stream.fold(0, |_, i| async move { i }).await; - assert_eq!(last, 5); - - // Verify take_future() works: - let stream = stream::iter(1..=10); - let stop_fut = make_stop_fut(5); - - let mut stream = stream.take_until(stop_fut); - - assert_eq!(stream.next().await, Some(1)); - assert_eq!(stream.next().await, Some(2)); - - stream.take_future(); - - let last = stream.fold(0, |_, i| async move { i }).await; - assert_eq!(last, 10); - - // Verify take_future() returns None if stream is stopped: - let stream = stream::iter(1u32..=10); - let stop_fut = make_stop_fut(1); - let mut stream = stream.take_until(stop_fut); - assert_eq!(stream.next().await, Some(1)); - assert_eq!(stream.next().await, None); - assert!(stream.take_future().is_none()); - - // Verify TakeUntil is fused: - let mut i = 0; - let stream = stream::poll_fn(move |_cx| { - i += 1; - match i { - 1 => Poll::Ready(Some(1)), - 2 => Poll::Ready(None), - _ => panic!("TakeUntil not fused"), - } - }); - - let stop_fut = make_stop_fut(1); - let mut stream = stream.take_until(stop_fut); - assert_eq!(stream.next().await, Some(1)); - assert_eq!(stream.next().await, None); - assert_eq!(stream.next().await, None); - }); -} - -#[test] -#[should_panic] -fn chunks_panic_on_cap_zero() { - let (_, rx1) = mpsc::channel::<()>(1); - - let _ = rx1.chunks(0); -} - -#[test] -#[should_panic] -fn ready_chunks_panic_on_cap_zero() { - let (_, rx1) = mpsc::channel::<()>(1); - - let _ = rx1.ready_chunks(0); -} - -#[test] -fn ready_chunks() { - let (mut tx, rx1) = mpsc::channel::(16); - - let mut s = rx1.ready_chunks(2); - - let mut cx = noop_context(); - assert!(s.next().poll_unpin(&mut cx).is_pending()); - - block_on(async { - tx.send(1).await.unwrap(); - - assert_eq!(s.next().await.unwrap(), vec![1]); - tx.send(2).await.unwrap(); - tx.send(3).await.unwrap(); - tx.send(4).await.unwrap(); - assert_eq!(s.next().await.unwrap(), vec![2, 3]); - assert_eq!(s.next().await.unwrap(), vec![4]); - }); -} - -struct SlowStream { - times_should_poll: usize, - times_polled: Rc>, -} -impl Stream for SlowStream { - type Item = usize; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.times_polled.set(self.times_polled.get() + 1); - if self.times_polled.get() % 2 == 0 { - cx.waker().wake_by_ref(); - return Poll::Pending; - } - if self.times_polled.get() >= self.times_should_poll { - return Poll::Ready(None); - } - Poll::Ready(Some(self.times_polled.get())) - } -} - -#[test] -fn select_with_strategy_doesnt_terminate_early() { - for side in [stream::PollNext::Left, stream::PollNext::Right] { - let times_should_poll = 10; - let count = Rc::new(Cell::new(0)); - let b = stream::iter([10, 20]); - - let mut selected = stream::select_with_strategy( - SlowStream { times_should_poll, times_polled: count.clone() }, - b, - |_: &mut ()| side, - ); - block_on(async move { while selected.next().await.is_some() {} }); - assert_eq!(count.get(), times_should_poll + 1); - } -} - -async fn is_even(number: u8) -> bool { - number % 2 == 0 -} - -#[test] -fn all() { - block_on(async { - let empty: [u8; 0] = []; - let st = stream::iter(empty); - let all = st.all(is_even).await; - assert!(all); - - let st = stream::iter([2, 4, 6, 8]); - let all = st.all(is_even).await; - assert!(all); - - let st = stream::iter([2, 3, 4]); - let all = st.all(is_even).await; - assert!(!all); - }); -} - -#[test] -fn any() { - block_on(async { - let empty: [u8; 0] = []; - let st = stream::iter(empty); - let any = st.any(is_even).await; - assert!(!any); - - let st = stream::iter([1, 2, 3]); - let any = st.any(is_even).await; - assert!(any); - - let st = stream::iter([1, 3, 5]); - let any = st.any(is_even).await; - assert!(!any); - }); -} diff --git a/futures/tests/stream_abortable.rs b/futures/tests/stream_abortable.rs deleted file mode 100644 index 2339dd0522..0000000000 --- a/futures/tests/stream_abortable.rs +++ /dev/null @@ -1,46 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::block_on; -use futures::stream::{abortable, Stream, StreamExt}; -use futures::task::{Context, Poll}; -use futures::SinkExt; -use futures_test::task::new_count_waker; -use std::pin::Pin; - -#[test] -fn abortable_works() { - let (_tx, a_rx) = mpsc::channel::<()>(1); - let (mut abortable_rx, abort_handle) = abortable(a_rx); - - abort_handle.abort(); - assert!(abortable_rx.is_aborted()); - assert_eq!(None, block_on(abortable_rx.next())); -} - -#[test] -fn abortable_awakens() { - let (_tx, a_rx) = mpsc::channel::<()>(1); - let (mut abortable_rx, abort_handle) = abortable(a_rx); - - let (waker, counter) = new_count_waker(); - let mut cx = Context::from_waker(&waker); - - assert_eq!(counter, 0); - assert_eq!(Poll::Pending, Pin::new(&mut abortable_rx).poll_next(&mut cx)); - assert_eq!(counter, 0); - - abort_handle.abort(); - assert_eq!(counter, 1); - assert!(abortable_rx.is_aborted()); - assert_eq!(Poll::Ready(None), Pin::new(&mut abortable_rx).poll_next(&mut cx)); -} - -#[test] -fn abortable_resolves() { - let (mut tx, a_rx) = mpsc::channel::<()>(1); - let (mut abortable_rx, _abort_handle) = abortable(a_rx); - - block_on(tx.send(())).unwrap(); - - assert!(!abortable_rx.is_aborted()); - assert_eq!(Some(()), block_on(abortable_rx.next())); -} diff --git a/futures/tests/stream_buffer_unordered.rs b/futures/tests/stream_buffer_unordered.rs deleted file mode 100644 index 9a2ee174ed..0000000000 --- a/futures/tests/stream_buffer_unordered.rs +++ /dev/null @@ -1,73 +0,0 @@ -use futures::channel::{mpsc, oneshot}; -use futures::executor::{block_on, block_on_stream}; -use futures::sink::SinkExt; -use futures::stream::StreamExt; -use std::sync::mpsc as std_mpsc; -use std::thread; - -#[test] -#[ignore] // FIXME: https://github.com/rust-lang/futures-rs/issues/1790 -fn works() { - const N: usize = 4; - - let (mut tx, rx) = mpsc::channel(1); - - let (tx2, rx2) = std_mpsc::channel(); - let (tx3, rx3) = std_mpsc::channel(); - let t1 = thread::spawn(move || { - for _ in 0..=N { - let (mytx, myrx) = oneshot::channel(); - block_on(tx.send(myrx)).unwrap(); - tx3.send(mytx).unwrap(); - } - rx2.recv().unwrap(); - for _ in 0..N { - let (mytx, myrx) = oneshot::channel(); - block_on(tx.send(myrx)).unwrap(); - tx3.send(mytx).unwrap(); - } - }); - - let (tx4, rx4) = std_mpsc::channel(); - let t2 = thread::spawn(move || { - for item in block_on_stream(rx.buffer_unordered(N)) { - tx4.send(item.unwrap()).unwrap(); - } - }); - - let o1 = rx3.recv().unwrap(); - let o2 = rx3.recv().unwrap(); - let o3 = rx3.recv().unwrap(); - let o4 = rx3.recv().unwrap(); - assert!(rx4.try_recv().is_err()); - - o1.send(1).unwrap(); - assert_eq!(rx4.recv(), Ok(1)); - o3.send(3).unwrap(); - assert_eq!(rx4.recv(), Ok(3)); - tx2.send(()).unwrap(); - o2.send(2).unwrap(); - assert_eq!(rx4.recv(), Ok(2)); - o4.send(4).unwrap(); - assert_eq!(rx4.recv(), Ok(4)); - - let o5 = rx3.recv().unwrap(); - let o6 = rx3.recv().unwrap(); - let o7 = rx3.recv().unwrap(); - let o8 = rx3.recv().unwrap(); - let o9 = rx3.recv().unwrap(); - - o5.send(5).unwrap(); - assert_eq!(rx4.recv(), Ok(5)); - o8.send(8).unwrap(); - assert_eq!(rx4.recv(), Ok(8)); - o9.send(9).unwrap(); - assert_eq!(rx4.recv(), Ok(9)); - o7.send(7).unwrap(); - assert_eq!(rx4.recv(), Ok(7)); - o6.send(6).unwrap(); - assert_eq!(rx4.recv(), Ok(6)); - - t1.join().unwrap(); - t2.join().unwrap(); -} diff --git a/futures/tests/stream_catch_unwind.rs b/futures/tests/stream_catch_unwind.rs deleted file mode 100644 index 8b23a0a7ef..0000000000 --- a/futures/tests/stream_catch_unwind.rs +++ /dev/null @@ -1,27 +0,0 @@ -use futures::executor::block_on_stream; -use futures::stream::{self, StreamExt}; - -#[test] -fn panic_in_the_middle_of_the_stream() { - let stream = stream::iter(vec![Some(10), None, Some(11)]); - - // panic on second element - let stream_panicking = stream.map(|o| o.unwrap()); - let mut iter = block_on_stream(stream_panicking.catch_unwind()); - - assert_eq!(10, iter.next().unwrap().ok().unwrap()); - assert!(iter.next().unwrap().is_err()); - assert!(iter.next().is_none()); -} - -#[test] -fn no_panic() { - let stream = stream::iter(vec![10, 11, 12]); - - let mut iter = block_on_stream(stream.catch_unwind()); - - assert_eq!(10, iter.next().unwrap().ok().unwrap()); - assert_eq!(11, iter.next().unwrap().ok().unwrap()); - assert_eq!(12, iter.next().unwrap().ok().unwrap()); - assert!(iter.next().is_none()); -} diff --git a/futures/tests/stream_futures_ordered.rs b/futures/tests/stream_futures_ordered.rs deleted file mode 100644 index f06ce263eb..0000000000 --- a/futures/tests/stream_futures_ordered.rs +++ /dev/null @@ -1,172 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::{block_on, block_on_stream}; -use futures::future::{self, join, Future, FutureExt, TryFutureExt}; -use futures::stream::{FuturesOrdered, StreamExt}; -use futures::task::Poll; -use futures_test::task::noop_context; -use std::any::Any; - -#[test] -fn works_1() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = vec![a_rx, b_rx, c_rx].into_iter().collect::>(); - - b_tx.send(99).unwrap(); - assert!(stream.poll_next_unpin(&mut noop_context()).is_pending()); - - a_tx.send(33).unwrap(); - c_tx.send(33).unwrap(); - - let mut iter = block_on_stream(stream); - assert_eq!(Some(Ok(33)), iter.next()); - assert_eq!(Some(Ok(99)), iter.next()); - assert_eq!(Some(Ok(33)), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn works_2() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = vec![a_rx.boxed(), join(b_rx, c_rx).map(|(a, b)| Ok(a? + b?)).boxed()] - .into_iter() - .collect::>(); - - let mut cx = noop_context(); - a_tx.send(33).unwrap(); - b_tx.send(33).unwrap(); - assert!(stream.poll_next_unpin(&mut cx).is_ready()); - assert!(stream.poll_next_unpin(&mut cx).is_pending()); - c_tx.send(33).unwrap(); - assert!(stream.poll_next_unpin(&mut cx).is_ready()); -} - -#[test] -fn test_push_front() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - let (d_tx, d_rx) = oneshot::channel::(); - - let mut stream = FuturesOrdered::new(); - - let mut cx = noop_context(); - - stream.push_back(a_rx); - stream.push_back(b_rx); - stream.push_back(c_rx); - - a_tx.send(1).unwrap(); - b_tx.send(2).unwrap(); - c_tx.send(3).unwrap(); - - // 1 and 2 should be received in order - assert_eq!(Poll::Ready(Some(Ok(1))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(2))), stream.poll_next_unpin(&mut cx)); - - stream.push_front(d_rx); - d_tx.send(4).unwrap(); - - // we pushed `d_rx` to the front and sent 4, so we should receive 4 next - // and then 3 after it - assert_eq!(Poll::Ready(Some(Ok(4))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(3))), stream.poll_next_unpin(&mut cx)); -} - -#[test] -fn test_push_back() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - let (d_tx, d_rx) = oneshot::channel::(); - - let mut stream = FuturesOrdered::new(); - - let mut cx = noop_context(); - - stream.push_back(a_rx); - stream.push_back(b_rx); - stream.push_back(c_rx); - - a_tx.send(1).unwrap(); - b_tx.send(2).unwrap(); - c_tx.send(3).unwrap(); - - // All results should be received in order - - assert_eq!(Poll::Ready(Some(Ok(1))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(2))), stream.poll_next_unpin(&mut cx)); - - stream.push_back(d_rx); - d_tx.send(4).unwrap(); - - assert_eq!(Poll::Ready(Some(Ok(3))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(4))), stream.poll_next_unpin(&mut cx)); -} - -#[test] -fn from_iterator() { - let stream = vec![future::ready::(1), future::ready::(2), future::ready::(3)] - .into_iter() - .collect::>(); - assert_eq!(stream.len(), 3); - assert_eq!(block_on(stream.collect::>()), vec![1, 2, 3]); -} - -#[test] -fn queue_never_unblocked() { - let (_a_tx, a_rx) = oneshot::channel::>(); - let (b_tx, b_rx) = oneshot::channel::>(); - let (c_tx, c_rx) = oneshot::channel::>(); - - let mut stream = vec![ - Box::new(a_rx) as Box + Unpin>, - Box::new( - future::try_select(b_rx, c_rx) - .map_err(|e| e.factor_first().0) - .and_then(|e| future::ok(Box::new(e) as Box)), - ) as _, - ] - .into_iter() - .collect::>(); - - let cx = &mut noop_context(); - for _ in 0..10 { - assert!(stream.poll_next_unpin(cx).is_pending()); - } - - b_tx.send(Box::new(())).unwrap(); - assert!(stream.poll_next_unpin(cx).is_pending()); - c_tx.send(Box::new(())).unwrap(); - assert!(stream.poll_next_unpin(cx).is_pending()); - assert!(stream.poll_next_unpin(cx).is_pending()); -} - -#[test] -fn test_push_front_negative() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = FuturesOrdered::new(); - - let mut cx = noop_context(); - - stream.push_front(a_rx); - stream.push_front(b_rx); - stream.push_front(c_rx); - - a_tx.send(1).unwrap(); - b_tx.send(2).unwrap(); - c_tx.send(3).unwrap(); - - // These should all be received in reverse order - assert_eq!(Poll::Ready(Some(Ok(3))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(2))), stream.poll_next_unpin(&mut cx)); - assert_eq!(Poll::Ready(Some(Ok(1))), stream.poll_next_unpin(&mut cx)); -} diff --git a/futures/tests/stream_futures_unordered.rs b/futures/tests/stream_futures_unordered.rs deleted file mode 100644 index 6be7f05be1..0000000000 --- a/futures/tests/stream_futures_unordered.rs +++ /dev/null @@ -1,431 +0,0 @@ -use futures::channel::oneshot; -use futures::executor::{block_on, block_on_stream}; -use futures::future::{self, join, Future, FutureExt}; -use futures::stream::{FusedStream, FuturesUnordered, StreamExt}; -use futures::task::{Context, Poll}; -use futures_test::future::FutureTestExt; -use futures_test::task::noop_context; -use futures_test::{assert_stream_done, assert_stream_next, assert_stream_pending}; -use std::iter::FromIterator; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, Ordering}; - -#[test] -fn is_terminated() { - let mut cx = noop_context(); - let mut tasks = FuturesUnordered::new(); - - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(None)); - assert!(tasks.is_terminated()); - - // Test that the sentinel value doesn't leak - assert!(tasks.is_empty()); - assert_eq!(tasks.len(), 0); - assert_eq!(tasks.iter_mut().len(), 0); - - tasks.push(future::ready(1)); - - assert!(!tasks.is_empty()); - assert_eq!(tasks.len(), 1); - assert_eq!(tasks.iter_mut().len(), 1); - - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(Some(1))); - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(None)); - assert!(tasks.is_terminated()); -} - -#[test] -fn works_1() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut iter = - block_on_stream(vec![a_rx, b_rx, c_rx].into_iter().collect::>()); - - b_tx.send(99).unwrap(); - assert_eq!(Some(Ok(99)), iter.next()); - - a_tx.send(33).unwrap(); - c_tx.send(33).unwrap(); - assert_eq!(Some(Ok(33)), iter.next()); - assert_eq!(Some(Ok(33)), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn works_2() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = vec![a_rx.boxed(), join(b_rx, c_rx).map(|(a, b)| Ok(a? + b?)).boxed()] - .into_iter() - .collect::>(); - - a_tx.send(9).unwrap(); - b_tx.send(10).unwrap(); - - let mut cx = noop_context(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(9)))); - c_tx.send(20).unwrap(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(30)))); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(None)); -} - -#[test] -fn from_iterator() { - let stream = vec![future::ready::(1), future::ready::(2), future::ready::(3)] - .into_iter() - .collect::>(); - assert_eq!(stream.len(), 3); - assert_eq!(block_on(stream.collect::>()), vec![1, 2, 3]); -} - -#[test] -fn finished_future() { - let (_a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = vec![ - Box::new(a_rx) as Box> + Unpin>, - Box::new(future::select(b_rx, c_rx).map(|e| e.factor_first().0)) as _, - ] - .into_iter() - .collect::>(); - - let cx = &mut noop_context(); - for _ in 0..10 { - assert!(stream.poll_next_unpin(cx).is_pending()); - } - - b_tx.send(12).unwrap(); - c_tx.send(3).unwrap(); - assert!(stream.poll_next_unpin(cx).is_ready()); - assert!(stream.poll_next_unpin(cx).is_pending()); - assert!(stream.poll_next_unpin(cx).is_pending()); -} - -#[test] -fn iter_mut_cancel() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let mut stream = vec![a_rx, b_rx, c_rx].into_iter().collect::>(); - - for rx in stream.iter_mut() { - rx.close(); - } - - let mut iter = block_on_stream(stream); - - assert!(a_tx.is_canceled()); - assert!(b_tx.is_canceled()); - assert!(c_tx.is_canceled()); - - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), None); -} - -#[test] -fn iter_mut_len() { - let mut stream = - vec![future::pending::<()>(), future::pending::<()>(), future::pending::<()>()] - .into_iter() - .collect::>(); - - let mut iter_mut = stream.iter_mut(); - assert_eq!(iter_mut.len(), 3); - assert!(iter_mut.next().is_some()); - assert_eq!(iter_mut.len(), 2); - assert!(iter_mut.next().is_some()); - assert_eq!(iter_mut.len(), 1); - assert!(iter_mut.next().is_some()); - assert_eq!(iter_mut.len(), 0); - assert!(iter_mut.next().is_none()); -} - -#[test] -fn iter_cancel() { - struct AtomicCancel { - future: F, - cancel: AtomicBool, - } - - impl Future for AtomicCancel { - type Output = Option<::Output>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.cancel.load(Ordering::Relaxed) { - Poll::Ready(None) - } else { - self.future.poll_unpin(cx).map(Some) - } - } - } - - impl AtomicCancel { - fn new(future: F) -> Self { - Self { future, cancel: AtomicBool::new(false) } - } - } - - let stream = vec![ - AtomicCancel::new(future::pending::<()>()), - AtomicCancel::new(future::pending::<()>()), - AtomicCancel::new(future::pending::<()>()), - ] - .into_iter() - .collect::>(); - - for f in stream.iter() { - f.cancel.store(true, Ordering::Relaxed); - } - - let mut iter = block_on_stream(stream); - - assert_eq!(iter.next(), Some(None)); - assert_eq!(iter.next(), Some(None)); - assert_eq!(iter.next(), Some(None)); - assert_eq!(iter.next(), None); -} - -#[test] -fn iter_len() { - let stream = vec![future::pending::<()>(), future::pending::<()>(), future::pending::<()>()] - .into_iter() - .collect::>(); - - let mut iter = stream.iter(); - assert_eq!(iter.len(), 3); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); -} - -#[test] -fn into_iter_cancel() { - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - - let stream = vec![a_rx, b_rx, c_rx].into_iter().collect::>(); - - let stream = stream - .into_iter() - .map(|mut rx| { - rx.close(); - rx - }) - .collect::>(); - - let mut iter = block_on_stream(stream); - - assert!(a_tx.is_canceled()); - assert!(b_tx.is_canceled()); - assert!(c_tx.is_canceled()); - - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled))); - assert_eq!(iter.next(), None); -} - -#[test] -fn into_iter_len() { - let stream = vec![future::pending::<()>(), future::pending::<()>(), future::pending::<()>()] - .into_iter() - .collect::>(); - - let mut into_iter = stream.into_iter(); - assert_eq!(into_iter.len(), 3); - assert!(into_iter.next().is_some()); - assert_eq!(into_iter.len(), 2); - assert!(into_iter.next().is_some()); - assert_eq!(into_iter.len(), 1); - assert!(into_iter.next().is_some()); - assert_eq!(into_iter.len(), 0); - assert!(into_iter.next().is_none()); -} - -#[test] -fn into_iter_partial() { - let stream = vec![future::ready(1), future::ready(2), future::ready(3), future::ready(4)] - .into_iter() - .collect::>(); - - let mut into_iter = stream.into_iter(); - assert!(into_iter.next().is_some()); - assert!(into_iter.next().is_some()); - assert!(into_iter.next().is_some()); - assert_eq!(into_iter.len(), 1); - // don't panic when iterator is dropped before completing -} - -#[test] -fn futures_not_moved_after_poll() { - // Future that will be ready after being polled twice, - // asserting that it does not move. - let fut = future::ready(()).pending_once().assert_unmoved(); - let mut stream = vec![fut; 3].into_iter().collect::>(); - assert_stream_pending!(stream); - assert_stream_next!(stream, ()); - assert_stream_next!(stream, ()); - assert_stream_next!(stream, ()); - assert_stream_done!(stream); -} - -#[test] -fn len_valid_during_out_of_order_completion() { - // Complete futures out-of-order and add new futures afterwards to ensure - // length values remain correct. - let (a_tx, a_rx) = oneshot::channel::(); - let (b_tx, b_rx) = oneshot::channel::(); - let (c_tx, c_rx) = oneshot::channel::(); - let (d_tx, d_rx) = oneshot::channel::(); - - let mut cx = noop_context(); - let mut stream = FuturesUnordered::new(); - assert_eq!(stream.len(), 0); - - stream.push(a_rx); - assert_eq!(stream.len(), 1); - stream.push(b_rx); - assert_eq!(stream.len(), 2); - stream.push(c_rx); - assert_eq!(stream.len(), 3); - - b_tx.send(4).unwrap(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(4)))); - assert_eq!(stream.len(), 2); - - stream.push(d_rx); - assert_eq!(stream.len(), 3); - - c_tx.send(5).unwrap(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(5)))); - assert_eq!(stream.len(), 2); - - d_tx.send(6).unwrap(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(6)))); - assert_eq!(stream.len(), 1); - - a_tx.send(7).unwrap(); - assert_eq!(stream.poll_next_unpin(&mut cx), Poll::Ready(Some(Ok(7)))); - assert_eq!(stream.len(), 0); -} - -#[test] -fn polled_only_once_at_most_per_iteration() { - #[derive(Debug, Clone, Copy, Default)] - struct F { - polled: bool, - } - - impl Future for F { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { - if self.polled { - panic!("polled twice") - } else { - self.polled = true; - Poll::Pending - } - } - } - - let cx = &mut noop_context(); - - let mut tasks = FuturesUnordered::from_iter(vec![F::default(); 10]); - assert!(tasks.poll_next_unpin(cx).is_pending()); - assert_eq!(10, tasks.iter().filter(|f| f.polled).count()); - - let mut tasks = FuturesUnordered::from_iter(vec![F::default(); 33]); - assert!(tasks.poll_next_unpin(cx).is_pending()); - assert_eq!(33, tasks.iter().filter(|f| f.polled).count()); - - let mut tasks = FuturesUnordered::::new(); - assert_eq!(Poll::Ready(None), tasks.poll_next_unpin(cx)); -} - -#[test] -fn clear() { - let mut tasks = FuturesUnordered::from_iter(vec![future::ready(1), future::ready(2)]); - - assert_eq!(block_on(tasks.next()), Some(1)); - assert!(!tasks.is_empty()); - - tasks.clear(); - assert!(tasks.is_empty()); - - tasks.push(future::ready(3)); - assert!(!tasks.is_empty()); - - tasks.clear(); - assert!(tasks.is_empty()); - - assert_eq!(block_on(tasks.next()), None); - assert!(tasks.is_terminated()); - tasks.clear(); - assert!(!tasks.is_terminated()); -} - -// https://github.com/rust-lang/futures-rs/issues/2529#issuecomment-997290279 -#[test] -fn clear_in_loop() { - const N: usize = - if cfg!(miri) || option_env!("QEMU_LD_PREFIX").is_some() { 100 } else { 10_000 }; - futures::executor::block_on(async { - async fn task() { - let (s, r) = oneshot::channel(); - std::thread::spawn(|| { - std::thread::sleep(std::time::Duration::from_micros(100)); - let _ = s.send(()); - }); - r.await.unwrap() - } - let mut futures = FuturesUnordered::new(); - for _ in 0..N { - for _ in 0..24 { - futures.push(task()); - } - let _ = futures.next().await; - futures.clear(); - } - }); -} - -// https://github.com/rust-lang/futures-rs/issues/2863#issuecomment-2219441515 -#[test] -#[should_panic] -fn panic_on_drop_fut() { - struct BadFuture; - - impl Drop for BadFuture { - fn drop(&mut self) { - panic!() - } - } - - impl Future for BadFuture { - type Output = (); - - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - Poll::Pending - } - } - - FuturesUnordered::default().push(BadFuture); -} diff --git a/futures/tests/stream_into_async_read.rs b/futures/tests/stream_into_async_read.rs deleted file mode 100644 index 60188d3e58..0000000000 --- a/futures/tests/stream_into_async_read.rs +++ /dev/null @@ -1,94 +0,0 @@ -use core::pin::Pin; -use futures::io::{AsyncBufRead, AsyncRead}; -use futures::stream::{self, TryStreamExt}; -use futures::task::Poll; -use futures_test::{stream::StreamTestExt, task::noop_context}; - -macro_rules! assert_read { - ($reader:expr, $buf:expr, $item:expr) => { - let mut cx = noop_context(); - loop { - match Pin::new(&mut $reader).poll_read(&mut cx, $buf) { - Poll::Ready(Ok(x)) => { - assert_eq!(x, $item); - break; - } - Poll::Ready(Err(err)) => { - panic!("assertion failed: expected value but got {}", err); - } - Poll::Pending => { - continue; - } - } - } - }; -} - -macro_rules! assert_fill_buf { - ($reader:expr, $buf:expr) => { - let mut cx = noop_context(); - loop { - match Pin::new(&mut $reader).poll_fill_buf(&mut cx) { - Poll::Ready(Ok(x)) => { - assert_eq!(x, $buf); - break; - } - Poll::Ready(Err(err)) => { - panic!("assertion failed: expected value but got {}", err); - } - Poll::Pending => { - continue; - } - } - } - }; -} - -#[test] -fn test_into_async_read() { - let stream = stream::iter((1..=3).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])])); - let mut reader = stream.interleave_pending().into_async_read(); - let mut buf = vec![0; 3]; - - assert_read!(reader, &mut buf, 3); - assert_eq!(&buf, &[1, 2, 3]); - - assert_read!(reader, &mut buf, 2); - assert_eq!(&buf[..2], &[4, 5]); - - assert_read!(reader, &mut buf, 3); - assert_eq!(&buf, &[1, 2, 3]); - - assert_read!(reader, &mut buf, 2); - assert_eq!(&buf[..2], &[4, 5]); - - assert_read!(reader, &mut buf, 3); - assert_eq!(&buf, &[1, 2, 3]); - - assert_read!(reader, &mut buf, 2); - assert_eq!(&buf[..2], &[4, 5]); - - assert_read!(reader, &mut buf, 0); -} - -#[test] -fn test_into_async_bufread() { - let stream = stream::iter((1..=2).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])])); - let mut reader = stream.interleave_pending().into_async_read(); - - let mut reader = Pin::new(&mut reader); - - assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]); - reader.as_mut().consume(3); - - assert_fill_buf!(reader, &[4, 5][..]); - reader.as_mut().consume(2); - - assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]); - reader.as_mut().consume(2); - - assert_fill_buf!(reader, &[3, 4, 5][..]); - reader.as_mut().consume(3); - - assert_fill_buf!(reader, &[][..]); -} diff --git a/futures/tests/stream_peekable.rs b/futures/tests/stream_peekable.rs deleted file mode 100644 index 06668f444d..0000000000 --- a/futures/tests/stream_peekable.rs +++ /dev/null @@ -1,58 +0,0 @@ -use futures::executor::block_on; -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(); - 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(); - let mut s = pin!(s); - assert_eq!(s.as_mut().peek().await, Some(&1u8)); - assert_eq!(s.collect::>().await, vec![1]); - }); -} - -#[test] -fn peekable_mut() { - block_on(async { - let s = stream::iter(vec![1u8, 2, 3]).peekable(); - let mut s = pin!(s); - if let Some(p) = s.as_mut().peek_mut().await { - if *p == 1 { - *p = 5; - } - } - assert_eq!(s.collect::>().await, vec![5, 2, 3]); - }); -} - -#[test] -fn peekable_next_if_eq() { - block_on(async { - // first, try on references - let s = stream::iter(vec!["Heart", "of", "Gold"]).peekable(); - 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")); - // try after peek() - assert_eq!(s.as_mut().peek().await, Some(&"of")); - assert_eq!(s.as_mut().next_if_eq(&"of").await, Some("of")); - assert_eq!(s.as_mut().next_if_eq(&"zaphod").await, None); - // make sure `next()` still behaves - assert_eq!(s.next().await, Some("Gold")); - - // make sure comparison works for owned values - let s = stream::iter(vec![String::from("Ludicrous"), "speed".into()]).peekable(); - 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())); - assert_eq!(s.as_mut().next_if_eq("").await, None); - }); -} diff --git a/futures/tests/stream_select_all.rs b/futures/tests/stream_select_all.rs deleted file mode 100644 index 12a9936677..0000000000 --- a/futures/tests/stream_select_all.rs +++ /dev/null @@ -1,196 +0,0 @@ -use futures::channel::mpsc; -use futures::executor::{block_on, block_on_stream}; -use futures::future::{self, FutureExt}; -use futures::stream::{self, select_all, FusedStream, SelectAll, StreamExt}; -use futures::task::Poll; -use futures_test::task::noop_context; - -#[test] -fn is_terminated() { - let mut cx = noop_context(); - let mut tasks = SelectAll::new(); - - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(None)); - assert!(tasks.is_terminated()); - - // Test that the sentinel value doesn't leak - assert!(tasks.is_empty()); - assert_eq!(tasks.len(), 0); - - tasks.push(future::ready(1).into_stream()); - - assert!(!tasks.is_empty()); - assert_eq!(tasks.len(), 1); - - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(Some(1))); - assert!(!tasks.is_terminated()); - assert_eq!(tasks.poll_next_unpin(&mut cx), Poll::Ready(None)); - assert!(tasks.is_terminated()); -} - -#[test] -fn issue_1626() { - let a = stream::iter(0..=2); - let b = stream::iter(10..=14); - - let mut s = block_on_stream(stream::select_all(vec![a, b])); - - assert_eq!(s.next(), Some(0)); - assert_eq!(s.next(), Some(10)); - assert_eq!(s.next(), Some(1)); - assert_eq!(s.next(), Some(11)); - assert_eq!(s.next(), Some(2)); - assert_eq!(s.next(), Some(12)); - assert_eq!(s.next(), Some(13)); - assert_eq!(s.next(), Some(14)); - assert_eq!(s.next(), None); -} - -#[test] -fn works_1() { - let (a_tx, a_rx) = mpsc::unbounded::(); - let (b_tx, b_rx) = mpsc::unbounded::(); - let (c_tx, c_rx) = mpsc::unbounded::(); - - let streams = vec![a_rx, b_rx, c_rx]; - - let mut stream = block_on_stream(select_all(streams)); - - b_tx.unbounded_send(99).unwrap(); - a_tx.unbounded_send(33).unwrap(); - assert_eq!(Some(33), stream.next()); - assert_eq!(Some(99), stream.next()); - - b_tx.unbounded_send(99).unwrap(); - a_tx.unbounded_send(33).unwrap(); - assert_eq!(Some(33), stream.next()); - assert_eq!(Some(99), stream.next()); - - c_tx.unbounded_send(42).unwrap(); - assert_eq!(Some(42), stream.next()); - a_tx.unbounded_send(43).unwrap(); - assert_eq!(Some(43), stream.next()); - - drop((a_tx, b_tx, c_tx)); - assert_eq!(None, stream.next()); -} - -#[test] -fn clear() { - let mut tasks = select_all(vec![stream::iter(vec![1]), stream::iter(vec![2])]); - - assert_eq!(block_on(tasks.next()), Some(1)); - assert!(!tasks.is_empty()); - - tasks.clear(); - assert!(tasks.is_empty()); - - tasks.push(stream::iter(vec![3])); - assert!(!tasks.is_empty()); - - tasks.clear(); - assert!(tasks.is_empty()); - - assert_eq!(block_on(tasks.next()), None); - assert!(tasks.is_terminated()); - tasks.clear(); - assert!(!tasks.is_terminated()); -} - -#[test] -fn iter_mut() { - let mut stream = - vec![stream::pending::<()>(), stream::pending::<()>(), stream::pending::<()>()] - .into_iter() - .collect::>(); - - let mut iter = stream.iter_mut(); - assert_eq!(iter.len(), 3); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); - - let mut stream = vec![stream::iter(vec![]), stream::iter(vec![1]), stream::iter(vec![2])] - .into_iter() - .collect::>(); - - assert_eq!(stream.len(), 3); - assert_eq!(block_on(stream.next()), Some(1)); - assert_eq!(stream.len(), 2); - let mut iter = stream.iter_mut(); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); - - assert_eq!(block_on(stream.next()), Some(2)); - assert_eq!(stream.len(), 2); - assert_eq!(block_on(stream.next()), None); - let mut iter = stream.iter_mut(); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); -} - -#[test] -fn iter() { - let stream = vec![stream::pending::<()>(), stream::pending::<()>(), stream::pending::<()>()] - .into_iter() - .collect::>(); - - let mut iter = stream.iter(); - assert_eq!(iter.len(), 3); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); - - let mut stream = vec![stream::iter(vec![]), stream::iter(vec![1]), stream::iter(vec![2])] - .into_iter() - .collect::>(); - - assert_eq!(stream.len(), 3); - assert_eq!(block_on(stream.next()), Some(1)); - assert_eq!(stream.len(), 2); - let mut iter = stream.iter(); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); - - assert_eq!(block_on(stream.next()), Some(2)); - assert_eq!(stream.len(), 2); - assert_eq!(block_on(stream.next()), None); - let mut iter = stream.iter(); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); -} - -#[test] -fn into_iter() { - let stream = vec![stream::pending::<()>(), stream::pending::<()>(), stream::pending::<()>()] - .into_iter() - .collect::>(); - - let mut iter = stream.into_iter(); - assert_eq!(iter.len(), 3); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 2); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 1); - assert!(iter.next().is_some()); - assert_eq!(iter.len(), 0); - assert!(iter.next().is_none()); -} diff --git a/futures/tests/stream_select_next_some.rs b/futures/tests/stream_select_next_some.rs deleted file mode 100644 index 16b1a31394..0000000000 --- a/futures/tests/stream_select_next_some.rs +++ /dev/null @@ -1,86 +0,0 @@ -use futures::executor::block_on; -use futures::future::{self, FusedFuture, FutureExt}; -use futures::select; -use futures::stream::{FuturesUnordered, StreamExt}; -use futures::task::{Context, Poll}; -use futures_test::future::FutureTestExt; -use futures_test::task::new_count_waker; - -#[test] -fn is_terminated() { - let (waker, counter) = new_count_waker(); - let mut cx = Context::from_waker(&waker); - - let mut tasks = FuturesUnordered::new(); - - let mut select_next_some = tasks.select_next_some(); - assert!(!select_next_some.is_terminated()); - assert_eq!(select_next_some.poll_unpin(&mut cx), Poll::Pending); - assert_eq!(counter, 1); - assert!(select_next_some.is_terminated()); - drop(select_next_some); - - tasks.push(future::ready(1)); - - let mut select_next_some = tasks.select_next_some(); - assert!(!select_next_some.is_terminated()); - assert_eq!(select_next_some.poll_unpin(&mut cx), Poll::Ready(1)); - assert!(!select_next_some.is_terminated()); - assert_eq!(select_next_some.poll_unpin(&mut cx), Poll::Pending); - assert!(select_next_some.is_terminated()); -} - -#[test] -fn select() { - // Checks that even though `async_tasks` will yield a `None` and return - // `is_terminated() == true` during the first poll, it manages to toggle - // back to having items after a future is pushed into it during the second - // poll (after pending_once completes). - block_on(async { - let mut fut = future::ready(1).pending_once(); - let mut async_tasks = FuturesUnordered::new(); - let mut total = 0; - loop { - select! { - num = fut => { - total += num; - async_tasks.push(async { 5 }); - }, - num = async_tasks.select_next_some() => { - total += num; - } - complete => break, - } - } - assert_eq!(total, 6); - }); -} - -// Check that `select!` macro does not fail when importing from `futures_util`. -#[test] -fn futures_util_select() { - use futures_util::select; - - // Checks that even though `async_tasks` will yield a `None` and return - // `is_terminated() == true` during the first poll, it manages to toggle - // back to having items after a future is pushed into it during the second - // poll (after pending_once completes). - block_on(async { - let mut fut = future::ready(1).pending_once(); - let mut async_tasks = FuturesUnordered::new(); - let mut total = 0; - loop { - select! { - num = fut => { - total += num; - async_tasks.push(async { 5 }); - }, - num = async_tasks.select_next_some() => { - total += num; - } - complete => break, - } - } - assert_eq!(total, 6); - }); -} diff --git a/futures/tests/stream_split.rs b/futures/tests/stream_split.rs deleted file mode 100644 index 694c151807..0000000000 --- a/futures/tests/stream_split.rs +++ /dev/null @@ -1,57 +0,0 @@ -use futures::executor::block_on; -use futures::sink::{Sink, SinkExt}; -use futures::stream::{self, Stream, StreamExt}; -use futures::task::{Context, Poll}; -use pin_project::pin_project; -use std::pin::Pin; - -#[test] -fn test_split() { - #[pin_project] - struct Join { - #[pin] - stream: T, - #[pin] - sink: U, - } - - impl Stream for Join { - type Item = T::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().stream.poll_next(cx) - } - } - - impl, Item> Sink for Join { - type Error = U::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().sink.poll_ready(cx) - } - - fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> { - self.project().sink.start_send(item) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().sink.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().sink.poll_close(cx) - } - } - - let mut dest: Vec = Vec::new(); - { - let join = Join { stream: stream::iter(vec![10, 20, 30]), sink: &mut dest }; - - let (sink, stream) = join.split(); - let join = sink.reunite(stream).expect("test_split: reunite error"); - let (mut sink, stream) = join.split(); - let mut stream = stream.map(Ok); - block_on(sink.send_all(&mut stream)).unwrap(); - } - assert_eq!(dest, vec![10, 20, 30]); -} diff --git a/futures/tests/stream_try_stream.rs b/futures/tests/stream_try_stream.rs deleted file mode 100644 index 6530da0fd1..0000000000 --- a/futures/tests/stream_try_stream.rs +++ /dev/null @@ -1,183 +0,0 @@ -use core::pin::Pin; -use std::convert::Infallible; - -use futures::{ - stream::{self, repeat, Repeat, StreamExt, TryStreamExt}, - task::Poll, - Stream, -}; -use futures_executor::block_on; -use futures_task::Context; -use futures_test::task::noop_context; - -#[test] -fn try_filter_map_after_err() { - let cx = &mut noop_context(); - let mut s = stream::iter(1..=3) - .map(Ok) - .try_filter_map(|v| async move { Err::, _>(v) }) - .filter_map(|r| async move { r.ok() }) - .boxed(); - assert_eq!(Poll::Ready(None), s.poll_next_unpin(cx)); -} - -#[test] -fn try_skip_while_after_err() { - let cx = &mut noop_context(); - let mut s = stream::iter(1..=3) - .map(Ok) - .try_skip_while(|_| async move { Err::<_, ()>(()) }) - .filter_map(|r| async move { r.ok() }) - .boxed(); - assert_eq!(Poll::Ready(None), s.poll_next_unpin(cx)); -} - -#[test] -fn try_take_while_after_err() { - let cx = &mut noop_context(); - let mut s = stream::iter(1..=3) - .map(Ok) - .try_take_while(|_| async move { Err::<_, ()>(()) }) - .filter_map(|r| async move { r.ok() }) - .boxed(); - assert_eq!(Poll::Ready(None), s.poll_next_unpin(cx)); -} - -#[test] -fn try_flatten_unordered() { - let test_st = stream::iter(1..7) - .map(|val: u32| { - if val % 2 == 0 { - Ok(stream::unfold((val, 1), |(val, pow)| async move { - Some((val.pow(pow), (val, pow + 1))) - }) - .take(3) - .map(move |val| if val % 16 != 0 { Ok(val) } else { Err(val) })) - } else { - Err(val) - } - }) - .map_ok(Box::pin) - .try_flatten_unordered(None); - - block_on(async move { - assert_eq!( - // All numbers can be divided by 16 and odds must be `Err` - // For all basic evens we must have powers from 1 to 3 - vec![ - Err(1), - Err(3), - Err(5), - Ok(2), - Ok(4), - Ok(6), - Ok(4), - Err(16), - Ok(36), - Ok(8), - Err(64), - Ok(216) - ], - test_st.collect::>().await - ) - }); - - #[derive(Clone, Debug)] - struct ErrorStream { - error_after: usize, - polled: usize, - } - - impl Stream for ErrorStream { - type Item = Result>, ()>; - - fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - if self.polled > self.error_after { - panic!("Polled after error"); - } else { - let out = - if self.polled == self.error_after { Err(()) } else { Ok(repeat(Ok(()))) }; - self.polled += 1; - Poll::Ready(Some(out)) - } - } - } - - block_on(async move { - let mut st = ErrorStream { error_after: 3, polled: 0 }.try_flatten_unordered(None); - let mut ctr = 0; - while (st.try_next().await).is_ok() { - ctr += 1; - } - assert_eq!(ctr, 0); - - assert_eq!( - ErrorStream { error_after: 10, polled: 0 } - .try_flatten_unordered(None) - .inspect_ok(|_| panic!("Unexpected `Ok`")) - .try_collect::>() - .await, - Err(()) - ); - - let mut taken = 0; - assert_eq!( - ErrorStream { error_after: 10, polled: 0 } - .map_ok(|st| st.take(3)) - .try_flatten_unordered(1) - .inspect(|_| taken += 1) - .try_fold((), |(), res| async move { res }) - .await, - Err(()) - ); - assert_eq!(taken, 31); - }) -} - -async fn is_even(number: u8) -> bool { - number % 2 == 0 -} - -#[test] -fn try_all() { - block_on(async { - let empty: [Result; 0] = []; - let st = stream::iter(empty); - let all = st.try_all(is_even).await; - assert_eq!(Ok(true), all); - - let st = stream::iter([Ok::<_, Infallible>(2), Ok(4), Ok(6), Ok(8)]); - let all = st.try_all(is_even).await; - assert_eq!(Ok(true), all); - - let st = stream::iter([Ok::<_, Infallible>(2), Ok(3), Ok(4)]); - let all = st.try_all(is_even).await; - assert_eq!(Ok(false), all); - - let st = stream::iter([Ok(2), Ok(4), Err("err"), Ok(8)]); - let all = st.try_all(is_even).await; - assert_eq!(Err("err"), all); - }); -} - -#[test] -fn try_any() { - block_on(async { - let empty: [Result; 0] = []; - let st = stream::iter(empty); - let any = st.try_any(is_even).await; - assert_eq!(Ok(false), any); - - let st = stream::iter([Ok::<_, Infallible>(1), Ok(2), Ok(3)]); - let any = st.try_any(is_even).await; - assert_eq!(Ok(true), any); - - let st = stream::iter([Ok::<_, Infallible>(1), Ok(3), Ok(5)]); - let any = st.try_any(is_even).await; - assert_eq!(Ok(false), any); - - let st = stream::iter([Ok(1), Ok(3), Err("err"), Ok(8)]); - let any = st.try_any(is_even).await; - assert_eq!(Err("err"), any); - }); -} diff --git a/futures/tests/stream_unfold.rs b/futures/tests/stream_unfold.rs deleted file mode 100644 index 16b10813b1..0000000000 --- a/futures/tests/stream_unfold.rs +++ /dev/null @@ -1,32 +0,0 @@ -use futures::future; -use futures::stream; -use futures_test::future::FutureTestExt; -use futures_test::{assert_stream_done, assert_stream_next, assert_stream_pending}; - -#[test] -fn unfold1() { - let mut stream = stream::unfold(0, |state| { - if state <= 2 { - future::ready(Some((state * 2, state + 1))).pending_once() - } else { - future::ready(None).pending_once() - } - }); - - // Creates the future with the closure - // Not ready (delayed future) - assert_stream_pending!(stream); - // Future is ready, yields the item - assert_stream_next!(stream, 0); - - // Repeat - assert_stream_pending!(stream); - assert_stream_next!(stream, 2); - - assert_stream_pending!(stream); - assert_stream_next!(stream, 4); - - // No more items - assert_stream_pending!(stream); - assert_stream_done!(stream); -} diff --git a/futures/tests/task_arc_wake.rs b/futures/tests/task_arc_wake.rs deleted file mode 100644 index aedc15bcb8..0000000000 --- a/futures/tests/task_arc_wake.rs +++ /dev/null @@ -1,79 +0,0 @@ -use futures::task::{self, ArcWake, Waker}; -use std::panic; -use std::sync::{Arc, Mutex}; - -struct CountingWaker { - nr_wake: Mutex, -} - -impl CountingWaker { - fn new() -> Self { - Self { nr_wake: Mutex::new(0) } - } - - fn wakes(&self) -> i32 { - *self.nr_wake.lock().unwrap() - } -} - -impl ArcWake for CountingWaker { - fn wake_by_ref(arc_self: &Arc) { - let mut lock = arc_self.nr_wake.lock().unwrap(); - *lock += 1; - } -} - -#[test] -fn create_from_arc() { - let some_w = Arc::new(CountingWaker::new()); - - let w1: Waker = task::waker(some_w.clone()); - assert_eq!(2, Arc::strong_count(&some_w)); - w1.wake_by_ref(); - assert_eq!(1, some_w.wakes()); - - let w2 = w1.clone(); - assert_eq!(3, Arc::strong_count(&some_w)); - - w2.wake_by_ref(); - assert_eq!(2, some_w.wakes()); - - drop(w2); - assert_eq!(2, Arc::strong_count(&some_w)); - drop(w1); - assert_eq!(1, Arc::strong_count(&some_w)); -} - -#[test] -fn ref_wake_same() { - let some_w = Arc::new(CountingWaker::new()); - - let w1: Waker = task::waker(some_w.clone()); - let w2 = task::waker_ref(&some_w); - let w3 = w2.clone(); - - assert!(w1.will_wake(&w2)); - assert!(w2.will_wake(&w3)); -} - -#[test] -fn proper_refcount_on_wake_panic() { - struct PanicWaker; - - impl ArcWake for PanicWaker { - fn wake_by_ref(_arc_self: &Arc) { - panic!("WAKE UP"); - } - } - - let some_w = Arc::new(PanicWaker); - - let w1: Waker = task::waker(some_w.clone()); - assert_eq!( - "WAKE UP", - *panic::catch_unwind(|| w1.wake_by_ref()).unwrap_err().downcast::<&str>().unwrap() - ); - assert_eq!(2, Arc::strong_count(&some_w)); // some_w + w1 - drop(w1); - assert_eq!(1, Arc::strong_count(&some_w)); // some_w -} diff --git a/futures/tests/task_atomic_waker.rs b/futures/tests/task_atomic_waker.rs deleted file mode 100644 index cec3db2876..0000000000 --- a/futures/tests/task_atomic_waker.rs +++ /dev/null @@ -1,48 +0,0 @@ -use futures::executor::block_on; -use futures::future::poll_fn; -use futures::task::{AtomicWaker, Poll}; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::thread; - -#[test] -fn basic() { - let atomic_waker = Arc::new(AtomicWaker::new()); - let atomic_waker_copy = atomic_waker.clone(); - - let returned_pending = Arc::new(AtomicUsize::new(0)); - let returned_pending_copy = returned_pending.clone(); - - let woken = Arc::new(AtomicUsize::new(0)); - let woken_copy = woken.clone(); - - let t = thread::spawn(move || { - let mut pending_count = 0; - - block_on(poll_fn(move |cx| { - if woken_copy.load(Ordering::Relaxed) == 1 { - Poll::Ready(()) - } else { - // Assert we return pending exactly once - assert_eq!(0, pending_count); - pending_count += 1; - atomic_waker_copy.register(cx.waker()); - - returned_pending_copy.store(1, Ordering::Relaxed); - - Poll::Pending - } - })) - }); - - while returned_pending.load(Ordering::Relaxed) == 0 {} - - // give spawned thread some time to sleep in `block_on` - thread::yield_now(); - - woken.store(1, Ordering::Relaxed); - atomic_waker.wake(); - - t.join().unwrap(); -} diff --git a/futures/tests/test_macro.rs b/futures/tests/test_macro.rs deleted file mode 100644 index 6adf51d8bb..0000000000 --- a/futures/tests/test_macro.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[futures_test::test] -async fn it_works() { - let fut = async { true }; - assert!(fut.await); - - let fut = async { false }; - assert!(!fut.await); -} - -#[should_panic] -#[futures_test::test] -async fn it_is_being_run() { - let fut = async { false }; - assert!(fut.await); -} - -#[futures_test::test] -async fn return_ty() -> Result<(), ()> { - Ok(()) -} diff --git a/futures/tests/try_join.rs b/futures/tests/try_join.rs deleted file mode 100644 index 0281ab897d..0000000000 --- a/futures/tests/try_join.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![deny(unreachable_code)] - -use futures::{executor::block_on, try_join}; - -// TODO: This abuses https://github.com/rust-lang/rust/issues/58733 in order to -// test behavior of the `try_join!` macro with the never type before it is -// stabilized. Once `!` is again stabilized this can be removed and replaced -// with direct use of `!` below where `Never` is used. -trait MyTrait { - type Output; -} -impl MyTrait for fn() -> T { - type Output = T; -} -type Never = ! as MyTrait>::Output; - -#[test] -fn try_join_never_error() { - block_on(async { - let future1 = async { Ok::<(), Never>(()) }; - let future2 = async { Ok::<(), Never>(()) }; - try_join!(future1, future2) - }) - .unwrap(); -} - -#[test] -fn try_join_never_ok() { - block_on(async { - let future1 = async { Err::(()) }; - let future2 = async { Err::(()) }; - try_join!(future1, future2) - }) - .unwrap_err(); -} diff --git a/futures/tests_disabled/all.rs b/futures/tests_disabled/all.rs deleted file mode 100644 index a7a571040a..0000000000 --- a/futures/tests_disabled/all.rs +++ /dev/null @@ -1,400 +0,0 @@ -use futures::channel::oneshot::{self, Canceled}; -use futures::executor::block_on; -use futures::future; -use std::sync::mpsc::{channel, TryRecvError}; - -// mod support; -// use support::*; - -fn unselect(r: Result, Either<(E, B), (E, A)>>) -> Result { - match r { - Ok(Either::Left((t, _))) | Ok(Either::Right((t, _))) => Ok(t), - Err(Either::Left((e, _))) | Err(Either::Right((e, _))) => Err(e), - } -} - -#[test] -fn result_smoke() { - fn is_future_v(_: C) - where - A: Send + 'static, - B: Send + 'static, - C: Future, - { - } - - is_future_v::(f_ok(1).map(|a| a + 1)); - is_future_v::(f_ok(1).map_err(|a| a + 1)); - is_future_v::(f_ok(1).and_then(Ok)); - is_future_v::(f_ok(1).or_else(Err)); - is_future_v::<(i32, i32), u32, _>(f_ok(1).join(Err(3))); - is_future_v::(f_ok(1).map(f_ok).flatten()); - - assert_done(|| f_ok(1), r_ok(1)); - assert_done(|| f_err(1), r_err(1)); - assert_done(|| result(Ok(1)), r_ok(1)); - assert_done(|| result(Err(1)), r_err(1)); - assert_done(|| ok(1), r_ok(1)); - assert_done(|| err(1), r_err(1)); - assert_done(|| f_ok(1).map(|a| a + 2), r_ok(3)); - assert_done(|| f_err(1).map(|a| a + 2), r_err(1)); - assert_done(|| f_ok(1).map_err(|a| a + 2), r_ok(1)); - assert_done(|| f_err(1).map_err(|a| a + 2), r_err(3)); - assert_done(|| f_ok(1).and_then(|a| Ok(a + 2)), r_ok(3)); - assert_done(|| f_err(1).and_then(|a| Ok(a + 2)), r_err(1)); - assert_done(|| f_ok(1).and_then(|a| Err(a as u32 + 3)), r_err(4)); - assert_done(|| f_err(1).and_then(|a| Err(a as u32 + 4)), r_err(1)); - assert_done(|| f_ok(1).or_else(|a| Ok(a as i32 + 2)), r_ok(1)); - assert_done(|| f_err(1).or_else(|a| Ok(a as i32 + 2)), r_ok(3)); - assert_done(|| f_ok(1).or_else(|a| Err(a + 3)), r_ok(1)); - assert_done(|| f_err(1).or_else(|a| Err(a + 4)), r_err(5)); - assert_done(|| f_ok(1).select(f_err(2)).then(unselect), r_ok(1)); - assert_done(|| f_ok(1).select(Ok(2)).then(unselect), r_ok(1)); - assert_done(|| f_err(1).select(f_ok(1)).then(unselect), r_err(1)); - assert_done(|| f_ok(1).select(empty()).then(unselect), Ok(1)); - assert_done(|| empty().select(f_ok(1)).then(unselect), Ok(1)); - assert_done(|| f_ok(1).join(f_err(1)), Err(1)); - assert_done(|| f_ok(1).join(Ok(2)), Ok((1, 2))); - assert_done(|| f_err(1).join(f_ok(1)), Err(1)); - assert_done(|| f_ok(1).then(|_| Ok(2)), r_ok(2)); - assert_done(|| f_ok(1).then(|_| Err(2)), r_err(2)); - assert_done(|| f_err(1).then(|_| Ok(2)), r_ok(2)); - assert_done(|| f_err(1).then(|_| Err(2)), r_err(2)); -} - -#[test] -fn test_empty() { - fn empty() -> Empty { - future::empty() - } - - assert_empty(|| empty()); - assert_empty(|| empty().select(empty())); - assert_empty(|| empty().join(empty())); - assert_empty(|| empty().join(f_ok(1))); - assert_empty(|| f_ok(1).join(empty())); - assert_empty(|| empty().or_else(move |_| empty())); - assert_empty(|| empty().and_then(move |_| empty())); - assert_empty(|| f_err(1).or_else(move |_| empty())); - assert_empty(|| f_ok(1).and_then(move |_| empty())); - assert_empty(|| empty().map(|a| a + 1)); - assert_empty(|| empty().map_err(|a| a + 1)); - assert_empty(|| empty().then(|a| a)); -} - -#[test] -fn test_ok() { - assert_done(|| ok(1), r_ok(1)); - assert_done(|| err(1), r_err(1)); -} - -#[test] -fn flatten() { - fn ok(a: T) -> FutureResult { - future::ok(a) - } - fn err(b: E) -> FutureResult { - future::err(b) - } - - assert_done(|| ok(ok(1)).flatten(), r_ok(1)); - assert_done(|| ok(err(1)).flatten(), r_err(1)); - assert_done(|| err(1u32).map(ok).flatten(), r_err(1)); - assert_done(|| future::ok(future::ok(1)).flatten(), r_ok(1)); - assert_empty(|| ok(empty::()).flatten()); - assert_empty(|| empty::().map(ok).flatten()); -} - -#[test] -fn smoke_oneshot() { - assert_done( - || { - let (c, p) = oneshot::channel(); - c.send(1).unwrap(); - p - }, - Ok(1), - ); - assert_done( - || { - let (c, p) = oneshot::channel::(); - drop(c); - p - }, - Err(Canceled), - ); - let mut completes = Vec::new(); - assert_empty(|| { - let (a, b) = oneshot::channel::(); - completes.push(a); - b - }); - - let (c, mut p) = oneshot::channel::(); - drop(c); - let res = panic_waker_lw(|lw| p.poll(lw)); - assert!(res.is_err()); - let (c, p) = oneshot::channel::(); - drop(c); - let (tx, rx) = channel(); - p.then(move |_| tx.send(())).forget(); - rx.recv().unwrap(); -} - -#[test] -fn select_cancels() { - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |b| { - btx.send(b).unwrap(); - b - }); - let d = d.map(move |d| { - dtx.send(d).unwrap(); - d - }); - - let mut f = b.select(d).then(unselect); - // assert!(f.poll(&mut Task::new()).is_pending()); - assert!(brx.try_recv().is_err()); - assert!(drx.try_recv().is_err()); - a.send(1).unwrap(); - noop_waker_lw(|lw| { - let res = f.poll(lw); - assert!(res.ok().unwrap().is_ready()); - assert_eq!(brx.recv().unwrap(), 1); - drop(c); - assert!(drx.recv().is_err()); - - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, _brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |b| { - btx.send(b).unwrap(); - b - }); - let d = d.map(move |d| { - dtx.send(d).unwrap(); - d - }); - - let mut f = b.select(d).then(unselect); - assert!(f.poll(lw).ok().unwrap().is_pending()); - assert!(f.poll(lw).ok().unwrap().is_pending()); - a.send(1).unwrap(); - assert!(f.poll(lw).ok().unwrap().is_ready()); - drop((c, f)); - assert!(drx.recv().is_err()); - }) -} - -#[test] -fn join_cancels() { - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, _brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |b| { - btx.send(b).unwrap(); - b - }); - let d = d.map(move |d| { - dtx.send(d).unwrap(); - d - }); - - let mut f = b.join(d); - drop(a); - let res = panic_waker_lw(|lw| f.poll(lw)); - assert!(res.is_err()); - drop(c); - assert!(drx.recv().is_err()); - - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, _brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |b| { - btx.send(b).unwrap(); - b - }); - let d = d.map(move |d| { - dtx.send(d).unwrap(); - d - }); - - let (tx, rx) = channel(); - let f = b.join(d); - f.then(move |_| { - tx.send(()).unwrap(); - let res: Result<(), ()> = Ok(()); - res - }) - .forget(); - assert!(rx.try_recv().is_err()); - drop(a); - rx.recv().unwrap(); - drop(c); - assert!(drx.recv().is_err()); -} - -#[test] -fn join_incomplete() { - let (a, b) = oneshot::channel::(); - let (tx, rx) = channel(); - noop_waker_lw(|lw| { - let mut f = ok(1).join(b).map(move |r| tx.send(r).unwrap()); - assert!(f.poll(lw).ok().unwrap().is_pending()); - assert!(rx.try_recv().is_err()); - a.send(2).unwrap(); - assert!(f.poll(lw).ok().unwrap().is_ready()); - assert_eq!(rx.recv().unwrap(), (1, 2)); - - let (a, b) = oneshot::channel::(); - let (tx, rx) = channel(); - let mut f = b.join(Ok(2)).map(move |r| tx.send(r).unwrap()); - assert!(f.poll(lw).ok().unwrap().is_pending()); - assert!(rx.try_recv().is_err()); - a.send(1).unwrap(); - assert!(f.poll(lw).ok().unwrap().is_ready()); - assert_eq!(rx.recv().unwrap(), (1, 2)); - - let (a, b) = oneshot::channel::(); - let (tx, rx) = channel(); - let mut f = ok(1).join(b).map_err(move |_r| tx.send(2).unwrap()); - assert!(f.poll(lw).ok().unwrap().is_pending()); - assert!(rx.try_recv().is_err()); - drop(a); - assert!(f.poll(lw).is_err()); - assert_eq!(rx.recv().unwrap(), 2); - - let (a, b) = oneshot::channel::(); - let (tx, rx) = channel(); - let mut f = b.join(Ok(2)).map_err(move |_r| tx.send(1).unwrap()); - assert!(f.poll(lw).ok().unwrap().is_pending()); - assert!(rx.try_recv().is_err()); - drop(a); - assert!(f.poll(lw).is_err()); - assert_eq!(rx.recv().unwrap(), 1); - }) -} - -#[test] -fn select2() { - assert_done(|| f_ok(2).select(empty()).then(unselect), Ok(2)); - assert_done(|| empty().select(f_ok(2)).then(unselect), Ok(2)); - assert_done(|| f_err(2).select(empty()).then(unselect), Err(2)); - assert_done(|| empty().select(f_err(2)).then(unselect), Err(2)); - - assert_done( - || { - f_ok(1).select(f_ok(2)).map_err(|_| 0).and_then(|either_tup| { - let (a, b) = either_tup.into_inner(); - b.map(move |b| a + b) - }) - }, - Ok(3), - ); - - // Finish one half of a select and then fail the second, ensuring that we - // get the notification of the second one. - { - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let f = b.select(d); - let (tx, rx) = channel(); - f.map(move |r| tx.send(r).unwrap()).forget(); - a.send(1).unwrap(); - let (val, next) = rx.recv().unwrap().into_inner(); - assert_eq!(val, 1); - let (tx, rx) = channel(); - next.map_err(move |_r| tx.send(2).unwrap()).forget(); - assert_eq!(rx.try_recv().err().unwrap(), TryRecvError::Empty); - drop(c); - assert_eq!(rx.recv().unwrap(), 2); - } - - // Fail the second half and ensure that we see the first one finish - { - let ((a, b), (c, d)) = (oneshot::channel::(), oneshot::channel::()); - let f = b.select(d); - let (tx, rx) = channel(); - f.map_err(move |r| tx.send((1, r.into_inner().1)).unwrap()).forget(); - drop(c); - let (val, next) = rx.recv().unwrap(); - assert_eq!(val, 1); - let (tx, rx) = channel(); - next.map(move |r| tx.send(r).unwrap()).forget(); - assert_eq!(rx.try_recv().err().unwrap(), TryRecvError::Empty); - a.send(2).unwrap(); - assert_eq!(rx.recv().unwrap(), 2); - } - - // Cancelling the first half should cancel the second - { - let ((_a, b), (_c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |v| { - btx.send(v).unwrap(); - v - }); - let d = d.map(move |v| { - dtx.send(v).unwrap(); - v - }); - let f = b.select(d); - drop(f); - assert!(drx.recv().is_err()); - assert!(brx.recv().is_err()); - } - - // Cancel after a schedule - { - let ((_a, b), (_c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |v| { - btx.send(v).unwrap(); - v - }); - let d = d.map(move |v| { - dtx.send(v).unwrap(); - v - }); - let mut f = b.select(d); - let _res = noop_waker_lw(|lw| f.poll(lw)); - drop(f); - assert!(drx.recv().is_err()); - assert!(brx.recv().is_err()); - } - - // Cancel propagates - { - let ((a, b), (_c, d)) = (oneshot::channel::(), oneshot::channel::()); - let ((btx, brx), (dtx, drx)) = (channel(), channel()); - let b = b.map(move |v| { - btx.send(v).unwrap(); - v - }); - let d = d.map(move |v| { - dtx.send(v).unwrap(); - v - }); - let (tx, rx) = channel(); - b.select(d).map(move |_| tx.send(()).unwrap()).forget(); - drop(a); - assert!(drx.recv().is_err()); - assert!(brx.recv().is_err()); - assert!(rx.recv().is_err()); - } - - // Cancel on early drop - { - let (tx, rx) = channel(); - let f = f_ok(1).select(empty::<_, ()>().map(move |()| { - tx.send(()).unwrap(); - 1 - })); - drop(f); - assert!(rx.recv().is_err()); - } -} - -#[test] -fn option() { - assert_eq!(Ok(Some(())), block_on(Some(ok::<(), ()>(())).into_future())); - assert_eq!(Ok::<_, ()>(None::<()>), block_on(None::>.into_future())); -} diff --git a/futures/tests_disabled/stream.rs b/futures/tests_disabled/stream.rs deleted file mode 100644 index b00d2bb806..0000000000 --- a/futures/tests_disabled/stream.rs +++ /dev/null @@ -1,380 +0,0 @@ -use futures::channel::mpsc; -use futures::channel::oneshot; -use futures::executor::{block_on, block_on_stream}; -use futures::future::{err, ok}; -use futures::stream::{empty, iter_ok, poll_fn, Peekable}; - -// mod support; -// use support::*; - -pub struct Iter { - iter: I, -} - -pub fn iter(i: J) -> Iter -where - J: IntoIterator>, -{ - Iter { iter: i.into_iter() } -} - -impl Stream for Iter -where - I: Iterator>, -{ - type Item = T; - type Error = E; - - fn poll_next(&mut self, _: &mut Context<'_>) -> Poll, E> { - match self.iter.next() { - Some(Ok(e)) => Ok(Poll::Ready(Some(e))), - Some(Err(e)) => Err(e), - None => Ok(Poll::Ready(None)), - } - } -} - -fn list() -> Box + Send> { - let (tx, rx) = mpsc::channel(1); - tx.send(Ok(1)).and_then(|tx| tx.send(Ok(2))).and_then(|tx| tx.send(Ok(3))).forget(); - Box::new(rx.then(|r| r.unwrap())) -} - -fn err_list() -> Box + Send> { - let (tx, rx) = mpsc::channel(1); - tx.send(Ok(1)).and_then(|tx| tx.send(Ok(2))).and_then(|tx| tx.send(Err(3))).forget(); - Box::new(rx.then(|r| r.unwrap())) -} - -#[test] -fn map() { - assert_done(|| list().map(|a| a + 1).collect(), Ok(vec![2, 3, 4])); -} - -#[test] -fn map_err() { - assert_done(|| err_list().map_err(|a| a + 1).collect::>(), Err(4)); -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct FromErrTest(u32); - -impl From for FromErrTest { - fn from(i: u32) -> Self { - Self(i) - } -} - -#[test] -fn from_err() { - assert_done(|| err_list().err_into().collect::>(), Err(FromErrTest(3))); -} - -#[test] -fn fold() { - assert_done(|| list().fold(0, |a, b| ok::(a + b)), Ok(6)); - assert_done(|| err_list().fold(0, |a, b| ok::(a + b)), Err(3)); -} - -#[test] -fn filter() { - assert_done(|| list().filter(|a| ok(*a % 2 == 0)).collect(), Ok(vec![2])); -} - -#[test] -fn filter_map() { - assert_done( - || list().filter_map(|x| ok(if x % 2 == 0 { Some(x + 10) } else { None })).collect(), - Ok(vec![12]), - ); -} - -#[test] -fn and_then() { - assert_done(|| list().and_then(|a| Ok(a + 1)).collect(), Ok(vec![2, 3, 4])); - assert_done(|| list().and_then(|a| err::(a as u32)).collect::>(), Err(1)); -} - -#[test] -fn then() { - assert_done(|| list().then(|a| a.map(|e| e + 1)).collect(), Ok(vec![2, 3, 4])); -} - -#[test] -fn or_else() { - assert_done(|| err_list().or_else(|a| ok::(a as i32)).collect(), Ok(vec![1, 2, 3])); -} - -#[test] -fn flatten() { - assert_done(|| list().map(|_| list()).flatten().collect(), Ok(vec![1, 2, 3, 1, 2, 3, 1, 2, 3])); -} - -#[test] -fn skip() { - assert_done(|| list().skip(2).collect(), Ok(vec![3])); -} - -#[test] -fn skip_passes_errors_through() { - let mut s = block_on_stream(iter(vec![Err(1), Err(2), Ok(3), Ok(4), Ok(5)]).skip(1)); - assert_eq!(s.next(), Some(Err(1))); - assert_eq!(s.next(), Some(Err(2))); - assert_eq!(s.next(), Some(Ok(4))); - assert_eq!(s.next(), Some(Ok(5))); - assert_eq!(s.next(), None); -} - -#[test] -fn skip_while() { - assert_done(|| list().skip_while(|e| Ok(*e % 2 == 1)).collect(), Ok(vec![2, 3])); -} -#[test] -fn take() { - assert_done(|| list().take(2).collect(), Ok(vec![1, 2])); -} - -#[test] -fn take_while() { - assert_done(|| list().take_while(|e| Ok(*e < 3)).collect(), Ok(vec![1, 2])); -} - -#[test] -fn take_passes_errors_through() { - let mut s = block_on_stream(iter(vec![Err(1), Err(2), Ok(3), Ok(4), Err(4)]).take(1)); - assert_eq!(s.next(), Some(Err(1))); - assert_eq!(s.next(), Some(Err(2))); - assert_eq!(s.next(), Some(Ok(3))); - assert_eq!(s.next(), None); - - let mut s = block_on_stream(iter(vec![Ok(1), Err(2)]).take(1)); - assert_eq!(s.next(), Some(Ok(1))); - assert_eq!(s.next(), None); -} - -#[test] -fn peekable() { - assert_done(|| list().peekable().collect(), Ok(vec![1, 2, 3])); -} - -#[test] -fn fuse() { - let mut stream = block_on_stream(list().fuse()); - assert_eq!(stream.next(), Some(Ok(1))); - assert_eq!(stream.next(), Some(Ok(2))); - assert_eq!(stream.next(), Some(Ok(3))); - assert_eq!(stream.next(), None); - assert_eq!(stream.next(), None); - assert_eq!(stream.next(), None); -} - -#[test] -fn buffered() { - let (tx, rx) = mpsc::channel(1); - let (a, b) = oneshot::channel::(); - let (c, d) = oneshot::channel::(); - - tx.send(Box::new(b.recover(|_| panic!())) as Box + Send>) - .and_then(|tx| tx.send(Box::new(d.map_err(|_| panic!())))) - .forget(); - - let mut rx = rx.buffered(2); - sassert_empty(&mut rx); - c.send(3).unwrap(); - sassert_empty(&mut rx); - a.send(5).unwrap(); - let mut rx = block_on_stream(rx); - assert_eq!(rx.next(), Some(Ok(5))); - assert_eq!(rx.next(), Some(Ok(3))); - assert_eq!(rx.next(), None); - - let (tx, rx) = mpsc::channel(1); - let (a, b) = oneshot::channel::(); - let (c, d) = oneshot::channel::(); - - tx.send(Box::new(b.recover(|_| panic!())) as Box + Send>) - .and_then(|tx| tx.send(Box::new(d.map_err(|_| panic!())))) - .forget(); - - let mut rx = rx.buffered(1); - sassert_empty(&mut rx); - c.send(3).unwrap(); - sassert_empty(&mut rx); - a.send(5).unwrap(); - let mut rx = block_on_stream(rx); - assert_eq!(rx.next(), Some(Ok(5))); - assert_eq!(rx.next(), Some(Ok(3))); - assert_eq!(rx.next(), None); -} - -#[test] -fn unordered() { - let (tx, rx) = mpsc::channel(1); - let (a, b) = oneshot::channel::(); - let (c, d) = oneshot::channel::(); - - tx.send(Box::new(b.recover(|_| panic!())) as Box + Send>) - .and_then(|tx| tx.send(Box::new(d.recover(|_| panic!())))) - .forget(); - - let mut rx = rx.buffer_unordered(2); - sassert_empty(&mut rx); - let mut rx = block_on_stream(rx); - c.send(3).unwrap(); - assert_eq!(rx.next(), Some(Ok(3))); - a.send(5).unwrap(); - assert_eq!(rx.next(), Some(Ok(5))); - assert_eq!(rx.next(), None); - - let (tx, rx) = mpsc::channel(1); - let (a, b) = oneshot::channel::(); - let (c, d) = oneshot::channel::(); - - tx.send(Box::new(b.recover(|_| panic!())) as Box + Send>) - .and_then(|tx| tx.send(Box::new(d.recover(|_| panic!())))) - .forget(); - - // We don't even get to see `c` until `a` completes. - let mut rx = rx.buffer_unordered(1); - sassert_empty(&mut rx); - c.send(3).unwrap(); - sassert_empty(&mut rx); - a.send(5).unwrap(); - let mut rx = block_on_stream(rx); - assert_eq!(rx.next(), Some(Ok(5))); - assert_eq!(rx.next(), Some(Ok(3))); - assert_eq!(rx.next(), None); -} - -#[test] -fn zip() { - assert_done(|| list().zip(list()).collect(), Ok(vec![(1, 1), (2, 2), (3, 3)])); - assert_done(|| list().zip(list().take(2)).collect(), Ok(vec![(1, 1), (2, 2)])); - assert_done(|| list().take(2).zip(list()).collect(), Ok(vec![(1, 1), (2, 2)])); - assert_done(|| err_list().zip(list()).collect::>(), Err(3)); - assert_done(|| list().zip(list().map(|x| x + 1)).collect(), Ok(vec![(1, 2), (2, 3), (3, 4)])); -} - -#[test] -fn peek() { - struct Peek { - inner: Peekable + Send>>, - } - - impl Future for Peek { - type Item = (); - type Error = u32; - - fn poll(&mut self, cx: &mut Context<'_>) -> Poll<(), u32> { - { - let res = ready!(self.inner.peek(cx))?; - assert_eq!(res, Some(&1)); - } - assert_eq!(self.inner.peek(cx).unwrap(), Some(&1).into()); - assert_eq!(self.inner.poll_next(cx).unwrap(), Some(1).into()); - Ok(Poll::Ready(())) - } - } - - block_on(Peek { inner: list().peekable() }).unwrap() -} - -#[test] -fn wait() { - assert_eq!(block_on_stream(list()).collect::, _>>(), Ok(vec![1, 2, 3])); -} - -#[test] -fn chunks() { - assert_done(|| list().chunks(3).collect(), Ok(vec![vec![1, 2, 3]])); - assert_done(|| list().chunks(1).collect(), Ok(vec![vec![1], vec![2], vec![3]])); - assert_done(|| list().chunks(2).collect(), Ok(vec![vec![1, 2], vec![3]])); - let mut list = block_on_stream(err_list().chunks(3)); - let i = list.next().unwrap().unwrap(); - assert_eq!(i, vec![1, 2]); - let i = list.next().unwrap().unwrap_err(); - assert_eq!(i, 3); -} - -#[test] -#[should_panic] -fn chunks_panic_on_cap_zero() { - let _ = list().chunks(0); -} - -#[test] -fn forward() { - let v = Vec::new(); - let v = block_on(iter(vec![0, 1]).forward(v)).unwrap().1; - assert_eq!(v, vec![0, 1]); - - let v = block_on(iter(vec![2, 3]).forward(v)).unwrap().1; - assert_eq!(v, vec![0, 1, 2, 3]); - - assert_done(move || iter(vec![4, 5]).forward(v).map(|(_, s)| s), Ok(vec![0, 1, 2, 3, 4, 5])); -} - -#[test] -fn try_forward() { - let v = Vec::new(); - let v = block_on(iter_ok::<_, Never>(vec![0, 1]).try_forward(v)).unwrap().1; - assert_eq!(v, vec![0, 1]); - - let v = block_on(iter_ok::<_, Never>(vec![2, 3]).try_forward(v)).unwrap().1; - assert_eq!(v, vec![0, 1, 2, 3]); - - assert_done( - move || iter_ok::<_, Never>(vec![4, 5]).try_forward(v).map(|(_, s)| s), - Ok(vec![0, 1, 2, 3, 4, 5]), - ); -} - -#[test] -fn concat() { - let a = iter_ok::<_, ()>(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]); - assert_done(move || a.concat(), Ok(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])); - - let b = iter(vec![Ok::<_, ()>(vec![1, 2, 3]), Err(()), Ok(vec![7, 8, 9])]); - assert_done(move || b.concat(), Err(())); -} - -#[test] -fn concat2() { - let a = iter_ok::<_, ()>(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]); - assert_done(move || a.concat(), Ok(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])); - - let b = iter(vec![Ok::<_, ()>(vec![1, 2, 3]), Err(()), Ok(vec![7, 8, 9])]); - assert_done(move || b.concat(), Err(())); - - let c = empty::, ()>(); - assert_done(move || c.concat(), Ok(vec![])) -} - -#[test] -fn stream_poll_fn() { - let mut counter = 5usize; - - let read_stream = poll_fn(move |_| -> Poll, std::io::Error> { - if counter == 0 { - return Ok(Poll::Ready(None)); - } - counter -= 1; - Ok(Poll::Ready(Some(counter))) - }); - - assert_eq!(block_on_stream(read_stream).count(), 5); -} - -#[test] -fn inspect() { - let mut seen = vec![]; - assert_done(|| list().inspect(|&a| seen.push(a)).collect(), Ok(vec![1, 2, 3])); - assert_eq!(seen, [1, 2, 3]); -} - -#[test] -fn inspect_err() { - let mut seen = vec![]; - assert_done(|| err_list().inspect_err(|&a| seen.push(a)).collect::>(), Err(3)); - assert_eq!(seen, [3]); -} diff --git a/imprint.md b/imprint.md new file mode 100644 index 0000000000..2ec357c273 --- /dev/null +++ b/imprint.md @@ -0,0 +1,17 @@ +--- +layout: page +title: Imprint +permalink: /imprint/ +--- + +Futures-rs is maintained by the Rust Networking Working Group. + +You can find us +[on GitHub](https://github.com/rust-lang-nursery/net-wg). Or you can talk to +us [on Discord](https://discordapp.com/invite/rust-lang) (channel #wg-net). + +## License +The contents on this site are licensed under either the MIT license or the Apache License 2.0 at your option. Code from code examples may be used without restrictions (unless noted otherwise). + +## Liability for Links +This site contains links to external websites of third parties on whose contents we have no influence. Therefore, we can not assume any liability for these external contents. The respective provider or operator of the pages is always responsible for the contents of the linked pages. The linked pages were checked for possible legal violations at the time of linking. Illegal content was not recognizable at the time of linking. However, a permanent content control of the linked pages is not reasonable without concrete evidence of an infringement. Upon notification of violations, we will remove such links immediately. diff --git a/index.md b/index.md new file mode 100644 index 0000000000..e4d427d215 --- /dev/null +++ b/index.md @@ -0,0 +1,3 @@ +--- +layout: home +--- diff --git a/triagebot.toml b/triagebot.toml deleted file mode 100644 index 5852e1136c..0000000000 --- a/triagebot.toml +++ /dev/null @@ -1,52 +0,0 @@ -[relabel] -allow-unauthenticated = [ - "S-*", -] - -[review-submitted] -# This label is added when a "request changes" review is submitted. -reviewed_label = "S-waiting-on-author" -# These labels are removed when a "request changes" review is submitted. -review_labels = ["S-waiting-on-review"] - -[review-requested] -# Those labels are removed when PR author requests a review from an assignee -remove_labels = ["S-waiting-on-author"] -# Those labels are added when PR author requests a review from an assignee -add_labels = ["S-waiting-on-review"] - -[assign] -warn_non_default_branch = true - -[autolabel."A-channel"] -trigger_files = ["futures-channel/src"] - -[autolabel."A-compat"] -trigger_files = ["futures-util/src/compat"] - -[autolabel."A-executor"] -trigger_files = ["futures-executor/src"] - -[autolabel."A-future"] -trigger_files = ["futures-core/src/future.rs", "futures-util/src/future"] - -[autolabel."A-io"] -trigger_files = ["futures-io/src", "futures-util/src/io"] - -[autolabel."A-lock"] -trigger_files = ["futures-util/src/lock"] - -[autolabel."A-macro"] -trigger_files = ["futures-macro/src", "futures-util/src/async_await"] - -[autolabel."A-sink"] -trigger_files = ["futures-sink/src", "futures-util/src/sink"] - -[autolabel."A-stream"] -trigger_files = ["futures-core/src/stream.rs", "futures-util/src/stream"] - -[autolabel."A-task"] -trigger_files = ["futures-core/src/task", "futures-task/src", "futures-util/src/task"] - -[autolabel."S-waiting-on-review"] -new_pr = true