forked from mirror/async-std
Merge branch 'master' into add_future_delay
This commit is contained in:
commit
5c9cfb4fe8
96 changed files with 3740 additions and 1925 deletions
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -11,6 +11,8 @@ jobs:
|
||||||
build_and_test:
|
build_and_test:
|
||||||
name: Build and test
|
name: Build and test
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -Dwarnings
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
@ -29,7 +31,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
args: --all --benches --bins --examples --tests
|
args: --all --bins --examples
|
||||||
|
|
||||||
- name: check unstable
|
- name: check unstable
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
@ -41,11 +43,13 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --all --doc --features unstable
|
args: --all --features unstable
|
||||||
|
|
||||||
check_fmt_and_docs:
|
check_fmt_and_docs:
|
||||||
name: Checking fmt and docs
|
name: Checking fmt and docs
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -Dwarnings
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
|
|
||||||
|
@ -77,6 +81,9 @@ jobs:
|
||||||
clippy_check:
|
clippy_check:
|
||||||
name: Clippy check
|
name: Clippy check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# TODO: There is a lot of warnings
|
||||||
|
# env:
|
||||||
|
# RUSTFLAGS: -Dwarnings
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- id: component
|
- id: component
|
||||||
|
|
101
CHANGELOG.md
101
CHANGELOG.md
|
@ -7,6 +7,104 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
# [0.99.10] - 2019-10-16
|
||||||
|
|
||||||
|
This patch stabilizes several core concurrency macros, introduces async versions
|
||||||
|
of `Path` and `PathBuf`, and adds almost 100 other commits.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
__Asynchronously read directories from the filesystem__
|
||||||
|
```rust
|
||||||
|
use async_std::fs;
|
||||||
|
use async_std::path::Path;
|
||||||
|
use async_std::prelude::*;
|
||||||
|
|
||||||
|
let path = Path::new("/laputa");
|
||||||
|
let mut dir = fs::read_dir(&path).await.unwrap();
|
||||||
|
while let Some(entry) = dir.next().await {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
println!("{:?}", entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
__Cooperatively reschedule the current task on the executor__
|
||||||
|
```rust
|
||||||
|
use async_std::prelude::*;
|
||||||
|
use async_std::task;
|
||||||
|
|
||||||
|
task::spawn(async {
|
||||||
|
let x = fibonnacci(1000); // Do expensive work
|
||||||
|
task::yield_now().await; // Allow other tasks to run
|
||||||
|
x + fibonnacci(100) // Do more work
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
__Create an interval stream__
|
||||||
|
```rust
|
||||||
|
use async_std::prelude::*;
|
||||||
|
use async_std::stream;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
let mut interval = stream::interval(Duration::from_secs(4));
|
||||||
|
while let Some(_) = interval.next().await {
|
||||||
|
println!("prints every four seconds");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Added `FutureExt` to the `prelude`, allowing us to extend `Future`
|
||||||
|
- Added `Stream::cmp`
|
||||||
|
- Added `Stream::ge`
|
||||||
|
- Added `Stream::last`
|
||||||
|
- Added `Stream::le`
|
||||||
|
- Added `Stream::lt`
|
||||||
|
- Added `Stream::merge` as "unstable", replacing `stream::join!`
|
||||||
|
- Added `Stream::partial_cmp`
|
||||||
|
- Added `Stream::take_while`
|
||||||
|
- Added `Stream::try_fold`
|
||||||
|
- Added `future::IntoFuture` as "unstable"
|
||||||
|
- Added `io::BufRead::split`
|
||||||
|
- Added `io::Write::write_fmt`
|
||||||
|
- Added `print!`, `println!`, `eprint!`, `eprintln!` macros as "unstable"
|
||||||
|
- Added `process` as "unstable", re-exporting std types only for now
|
||||||
|
- Added `std::net` re-exports to the `net` submodule
|
||||||
|
- Added `std::path::PathBuf` with all associated methods
|
||||||
|
- Added `std::path::Path` with all associated methods
|
||||||
|
- Added `stream::ExactSizeStream` as "unstable"
|
||||||
|
- Added `stream::FusedStream` as "unstable"
|
||||||
|
- Added `stream::Product`
|
||||||
|
- Added `stream::Sum`
|
||||||
|
- Added `stream::from_fn`
|
||||||
|
- Added `stream::interval` as "unstable"
|
||||||
|
- Added `stream::repeat_with`
|
||||||
|
- Added `task::spawn_blocking` as "unstable", replacing `task::blocking`
|
||||||
|
- Added `task::yield_now`
|
||||||
|
- Added `write!` and `writeln!` macros as "unstable"
|
||||||
|
- Stabilized `future::join!` and `future::try_join!`
|
||||||
|
- Stabilized `future::timeout`
|
||||||
|
- Stabilized `path`
|
||||||
|
- Stabilized `task::ready!`
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Fixed `BufWriter::into_inner` so it calls `flush` before yielding
|
||||||
|
- Refactored `io::BufWriter` internals
|
||||||
|
- Refactored `net::ToSocketAddrs` internals
|
||||||
|
- Removed Travis CI entirely
|
||||||
|
- Rewrote the README.md
|
||||||
|
- Stabilized `io::Cursor`
|
||||||
|
- Switched bors over to use GitHub actions
|
||||||
|
- Updated the `io` documentation to match std's `io` docs
|
||||||
|
- Updated the `task` documentation to match std's `thread` docs
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Removed the "unstable" `stream::join!` in favor of `Stream::merge`
|
||||||
|
- Removed the "unstable" `task::blocking` in favor of `task::spawn_blocking`
|
||||||
|
|
||||||
# [0.99.9] - 2019-10-08
|
# [0.99.9] - 2019-10-08
|
||||||
|
|
||||||
This patch upgrades our `futures-rs` version, allowing us to build on the 1.39
|
This patch upgrades our `futures-rs` version, allowing us to build on the 1.39
|
||||||
|
@ -183,7 +281,8 @@ task::blocking(async {
|
||||||
|
|
||||||
- Initial beta release
|
- Initial beta release
|
||||||
|
|
||||||
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.9...HEAD
|
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.10...HEAD
|
||||||
|
[0.99.10]: https://github.com/async-rs/async-std/compare/v0.99.9...v0.99.10
|
||||||
[0.99.9]: https://github.com/async-rs/async-std/compare/v0.99.8...v0.99.9
|
[0.99.9]: https://github.com/async-rs/async-std/compare/v0.99.8...v0.99.9
|
||||||
[0.99.8]: https://github.com/async-rs/async-std/compare/v0.99.7...v0.99.8
|
[0.99.8]: https://github.com/async-rs/async-std/compare/v0.99.7...v0.99.8
|
||||||
[0.99.7]: https://github.com/async-rs/async-std/compare/v0.99.6...v0.99.7
|
[0.99.7]: https://github.com/async-rs/async-std/compare/v0.99.6...v0.99.7
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "async-std"
|
name = "async-std"
|
||||||
version = "0.99.9"
|
version = "0.99.10"
|
||||||
authors = [
|
authors = [
|
||||||
"Stjepan Glavina <stjepang@gmail.com>",
|
"Stjepan Glavina <stjepang@gmail.com>",
|
||||||
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
|
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
|
||||||
|
@ -21,15 +21,15 @@ features = ["docs"]
|
||||||
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
docs = ["broadcaster"]
|
docs = ["unstable"]
|
||||||
unstable = ["broadcaster"]
|
unstable = ["broadcaster"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-macros = "1.0.0"
|
async-macros = "1.0.0"
|
||||||
async-task = "1.0.0"
|
async-task = "1.0.0"
|
||||||
cfg-if = "0.1.9"
|
|
||||||
crossbeam-channel = "0.3.9"
|
crossbeam-channel = "0.3.9"
|
||||||
crossbeam-deque = "0.7.1"
|
crossbeam-deque = "0.7.1"
|
||||||
|
crossbeam-utils = "0.6.6"
|
||||||
futures-core-preview = "=0.3.0-alpha.19"
|
futures-core-preview = "=0.3.0-alpha.19"
|
||||||
futures-io-preview = "=0.3.0-alpha.19"
|
futures-io-preview = "=0.3.0-alpha.19"
|
||||||
futures-timer = "1.0.2"
|
futures-timer = "1.0.2"
|
||||||
|
@ -43,9 +43,11 @@ pin-utils = "0.1.0-alpha.4"
|
||||||
slab = "0.4.2"
|
slab = "0.4.2"
|
||||||
kv-log-macro = "1.0.4"
|
kv-log-macro = "1.0.4"
|
||||||
broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] }
|
broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] }
|
||||||
|
pin-project-lite = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
femme = "1.2.0"
|
femme = "1.2.0"
|
||||||
|
rand = "0.7.2"
|
||||||
# surf = "1.0.2"
|
# surf = "1.0.2"
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] }
|
futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] }
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
use crate::task::blocking;
|
use crate::task::blocking;
|
||||||
|
@ -113,17 +111,9 @@ impl DirBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::fs::DirBuilderExt;
|
use crate::os::unix::fs::DirBuilderExt;
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::fs::DirBuilderExt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl DirBuilderExt for DirBuilder {
|
impl DirBuilderExt for DirBuilder {
|
||||||
fn mode(&mut self, mode: u32) -> &mut Self {
|
fn mode(&mut self, mode: u32) -> &mut Self {
|
||||||
self.mode = Some(mode);
|
self.mode = Some(mode);
|
||||||
|
@ -131,4 +121,3 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ use std::ffi::OsString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::fs::{FileType, Metadata};
|
use crate::fs::{FileType, Metadata};
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::path::PathBuf;
|
use crate::path::PathBuf;
|
||||||
|
@ -160,21 +158,12 @@ impl fmt::Debug for DirEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::fs::DirEntryExt;
|
use crate::os::unix::fs::DirEntryExt;
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::fs::DirEntryExt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl DirEntryExt for DirEntry {
|
impl DirEntryExt for DirEntry {
|
||||||
fn ino(&self) -> u64 {
|
fn ino(&self) -> u64 {
|
||||||
self.0.ino()
|
self.0.ino()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ use std::pin::Pin;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::fs::{Metadata, Permissions};
|
use crate::fs::{Metadata, Permissions};
|
||||||
use crate::future;
|
use crate::future;
|
||||||
use crate::io::{self, Read, Seek, SeekFrom, Write};
|
use crate::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
|
@ -401,20 +399,9 @@ impl From<std::fs::File> for File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for File {
|
impl AsRawFd for File {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.file.as_raw_fd()
|
self.file.as_raw_fd()
|
||||||
|
@ -437,11 +424,10 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
|
||||||
impl AsRawHandle for File {
|
impl AsRawHandle for File {
|
||||||
fn as_raw_handle(&self) -> RawHandle {
|
fn as_raw_handle(&self) -> RawHandle {
|
||||||
self.file.as_raw_handle()
|
self.file.as_raw_handle()
|
||||||
|
@ -464,7 +450,6 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// An async mutex with non-borrowing lock guards.
|
/// An async mutex with non-borrowing lock guards.
|
||||||
struct Lock<T>(Arc<LockState<T>>);
|
struct Lock<T>(Arc<LockState<T>>);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use cfg_if::cfg_if;
|
cfg_not_docs! {
|
||||||
|
pub use std::fs::FileType;
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
/// The type of a file or directory.
|
/// The type of a file or directory.
|
||||||
///
|
///
|
||||||
/// A file type is returned by [`Metadata::file_type`].
|
/// A file type is returned by [`Metadata::file_type`].
|
||||||
|
@ -80,7 +81,4 @@ cfg_if! {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::fs::FileType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
use crate::task::blocking;
|
use crate::task::blocking;
|
||||||
|
@ -39,8 +37,11 @@ pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
||||||
blocking::spawn(move || std::fs::metadata(path)).await
|
blocking::spawn(move || std::fs::metadata(path)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_not_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
pub use std::fs::Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_docs! {
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use crate::fs::{FileType, Permissions};
|
use crate::fs::{FileType, Permissions};
|
||||||
|
@ -225,7 +226,4 @@ cfg_if! {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::fs::Metadata;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::fs::File;
|
use crate::fs::File;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
|
@ -296,17 +294,9 @@ impl Default for OpenOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::fs::OpenOptionsExt;
|
use crate::os::unix::fs::OpenOptionsExt;
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl OpenOptionsExt for OpenOptions {
|
impl OpenOptionsExt for OpenOptions {
|
||||||
fn mode(&mut self, mode: u32) -> &mut Self {
|
fn mode(&mut self, mode: u32) -> &mut Self {
|
||||||
self.0.mode(mode);
|
self.0.mode(mode);
|
||||||
|
@ -319,4 +309,3 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use cfg_if::cfg_if;
|
cfg_not_docs! {
|
||||||
|
pub use std::fs::Permissions;
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
/// A set of permissions on a file or directory.
|
/// A set of permissions on a file or directory.
|
||||||
///
|
///
|
||||||
/// This type is a re-export of [`std::fs::Permissions`].
|
/// This type is a re-export of [`std::fs::Permissions`].
|
||||||
|
@ -52,7 +53,4 @@ cfg_if! {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::fs::Permissions;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
use crate::utils::extension_trait;
|
cfg_unstable! {
|
||||||
|
mod delay;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
use std::time::Duration;
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
|
use delay::DelayFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension_trait! {
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
mod delay;
|
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
use delay::DelayFuture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_trait! {
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
A future represents an asynchronous computation.
|
A future represents an asynchronous computation.
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::future::Future;
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
pub trait IntoFuture {
|
pub trait IntoFuture {
|
||||||
/// The type of value produced on completion.
|
/// The type of value produced on completion.
|
||||||
|
|
|
@ -44,12 +44,6 @@
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use async_macros::{join, try_join};
|
pub use async_macros::{join, try_join};
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
|
||||||
pub use async_macros::{select, try_select};
|
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
pub use future::Future;
|
pub use future::Future;
|
||||||
pub use pending::pending;
|
pub use pending::pending;
|
||||||
pub use poll_fn::poll_fn;
|
pub use poll_fn::poll_fn;
|
||||||
|
@ -62,10 +56,10 @@ mod poll_fn;
|
||||||
mod ready;
|
mod ready;
|
||||||
mod timeout;
|
mod timeout;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unstable! {
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
#[doc(inline)]
|
||||||
mod into_future;
|
pub use async_macros::{select, try_select};
|
||||||
|
|
||||||
pub use into_future::IntoFuture;
|
pub use into_future::IntoFuture;
|
||||||
}
|
mod into_future;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::pin::Pin;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
@ -39,24 +40,24 @@ where
|
||||||
f.await
|
f.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A future that times out after a duration of time.
|
/// A future that times out after a duration of time.
|
||||||
struct TimeoutFuture<F> {
|
struct TimeoutFuture<F> {
|
||||||
|
#[pin]
|
||||||
future: F,
|
future: F,
|
||||||
|
#[pin]
|
||||||
delay: Delay,
|
delay: Delay,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TimeoutFuture<F> {
|
|
||||||
pin_utils::unsafe_pinned!(future: F);
|
|
||||||
pin_utils::unsafe_pinned!(delay: Delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Future> Future for TimeoutFuture<F> {
|
impl<F: Future> Future for TimeoutFuture<F> {
|
||||||
type Output = Result<F::Output, TimeoutError>;
|
type Output = Result<F::Output, TimeoutError>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.as_mut().future().poll(cx) {
|
let this = self.project();
|
||||||
|
match this.future.poll(cx) {
|
||||||
Poll::Ready(v) => Poll::Ready(Ok(v)),
|
Poll::Ready(v) => Poll::Ready(Ok(v)),
|
||||||
Poll::Pending => match self.delay().poll(cx) {
|
Poll::Pending => match this.delay.poll(cx) {
|
||||||
Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })),
|
Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })),
|
||||||
Poll::Pending => Poll::Pending,
|
Poll::Pending => Poll::Pending,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,11 +2,14 @@ use std::mem;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::read_until_internal;
|
use super::read_until_internal;
|
||||||
use crate::io::{self, BufRead};
|
use crate::io::{self, BufRead};
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream of lines in a byte stream.
|
/// A stream of lines in a byte stream.
|
||||||
///
|
///
|
||||||
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
|
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
|
||||||
|
@ -18,34 +21,36 @@ use crate::task::{Context, Poll};
|
||||||
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
|
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Lines<R> {
|
pub struct Lines<R> {
|
||||||
|
#[pin]
|
||||||
pub(crate) reader: R,
|
pub(crate) reader: R,
|
||||||
pub(crate) buf: String,
|
pub(crate) buf: String,
|
||||||
pub(crate) bytes: Vec<u8>,
|
pub(crate) bytes: Vec<u8>,
|
||||||
pub(crate) read: usize,
|
pub(crate) read: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: BufRead> Stream for Lines<R> {
|
impl<R: BufRead> Stream for Lines<R> {
|
||||||
type Item = io::Result<String>;
|
type Item = io::Result<String>;
|
||||||
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let Self {
|
let this = self.project();
|
||||||
reader,
|
let n = futures_core::ready!(read_line_internal(
|
||||||
buf,
|
this.reader,
|
||||||
bytes,
|
cx,
|
||||||
read,
|
this.buf,
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
this.bytes,
|
||||||
let reader = unsafe { Pin::new_unchecked(reader) };
|
this.read
|
||||||
let n = futures_core::ready!(read_line_internal(reader, cx, buf, bytes, read))?;
|
))?;
|
||||||
if n == 0 && buf.is_empty() {
|
if n == 0 && this.buf.is_empty() {
|
||||||
return Poll::Ready(None);
|
return Poll::Ready(None);
|
||||||
}
|
}
|
||||||
if buf.ends_with('\n') {
|
if this.buf.ends_with('\n') {
|
||||||
buf.pop();
|
this.buf.pop();
|
||||||
if buf.ends_with('\r') {
|
if this.buf.ends_with('\r') {
|
||||||
buf.pop();
|
this.buf.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Poll::Ready(Some(Ok(mem::replace(buf, String::new()))))
|
Poll::Ready(Some(Ok(mem::replace(this.buf, String::new()))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,12 @@ use read_until::ReadUntilFuture;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
use crate::utils::extension_trait;
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_trait! {
|
extension_trait! {
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
Allows reading from a buffered byte stream.
|
Allows reading from a buffered byte stream.
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::read_until_internal;
|
use super::read_until_internal;
|
||||||
use crate::io::{self, BufRead};
|
use crate::io::{self, BufRead};
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream over the contents of an instance of [`BufRead`] split on a particular byte.
|
/// A stream over the contents of an instance of [`BufRead`] split on a particular byte.
|
||||||
///
|
///
|
||||||
/// This stream is created by the [`split`] method on types that implement [`BufRead`].
|
/// This stream is created by the [`split`] method on types that implement [`BufRead`].
|
||||||
|
@ -17,30 +20,32 @@ use crate::task::{Context, Poll};
|
||||||
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
|
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Split<R> {
|
pub struct Split<R> {
|
||||||
|
#[pin]
|
||||||
pub(crate) reader: R,
|
pub(crate) reader: R,
|
||||||
pub(crate) buf: Vec<u8>,
|
pub(crate) buf: Vec<u8>,
|
||||||
pub(crate) read: usize,
|
pub(crate) read: usize,
|
||||||
pub(crate) delim: u8,
|
pub(crate) delim: u8,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: BufRead> Stream for Split<R> {
|
impl<R: BufRead> Stream for Split<R> {
|
||||||
type Item = io::Result<Vec<u8>>;
|
type Item = io::Result<Vec<u8>>;
|
||||||
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let Self {
|
let this = self.project();
|
||||||
reader,
|
let n = futures_core::ready!(read_until_internal(
|
||||||
buf,
|
this.reader,
|
||||||
read,
|
cx,
|
||||||
delim,
|
*this.delim,
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
this.buf,
|
||||||
let reader = unsafe { Pin::new_unchecked(reader) };
|
this.read
|
||||||
let n = futures_core::ready!(read_until_internal(reader, cx, *delim, buf, read))?;
|
))?;
|
||||||
if n == 0 && buf.is_empty() {
|
if n == 0 && this.buf.is_empty() {
|
||||||
return Poll::Ready(None);
|
return Poll::Ready(None);
|
||||||
}
|
}
|
||||||
if buf[buf.len() - 1] == *delim {
|
if this.buf[this.buf.len() - 1] == *this.delim {
|
||||||
buf.pop();
|
this.buf.pop();
|
||||||
}
|
}
|
||||||
Poll::Ready(Some(Ok(mem::replace(buf, vec![]))))
|
Poll::Ready(Some(Ok(mem::replace(this.buf, vec![]))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,14 @@ use std::io::{IoSliceMut, Read as _};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::io::{self, BufRead, Read, Seek, SeekFrom};
|
use crate::io::{self, BufRead, Read, Seek, SeekFrom};
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
const DEFAULT_CAPACITY: usize = 8 * 1024;
|
const DEFAULT_CAPACITY: usize = 8 * 1024;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Adds buffering to any reader.
|
/// Adds buffering to any reader.
|
||||||
///
|
///
|
||||||
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
|
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
|
||||||
|
@ -43,11 +46,13 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
|
||||||
/// # Ok(()) }) }
|
/// # Ok(()) }) }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct BufReader<R> {
|
pub struct BufReader<R> {
|
||||||
|
#[pin]
|
||||||
inner: R,
|
inner: R,
|
||||||
buf: Box<[u8]>,
|
buf: Box<[u8]>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
cap: usize,
|
cap: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: io::Read> BufReader<R> {
|
impl<R: io::Read> BufReader<R> {
|
||||||
/// Creates a buffered reader with default buffer capacity.
|
/// Creates a buffered reader with default buffer capacity.
|
||||||
|
@ -95,10 +100,6 @@ impl<R: io::Read> BufReader<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> BufReader<R> {
|
impl<R> BufReader<R> {
|
||||||
pin_utils::unsafe_pinned!(inner: R);
|
|
||||||
pin_utils::unsafe_unpinned!(pos: usize);
|
|
||||||
pin_utils::unsafe_unpinned!(cap: usize);
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying reader.
|
/// Gets a reference to the underlying reader.
|
||||||
///
|
///
|
||||||
/// It is inadvisable to directly read from the underlying reader.
|
/// It is inadvisable to directly read from the underlying reader.
|
||||||
|
@ -141,6 +142,13 @@ impl<R> BufReader<R> {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a pinned mutable reference to the underlying reader.
|
||||||
|
///
|
||||||
|
/// It is inadvisable to directly read from the underlying reader.
|
||||||
|
fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> {
|
||||||
|
self.project().inner
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to the internal buffer.
|
/// Returns a reference to the internal buffer.
|
||||||
///
|
///
|
||||||
/// This function will not attempt to fill the buffer if it is empty.
|
/// This function will not attempt to fill the buffer if it is empty.
|
||||||
|
@ -185,9 +193,10 @@ impl<R> BufReader<R> {
|
||||||
|
|
||||||
/// Invalidates all data in the internal buffer.
|
/// Invalidates all data in the internal buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn discard_buffer(mut self: Pin<&mut Self>) {
|
fn discard_buffer(self: Pin<&mut Self>) {
|
||||||
*self.as_mut().pos() = 0;
|
let this = self.project();
|
||||||
*self.cap() = 0;
|
*this.pos = 0;
|
||||||
|
*this.cap = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +210,7 @@ impl<R: Read> Read for BufReader<R> {
|
||||||
// (larger than our internal buffer), bypass our internal buffer
|
// (larger than our internal buffer), bypass our internal buffer
|
||||||
// entirely.
|
// entirely.
|
||||||
if self.pos == self.cap && buf.len() >= self.buf.len() {
|
if self.pos == self.cap && buf.len() >= self.buf.len() {
|
||||||
let res = futures_core::ready!(self.as_mut().inner().poll_read(cx, buf));
|
let res = futures_core::ready!(self.as_mut().get_pin_mut().poll_read(cx, buf));
|
||||||
self.discard_buffer();
|
self.discard_buffer();
|
||||||
return Poll::Ready(res);
|
return Poll::Ready(res);
|
||||||
}
|
}
|
||||||
|
@ -218,7 +227,8 @@ impl<R: Read> Read for BufReader<R> {
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
|
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
|
||||||
if self.pos == self.cap && total_len >= self.buf.len() {
|
if self.pos == self.cap && total_len >= self.buf.len() {
|
||||||
let res = futures_core::ready!(self.as_mut().inner().poll_read_vectored(cx, bufs));
|
let res =
|
||||||
|
futures_core::ready!(self.as_mut().get_pin_mut().poll_read_vectored(cx, bufs));
|
||||||
self.discard_buffer();
|
self.discard_buffer();
|
||||||
return Poll::Ready(res);
|
return Poll::Ready(res);
|
||||||
}
|
}
|
||||||
|
@ -234,28 +244,23 @@ impl<R: Read> BufRead for BufReader<R> {
|
||||||
self: Pin<&'a mut Self>,
|
self: Pin<&'a mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<io::Result<&'a [u8]>> {
|
) -> Poll<io::Result<&'a [u8]>> {
|
||||||
let Self {
|
let mut this = self.project();
|
||||||
inner,
|
|
||||||
buf,
|
|
||||||
cap,
|
|
||||||
pos,
|
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
|
||||||
let mut inner = unsafe { Pin::new_unchecked(inner) };
|
|
||||||
|
|
||||||
// If we've reached the end of our internal buffer then we need to fetch
|
// If we've reached the end of our internal buffer then we need to fetch
|
||||||
// some more data from the underlying reader.
|
// some more data from the underlying reader.
|
||||||
// Branch using `>=` instead of the more correct `==`
|
// Branch using `>=` instead of the more correct `==`
|
||||||
// to tell the compiler that the pos..cap slice is always valid.
|
// to tell the compiler that the pos..cap slice is always valid.
|
||||||
if *pos >= *cap {
|
if *this.pos >= *this.cap {
|
||||||
debug_assert!(*pos == *cap);
|
debug_assert!(*this.pos == *this.cap);
|
||||||
*cap = futures_core::ready!(inner.as_mut().poll_read(cx, buf))?;
|
*this.cap = futures_core::ready!(this.inner.as_mut().poll_read(cx, this.buf))?;
|
||||||
*pos = 0;
|
*this.pos = 0;
|
||||||
}
|
}
|
||||||
Poll::Ready(Ok(&buf[*pos..*cap]))
|
Poll::Ready(Ok(&this.buf[*this.pos..*this.cap]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(mut self: Pin<&mut Self>, amt: usize) {
|
fn consume(self: Pin<&mut Self>, amt: usize) {
|
||||||
*self.as_mut().pos() = cmp::min(self.pos + amt, self.cap);
|
let this = self.project();
|
||||||
|
*this.pos = cmp::min(*this.pos + amt, *this.cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,24 +310,26 @@ impl<R: Seek> Seek for BufReader<R> {
|
||||||
if let Some(offset) = n.checked_sub(remainder) {
|
if let Some(offset) = n.checked_sub(remainder) {
|
||||||
result = futures_core::ready!(
|
result = futures_core::ready!(
|
||||||
self.as_mut()
|
self.as_mut()
|
||||||
.inner()
|
.get_pin_mut()
|
||||||
.poll_seek(cx, SeekFrom::Current(offset))
|
.poll_seek(cx, SeekFrom::Current(offset))
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
// seek backwards by our remainder, and then by the offset
|
// seek backwards by our remainder, and then by the offset
|
||||||
futures_core::ready!(
|
futures_core::ready!(
|
||||||
self.as_mut()
|
self.as_mut()
|
||||||
.inner()
|
.get_pin_mut()
|
||||||
.poll_seek(cx, SeekFrom::Current(-remainder))
|
.poll_seek(cx, SeekFrom::Current(-remainder))
|
||||||
)?;
|
)?;
|
||||||
self.as_mut().discard_buffer();
|
self.as_mut().discard_buffer();
|
||||||
result = futures_core::ready!(
|
result = futures_core::ready!(
|
||||||
self.as_mut().inner().poll_seek(cx, SeekFrom::Current(n))
|
self.as_mut()
|
||||||
|
.get_pin_mut()
|
||||||
|
.poll_seek(cx, SeekFrom::Current(n))
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Seeking with Start/End doesn't care about our buffer length.
|
// Seeking with Start/End doesn't care about our buffer length.
|
||||||
result = futures_core::ready!(self.as_mut().inner().poll_seek(cx, pos))?;
|
result = futures_core::ready!(self.as_mut().get_pin_mut().poll_seek(cx, pos))?;
|
||||||
}
|
}
|
||||||
self.discard_buffer();
|
self.discard_buffer();
|
||||||
Poll::Ready(Ok(result))
|
Poll::Ready(Ok(result))
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::fmt;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::io::write::WriteExt;
|
use crate::io::write::WriteExt;
|
||||||
use crate::io::{self, Seek, SeekFrom, Write};
|
use crate::io::{self, Seek, SeekFrom, Write};
|
||||||
|
@ -9,6 +10,7 @@ use crate::task::{Context, Poll};
|
||||||
|
|
||||||
const DEFAULT_CAPACITY: usize = 8 * 1024;
|
const DEFAULT_CAPACITY: usize = 8 * 1024;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Wraps a writer and buffers its output.
|
/// Wraps a writer and buffers its output.
|
||||||
///
|
///
|
||||||
/// It can be excessively inefficient to work directly with something that
|
/// It can be excessively inefficient to work directly with something that
|
||||||
|
@ -79,18 +81,17 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
|
||||||
/// [`TcpStream`]: ../net/struct.TcpStream.html
|
/// [`TcpStream`]: ../net/struct.TcpStream.html
|
||||||
/// [`flush`]: trait.Write.html#tymethod.flush
|
/// [`flush`]: trait.Write.html#tymethod.flush
|
||||||
pub struct BufWriter<W> {
|
pub struct BufWriter<W> {
|
||||||
|
#[pin]
|
||||||
inner: W,
|
inner: W,
|
||||||
buf: Vec<u8>,
|
buf: Vec<u8>,
|
||||||
written: usize,
|
written: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IntoInnerError<W>(W, std::io::Error);
|
pub struct IntoInnerError<W>(W, std::io::Error);
|
||||||
|
|
||||||
impl<W: Write> BufWriter<W> {
|
impl<W: Write> BufWriter<W> {
|
||||||
pin_utils::unsafe_pinned!(inner: W);
|
|
||||||
pin_utils::unsafe_unpinned!(buf: Vec<u8>);
|
|
||||||
|
|
||||||
/// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
|
/// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
|
||||||
/// but may change in the future.
|
/// but may change in the future.
|
||||||
///
|
///
|
||||||
|
@ -178,6 +179,13 @@ impl<W: Write> BufWriter<W> {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a pinned mutable reference to the underlying writer.
|
||||||
|
///
|
||||||
|
/// It is inadvisable to directly write to the underlying writer.
|
||||||
|
fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut W> {
|
||||||
|
self.project().inner
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes BufWriter, returning the underlying writer
|
/// Consumes BufWriter, returning the underlying writer
|
||||||
///
|
///
|
||||||
/// This method will not write leftover data, it will be lost.
|
/// This method will not write leftover data, it will be lost.
|
||||||
|
@ -234,16 +242,15 @@ impl<W: Write> BufWriter<W> {
|
||||||
///
|
///
|
||||||
/// [`LineWriter`]: struct.LineWriter.html
|
/// [`LineWriter`]: struct.LineWriter.html
|
||||||
fn poll_flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
fn poll_flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
let Self {
|
let mut this = self.project();
|
||||||
inner,
|
let len = this.buf.len();
|
||||||
buf,
|
|
||||||
written,
|
|
||||||
} = unsafe { Pin::get_unchecked_mut(self) };
|
|
||||||
let mut inner = unsafe { Pin::new_unchecked(inner) };
|
|
||||||
let len = buf.len();
|
|
||||||
let mut ret = Ok(());
|
let mut ret = Ok(());
|
||||||
while *written < len {
|
while *this.written < len {
|
||||||
match inner.as_mut().poll_write(cx, &buf[*written..]) {
|
match this
|
||||||
|
.inner
|
||||||
|
.as_mut()
|
||||||
|
.poll_write(cx, &this.buf[*this.written..])
|
||||||
|
{
|
||||||
Poll::Ready(Ok(0)) => {
|
Poll::Ready(Ok(0)) => {
|
||||||
ret = Err(io::Error::new(
|
ret = Err(io::Error::new(
|
||||||
io::ErrorKind::WriteZero,
|
io::ErrorKind::WriteZero,
|
||||||
|
@ -251,7 +258,7 @@ impl<W: Write> BufWriter<W> {
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Poll::Ready(Ok(n)) => *written += n,
|
Poll::Ready(Ok(n)) => *this.written += n,
|
||||||
Poll::Ready(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {}
|
Poll::Ready(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||||
Poll::Ready(Err(e)) => {
|
Poll::Ready(Err(e)) => {
|
||||||
ret = Err(e);
|
ret = Err(e);
|
||||||
|
@ -260,10 +267,10 @@ impl<W: Write> BufWriter<W> {
|
||||||
Poll::Pending => return Poll::Pending,
|
Poll::Pending => return Poll::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if *written > 0 {
|
if *this.written > 0 {
|
||||||
buf.drain(..*written);
|
this.buf.drain(..*this.written);
|
||||||
}
|
}
|
||||||
*written = 0;
|
*this.written = 0;
|
||||||
Poll::Ready(ret)
|
Poll::Ready(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,20 +285,20 @@ impl<W: Write> Write for BufWriter<W> {
|
||||||
ready!(self.as_mut().poll_flush_buf(cx))?;
|
ready!(self.as_mut().poll_flush_buf(cx))?;
|
||||||
}
|
}
|
||||||
if buf.len() >= self.buf.capacity() {
|
if buf.len() >= self.buf.capacity() {
|
||||||
self.inner().poll_write(cx, buf)
|
self.get_pin_mut().poll_write(cx, buf)
|
||||||
} else {
|
} else {
|
||||||
Pin::new(&mut *self.buf()).poll_write(cx, buf)
|
Pin::new(&mut *self.project().buf).poll_write(cx, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
ready!(self.as_mut().poll_flush_buf(cx))?;
|
ready!(self.as_mut().poll_flush_buf(cx))?;
|
||||||
self.inner().poll_flush(cx)
|
self.get_pin_mut().poll_flush(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
ready!(self.as_mut().poll_flush_buf(cx))?;
|
ready!(self.as_mut().poll_flush_buf(cx))?;
|
||||||
self.inner().poll_close(cx)
|
self.get_pin_mut().poll_close(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,6 +321,6 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
|
||||||
pos: SeekFrom,
|
pos: SeekFrom,
|
||||||
) -> Poll<io::Result<u64>> {
|
) -> Poll<io::Result<u64>> {
|
||||||
ready!(self.as_mut().poll_flush_buf(cx))?;
|
ready!(self.as_mut().poll_flush_buf(cx))?;
|
||||||
self.inner().poll_seek(cx, pos)
|
self.get_pin_mut().poll_seek(cx, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::io::{self, BufRead, BufReader, Read, Write};
|
use crate::io::{self, BufRead, BufReader, Read, Write};
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
@ -46,47 +48,38 @@ where
|
||||||
R: Read + Unpin + ?Sized,
|
R: Read + Unpin + ?Sized,
|
||||||
W: Write + Unpin + ?Sized,
|
W: Write + Unpin + ?Sized,
|
||||||
{
|
{
|
||||||
pub struct CopyFuture<'a, R, W: ?Sized> {
|
pin_project! {
|
||||||
|
struct CopyFuture<R, W> {
|
||||||
|
#[pin]
|
||||||
reader: R,
|
reader: R,
|
||||||
writer: &'a mut W,
|
#[pin]
|
||||||
|
writer: W,
|
||||||
amt: u64,
|
amt: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, W: Unpin + ?Sized> CopyFuture<'_, R, W> {
|
|
||||||
fn project(self: Pin<&mut Self>) -> (Pin<&mut R>, Pin<&mut W>, &mut u64) {
|
|
||||||
unsafe {
|
|
||||||
let this = self.get_unchecked_mut();
|
|
||||||
(
|
|
||||||
Pin::new_unchecked(&mut this.reader),
|
|
||||||
Pin::new(&mut *this.writer),
|
|
||||||
&mut this.amt,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, W> Future for CopyFuture<'_, R, W>
|
impl<R, W> Future for CopyFuture<R, W>
|
||||||
where
|
where
|
||||||
R: BufRead,
|
R: BufRead,
|
||||||
W: Write + Unpin + ?Sized,
|
W: Write + Unpin,
|
||||||
{
|
{
|
||||||
type Output = io::Result<u64>;
|
type Output = io::Result<u64>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let (mut reader, mut writer, amt) = self.project();
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let buffer = futures_core::ready!(reader.as_mut().poll_fill_buf(cx))?;
|
let buffer = futures_core::ready!(this.reader.as_mut().poll_fill_buf(cx))?;
|
||||||
if buffer.is_empty() {
|
if buffer.is_empty() {
|
||||||
futures_core::ready!(writer.as_mut().poll_flush(cx))?;
|
futures_core::ready!(this.writer.as_mut().poll_flush(cx))?;
|
||||||
return Poll::Ready(Ok(*amt));
|
return Poll::Ready(Ok(*this.amt));
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = futures_core::ready!(writer.as_mut().poll_write(cx, buffer))?;
|
let i = futures_core::ready!(this.writer.as_mut().poll_write(cx, buffer))?;
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
||||||
}
|
}
|
||||||
*amt += i as u64;
|
*this.amt += i as u64;
|
||||||
reader.as_mut().consume(i);
|
this.reader.as_mut().consume(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::io::IoSliceMut;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use crate::io::{self, BufRead, Read};
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
use crate::io::{self, BufRead, IoSliceMut, Read};
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Adaptor to chain together two readers.
|
/// Adaptor to chain together two readers.
|
||||||
///
|
///
|
||||||
/// This struct is generally created by calling [`chain`] on a reader.
|
/// This struct is generally created by calling [`chain`] on a reader.
|
||||||
|
@ -12,10 +14,13 @@ use crate::task::{Context, Poll};
|
||||||
///
|
///
|
||||||
/// [`chain`]: trait.Read.html#method.chain
|
/// [`chain`]: trait.Read.html#method.chain
|
||||||
pub struct Chain<T, U> {
|
pub struct Chain<T, U> {
|
||||||
|
#[pin]
|
||||||
pub(crate) first: T,
|
pub(crate) first: T,
|
||||||
|
#[pin]
|
||||||
pub(crate) second: U,
|
pub(crate) second: U,
|
||||||
pub(crate) done_first: bool,
|
pub(crate) done_first: bool,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, U> Chain<T, U> {
|
impl<T, U> Chain<T, U> {
|
||||||
/// Consumes the `Chain`, returning the wrapped readers.
|
/// Consumes the `Chain`, returning the wrapped readers.
|
||||||
|
@ -98,76 +103,64 @@ impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read + Unpin, U: Read + Unpin> Read for Chain<T, U> {
|
impl<T: Read, U: Read> Read for Chain<T, U> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
if !self.done_first {
|
let this = self.project();
|
||||||
let rd = Pin::new(&mut self.first);
|
if !*this.done_first {
|
||||||
|
match futures_core::ready!(this.first.poll_read(cx, buf)) {
|
||||||
match futures_core::ready!(rd.poll_read(cx, buf)) {
|
Ok(0) if !buf.is_empty() => *this.done_first = true,
|
||||||
Ok(0) if !buf.is_empty() => self.done_first = true,
|
|
||||||
Ok(n) => return Poll::Ready(Ok(n)),
|
Ok(n) => return Poll::Ready(Ok(n)),
|
||||||
Err(err) => return Poll::Ready(Err(err)),
|
Err(err) => return Poll::Ready(Err(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rd = Pin::new(&mut self.second);
|
this.second.poll_read(cx, buf)
|
||||||
rd.poll_read(cx, buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_read_vectored(
|
fn poll_read_vectored(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
bufs: &mut [IoSliceMut<'_>],
|
bufs: &mut [IoSliceMut<'_>],
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
if !self.done_first {
|
let this = self.project();
|
||||||
let rd = Pin::new(&mut self.first);
|
if !*this.done_first {
|
||||||
|
match futures_core::ready!(this.first.poll_read_vectored(cx, bufs)) {
|
||||||
match futures_core::ready!(rd.poll_read_vectored(cx, bufs)) {
|
Ok(0) if !bufs.is_empty() => *this.done_first = true,
|
||||||
Ok(0) if !bufs.is_empty() => self.done_first = true,
|
|
||||||
Ok(n) => return Poll::Ready(Ok(n)),
|
Ok(n) => return Poll::Ready(Ok(n)),
|
||||||
Err(err) => return Poll::Ready(Err(err)),
|
Err(err) => return Poll::Ready(Err(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rd = Pin::new(&mut self.second);
|
this.second.poll_read_vectored(cx, bufs)
|
||||||
rd.poll_read_vectored(cx, bufs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BufRead + Unpin, U: BufRead + Unpin> BufRead for Chain<T, U> {
|
impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
|
||||||
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
|
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
|
||||||
let Self {
|
let this = self.project();
|
||||||
first,
|
if !*this.done_first {
|
||||||
second,
|
match futures_core::ready!(this.first.poll_fill_buf(cx)) {
|
||||||
done_first,
|
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
|
||||||
|
|
||||||
if !*done_first {
|
|
||||||
let first = unsafe { Pin::new_unchecked(first) };
|
|
||||||
match futures_core::ready!(first.poll_fill_buf(cx)) {
|
|
||||||
Ok(buf) if buf.is_empty() => {
|
Ok(buf) if buf.is_empty() => {
|
||||||
*done_first = true;
|
*this.done_first = true;
|
||||||
}
|
}
|
||||||
Ok(buf) => return Poll::Ready(Ok(buf)),
|
Ok(buf) => return Poll::Ready(Ok(buf)),
|
||||||
Err(err) => return Poll::Ready(Err(err)),
|
Err(err) => return Poll::Ready(Err(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let second = unsafe { Pin::new_unchecked(second) };
|
this.second.poll_fill_buf(cx)
|
||||||
second.poll_fill_buf(cx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(mut self: Pin<&mut Self>, amt: usize) {
|
fn consume(self: Pin<&mut Self>, amt: usize) {
|
||||||
if !self.done_first {
|
let this = self.project();
|
||||||
let rd = Pin::new(&mut self.first);
|
if !*this.done_first {
|
||||||
rd.consume(amt)
|
this.first.consume(amt)
|
||||||
} else {
|
} else {
|
||||||
let rd = Pin::new(&mut self.second);
|
this.second.consume(amt)
|
||||||
rd.consume(amt)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,23 +13,17 @@ use read_to_end::{read_to_end_internal, ReadToEndFuture};
|
||||||
use read_to_string::ReadToStringFuture;
|
use read_to_string::ReadToStringFuture;
|
||||||
use read_vectored::ReadVectoredFuture;
|
use read_vectored::ReadVectoredFuture;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use crate::io::IoSliceMut;
|
use crate::io::IoSliceMut;
|
||||||
use crate::utils::extension_trait;
|
|
||||||
|
|
||||||
cfg_if! {
|
extension_trait! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_trait! {
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
Allows reading from a byte stream.
|
Allows reading from a byte stream.
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::io::{self, BufRead, Read};
|
use crate::io::{self, BufRead, Read};
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Reader adaptor which limits the bytes read from an underlying reader.
|
/// Reader adaptor which limits the bytes read from an underlying reader.
|
||||||
///
|
///
|
||||||
/// This struct is generally created by calling [`take`] on a reader.
|
/// This struct is generally created by calling [`take`] on a reader.
|
||||||
|
@ -12,9 +15,11 @@ use crate::task::{Context, Poll};
|
||||||
/// [`take`]: trait.Read.html#method.take
|
/// [`take`]: trait.Read.html#method.take
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Take<T> {
|
pub struct Take<T> {
|
||||||
|
#[pin]
|
||||||
pub(crate) inner: T,
|
pub(crate) inner: T,
|
||||||
pub(crate) limit: u64,
|
pub(crate) limit: u64,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Take<T> {
|
impl<T> Take<T> {
|
||||||
/// Returns the number of bytes that can be read before this instance will
|
/// Returns the number of bytes that can be read before this instance will
|
||||||
|
@ -152,15 +157,15 @@ impl<T> Take<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read + Unpin> Read for Take<T> {
|
impl<T: Read> Read for Take<T> {
|
||||||
/// Attempt to read from the `AsyncRead` into `buf`.
|
/// Attempt to read from the `AsyncRead` into `buf`.
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
let Self { inner, limit } = &mut *self;
|
let this = self.project();
|
||||||
take_read_internal(Pin::new(inner), cx, buf, limit)
|
take_read_internal(this.inner, cx, buf, this.limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,31 +191,30 @@ pub fn take_read_internal<R: Read + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BufRead + Unpin> BufRead for Take<T> {
|
impl<T: BufRead> BufRead for Take<T> {
|
||||||
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
|
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
|
||||||
let Self { inner, limit } = unsafe { self.get_unchecked_mut() };
|
let this = self.project();
|
||||||
let inner = unsafe { Pin::new_unchecked(inner) };
|
|
||||||
|
|
||||||
if *limit == 0 {
|
if *this.limit == 0 {
|
||||||
return Poll::Ready(Ok(&[]));
|
return Poll::Ready(Ok(&[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
match futures_core::ready!(inner.poll_fill_buf(cx)) {
|
match futures_core::ready!(this.inner.poll_fill_buf(cx)) {
|
||||||
Ok(buf) => {
|
Ok(buf) => {
|
||||||
let cap = cmp::min(buf.len() as u64, *limit) as usize;
|
let cap = cmp::min(buf.len() as u64, *this.limit) as usize;
|
||||||
Poll::Ready(Ok(&buf[..cap]))
|
Poll::Ready(Ok(&buf[..cap]))
|
||||||
}
|
}
|
||||||
Err(e) => Poll::Ready(Err(e)),
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(mut self: Pin<&mut Self>, amt: usize) {
|
fn consume(self: Pin<&mut Self>, amt: usize) {
|
||||||
|
let this = self.project();
|
||||||
// Don't let callers reset the limit by passing an overlarge value
|
// Don't let callers reset the limit by passing an overlarge value
|
||||||
let amt = cmp::min(amt as u64, self.limit) as usize;
|
let amt = cmp::min(amt as u64, *this.limit) as usize;
|
||||||
self.limit -= amt as u64;
|
*this.limit -= amt as u64;
|
||||||
|
|
||||||
let rd = Pin::new(&mut self.inner);
|
this.inner.consume(amt);
|
||||||
rd.consume(amt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
use std::pin::Pin;
|
mod seek;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use seek::SeekFuture;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::io::SeekFrom;
|
||||||
use crate::io::{self, SeekFrom};
|
|
||||||
use crate::task::{Context, Poll};
|
|
||||||
use crate::utils::extension_trait;
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_trait! {
|
extension_trait! {
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use crate::io;
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
Allows seeking through a byte stream.
|
Allows seeking through a byte stream.
|
||||||
|
|
||||||
|
@ -114,19 +111,3 @@ extension_trait! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct SeekFuture<'a, T: Unpin + ?Sized> {
|
|
||||||
seeker: &'a mut T,
|
|
||||||
pos: SeekFrom,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SeekExt + Unpin + ?Sized> Future for SeekFuture<'_, T> {
|
|
||||||
type Output = io::Result<u64>;
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
let pos = self.pos;
|
|
||||||
Pin::new(&mut *self.seeker).poll_seek(cx, pos)
|
|
||||||
}
|
|
||||||
}
|
|
21
src/io/seek/seek.rs
Normal file
21
src/io/seek/seek.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use crate::future::Future;
|
||||||
|
use crate::io::{self, Seek, SeekFrom};
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct SeekFuture<'a, T: Unpin + ?Sized> {
|
||||||
|
pub(crate) seeker: &'a mut T,
|
||||||
|
pub(crate) pos: SeekFrom,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Seek + Unpin + ?Sized> Future for SeekFuture<'_, T> {
|
||||||
|
type Output = io::Result<u64>;
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let pos = self.pos;
|
||||||
|
Pin::new(&mut *self.seeker).poll_seek(cx, pos)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::io::{self, Write};
|
use crate::io::{self, Write};
|
||||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||||
|
@ -162,35 +160,22 @@ impl Write for Stderr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, RawFd};
|
||||||
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
use std::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for Stderr {
|
impl AsRawFd for Stderr {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
std::io::stderr().as_raw_fd()
|
std::io::stderr().as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
|
||||||
impl AsRawHandle for Stderr {
|
impl AsRawHandle for Stderr {
|
||||||
fn as_raw_handle(&self) -> RawHandle {
|
fn as_raw_handle(&self) -> RawHandle {
|
||||||
std::io::stderr().as_raw_handle()
|
std::io::stderr().as_raw_handle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::future::{self, Future};
|
use crate::future::{self, Future};
|
||||||
use crate::io::{self, Read};
|
use crate::io::{self, Read};
|
||||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||||
|
@ -186,35 +184,22 @@ impl Read for Stdin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, RawFd};
|
||||||
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
use std::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for Stdin {
|
impl AsRawFd for Stdin {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
std::io::stdin().as_raw_fd()
|
std::io::stdin().as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
|
||||||
impl AsRawHandle for Stdin {
|
impl AsRawHandle for Stdin {
|
||||||
fn as_raw_handle(&self) -> RawHandle {
|
fn as_raw_handle(&self) -> RawHandle {
|
||||||
std::io::stdin().as_raw_handle()
|
std::io::stdin().as_raw_handle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::io::{self, Write};
|
use crate::io::{self, Write};
|
||||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||||
|
@ -162,35 +160,22 @@ impl Write for Stdout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, RawFd};
|
||||||
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
use std::os::windows::io::{AsRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for Stdout {
|
impl AsRawFd for Stdout {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
std::io::stdout().as_raw_fd()
|
std::io::stdout().as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
use crate::os::windows::io::{AsRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
|
||||||
impl AsRawHandle for Stdout {
|
impl AsRawHandle for Stdout {
|
||||||
fn as_raw_handle(&self) -> RawHandle {
|
fn as_raw_handle(&self) -> RawHandle {
|
||||||
std::io::stdout().as_raw_handle()
|
std::io::stdout().as_raw_handle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::task::{Context, Poll};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
use pin_utils::unsafe_pinned;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
|
@ -43,22 +43,18 @@ where
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Future returned by the `FutureExt::timeout` method.
|
/// Future returned by the `FutureExt::timeout` method.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Timeout<F, T>
|
pub struct Timeout<F, T>
|
||||||
where
|
where
|
||||||
F: Future<Output = io::Result<T>>,
|
F: Future<Output = io::Result<T>>,
|
||||||
{
|
{
|
||||||
|
#[pin]
|
||||||
future: F,
|
future: F,
|
||||||
|
#[pin]
|
||||||
timeout: Delay,
|
timeout: Delay,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, T> Timeout<F, T>
|
|
||||||
where
|
|
||||||
F: Future<Output = io::Result<T>>,
|
|
||||||
{
|
|
||||||
unsafe_pinned!(future: F);
|
|
||||||
unsafe_pinned!(timeout: Delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, T> Future for Timeout<F, T>
|
impl<F, T> Future for Timeout<F, T>
|
||||||
|
@ -67,14 +63,15 @@ where
|
||||||
{
|
{
|
||||||
type Output = io::Result<T>;
|
type Output = io::Result<T>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.as_mut().future().poll(cx) {
|
let this = self.project();
|
||||||
|
match this.future.poll(cx) {
|
||||||
Poll::Pending => {}
|
Poll::Pending => {}
|
||||||
other => return other,
|
other => return other,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.timeout().poll(cx).is_ready() {
|
if this.timeout.poll(cx).is_ready() {
|
||||||
let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out").into());
|
let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out"));
|
||||||
Poll::Ready(err)
|
Poll::Ready(err)
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
|
|
|
@ -10,22 +10,14 @@ use write_all::WriteAllFuture;
|
||||||
use write_fmt::WriteFmtFuture;
|
use write_fmt::WriteFmtFuture;
|
||||||
use write_vectored::WriteVectoredFuture;
|
use write_vectored::WriteVectoredFuture;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use crate::io::{self, IoSlice};
|
||||||
|
|
||||||
use crate::io::IoSlice;
|
|
||||||
use crate::utils::extension_trait;
|
|
||||||
|
|
||||||
use crate::io;
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use crate::task::{Context, Poll};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_trait! {
|
extension_trait! {
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
Allows writing to a byte stream.
|
Allows writing to a byte stream.
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
|
||||||
buffer,
|
buffer,
|
||||||
..
|
..
|
||||||
} = &mut *self;
|
} = &mut *self;
|
||||||
let mut buffer = buffer.as_mut().unwrap();
|
let buffer = buffer.as_mut().unwrap();
|
||||||
|
|
||||||
// Copy the data from the buffer into the writer until it's done.
|
// Copy the data from the buffer into the writer until it's done.
|
||||||
loop {
|
loop {
|
||||||
|
@ -40,7 +40,7 @@ impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
|
||||||
futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?;
|
futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?;
|
||||||
return Poll::Ready(Ok(()));
|
return Poll::Ready(Ok(()));
|
||||||
}
|
}
|
||||||
let i = futures_core::ready!(Pin::new(&mut **writer).poll_write(cx, &mut buffer))?;
|
let i = futures_core::ready!(Pin::new(&mut **writer).poll_write(cx, buffer))?;
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
||||||
}
|
}
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -48,7 +48,8 @@
|
||||||
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
|
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
|
||||||
#![recursion_limit = "1024"]
|
#![recursion_limit = "1024"]
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
#[macro_use]
|
||||||
|
mod utils;
|
||||||
|
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod future;
|
pub mod future;
|
||||||
|
@ -61,11 +62,8 @@ pub mod stream;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unstable! {
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
|
||||||
pub mod pin;
|
pub mod pin;
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
|
||||||
mod unit;
|
mod unit;
|
||||||
|
@ -74,13 +72,9 @@ cfg_if! {
|
||||||
mod option;
|
mod option;
|
||||||
mod string;
|
mod string;
|
||||||
mod collections;
|
mod collections;
|
||||||
}
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use std::{write, writeln};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod macros;
|
mod macros;
|
||||||
pub(crate) mod utils;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use std::{write, writeln};
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
/// #
|
/// #
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
|
@ -81,12 +81,15 @@ macro_rules! print {
|
||||||
/// #
|
/// #
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
() => ($crate::print!("\n"));
|
() => ($crate::print!("\n"));
|
||||||
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)))
|
($($arg:tt)*) => (async {
|
||||||
|
$crate::io::_print(format_args!($($arg)*)).await;
|
||||||
|
$crate::io::_print(format_args!("\n")).await;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints to the standard error.
|
/// Prints to the standard error.
|
||||||
|
@ -116,7 +119,7 @@ macro_rules! println {
|
||||||
/// #
|
/// #
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! eprint {
|
macro_rules! eprint {
|
||||||
|
@ -150,7 +153,7 @@ macro_rules! eprint {
|
||||||
/// #
|
/// #
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! eprintln {
|
macro_rules! eprintln {
|
||||||
|
@ -158,6 +161,7 @@ macro_rules! eprintln {
|
||||||
($($arg:tt)*) => (
|
($($arg:tt)*) => (
|
||||||
async {
|
async {
|
||||||
$crate::io::_eprint(format_args!($($arg)*)).await;
|
$crate::io::_eprint(format_args!($($arg)*)).await;
|
||||||
|
$crate::io::_eprint(format_args!("\n")).await;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,25 +3,23 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||||
|
|
||||||
cfg_if! {
|
cfg_not_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
macro_rules! ret {
|
||||||
|
(impl Future<Output = $out:ty>, $fut:ty) => ($fut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_docs! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
|
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
|
||||||
|
|
||||||
macro_rules! ret {
|
macro_rules! ret {
|
||||||
(impl Future<Output = $out:ty>, $fut:ty) => (ImplFuture<$out>);
|
(impl Future<Output = $out:ty>, $fut:ty) => (ImplFuture<$out>);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
macro_rules! ret {
|
|
||||||
(impl Future<Output = $out:ty>, $fut:ty) => ($fut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts or resolves addresses to [`SocketAddr`] values.
|
/// Converts or resolves addresses to [`SocketAddr`] values.
|
||||||
|
@ -212,7 +210,7 @@ impl ToSocketAddrs for str {
|
||||||
impl Future<Output = Self::Iter>,
|
impl Future<Output = Self::Iter>,
|
||||||
ToSocketAddrsFuture<Self::Iter>
|
ToSocketAddrsFuture<Self::Iter>
|
||||||
) {
|
) {
|
||||||
if let Some(addr) = self.parse().ok() {
|
if let Ok(addr) = self.parse() {
|
||||||
return ToSocketAddrsFuture::Ready(Ok(vec![addr].into_iter()));
|
return ToSocketAddrsFuture::Ready(Ok(vec![addr].into_iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use super::TcpStream;
|
|
||||||
use crate::future::{self, Future};
|
use crate::future::{self, Future};
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::net::driver::Watcher;
|
use crate::net::driver::Watcher;
|
||||||
use crate::net::ToSocketAddrs;
|
use crate::net::{TcpStream, ToSocketAddrs};
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
@ -213,20 +210,9 @@ impl From<std::net::TcpListener> for TcpListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
// use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for TcpListener {
|
impl AsRawFd for TcpListener {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.watcher.get_ref().as_raw_fd()
|
self.watcher.get_ref().as_raw_fd()
|
||||||
|
@ -245,11 +231,10 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
//
|
||||||
// impl AsRawSocket for TcpListener {
|
// impl AsRawSocket for TcpListener {
|
||||||
// fn as_raw_socket(&self) -> RawSocket {
|
// fn as_raw_socket(&self) -> RawSocket {
|
||||||
// self.raw_socket
|
// self.raw_socket
|
||||||
|
@ -268,4 +253,3 @@ cfg_if! {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ use std::io::{IoSlice, IoSliceMut, Read as _, Write as _};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::future;
|
use crate::future;
|
||||||
use crate::io::{self, Read, Write};
|
use crate::io::{self, Read, Write};
|
||||||
use crate::net::driver::Watcher;
|
use crate::net::driver::Watcher;
|
||||||
|
@ -367,20 +365,9 @@ impl From<std::net::TcpStream> for TcpStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
// use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for TcpStream {
|
impl AsRawFd for TcpStream {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.watcher.get_ref().as_raw_fd()
|
self.watcher.get_ref().as_raw_fd()
|
||||||
|
@ -399,11 +386,10 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
//
|
||||||
// impl AsRawSocket for TcpStream {
|
// impl AsRawSocket for TcpStream {
|
||||||
// fn as_raw_socket(&self) -> RawSocket {
|
// fn as_raw_socket(&self) -> RawSocket {
|
||||||
// self.raw_socket
|
// self.raw_socket
|
||||||
|
@ -422,4 +408,3 @@ cfg_if! {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use crate::future;
|
use crate::future;
|
||||||
|
@ -463,20 +461,9 @@ impl From<std::net::UdpSocket> for UdpSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unix! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
} else if #[cfg(unix)] {
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
} else if #[cfg(windows)] {
|
|
||||||
// use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(unix, feature = "docs"))] {
|
|
||||||
impl AsRawFd for UdpSocket {
|
impl AsRawFd for UdpSocket {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.watcher.get_ref().as_raw_fd()
|
self.watcher.get_ref().as_raw_fd()
|
||||||
|
@ -495,12 +482,9 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
cfg_windows! {
|
||||||
cfg_if! {
|
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
||||||
if #[cfg(any(windows, feature = "docs"))] {
|
|
||||||
// use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
|
|
||||||
//
|
//
|
||||||
// impl AsRawSocket for UdpSocket {
|
// impl AsRawSocket for UdpSocket {
|
||||||
// fn as_raw_socket(&self) -> RawSocket {
|
// fn as_raw_socket(&self) -> RawSocket {
|
||||||
|
@ -520,4 +504,3 @@ cfg_if! {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! OS-specific extensions.
|
//! OS-specific extensions.
|
||||||
|
|
||||||
#[cfg(any(unix, feature = "docs"))]
|
cfg_unix! {
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(windows, feature = "docs"))]
|
cfg_windows! {
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! Unix-specific filesystem extensions.
|
//! Unix-specific filesystem extensions.
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
use crate::task::blocking;
|
use crate::task::blocking;
|
||||||
|
@ -31,8 +29,11 @@ pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Resu
|
||||||
blocking::spawn(move || std::os::unix::fs::symlink(&src, &dst)).await
|
blocking::spawn(move || std::os::unix::fs::symlink(&src, &dst)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_not_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
pub use std::os::unix::fs::{DirBuilderExt, DirEntryExt, OpenOptionsExt};
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_docs! {
|
||||||
/// Unix-specific extensions to `DirBuilder`.
|
/// Unix-specific extensions to `DirBuilder`.
|
||||||
pub trait DirBuilderExt {
|
pub trait DirBuilderExt {
|
||||||
/// Sets the mode to create new directories with. This option defaults to
|
/// Sets the mode to create new directories with. This option defaults to
|
||||||
|
@ -67,7 +68,4 @@ cfg_if! {
|
||||||
/// This options overwrites any previously set custom flags.
|
/// This options overwrites any previously set custom flags.
|
||||||
fn custom_flags(&mut self, flags: i32) -> &mut Self;
|
fn custom_flags(&mut self, flags: i32) -> &mut Self;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
//! Unix-specific I/O extensions.
|
//! Unix-specific I/O extensions.
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
cfg_not_docs! {
|
||||||
|
pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
/// Raw file descriptors.
|
/// Raw file descriptors.
|
||||||
pub type RawFd = std::os::raw::c_int;
|
pub type RawFd = std::os::raw::c_int;
|
||||||
|
|
||||||
|
@ -50,7 +51,4 @@ cfg_if! {
|
||||||
/// and must close the descriptor once it's no longer needed.
|
/// and must close the descriptor once it's no longer needed.
|
||||||
fn into_raw_fd(self) -> RawFd;
|
fn into_raw_fd(self) -> RawFd;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! Unix-specific networking extensions.
|
//! Unix-specific networking extensions.
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
pub use datagram::UnixDatagram;
|
pub use datagram::UnixDatagram;
|
||||||
pub use listener::{Incoming, UnixListener};
|
pub use listener::{Incoming, UnixListener};
|
||||||
pub use stream::UnixStream;
|
pub use stream::UnixStream;
|
||||||
|
@ -10,8 +8,11 @@ mod datagram;
|
||||||
mod listener;
|
mod listener;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_not_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
pub use std::os::unix::net::SocketAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_docs! {
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
|
@ -93,7 +94,4 @@ cfg_if! {
|
||||||
unreachable!("this impl only appears in the rendered docs")
|
unreachable!("this impl only appears in the rendered docs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::os::unix::net::SocketAddr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
//! Windows-specific I/O extensions.
|
//! Windows-specific I/O extensions.
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
cfg_not_docs! {
|
||||||
|
pub use std::os::windows::io::{
|
||||||
|
AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, RawSocket,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_docs! {
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
/// Raw HANDLEs.
|
/// Raw HANDLEs.
|
||||||
pub type RawHandle = *mut std::os::raw::c_void;
|
pub type RawHandle = *mut std::os::raw::c_void;
|
||||||
|
|
||||||
|
@ -42,9 +45,4 @@ cfg_if! {
|
||||||
/// it once it's no longer needed.
|
/// it once it's no longer needed.
|
||||||
fn into_raw_handle(self) -> RawHandle;
|
fn into_raw_handle(self) -> RawHandle;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pub use std::os::windows::io::{
|
|
||||||
AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, RawSocket,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,7 +799,7 @@ impl AsRef<Path> for String {
|
||||||
|
|
||||||
impl AsRef<Path> for std::path::PathBuf {
|
impl AsRef<Path> for std::path::PathBuf {
|
||||||
fn as_ref(&self) -> &Path {
|
fn as_ref(&self) -> &Path {
|
||||||
Path::new(self.into())
|
Path::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::path::Path;
|
||||||
/// This struct is an async version of [`std::path::PathBuf`].
|
/// This struct is an async version of [`std::path::PathBuf`].
|
||||||
///
|
///
|
||||||
/// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
|
/// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
pub struct PathBuf {
|
pub struct PathBuf {
|
||||||
inner: std::path::PathBuf,
|
inner: std::path::PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ impl From<std::path::PathBuf> for PathBuf {
|
||||||
|
|
||||||
impl Into<std::path::PathBuf> for PathBuf {
|
impl Into<std::path::PathBuf> for PathBuf {
|
||||||
fn into(self) -> std::path::PathBuf {
|
fn into(self) -> std::path::PathBuf {
|
||||||
self.inner.into()
|
self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
//! use async_std::prelude::*;
|
//! use async_std::prelude::*;
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::future::Future;
|
pub use crate::future::Future;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
|
@ -41,12 +39,9 @@ pub use crate::io::write::WriteExt as _;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::stream::stream::StreamExt as _;
|
pub use crate::stream::stream::StreamExt as _;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unstable! {
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::stream::DoubleEndedStream;
|
pub use crate::stream::DoubleEndedStream;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::stream::ExactSizeStream;
|
pub use crate::stream::ExactSizeStream;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ use std::task::{Context, Poll};
|
||||||
/// `Item`s from the back, as well as the front.
|
/// `Item`s from the back, as well as the front.
|
||||||
///
|
///
|
||||||
/// [`Stream`]: trait.Stream.html
|
/// [`Stream`]: trait.Stream.html
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait DoubleEndedStream: Stream {
|
pub trait DoubleEndedStream: Stream {
|
||||||
/// Removes and returns an element from the end of the stream.
|
/// Removes and returns an element from the end of the stream.
|
||||||
///
|
///
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub use crate::stream::Stream;
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// impl ExactSizeStream for Counter {
|
/// impl ExactSizeStream for Counter {
|
||||||
/// // We can easily calculate the remaining number of iterations.
|
/// // We can easily calculate the remaining number of iterations.
|
||||||
|
@ -74,10 +74,9 @@ pub use crate::stream::Stream;
|
||||||
///
|
///
|
||||||
/// assert_eq!(5, counter.len());
|
/// assert_eq!(5, counter.len());
|
||||||
/// # });
|
/// # });
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait ExactSizeStream: Stream {
|
pub trait ExactSizeStream: Stream {
|
||||||
/// Returns the exact number of times the stream will iterate.
|
/// Returns the exact number of times the stream will iterate.
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::stream::IntoStream;
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::prelude::*;
|
/// use async_std::prelude::*;
|
||||||
/// use async_std::stream::{self, Extend};
|
/// use async_std::stream::{self, Extend};
|
||||||
|
@ -25,8 +25,9 @@ use crate::stream::IntoStream;
|
||||||
///
|
///
|
||||||
/// assert_eq!(v, vec![1, 2, 3, 3, 3]);
|
/// assert_eq!(v, vec![1, 2, 3, 3, 3]);
|
||||||
/// #
|
/// #
|
||||||
/// # }) }
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
pub trait Extend<A> {
|
pub trait Extend<A> {
|
||||||
/// Extends a collection with the contents of a stream.
|
/// Extends a collection with the contents of a stream.
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that yields elements by calling a closure.
|
/// A stream that yields elements by calling a closure.
|
||||||
///
|
///
|
||||||
/// This stream is constructed by [`from_fn`] function.
|
/// This stream is constructed by [`from_fn`] function.
|
||||||
|
@ -13,9 +16,11 @@ use crate::task::{Context, Poll};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FromFn<F, Fut, T> {
|
pub struct FromFn<F, Fut, T> {
|
||||||
f: F,
|
f: F,
|
||||||
|
#[pin]
|
||||||
future: Option<Fut>,
|
future: Option<Fut>,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new stream where to produce each new element a provided closure is called.
|
/// Creates a new stream where to produce each new element a provided closure is called.
|
||||||
///
|
///
|
||||||
|
@ -25,7 +30,7 @@ pub struct FromFn<F, Fut, T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::prelude::*;
|
/// use async_std::prelude::*;
|
||||||
/// use async_std::sync::Mutex;
|
/// use async_std::sync::Mutex;
|
||||||
|
@ -53,8 +58,7 @@ pub struct FromFn<F, Fut, T> {
|
||||||
/// assert_eq!(s.next().await, Some(3));
|
/// assert_eq!(s.next().await, Some(3));
|
||||||
/// assert_eq!(s.next().await, None);
|
/// assert_eq!(s.next().await, None);
|
||||||
/// #
|
/// #
|
||||||
/// # }) }
|
/// # })
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_fn<T, F, Fut>(f: F) -> FromFn<F, Fut, T>
|
pub fn from_fn<T, F, Fut>(f: F) -> FromFn<F, Fut, T>
|
||||||
where
|
where
|
||||||
|
@ -68,11 +72,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, Fut, T> FromFn<F, Fut, T> {
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
pin_utils::unsafe_pinned!(future: Option<Fut>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F, Fut, T> Stream for FromFn<F, Fut, T>
|
impl<F, Fut, T> Stream for FromFn<F, Fut, T>
|
||||||
where
|
where
|
||||||
F: FnMut() -> Fut,
|
F: FnMut() -> Fut,
|
||||||
|
@ -80,20 +79,18 @@ where
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
match &self.future {
|
if this.future.is_some() {
|
||||||
Some(_) => {
|
|
||||||
let next =
|
let next =
|
||||||
futures_core::ready!(self.as_mut().future().as_pin_mut().unwrap().poll(cx));
|
futures_core::ready!(this.future.as_mut().as_pin_mut().unwrap().poll(cx));
|
||||||
self.as_mut().future().set(None);
|
this.future.set(None);
|
||||||
|
|
||||||
return Poll::Ready(next);
|
return Poll::Ready(next);
|
||||||
}
|
} else {
|
||||||
None => {
|
let fut = (this.f)();
|
||||||
let fut = (self.as_mut().f())();
|
this.future.set(Some(fut));
|
||||||
self.as_mut().future().set(Some(fut));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,8 +106,8 @@ use std::pin::Pin;
|
||||||
///```
|
///```
|
||||||
///
|
///
|
||||||
/// [`IntoStream`]: trait.IntoStream.html
|
/// [`IntoStream`]: trait.IntoStream.html
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait FromStream<T> {
|
pub trait FromStream<T> {
|
||||||
/// Creates a value from a stream.
|
/// Creates a value from a stream.
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::stream::Stream;
|
||||||
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
|
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
|
||||||
/// [`Stream::fuse`]: trait.Stream.html#method.fuse
|
/// [`Stream::fuse`]: trait.Stream.html#method.fuse
|
||||||
/// [`Fuse`]: struct.Fuse.html
|
/// [`Fuse`]: struct.Fuse.html
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
pub trait FusedStream: Stream {}
|
pub trait FusedStream: Stream {}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use futures_core::future::Future;
|
use futures_core::future::Future;
|
||||||
use futures_core::stream::Stream;
|
use futures_core::stream::Stream;
|
||||||
use pin_utils::unsafe_pinned;
|
|
||||||
|
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
|
|
||||||
/// Creates a new stream that yields at a set interval.
|
/// Creates a new stream that yields at a set interval.
|
||||||
|
@ -43,8 +41,8 @@ use futures_timer::Delay;
|
||||||
/// #
|
/// #
|
||||||
/// # Ok(()) }) }
|
/// # Ok(()) }) }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[doc(inline)]
|
|
||||||
pub fn interval(dur: Duration) -> Interval {
|
pub fn interval(dur: Duration) -> Interval {
|
||||||
Interval {
|
Interval {
|
||||||
delay: Delay::new(dur),
|
delay: Delay::new(dur),
|
||||||
|
@ -54,23 +52,19 @@ pub fn interval(dur: Duration) -> Interval {
|
||||||
|
|
||||||
/// A stream representing notifications at fixed interval
|
/// A stream representing notifications at fixed interval
|
||||||
///
|
///
|
||||||
#[derive(Debug)]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[doc(inline)]
|
#[derive(Debug)]
|
||||||
pub struct Interval {
|
pub struct Interval {
|
||||||
delay: Delay,
|
delay: Delay,
|
||||||
interval: Duration,
|
interval: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interval {
|
|
||||||
unsafe_pinned!(delay: Delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stream for Interval {
|
impl Stream for Interval {
|
||||||
type Item = ();
|
type Item = ();
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
if Pin::new(&mut *self).delay().poll(cx).is_pending() {
|
if Pin::new(&mut self.delay).poll(cx).is_pending() {
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
let when = Instant::now();
|
let when = Instant::now();
|
||||||
|
|
|
@ -13,8 +13,8 @@ use crate::stream::Stream;
|
||||||
/// See also: [`FromStream`].
|
/// See also: [`FromStream`].
|
||||||
///
|
///
|
||||||
/// [`FromStream`]: trait.FromStream.html
|
/// [`FromStream`]: trait.FromStream.html
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait IntoStream {
|
pub trait IntoStream {
|
||||||
/// The type of the elements being iterated over.
|
/// The type of the elements being iterated over.
|
||||||
type Item;
|
type Item;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Asynchronous iteration.
|
//! Composable asynchronous iteration.
|
||||||
//!
|
//!
|
||||||
//! This module is an async version of [`std::iter`].
|
//! This module is an async version of [`std::iter`].
|
||||||
//!
|
//!
|
||||||
|
@ -21,12 +21,11 @@
|
||||||
//! # })
|
//! # })
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
pub use empty::{empty, Empty};
|
pub use empty::{empty, Empty};
|
||||||
pub use from_fn::{from_fn, FromFn};
|
pub use from_fn::{from_fn, FromFn};
|
||||||
pub use once::{once, Once};
|
pub use once::{once, Once};
|
||||||
pub use repeat::{repeat, Repeat};
|
pub use repeat::{repeat, Repeat};
|
||||||
|
pub use repeat_with::{repeat_with, RepeatWith};
|
||||||
pub use stream::{
|
pub use stream::{
|
||||||
Chain, Filter, Fuse, Inspect, Scan, Skip, SkipWhile, StepBy, Stream, Take, TakeWhile, Zip,
|
Chain, Filter, Fuse, Inspect, Scan, Skip, SkipWhile, StepBy, Stream, Take, TakeWhile, Zip,
|
||||||
};
|
};
|
||||||
|
@ -37,9 +36,9 @@ mod empty;
|
||||||
mod from_fn;
|
mod from_fn;
|
||||||
mod once;
|
mod once;
|
||||||
mod repeat;
|
mod repeat;
|
||||||
|
mod repeat_with;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_unstable! {
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
mod double_ended_stream;
|
mod double_ended_stream;
|
||||||
mod exact_size_stream;
|
mod exact_size_stream;
|
||||||
mod extend;
|
mod extend;
|
||||||
|
@ -58,8 +57,6 @@ cfg_if! {
|
||||||
pub use interval::{interval, Interval};
|
pub use interval::{interval, Interval};
|
||||||
pub use into_stream::IntoStream;
|
pub use into_stream::IntoStream;
|
||||||
pub use product::Product;
|
pub use product::Product;
|
||||||
pub use sum::Sum;
|
|
||||||
|
|
||||||
pub use stream::Merge;
|
pub use stream::Merge;
|
||||||
}
|
pub use sum::Sum;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
@ -24,6 +26,7 @@ pub fn once<T>(t: T) -> Once<T> {
|
||||||
Once { value: Some(t) }
|
Once { value: Some(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that yields a single item.
|
/// A stream that yields a single item.
|
||||||
///
|
///
|
||||||
/// This stream is constructed by the [`once`] function.
|
/// This stream is constructed by the [`once`] function.
|
||||||
|
@ -33,11 +36,12 @@ pub fn once<T>(t: T) -> Once<T> {
|
||||||
pub struct Once<T> {
|
pub struct Once<T> {
|
||||||
value: Option<T>,
|
value: Option<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Unpin> Stream for Once<T> {
|
impl<T: Unpin> Stream for Once<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
|
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
Poll::Ready(self.value.take())
|
Poll::Ready(self.project().value.take())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ use crate::stream::Stream;
|
||||||
/// [`product`]: trait.Product.html#tymethod.product
|
/// [`product`]: trait.Product.html#tymethod.product
|
||||||
/// [`FromStream`]: trait.FromStream.html
|
/// [`FromStream`]: trait.FromStream.html
|
||||||
/// [`Stream::product`]: trait.Stream.html#method.product
|
/// [`Stream::product`]: trait.Stream.html#method.product
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait Product<A = Self>: Sized {
|
pub trait Product<A = Self>: Sized {
|
||||||
/// Method which takes a stream and generates `Self` from the elements by
|
/// Method which takes a stream and generates `Self` from the elements by
|
||||||
/// multiplying the items.
|
/// multiplying the items.
|
||||||
|
|
100
src/stream/repeat_with.rs
Normal file
100
src/stream/repeat_with.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
use crate::future::Future;
|
||||||
|
use crate::stream::Stream;
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
/// A stream that repeats elements of type `T` endlessly by applying a provided closure.
|
||||||
|
///
|
||||||
|
/// This stream is constructed by the [`repeat_with`] function.
|
||||||
|
///
|
||||||
|
/// [`repeat_with`]: fn.repeat_with.html
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RepeatWith<F, Fut, A> {
|
||||||
|
f: F,
|
||||||
|
#[pin]
|
||||||
|
future: Option<Fut>,
|
||||||
|
__a: PhantomData<A>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new stream that repeats elements of type `A` endlessly by applying the provided closure.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # async_std::task::block_on(async {
|
||||||
|
/// #
|
||||||
|
/// use async_std::prelude::*;
|
||||||
|
/// use async_std::stream;
|
||||||
|
///
|
||||||
|
/// let s = stream::repeat_with(|| async { 1 });
|
||||||
|
///
|
||||||
|
/// pin_utils::pin_mut!(s);
|
||||||
|
///
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// # })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Going finite:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # async_std::task::block_on(async {
|
||||||
|
/// #
|
||||||
|
/// use async_std::prelude::*;
|
||||||
|
/// use async_std::stream;
|
||||||
|
///
|
||||||
|
/// let s = stream::repeat_with(|| async { 1u8 }).take(2);
|
||||||
|
///
|
||||||
|
/// pin_utils::pin_mut!(s);
|
||||||
|
///
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// assert_eq!(s.next().await, Some(1));
|
||||||
|
/// assert_eq!(s.next().await, None);
|
||||||
|
/// # })
|
||||||
|
/// ```
|
||||||
|
pub fn repeat_with<F, Fut, A>(repeater: F) -> RepeatWith<F, Fut, A>
|
||||||
|
where
|
||||||
|
F: FnMut() -> Fut,
|
||||||
|
Fut: Future<Output = A>,
|
||||||
|
{
|
||||||
|
RepeatWith {
|
||||||
|
f: repeater,
|
||||||
|
future: None,
|
||||||
|
__a: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, Fut, A> Stream for RepeatWith<F, Fut, A>
|
||||||
|
where
|
||||||
|
F: FnMut() -> Fut,
|
||||||
|
Fut: Future<Output = A>,
|
||||||
|
{
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let mut this = self.project();
|
||||||
|
loop {
|
||||||
|
if this.future.is_some() {
|
||||||
|
let res = futures_core::ready!(this.future.as_mut().as_pin_mut().unwrap().poll(cx));
|
||||||
|
|
||||||
|
this.future.set(None);
|
||||||
|
|
||||||
|
return Poll::Ready(Some(res));
|
||||||
|
} else {
|
||||||
|
let fut = (this.f)();
|
||||||
|
|
||||||
|
this.future.set(Some(fut));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,23 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::fuse::Fuse;
|
use super::fuse::Fuse;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Chains two streams one after another.
|
/// Chains two streams one after another.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Chain<S, U> {
|
pub struct Chain<S, U> {
|
||||||
|
#[pin]
|
||||||
first: Fuse<S>,
|
first: Fuse<S>,
|
||||||
|
#[pin]
|
||||||
second: Fuse<U>,
|
second: Fuse<U>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Stream, U: Stream> Chain<S, U> {
|
impl<S: Stream, U: Stream> Chain<S, U> {
|
||||||
pin_utils::unsafe_pinned!(first: Fuse<S>);
|
|
||||||
pin_utils::unsafe_pinned!(second: Fuse<U>);
|
|
||||||
|
|
||||||
pub(super) fn new(first: S, second: U) -> Self {
|
pub(super) fn new(first: S, second: U) -> Self {
|
||||||
Chain {
|
Chain {
|
||||||
first: first.fuse(),
|
first: first.fuse(),
|
||||||
|
@ -26,22 +29,23 @@ impl<S: Stream, U: Stream> Chain<S, U> {
|
||||||
impl<S: Stream, U: Stream<Item = S::Item>> Stream for Chain<S, U> {
|
impl<S: Stream, U: Stream<Item = S::Item>> Stream for Chain<S, U> {
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
if !self.first.done {
|
let mut this = self.project();
|
||||||
let next = futures_core::ready!(self.as_mut().first().poll_next(cx));
|
if !this.first.done {
|
||||||
|
let next = futures_core::ready!(this.first.as_mut().poll_next(cx));
|
||||||
if let Some(next) = next {
|
if let Some(next) = next {
|
||||||
return Poll::Ready(Some(next));
|
return Poll::Ready(Some(next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.second.done {
|
if !this.second.done {
|
||||||
let next = futures_core::ready!(self.as_mut().second().poll_next(cx));
|
let next = futures_core::ready!(this.second.as_mut().poll_next(cx));
|
||||||
if let Some(next) = next {
|
if let Some(next) = next {
|
||||||
return Poll::Ready(Some(next));
|
return Poll::Ready(Some(next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.first.done && self.second.done {
|
if this.first.done && this.second.done {
|
||||||
return Poll::Ready(None);
|
return Poll::Ready(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::fuse::Fuse;
|
use super::fuse::Fuse;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
// Lexicographically compares the elements of this `Stream` with those
|
// Lexicographically compares the elements of this `Stream` with those
|
||||||
// of another using `Ord`.
|
// of another using `Ord`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct CmpFuture<L: Stream, R: Stream> {
|
pub struct CmpFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
l: Fuse<L>,
|
l: Fuse<L>,
|
||||||
|
#[pin]
|
||||||
r: Fuse<R>,
|
r: Fuse<R>,
|
||||||
l_cache: Option<L::Item>,
|
l_cache: Option<L::Item>,
|
||||||
r_cache: Option<R::Item>,
|
r_cache: Option<R::Item>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> CmpFuture<L, R> {
|
impl<L: Stream, R: Stream> CmpFuture<L, R> {
|
||||||
pin_utils::unsafe_pinned!(l: Fuse<L>);
|
|
||||||
pin_utils::unsafe_pinned!(r: Fuse<R>);
|
|
||||||
pin_utils::unsafe_unpinned!(l_cache: Option<L::Item>);
|
|
||||||
pin_utils::unsafe_unpinned!(r_cache: Option<R::Item>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
CmpFuture {
|
CmpFuture {
|
||||||
l: l.fuse(),
|
l: l.fuse(),
|
||||||
|
@ -42,11 +43,12 @@ where
|
||||||
{
|
{
|
||||||
type Output = Ordering;
|
type Output = Ordering;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
// Stream that completes earliest can be considered Less, etc
|
// Stream that completes earliest can be considered Less, etc
|
||||||
let l_complete = self.l.done && self.as_mut().l_cache.is_none();
|
let l_complete = this.l.done && this.l_cache.is_none();
|
||||||
let r_complete = self.r.done && self.as_mut().r_cache.is_none();
|
let r_complete = this.r.done && this.r_cache.is_none();
|
||||||
|
|
||||||
if l_complete && r_complete {
|
if l_complete && r_complete {
|
||||||
return Poll::Ready(Ordering::Equal);
|
return Poll::Ready(Ordering::Equal);
|
||||||
|
@ -57,30 +59,30 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get next value if possible and necesary
|
// Get next value if possible and necesary
|
||||||
if !self.l.done && self.as_mut().l_cache.is_none() {
|
if !this.l.done && this.l_cache.is_none() {
|
||||||
let l_next = futures_core::ready!(self.as_mut().l().poll_next(cx));
|
let l_next = futures_core::ready!(this.l.as_mut().poll_next(cx));
|
||||||
if let Some(item) = l_next {
|
if let Some(item) = l_next {
|
||||||
*self.as_mut().l_cache() = Some(item);
|
*this.l_cache = Some(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.r.done && self.as_mut().r_cache.is_none() {
|
if !this.r.done && this.r_cache.is_none() {
|
||||||
let r_next = futures_core::ready!(self.as_mut().r().poll_next(cx));
|
let r_next = futures_core::ready!(this.r.as_mut().poll_next(cx));
|
||||||
if let Some(item) = r_next {
|
if let Some(item) = r_next {
|
||||||
*self.as_mut().r_cache() = Some(item);
|
*this.r_cache = Some(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare if both values are available.
|
// Compare if both values are available.
|
||||||
if self.as_mut().l_cache.is_some() && self.as_mut().r_cache.is_some() {
|
if this.l_cache.is_some() && this.r_cache.is_some() {
|
||||||
let l_value = self.as_mut().l_cache().take().unwrap();
|
let l_value = this.l_cache.take().unwrap();
|
||||||
let r_value = self.as_mut().r_cache().take().unwrap();
|
let r_value = this.r_cache.take().unwrap();
|
||||||
let result = l_value.cmp(&r_value);
|
let result = l_value.cmp(&r_value);
|
||||||
|
|
||||||
if let Ordering::Equal = result {
|
if let Ordering::Equal = result {
|
||||||
// Reset cache to prepare for next comparison
|
// Reset cache to prepare for next comparison
|
||||||
*self.as_mut().l_cache() = None;
|
*this.l_cache = None;
|
||||||
*self.as_mut().r_cache() = None;
|
*this.r_cache = None;
|
||||||
} else {
|
} else {
|
||||||
// Return non equal value
|
// Return non equal value
|
||||||
return Poll::Ready(result);
|
return Poll::Ready(result);
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use crate::task::{Context, Poll};
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
use crate::stream::Stream;
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Enumerate<S> {
|
pub struct Enumerate<S> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
i: usize,
|
i: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Enumerate<S> {
|
impl<S> Enumerate<S> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(i: usize);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S) -> Self {
|
pub(super) fn new(stream: S) -> Self {
|
||||||
Enumerate { stream, i: 0 }
|
Enumerate { stream, i: 0 }
|
||||||
}
|
}
|
||||||
|
@ -25,13 +27,14 @@ where
|
||||||
{
|
{
|
||||||
type Item = (usize, S::Item);
|
type Item = (usize, S::Item);
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let ret = (self.i, v);
|
let ret = (*this.i, v);
|
||||||
*self.as_mut().i() += 1;
|
*this.i += 1;
|
||||||
Poll::Ready(Some(ret))
|
Poll::Ready(Some(ret))
|
||||||
}
|
}
|
||||||
None => Poll::Ready(None),
|
None => Poll::Ready(None),
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream to filter elements of another stream with a predicate.
|
/// A stream to filter elements of another stream with a predicate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Filter<S, P, T> {
|
pub struct Filter<S, P, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
predicate: P,
|
predicate: P,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, P, T> Filter<S, P, T> {
|
impl<S, P, T> Filter<S, P, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(predicate: P);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, predicate: P) -> Self {
|
pub(super) fn new(stream: S, predicate: P) -> Self {
|
||||||
Filter {
|
Filter {
|
||||||
stream,
|
stream,
|
||||||
|
@ -32,11 +34,12 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) if (self.as_mut().predicate())(&v) => Poll::Ready(Some(v)),
|
Some(v) if (this.predicate)(&v) => Poll::Ready(Some(v)),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
|
|
|
@ -2,21 +2,23 @@ use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct FilterMap<S, F, T, B> {
|
pub struct FilterMap<S, F, T, B> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
__from: PhantomData<T>,
|
__from: PhantomData<T>,
|
||||||
__to: PhantomData<B>,
|
__to: PhantomData<B>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T, B> FilterMap<S, F, T, B> {
|
impl<S, F, T, B> FilterMap<S, F, T, B> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, f: F) -> Self {
|
pub(crate) fn new(stream: S, f: F) -> Self {
|
||||||
FilterMap {
|
FilterMap {
|
||||||
stream,
|
stream,
|
||||||
|
@ -34,10 +36,11 @@ where
|
||||||
{
|
{
|
||||||
type Item = B;
|
type Item = B;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
match next {
|
match next {
|
||||||
Some(v) => match (self.as_mut().f())(v) {
|
Some(v) => match (this.f)(v) {
|
||||||
Some(b) => Poll::Ready(Some(b)),
|
Some(b) => Poll::Ready(Some(b)),
|
||||||
None => {
|
None => {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct FoldFuture<S, F, T, B> {
|
pub struct FoldFuture<S, F, T, B> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
acc: Option<B>,
|
acc: Option<B>,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T, B> FoldFuture<S, F, T, B> {
|
impl<S, F, T, B> FoldFuture<S, F, T, B> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
pin_utils::unsafe_unpinned!(acc: Option<B>);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, init: B, f: F) -> Self {
|
pub(super) fn new(stream: S, init: B, f: F) -> Self {
|
||||||
FoldFuture {
|
FoldFuture {
|
||||||
stream,
|
stream,
|
||||||
|
@ -36,17 +37,18 @@ where
|
||||||
{
|
{
|
||||||
type Output = B;
|
type Output = B;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let old = self.as_mut().acc().take().unwrap();
|
let old = this.acc.take().unwrap();
|
||||||
let new = (self.as_mut().f())(old, v);
|
let new = (this.f)(old, v);
|
||||||
*self.as_mut().acc() = Some(new);
|
*this.acc = Some(new);
|
||||||
}
|
}
|
||||||
None => return Poll::Ready(self.as_mut().acc().take().unwrap()),
|
None => return Poll::Ready(this.acc.take().unwrap()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct ForEachFuture<S, F, T> {
|
pub struct ForEachFuture<S, F, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T> ForEachFuture<S, F, T> {
|
impl<S, F, T> ForEachFuture<S, F, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, f: F) -> Self {
|
pub(super) fn new(stream: S, f: F) -> Self {
|
||||||
ForEachFuture {
|
ForEachFuture {
|
||||||
stream,
|
stream,
|
||||||
|
@ -33,12 +35,13 @@ where
|
||||||
{
|
{
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => (self.as_mut().f())(v),
|
Some(v) => (this.f)(v),
|
||||||
None => return Poll::Ready(()),
|
None => return Poll::Ready(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A `Stream` that is permanently closed once a single call to `poll` results in
|
/// A `Stream` that is permanently closed once a single call to `poll` results in
|
||||||
/// `Poll::Ready(None)`, returning `Poll::Ready(None)` for all future calls to `poll`.
|
/// `Poll::Ready(None)`, returning `Poll::Ready(None)` for all future calls to `poll`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Fuse<S> {
|
pub struct Fuse<S> {
|
||||||
|
#[pin]
|
||||||
pub(crate) stream: S,
|
pub(crate) stream: S,
|
||||||
pub(crate) done: bool,
|
pub(crate) done: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Unpin> Unpin for Fuse<S> {}
|
|
||||||
|
|
||||||
impl<S: Stream> Fuse<S> {
|
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(done: bool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Stream> Stream for Fuse<S> {
|
impl<S: Stream> Stream for Fuse<S> {
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
||||||
if self.done {
|
let this = self.project();
|
||||||
|
if *this.done {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
if next.is_none() {
|
if next.is_none() {
|
||||||
*self.as_mut().done() = true;
|
*this.done = true;
|
||||||
}
|
}
|
||||||
Poll::Ready(next)
|
Poll::Ready(next)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,29 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::partial_cmp::PartialCmpFuture;
|
use super::partial_cmp::PartialCmpFuture;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
// Determines if the elements of this `Stream` are lexicographically
|
// Determines if the elements of this `Stream` are lexicographically
|
||||||
// greater than or equal to those of another.
|
// greater than or equal to those of another.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct GeFuture<L: Stream, R: Stream> {
|
pub struct GeFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
partial_cmp: PartialCmpFuture<L, R>,
|
partial_cmp: PartialCmpFuture<L, R>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> GeFuture<L, R>
|
impl<L: Stream, R: Stream> GeFuture<L, R>
|
||||||
where
|
where
|
||||||
L::Item: PartialOrd<R::Item>,
|
L::Item: PartialOrd<R::Item>,
|
||||||
{
|
{
|
||||||
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
GeFuture {
|
GeFuture {
|
||||||
partial_cmp: l.partial_cmp(r),
|
partial_cmp: l.partial_cmp(r),
|
||||||
|
@ -30,14 +33,14 @@ where
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> Future for GeFuture<L, R>
|
impl<L: Stream, R: Stream> Future for GeFuture<L, R>
|
||||||
where
|
where
|
||||||
L: Stream + Sized,
|
L: Stream,
|
||||||
R: Stream + Sized,
|
R: Stream,
|
||||||
L::Item: PartialOrd<R::Item>,
|
L::Item: PartialOrd<R::Item>,
|
||||||
{
|
{
|
||||||
type Output = bool;
|
type Output = bool;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
|
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Ordering::Greater) | Some(Ordering::Equal) => Poll::Ready(true),
|
Some(Ordering::Greater) | Some(Ordering::Equal) => Poll::Ready(true),
|
||||||
|
|
|
@ -1,26 +1,29 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::partial_cmp::PartialCmpFuture;
|
use super::partial_cmp::PartialCmpFuture;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
// Determines if the elements of this `Stream` are lexicographically
|
// Determines if the elements of this `Stream` are lexicographically
|
||||||
// greater than those of another.
|
// greater than those of another.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct GtFuture<L: Stream, R: Stream> {
|
pub struct GtFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
partial_cmp: PartialCmpFuture<L, R>,
|
partial_cmp: PartialCmpFuture<L, R>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> GtFuture<L, R>
|
impl<L: Stream, R: Stream> GtFuture<L, R>
|
||||||
where
|
where
|
||||||
L::Item: PartialOrd<R::Item>,
|
L::Item: PartialOrd<R::Item>,
|
||||||
{
|
{
|
||||||
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
GtFuture {
|
GtFuture {
|
||||||
partial_cmp: l.partial_cmp(r),
|
partial_cmp: l.partial_cmp(r),
|
||||||
|
@ -36,8 +39,8 @@ where
|
||||||
{
|
{
|
||||||
type Output = bool;
|
type Output = bool;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
|
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Ordering::Greater) => Poll::Ready(true),
|
Some(Ordering::Greater) => Poll::Ready(true),
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that does something with each element of another stream.
|
/// A stream that does something with each element of another stream.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Inspect<S, F, T> {
|
pub struct Inspect<S, F, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T> Inspect<S, F, T> {
|
impl<S, F, T> Inspect<S, F, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, f: F) -> Self {
|
pub(super) fn new(stream: S, f: F) -> Self {
|
||||||
Inspect {
|
Inspect {
|
||||||
stream,
|
stream,
|
||||||
|
@ -32,11 +34,12 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let mut this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
Poll::Ready(next.and_then(|x| {
|
Poll::Ready(next.and_then(|x| {
|
||||||
(self.as_mut().f())(&x);
|
(this.f)(&x);
|
||||||
Some(x)
|
Some(x)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
45
src/stream/stream/last.rs
Normal file
45
src/stream/stream/last.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
use crate::future::Future;
|
||||||
|
use crate::stream::Stream;
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct LastFuture<S, T> {
|
||||||
|
#[pin]
|
||||||
|
stream: S,
|
||||||
|
last: Option<T>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, T> LastFuture<S, T> {
|
||||||
|
pub(crate) fn new(stream: S) -> Self {
|
||||||
|
LastFuture { stream, last: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Future for LastFuture<S, S::Item>
|
||||||
|
where
|
||||||
|
S: Stream + Unpin + Sized,
|
||||||
|
S::Item: Copy,
|
||||||
|
{
|
||||||
|
type Output = Option<S::Item>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
|
||||||
|
match next {
|
||||||
|
Some(new) => {
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
*this.last = Some(new);
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
None => Poll::Ready(*this.last),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,29 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::partial_cmp::PartialCmpFuture;
|
use super::partial_cmp::PartialCmpFuture;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// Determines if the elements of this `Stream` are lexicographically
|
/// Determines if the elements of this `Stream` are lexicographically
|
||||||
/// less or equal to those of another.
|
/// less or equal to those of another.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct LeFuture<L: Stream, R: Stream> {
|
pub struct LeFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
partial_cmp: PartialCmpFuture<L, R>,
|
partial_cmp: PartialCmpFuture<L, R>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> LeFuture<L, R>
|
impl<L: Stream, R: Stream> LeFuture<L, R>
|
||||||
where
|
where
|
||||||
L::Item: PartialOrd<R::Item>,
|
L::Item: PartialOrd<R::Item>,
|
||||||
{
|
{
|
||||||
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
LeFuture {
|
LeFuture {
|
||||||
partial_cmp: l.partial_cmp(r),
|
partial_cmp: l.partial_cmp(r),
|
||||||
|
@ -36,8 +39,8 @@ where
|
||||||
{
|
{
|
||||||
type Output = bool;
|
type Output = bool;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
|
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Ordering::Less) | Some(Ordering::Equal) => Poll::Ready(true),
|
Some(Ordering::Less) | Some(Ordering::Equal) => Poll::Ready(true),
|
||||||
|
|
|
@ -1,26 +1,29 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::partial_cmp::PartialCmpFuture;
|
use super::partial_cmp::PartialCmpFuture;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
// Determines if the elements of this `Stream` are lexicographically
|
// Determines if the elements of this `Stream` are lexicographically
|
||||||
// less than those of another.
|
// less than those of another.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct LtFuture<L: Stream, R: Stream> {
|
pub struct LtFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
partial_cmp: PartialCmpFuture<L, R>,
|
partial_cmp: PartialCmpFuture<L, R>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> LtFuture<L, R>
|
impl<L: Stream, R: Stream> LtFuture<L, R>
|
||||||
where
|
where
|
||||||
L::Item: PartialOrd<R::Item>,
|
L::Item: PartialOrd<R::Item>,
|
||||||
{
|
{
|
||||||
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
LtFuture {
|
LtFuture {
|
||||||
partial_cmp: l.partial_cmp(r),
|
partial_cmp: l.partial_cmp(r),
|
||||||
|
@ -36,8 +39,8 @@ where
|
||||||
{
|
{
|
||||||
type Output = bool;
|
type Output = bool;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
|
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Ordering::Less) => Poll::Ready(true),
|
Some(Ordering::Less) => Poll::Ready(true),
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Map<S, F, T, B> {
|
pub struct Map<S, F, T, B> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
__from: PhantomData<T>,
|
__from: PhantomData<T>,
|
||||||
__to: PhantomData<B>,
|
__to: PhantomData<B>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T, B> Map<S, F, T, B> {
|
impl<S, F, T, B> Map<S, F, T, B> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, f: F) -> Self {
|
pub(crate) fn new(stream: S, f: F) -> Self {
|
||||||
Map {
|
Map {
|
||||||
stream,
|
stream,
|
||||||
|
@ -34,8 +36,9 @@ where
|
||||||
{
|
{
|
||||||
type Item = B;
|
type Item = B;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
Poll::Ready(next.map(self.as_mut().f()))
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
Poll::Ready(next.map(this.f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,24 @@ use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that merges two other streams into a single stream.
|
/// A stream that merges two other streams into a single stream.
|
||||||
///
|
///
|
||||||
/// This stream is returned by [`Stream::merge`].
|
/// This stream is returned by [`Stream::merge`].
|
||||||
///
|
///
|
||||||
/// [`Stream::merge`]: trait.Stream.html#method.merge
|
/// [`Stream::merge`]: trait.Stream.html#method.merge
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Merge<L, R> {
|
pub struct Merge<L, R> {
|
||||||
|
#[pin]
|
||||||
left: L,
|
left: L,
|
||||||
|
#[pin]
|
||||||
right: R,
|
right: R,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
impl<L, R> Unpin for Merge<L, R> {}
|
|
||||||
|
|
||||||
impl<L, R> Merge<L, R> {
|
impl<L, R> Merge<L, R> {
|
||||||
pub(crate) fn new(left: L, right: R) -> Self {
|
pub(crate) fn new(left: L, right: R) -> Self {
|
||||||
|
@ -24,19 +29,20 @@ impl<L, R> Merge<L, R> {
|
||||||
|
|
||||||
impl<L, R, T> Stream for Merge<L, R>
|
impl<L, R, T> Stream for Merge<L, R>
|
||||||
where
|
where
|
||||||
L: Stream<Item = T> + Unpin,
|
L: Stream<Item = T>,
|
||||||
R: Stream<Item = T> + Unpin,
|
R: Stream<Item = T>,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
if let Poll::Ready(Some(item)) = Pin::new(&mut self.left).poll_next(cx) {
|
let this = self.project();
|
||||||
|
if let Poll::Ready(Some(item)) = this.left.poll_next(cx) {
|
||||||
// The first stream made progress. The Merge needs to be polled
|
// The first stream made progress. The Merge needs to be polled
|
||||||
// again to check the progress of the second stream.
|
// again to check the progress of the second stream.
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
Poll::Ready(Some(item))
|
Poll::Ready(Some(item))
|
||||||
} else {
|
} else {
|
||||||
Pin::new(&mut self.right).poll_next(cx)
|
this.right.poll_next(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct MinByFuture<S, F, T> {
|
pub struct MinByFuture<S, F, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
compare: F,
|
compare: F,
|
||||||
min: Option<T>,
|
min: Option<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T> MinByFuture<S, F, T> {
|
impl<S, F, T> MinByFuture<S, F, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(compare: F);
|
|
||||||
pin_utils::unsafe_unpinned!(min: Option<T>);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, compare: F) -> Self {
|
pub(super) fn new(stream: S, compare: F) -> Self {
|
||||||
MinByFuture {
|
MinByFuture {
|
||||||
stream,
|
stream,
|
||||||
|
@ -35,22 +36,23 @@ where
|
||||||
{
|
{
|
||||||
type Output = Option<S::Item>;
|
type Output = Option<S::Item>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(new) => {
|
Some(new) => {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
match self.as_mut().min().take() {
|
match this.min.take() {
|
||||||
None => *self.as_mut().min() = Some(new),
|
None => *this.min = Some(new),
|
||||||
Some(old) => match (&mut self.as_mut().compare())(&new, &old) {
|
Some(old) => match (this.compare)(&new, &old) {
|
||||||
Ordering::Less => *self.as_mut().min() = Some(new),
|
Ordering::Less => *this.min = Some(new),
|
||||||
_ => *self.as_mut().min() = Some(old),
|
_ => *this.min = Some(old),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
None => Poll::Ready(self.min),
|
None => Poll::Ready(*this.min),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ mod fuse;
|
||||||
mod ge;
|
mod ge;
|
||||||
mod gt;
|
mod gt;
|
||||||
mod inspect;
|
mod inspect;
|
||||||
|
mod last;
|
||||||
mod le;
|
mod le;
|
||||||
mod lt;
|
mod lt;
|
||||||
mod map;
|
mod map;
|
||||||
|
@ -64,6 +65,7 @@ use fold::FoldFuture;
|
||||||
use for_each::ForEachFuture;
|
use for_each::ForEachFuture;
|
||||||
use ge::GeFuture;
|
use ge::GeFuture;
|
||||||
use gt::GtFuture;
|
use gt::GtFuture;
|
||||||
|
use last::LastFuture;
|
||||||
use le::LeFuture;
|
use le::LeFuture;
|
||||||
use lt::LtFuture;
|
use lt::LtFuture;
|
||||||
use min_by::MinByFuture;
|
use min_by::MinByFuture;
|
||||||
|
@ -89,32 +91,22 @@ pub use zip::Zip;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
cfg_unstable! {
|
||||||
|
|
||||||
use crate::utils::extension_trait;
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature = "docs")] {
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use crate::task::{Context, Poll};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
mod merge;
|
|
||||||
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::FromStream;
|
use crate::stream::FromStream;
|
||||||
|
|
||||||
pub use merge::Merge;
|
pub use merge::Merge;
|
||||||
}
|
|
||||||
|
mod merge;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension_trait! {
|
extension_trait! {
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
An asynchronous stream of values.
|
An asynchronous stream of values.
|
||||||
|
|
||||||
|
@ -456,6 +448,54 @@ extension_trait! {
|
||||||
Inspect::new(self, f)
|
Inspect::new(self, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc = r#"
|
||||||
|
Returns the last element of the stream.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
Basic usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
# fn main() { async_std::task::block_on(async {
|
||||||
|
#
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use async_std::prelude::*;
|
||||||
|
|
||||||
|
let s: VecDeque<usize> = vec![1, 2, 3].into_iter().collect();
|
||||||
|
|
||||||
|
let last = s.last().await;
|
||||||
|
assert_eq!(last, Some(3));
|
||||||
|
#
|
||||||
|
# }) }
|
||||||
|
```
|
||||||
|
|
||||||
|
An empty stream will return `None:
|
||||||
|
```
|
||||||
|
# fn main() { async_std::task::block_on(async {
|
||||||
|
#
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use async_std::prelude::*;
|
||||||
|
|
||||||
|
let s: VecDeque<usize> = vec![].into_iter().collect();
|
||||||
|
|
||||||
|
let last = s.last().await;
|
||||||
|
assert_eq!(last, None);
|
||||||
|
#
|
||||||
|
# }) }
|
||||||
|
```
|
||||||
|
|
||||||
|
"#]
|
||||||
|
fn last(
|
||||||
|
self,
|
||||||
|
) -> impl Future<Output = Option<Self::Item>> [LastFuture<Self, Self::Item>]
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
LastFuture::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
#[doc = r#"
|
#[doc = r#"
|
||||||
Transforms this `Stream` into a "fused" `Stream` such that after the first time
|
Transforms this `Stream` into a "fused" `Stream` such that after the first time
|
||||||
`poll` returns `Poll::Ready(None)`, all future calls to `poll` will also return
|
`poll` returns `Poll::Ready(None)`, all future calls to `poll` will also return
|
||||||
|
@ -1226,7 +1266,7 @@ extension_trait! {
|
||||||
|
|
||||||
[`stream`]: trait.Stream.html#tymethod.next
|
[`stream`]: trait.Stream.html#tymethod.next
|
||||||
"#]
|
"#]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead (TODO)"]
|
#[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead (TODO)"]
|
||||||
fn collect<'a, B>(
|
fn collect<'a, B>(
|
||||||
|
@ -1265,7 +1305,7 @@ extension_trait! {
|
||||||
# });
|
# });
|
||||||
```
|
```
|
||||||
"#]
|
"#]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
fn merge<U>(self, other: U) -> Merge<Self, U>
|
fn merge<U>(self, other: U) -> Merge<Self, U>
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::fuse::Fuse;
|
use super::fuse::Fuse;
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
// Lexicographically compares the elements of this `Stream` with those
|
// Lexicographically compares the elements of this `Stream` with those
|
||||||
// of another.
|
// of another.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct PartialCmpFuture<L: Stream, R: Stream> {
|
pub struct PartialCmpFuture<L: Stream, R: Stream> {
|
||||||
|
#[pin]
|
||||||
l: Fuse<L>,
|
l: Fuse<L>,
|
||||||
|
#[pin]
|
||||||
r: Fuse<R>,
|
r: Fuse<R>,
|
||||||
l_cache: Option<L::Item>,
|
l_cache: Option<L::Item>,
|
||||||
r_cache: Option<R::Item>,
|
r_cache: Option<R::Item>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<L: Stream, R: Stream> PartialCmpFuture<L, R> {
|
impl<L: Stream, R: Stream> PartialCmpFuture<L, R> {
|
||||||
pin_utils::unsafe_pinned!(l: Fuse<L>);
|
|
||||||
pin_utils::unsafe_pinned!(r: Fuse<R>);
|
|
||||||
pin_utils::unsafe_unpinned!(l_cache: Option<L::Item>);
|
|
||||||
pin_utils::unsafe_unpinned!(r_cache: Option<R::Item>);
|
|
||||||
|
|
||||||
pub(super) fn new(l: L, r: R) -> Self {
|
pub(super) fn new(l: L, r: R) -> Self {
|
||||||
PartialCmpFuture {
|
PartialCmpFuture {
|
||||||
l: l.fuse(),
|
l: l.fuse(),
|
||||||
|
@ -42,12 +43,13 @@ where
|
||||||
{
|
{
|
||||||
type Output = Option<Ordering>;
|
type Output = Option<Ordering>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
// Short circuit logic
|
// Short circuit logic
|
||||||
// Stream that completes earliest can be considered Less, etc
|
// Stream that completes earliest can be considered Less, etc
|
||||||
let l_complete = self.l.done && self.as_mut().l_cache.is_none();
|
let l_complete = this.l.done && this.l_cache.is_none();
|
||||||
let r_complete = self.r.done && self.as_mut().r_cache.is_none();
|
let r_complete = this.r.done && this.r_cache.is_none();
|
||||||
|
|
||||||
if l_complete && r_complete {
|
if l_complete && r_complete {
|
||||||
return Poll::Ready(Some(Ordering::Equal));
|
return Poll::Ready(Some(Ordering::Equal));
|
||||||
|
@ -58,30 +60,30 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get next value if possible and necesary
|
// Get next value if possible and necesary
|
||||||
if !self.l.done && self.as_mut().l_cache.is_none() {
|
if !this.l.done && this.l_cache.is_none() {
|
||||||
let l_next = futures_core::ready!(self.as_mut().l().poll_next(cx));
|
let l_next = futures_core::ready!(this.l.as_mut().poll_next(cx));
|
||||||
if let Some(item) = l_next {
|
if let Some(item) = l_next {
|
||||||
*self.as_mut().l_cache() = Some(item);
|
*this.l_cache = Some(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.r.done && self.as_mut().r_cache.is_none() {
|
if !this.r.done && this.r_cache.is_none() {
|
||||||
let r_next = futures_core::ready!(self.as_mut().r().poll_next(cx));
|
let r_next = futures_core::ready!(this.r.as_mut().poll_next(cx));
|
||||||
if let Some(item) = r_next {
|
if let Some(item) = r_next {
|
||||||
*self.as_mut().r_cache() = Some(item);
|
*this.r_cache = Some(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare if both values are available.
|
// Compare if both values are available.
|
||||||
if self.as_mut().l_cache.is_some() && self.as_mut().r_cache.is_some() {
|
if this.l_cache.is_some() && this.r_cache.is_some() {
|
||||||
let l_value = self.as_mut().l_cache().take().unwrap();
|
let l_value = this.l_cache.as_mut().take().unwrap();
|
||||||
let r_value = self.as_mut().r_cache().take().unwrap();
|
let r_value = this.r_cache.as_mut().take().unwrap();
|
||||||
let result = l_value.partial_cmp(&r_value);
|
let result = l_value.partial_cmp(&r_value);
|
||||||
|
|
||||||
if let Some(Ordering::Equal) = result {
|
if let Some(Ordering::Equal) = result {
|
||||||
// Reset cache to prepare for next comparison
|
// Reset cache to prepare for next comparison
|
||||||
*self.as_mut().l_cache() = None;
|
*this.l_cache = None;
|
||||||
*self.as_mut().r_cache() = None;
|
*this.r_cache = None;
|
||||||
} else {
|
} else {
|
||||||
// Return non equal value
|
// Return non equal value
|
||||||
return Poll::Ready(result);
|
return Poll::Ready(result);
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream to maintain state while polling another stream.
|
/// A stream to maintain state while polling another stream.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Scan<S, St, F> {
|
pub struct Scan<S, St, F> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
state_f: (St, F),
|
state_f: (St, F),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, St, F> Scan<S, St, F> {
|
impl<S, St, F> Scan<S, St, F> {
|
||||||
pub(crate) fn new(stream: S, initial_state: St, f: F) -> Self {
|
pub(crate) fn new(stream: S, initial_state: St, f: F) -> Self {
|
||||||
|
@ -17,13 +22,8 @@ impl<S, St, F> Scan<S, St, F> {
|
||||||
state_f: (initial_state, f),
|
state_f: (initial_state, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(state_f: (St, F));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Unpin, St, F> Unpin for Scan<S, St, F> {}
|
|
||||||
|
|
||||||
impl<S, St, F, B> Stream for Scan<S, St, F>
|
impl<S, St, F, B> Stream for Scan<S, St, F>
|
||||||
where
|
where
|
||||||
S: Stream,
|
S: Stream,
|
||||||
|
@ -31,11 +31,12 @@ where
|
||||||
{
|
{
|
||||||
type Item = B;
|
type Item = B;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<B>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<B>> {
|
||||||
let poll_result = self.as_mut().stream().poll_next(cx);
|
let mut this = self.project();
|
||||||
|
let poll_result = this.stream.as_mut().poll_next(cx);
|
||||||
poll_result.map(|item| {
|
poll_result.map(|item| {
|
||||||
item.and_then(|item| {
|
item.and_then(|item| {
|
||||||
let (state, f) = self.as_mut().state_f();
|
let (state, f) = this.state_f;
|
||||||
f(state, item)
|
f(state, item)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream to skip first n elements of another stream.
|
/// A stream to skip first n elements of another stream.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Skip<S> {
|
pub struct Skip<S> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
n: usize,
|
n: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Skip<S> {
|
impl<S> Skip<S> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(n: usize);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, n: usize) -> Self {
|
pub(crate) fn new(stream: S, n: usize) -> Self {
|
||||||
Skip { stream, n }
|
Skip { stream, n }
|
||||||
}
|
}
|
||||||
|
@ -25,14 +27,15 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => match self.n {
|
Some(v) => match *this.n {
|
||||||
0 => return Poll::Ready(Some(v)),
|
0 => return Poll::Ready(Some(v)),
|
||||||
_ => *self.as_mut().n() -= 1,
|
_ => *this.n -= 1,
|
||||||
},
|
},
|
||||||
None => return Poll::Ready(None),
|
None => return Poll::Ready(None),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream to skip elements of another stream based on a predicate.
|
/// A stream to skip elements of another stream based on a predicate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SkipWhile<S, P, T> {
|
pub struct SkipWhile<S, P, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
predicate: Option<P>,
|
predicate: Option<P>,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, P, T> SkipWhile<S, P, T> {
|
impl<S, P, T> SkipWhile<S, P, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(predicate: Option<P>);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, predicate: P) -> Self {
|
pub(crate) fn new(stream: S, predicate: P) -> Self {
|
||||||
SkipWhile {
|
SkipWhile {
|
||||||
stream,
|
stream,
|
||||||
|
@ -32,15 +34,16 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => match self.as_mut().predicate() {
|
Some(v) => match this.predicate {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
if !p(&v) {
|
if !p(&v) {
|
||||||
*self.as_mut().predicate() = None;
|
*this.predicate = None;
|
||||||
return Poll::Ready(Some(v));
|
return Poll::Ready(Some(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that steps a given amount of elements of another stream.
|
/// A stream that steps a given amount of elements of another stream.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StepBy<S> {
|
pub struct StepBy<S> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
step: usize,
|
step: usize,
|
||||||
i: usize,
|
i: usize,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> StepBy<S> {
|
impl<S> StepBy<S> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(step: usize);
|
|
||||||
pin_utils::unsafe_unpinned!(i: usize);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, step: usize) -> Self {
|
pub(crate) fn new(stream: S, step: usize) -> Self {
|
||||||
StepBy {
|
StepBy {
|
||||||
stream,
|
stream,
|
||||||
|
@ -31,17 +32,18 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => match self.i {
|
Some(v) => match this.i {
|
||||||
0 => {
|
0 => {
|
||||||
*self.as_mut().i() = self.step;
|
*this.i = *this.step;
|
||||||
return Poll::Ready(Some(v));
|
return Poll::Ready(Some(v));
|
||||||
}
|
}
|
||||||
_ => *self.as_mut().i() -= 1,
|
_ => *this.i -= 1,
|
||||||
},
|
},
|
||||||
None => return Poll::Ready(None),
|
None => return Poll::Ready(None),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that yields the first `n` items of another stream.
|
/// A stream that yields the first `n` items of another stream.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Take<S> {
|
pub struct Take<S> {
|
||||||
|
#[pin]
|
||||||
pub(crate) stream: S,
|
pub(crate) stream: S,
|
||||||
pub(crate) remaining: usize,
|
pub(crate) remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Unpin> Unpin for Take<S> {}
|
|
||||||
|
|
||||||
impl<S: Stream> Take<S> {
|
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(remaining: usize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Stream> Stream for Take<S> {
|
impl<S: Stream> Stream for Take<S> {
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
||||||
if self.remaining == 0 {
|
let this = self.project();
|
||||||
|
if *this.remaining == 0 {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
match next {
|
match next {
|
||||||
Some(_) => *self.as_mut().remaining() -= 1,
|
Some(_) => *this.remaining -= 1,
|
||||||
None => *self.as_mut().remaining() = 0,
|
None => *this.remaining = 0,
|
||||||
}
|
}
|
||||||
Poll::Ready(next)
|
Poll::Ready(next)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// A stream that yields elements based on a predicate.
|
/// A stream that yields elements based on a predicate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TakeWhile<S, P, T> {
|
pub struct TakeWhile<S, P, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
predicate: P,
|
predicate: P,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, P, T> TakeWhile<S, P, T> {
|
impl<S, P, T> TakeWhile<S, P, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(predicate: P);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, predicate: P) -> Self {
|
pub(super) fn new(stream: S, predicate: P) -> Self {
|
||||||
TakeWhile {
|
TakeWhile {
|
||||||
stream,
|
stream,
|
||||||
|
@ -32,11 +34,12 @@ where
|
||||||
{
|
{
|
||||||
type Item = S::Item;
|
type Item = S::Item;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let this = self.project();
|
||||||
|
let next = futures_core::ready!(this.stream.poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) if (self.as_mut().predicate())(&v) => Poll::Ready(Some(v)),
|
Some(v) if (this.predicate)(&v) => Poll::Ready(Some(v)),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct TryFoldFuture<S, F, T> {
|
pub struct TryFoldFuture<S, F, T> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
acc: Option<T>,
|
acc: Option<T>,
|
||||||
__t: PhantomData<T>,
|
__t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T> TryFoldFuture<S, F, T> {
|
impl<S, F, T> TryFoldFuture<S, F, T> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
pin_utils::unsafe_unpinned!(acc: Option<T>);
|
|
||||||
|
|
||||||
pub(super) fn new(stream: S, init: T, f: F) -> Self {
|
pub(super) fn new(stream: S, init: T, f: F) -> Self {
|
||||||
TryFoldFuture {
|
TryFoldFuture {
|
||||||
stream,
|
stream,
|
||||||
|
@ -36,23 +37,22 @@ where
|
||||||
{
|
{
|
||||||
type Output = Result<T, E>;
|
type Output = Result<T, E>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let old = self.as_mut().acc().take().unwrap();
|
let old = this.acc.take().unwrap();
|
||||||
let new = (self.as_mut().f())(old, v);
|
let new = (this.f)(old, v);
|
||||||
|
|
||||||
match new {
|
match new {
|
||||||
Ok(o) => {
|
Ok(o) => *this.acc = Some(o),
|
||||||
*self.as_mut().acc() = Some(o);
|
|
||||||
}
|
|
||||||
Err(e) => return Poll::Ready(Err(e)),
|
Err(e) => return Poll::Ready(Err(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => return Poll::Ready(Ok(self.as_mut().acc().take().unwrap())),
|
None => return Poll::Ready(Ok(this.acc.take().unwrap())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::future::Future;
|
use crate::future::Future;
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct TryForEeachFuture<S, F, T, R> {
|
pub struct TryForEeachFuture<S, F, T, R> {
|
||||||
|
#[pin]
|
||||||
stream: S,
|
stream: S,
|
||||||
f: F,
|
f: F,
|
||||||
__from: PhantomData<T>,
|
__from: PhantomData<T>,
|
||||||
__to: PhantomData<R>,
|
__to: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, F, T, R> TryForEeachFuture<S, F, T, R> {
|
impl<S, F, T, R> TryForEeachFuture<S, F, T, R> {
|
||||||
pin_utils::unsafe_pinned!(stream: S);
|
|
||||||
pin_utils::unsafe_unpinned!(f: F);
|
|
||||||
|
|
||||||
pub(crate) fn new(stream: S, f: F) -> Self {
|
pub(crate) fn new(stream: S, f: F) -> Self {
|
||||||
TryForEeachFuture {
|
TryForEeachFuture {
|
||||||
stream,
|
stream,
|
||||||
|
@ -36,14 +38,15 @@ where
|
||||||
{
|
{
|
||||||
type Output = Result<(), E>;
|
type Output = Result<(), E>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
loop {
|
loop {
|
||||||
let item = futures_core::ready!(self.as_mut().stream().poll_next(cx));
|
let item = futures_core::ready!(this.stream.as_mut().poll_next(cx));
|
||||||
|
|
||||||
match item {
|
match item {
|
||||||
None => return Poll::Ready(Ok(())),
|
None => return Poll::Ready(Ok(())),
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let res = (self.as_mut().f())(v);
|
let res = (this.f)(v);
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
return Poll::Ready(Err(e));
|
return Poll::Ready(Err(e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::stream::Stream;
|
use crate::stream::Stream;
|
||||||
use crate::task::{Context, Poll};
|
use crate::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
/// An iterator that iterates two other iterators simultaneously.
|
/// An iterator that iterates two other iterators simultaneously.
|
||||||
pub struct Zip<A: Stream, B> {
|
pub struct Zip<A: Stream, B> {
|
||||||
item_slot: Option<A::Item>,
|
item_slot: Option<A::Item>,
|
||||||
|
#[pin]
|
||||||
first: A,
|
first: A,
|
||||||
|
#[pin]
|
||||||
second: B,
|
second: B,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Stream + fmt::Debug, B: fmt::Debug> fmt::Debug for Zip<A, B> {
|
impl<A: Stream + fmt::Debug, B: fmt::Debug> fmt::Debug for Zip<A, B> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -20,8 +26,6 @@ impl<A: Stream + fmt::Debug, B: fmt::Debug> fmt::Debug for Zip<A, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Stream + Unpin, B: Unpin> Unpin for Zip<A, B> {}
|
|
||||||
|
|
||||||
impl<A: Stream, B> Zip<A, B> {
|
impl<A: Stream, B> Zip<A, B> {
|
||||||
pub(crate) fn new(first: A, second: B) -> Self {
|
pub(crate) fn new(first: A, second: B) -> Self {
|
||||||
Zip {
|
Zip {
|
||||||
|
@ -30,25 +34,22 @@ impl<A: Stream, B> Zip<A, B> {
|
||||||
second,
|
second,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_utils::unsafe_unpinned!(item_slot: Option<A::Item>);
|
|
||||||
pin_utils::unsafe_pinned!(first: A);
|
|
||||||
pin_utils::unsafe_pinned!(second: B);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Stream, B: Stream> Stream for Zip<A, B> {
|
impl<A: Stream, B: Stream> Stream for Zip<A, B> {
|
||||||
type Item = (A::Item, B::Item);
|
type Item = (A::Item, B::Item);
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
if self.as_mut().item_slot().is_none() {
|
let this = self.project();
|
||||||
match self.as_mut().first().poll_next(cx) {
|
if this.item_slot.is_none() {
|
||||||
|
match this.first.poll_next(cx) {
|
||||||
Poll::Pending => return Poll::Pending,
|
Poll::Pending => return Poll::Pending,
|
||||||
Poll::Ready(None) => return Poll::Ready(None),
|
Poll::Ready(None) => return Poll::Ready(None),
|
||||||
Poll::Ready(Some(item)) => *self.as_mut().item_slot() = Some(item),
|
Poll::Ready(Some(item)) => *this.item_slot = Some(item),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let second_item = futures_core::ready!(self.as_mut().second().poll_next(cx));
|
let second_item = futures_core::ready!(this.second.poll_next(cx));
|
||||||
let first_item = self.as_mut().item_slot().take().unwrap();
|
let first_item = this.item_slot.take().unwrap();
|
||||||
Poll::Ready(second_item.map(|second_item| (first_item, second_item)))
|
Poll::Ready(second_item.map(|second_item| (first_item, second_item)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ use crate::stream::Stream;
|
||||||
/// [`sum`]: trait.Sum.html#tymethod.sum
|
/// [`sum`]: trait.Sum.html#tymethod.sum
|
||||||
/// [`FromStream`]: trait.FromStream.html
|
/// [`FromStream`]: trait.FromStream.html
|
||||||
/// [`Stream::sum`]: trait.Stream.html#method.sum
|
/// [`Stream::sum`]: trait.Stream.html#method.sum
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub trait Sum<A = Self>: Sized {
|
pub trait Sum<A = Self>: Sized {
|
||||||
/// Method which takes a stream and generates `Self` from the elements by
|
/// Method which takes a stream and generates `Self` from the elements by
|
||||||
/// "summing up" the items.
|
/// "summing up" the items.
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::sync::Mutex;
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::sync::{Arc, Barrier};
|
/// use async_std::sync::{Arc, Barrier};
|
||||||
/// use async_std::task;
|
/// use async_std::task;
|
||||||
|
@ -30,8 +30,8 @@ use crate::sync::Mutex;
|
||||||
/// handle.await;
|
/// handle.await;
|
||||||
/// }
|
/// }
|
||||||
/// # });
|
/// # });
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Barrier {
|
pub struct Barrier {
|
||||||
|
@ -61,6 +61,7 @@ struct BarrierState {
|
||||||
/// let barrier = Barrier::new(1);
|
/// let barrier = Barrier::new(1);
|
||||||
/// let barrier_wait_result = barrier.wait();
|
/// let barrier_wait_result = barrier.wait();
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BarrierWaitResult(bool);
|
pub struct BarrierWaitResult(bool);
|
||||||
|
@ -118,7 +119,7 @@ impl Barrier {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::sync::{Arc, Barrier};
|
/// use async_std::sync::{Arc, Barrier};
|
||||||
/// use async_std::task;
|
/// use async_std::task;
|
||||||
|
@ -140,7 +141,6 @@ impl Barrier {
|
||||||
/// handle.await;
|
/// handle.await;
|
||||||
/// }
|
/// }
|
||||||
/// # });
|
/// # });
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn wait(&self) -> BarrierWaitResult {
|
pub async fn wait(&self) -> BarrierWaitResult {
|
||||||
let mut lock = self.state.lock().await;
|
let mut lock = self.state.lock().await;
|
||||||
|
@ -188,7 +188,7 @@ impl BarrierWaitResult {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::sync::Barrier;
|
/// use async_std::sync::Barrier;
|
||||||
///
|
///
|
||||||
|
@ -196,7 +196,6 @@ impl BarrierWaitResult {
|
||||||
/// let barrier_wait_result = barrier.wait().await;
|
/// let barrier_wait_result = barrier.wait().await;
|
||||||
/// println!("{:?}", barrier_wait_result.is_leader());
|
/// println!("{:?}", barrier_wait_result.is_leader());
|
||||||
/// # });
|
/// # });
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn is_leader(&self) -> bool {
|
pub fn is_leader(&self) -> bool {
|
||||||
self.0
|
self.0
|
||||||
|
|
1132
src/sync/channel.rs
Normal file
1132
src/sync/channel.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -32,14 +32,16 @@
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use std::sync::{Arc, Weak};
|
pub use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
pub use barrier::{Barrier, BarrierWaitResult};
|
|
||||||
|
|
||||||
pub use mutex::{Mutex, MutexGuard};
|
pub use mutex::{Mutex, MutexGuard};
|
||||||
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
|
||||||
mod barrier;
|
|
||||||
mod mutex;
|
mod mutex;
|
||||||
mod rwlock;
|
mod rwlock;
|
||||||
|
|
||||||
|
cfg_unstable! {
|
||||||
|
pub use barrier::{Barrier, BarrierWaitResult};
|
||||||
|
pub use channel::{channel, Sender, Receiver};
|
||||||
|
|
||||||
|
mod barrier;
|
||||||
|
mod channel;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::{Cell, UnsafeCell};
|
||||||
use std::mem::{self, ManuallyDrop};
|
use std::mem::{self, ManuallyDrop};
|
||||||
use std::panic::{self, AssertUnwindSafe, UnwindSafe};
|
use std::panic::{self, AssertUnwindSafe, UnwindSafe};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::task::{RawWaker, RawWakerVTable};
|
use std::task::{RawWaker, RawWakerVTable};
|
||||||
use std::thread::{self, Thread};
|
use std::thread;
|
||||||
|
|
||||||
|
use crossbeam_utils::sync::Parker;
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::task;
|
use super::task;
|
||||||
use super::task_local;
|
use super::task_local;
|
||||||
|
@ -98,19 +101,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
struct CatchUnwindFuture<F> {
|
struct CatchUnwindFuture<F> {
|
||||||
|
#[pin]
|
||||||
future: F,
|
future: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> CatchUnwindFuture<F> {
|
|
||||||
pin_utils::unsafe_pinned!(future: F);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Future + UnwindSafe> Future for CatchUnwindFuture<F> {
|
impl<F: Future + UnwindSafe> Future for CatchUnwindFuture<F> {
|
||||||
type Output = thread::Result<F::Output>;
|
type Output = thread::Result<F::Output>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
panic::catch_unwind(AssertUnwindSafe(|| self.future().poll(cx)))?.map(Ok)
|
panic::catch_unwind(AssertUnwindSafe(|| self.project().future.poll(cx)))?.map(Ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,13 +121,21 @@ where
|
||||||
F: Future<Output = T>,
|
F: Future<Output = T>,
|
||||||
{
|
{
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static ARC_THREAD: Arc<Thread> = Arc::new(thread::current());
|
// May hold a pre-allocated parker that can be reused for efficiency.
|
||||||
|
//
|
||||||
|
// Note that each invocation of `block` needs its own parker. In particular, if `block`
|
||||||
|
// recursively calls itself, we must make sure that each recursive call uses a distinct
|
||||||
|
// parker instance.
|
||||||
|
static CACHE: Cell<Option<Arc<Parker>>> = Cell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_utils::pin_mut!(f);
|
pin_utils::pin_mut!(f);
|
||||||
|
|
||||||
ARC_THREAD.with(|arc_thread: &Arc<Thread>| {
|
CACHE.with(|cache| {
|
||||||
let ptr = (&**arc_thread as *const Thread) as *const ();
|
// Reuse a cached parker or create a new one for this invocation of `block`.
|
||||||
|
let arc_parker: Arc<Parker> = cache.take().unwrap_or_else(|| Arc::new(Parker::new()));
|
||||||
|
|
||||||
|
let ptr = (&*arc_parker as *const Parker) as *const ();
|
||||||
let vt = vtable();
|
let vt = vtable();
|
||||||
|
|
||||||
let waker = unsafe { ManuallyDrop::new(Waker::from_raw(RawWaker::new(ptr, vt))) };
|
let waker = unsafe { ManuallyDrop::new(Waker::from_raw(RawWaker::new(ptr, vt))) };
|
||||||
|
@ -133,32 +143,34 @@ where
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Poll::Ready(t) = f.as_mut().poll(cx) {
|
if let Poll::Ready(t) = f.as_mut().poll(cx) {
|
||||||
|
// Save the parker for the next invocation of `block`.
|
||||||
|
cache.set(Some(arc_parker));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
thread::park();
|
arc_parker.park();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vtable() -> &'static RawWakerVTable {
|
fn vtable() -> &'static RawWakerVTable {
|
||||||
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
|
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
|
||||||
let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Thread));
|
let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Parker));
|
||||||
mem::forget(arc.clone());
|
mem::forget(arc.clone());
|
||||||
RawWaker::new(ptr, vtable())
|
RawWaker::new(ptr, vtable())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn wake_raw(ptr: *const ()) {
|
unsafe fn wake_raw(ptr: *const ()) {
|
||||||
let arc = Arc::from_raw(ptr as *const Thread);
|
let arc = Arc::from_raw(ptr as *const Parker);
|
||||||
arc.unpark();
|
arc.unparker().unpark();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn wake_by_ref_raw(ptr: *const ()) {
|
unsafe fn wake_by_ref_raw(ptr: *const ()) {
|
||||||
let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Thread));
|
let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const Parker));
|
||||||
arc.unpark();
|
arc.unparker().unpark();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn drop_raw(ptr: *const ()) {
|
unsafe fn drop_raw(ptr: *const ()) {
|
||||||
drop(Arc::from_raw(ptr as *const Thread))
|
drop(Arc::from_raw(ptr as *const Parker))
|
||||||
}
|
}
|
||||||
|
|
||||||
&RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw)
|
&RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw)
|
||||||
|
|
122
src/task/mod.rs
122
src/task/mod.rs
|
@ -1,26 +1,122 @@
|
||||||
//! Asynchronous tasks.
|
//! Types and traits for working with asynchronous tasks.
|
||||||
//!
|
//!
|
||||||
//! This module is similar to [`std::thread`], except it uses asynchronous tasks in place of
|
//! This module is similar to [`std::thread`], except it uses asynchronous tasks in place of
|
||||||
//! threads.
|
//! threads.
|
||||||
//!
|
//!
|
||||||
//! [`std::thread`]: https://doc.rust-lang.org/std/thread/index.html
|
//! [`std::thread`]: https://doc.rust-lang.org/std/thread
|
||||||
//!
|
//!
|
||||||
//! # Examples
|
//! ## The task model
|
||||||
//!
|
//!
|
||||||
//! Spawn a task and await its result:
|
//! An executing asynchronous Rust program consists of a collection of native OS threads, on top of
|
||||||
|
//! which multiple stackless coroutines are multiplexed. We refer to these as "tasks". Tasks can
|
||||||
|
//! be named, and provide some built-in support for synchronization.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! Communication between tasks can be done through channels, Rust's message-passing types, along
|
||||||
//! # async_std::task::block_on(async {
|
//! with [other forms of tasks synchronization](../sync/index.html) and shared-memory data
|
||||||
//! #
|
//! structures. In particular, types that are guaranteed to be threadsafe are easily shared between
|
||||||
|
//! tasks using the atomically-reference-counted container, [`Arc`].
|
||||||
|
//!
|
||||||
|
//! Fatal logic errors in Rust cause *thread panic*, during which a thread will unwind the stack,
|
||||||
|
//! running destructors and freeing owned resources. If a panic occurs inside a task, there is no
|
||||||
|
//! meaningful way of recovering, so the panic will propagate through any thread boundaries all the
|
||||||
|
//! way to the root task. This is also known as a "panic = abort" model.
|
||||||
|
//!
|
||||||
|
//! ## Spawning a task
|
||||||
|
//!
|
||||||
|
//! A new task can be spawned using the [`task::spawn`][`spawn`] function:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
//! use async_std::task;
|
//! use async_std::task;
|
||||||
//!
|
//!
|
||||||
//! let handle = task::spawn(async {
|
//! task::spawn(async {
|
||||||
//! 1 + 2
|
//! // some work here
|
||||||
//! });
|
//! });
|
||||||
//! assert_eq!(handle.await, 3);
|
//! ```
|
||||||
|
//!
|
||||||
|
//! In this example, the spawned task is "detached" from the current task. This means that it can
|
||||||
|
//! outlive its parent (the task that spawned it), unless this parent is the root task.
|
||||||
|
//!
|
||||||
|
//! The root task can also wait on the completion of the child task; a call to [`spawn`] produces a
|
||||||
|
//! [`JoinHandle`], which provides implements `Future` and can be `await`ed:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use async_std::task;
|
||||||
|
//!
|
||||||
|
//! # async_std::task::block_on(async {
|
||||||
|
//! #
|
||||||
|
//! let child = task::spawn(async {
|
||||||
|
//! // some work here
|
||||||
|
//! });
|
||||||
|
//! // some work here
|
||||||
|
//! let res = child.await;
|
||||||
//! #
|
//! #
|
||||||
//! # })
|
//! # })
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The `await` operator returns the final value produced by the child task.
|
||||||
|
//!
|
||||||
|
//! ## Configuring tasks
|
||||||
|
//!
|
||||||
|
//! A new task can be configured before it is spawned via the [`Builder`] type,
|
||||||
|
//! which currently allows you to set the name and stack size for the child task:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # #![allow(unused_must_use)]
|
||||||
|
//! use async_std::task;
|
||||||
|
//!
|
||||||
|
//! # async_std::task::block_on(async {
|
||||||
|
//! #
|
||||||
|
//! task::Builder::new().name("child1".to_string()).spawn(async {
|
||||||
|
//! println!("Hello, world!");
|
||||||
|
//! });
|
||||||
|
//! #
|
||||||
|
//! # })
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## The `Task` type
|
||||||
|
//!
|
||||||
|
//! Tasks are represented via the [`Task`] type, which you can get in one of
|
||||||
|
//! two ways:
|
||||||
|
//!
|
||||||
|
//! * By spawning a new task, e.g., using the [`task::spawn`][`spawn`]
|
||||||
|
//! function, and calling [`task`][`JoinHandle::task`] on the [`JoinHandle`].
|
||||||
|
//! * By requesting the current task, using the [`task::current`] function.
|
||||||
|
//!
|
||||||
|
//! ## Task-local storage
|
||||||
|
//!
|
||||||
|
//! This module also provides an implementation of task-local storage for Rust
|
||||||
|
//! programs. Task-local storage is a method of storing data into a global
|
||||||
|
//! variable that each task in the program will have its own copy of.
|
||||||
|
//! Tasks do not share this data, so accesses do not need to be synchronized.
|
||||||
|
//!
|
||||||
|
//! A task-local key owns the value it contains and will destroy the value when the
|
||||||
|
//! task exits. It is created with the [`task_local!`] macro and can contain any
|
||||||
|
//! value that is `'static` (no borrowed pointers). It provides an accessor function,
|
||||||
|
//! [`with`], that yields a shared reference to the value to the specified
|
||||||
|
//! closure. Task-local keys allow only shared access to values, as there would be no
|
||||||
|
//! way to guarantee uniqueness if mutable borrows were allowed.
|
||||||
|
//!
|
||||||
|
//! ## Naming tasks
|
||||||
|
//!
|
||||||
|
//! Tasks are able to have associated names for identification purposes. By default, spawned
|
||||||
|
//! tasks are unnamed. To specify a name for a task, build the task with [`Builder`] and pass
|
||||||
|
//! the desired task name to [`Builder::name`]. To retrieve the task name from within the
|
||||||
|
//! task, use [`Task::name`].
|
||||||
|
//!
|
||||||
|
//! [`Arc`]: ../gsync/struct.Arc.html
|
||||||
|
//! [`spawn`]: fn.spawn.html
|
||||||
|
//! [`JoinHandle`]: struct.JoinHandle.html
|
||||||
|
//! [`JoinHandle::task`]: struct.JoinHandle.html#method.task
|
||||||
|
//! [`join`]: struct.JoinHandle.html#method.join
|
||||||
|
//! [`panic!`]: https://doc.rust-lang.org/std/macro.panic.html
|
||||||
|
//! [`Builder`]: struct.Builder.html
|
||||||
|
//! [`Builder::stack_size`]: struct.Builder.html#method.stack_size
|
||||||
|
//! [`Builder::name`]: struct.Builder.html#method.name
|
||||||
|
//! [`task::current`]: fn.current.html
|
||||||
|
//! [`Task`]: struct.Thread.html
|
||||||
|
//! [`Task::name`]: struct.Task.html#method.name
|
||||||
|
//! [`task_local!`]: ../macro.task_local.html
|
||||||
|
//! [`with`]: struct.LocalKey.html#method.with
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use std::task::{Context, Poll, Waker};
|
pub use std::task::{Context, Poll, Waker};
|
||||||
|
@ -47,12 +143,10 @@ mod worker;
|
||||||
|
|
||||||
pub(crate) mod blocking;
|
pub(crate) mod blocking;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_unstable! {
|
||||||
if #[cfg(any(feature = "unstable", feature = "docs"))] {
|
|
||||||
mod yield_now;
|
mod yield_now;
|
||||||
pub use yield_now::yield_now;
|
pub use yield_now::yield_now;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawns a blocking task.
|
/// Spawns a blocking task.
|
||||||
///
|
///
|
||||||
|
@ -82,7 +176,7 @@ cfg_if::cfg_if! {
|
||||||
/// ```
|
/// ```
|
||||||
// Once this function stabilizes we should merge `blocking::spawn` into this so
|
// Once this function stabilizes we should merge `blocking::spawn` into this so
|
||||||
// all code in our crate uses `task::blocking` too.
|
// all code in our crate uses `task::blocking` too.
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn spawn_blocking<F, R>(f: F) -> task::JoinHandle<R>
|
pub fn spawn_blocking<F, R>(f: F) -> task::JoinHandle<R>
|
||||||
|
|
|
@ -18,15 +18,15 @@ use std::pin::Pin;
|
||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() { async_std::task::block_on(async {
|
/// # async_std::task::block_on(async {
|
||||||
/// #
|
/// #
|
||||||
/// use async_std::task;
|
/// use async_std::task;
|
||||||
///
|
///
|
||||||
/// task::yield_now().await;
|
/// task::yield_now().await;
|
||||||
/// #
|
/// #
|
||||||
/// # }) }
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
#[cfg(feature = "unstable")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn yield_now() {
|
pub async fn yield_now() {
|
||||||
|
|
69
src/utils.rs
69
src/utils.rs
|
@ -20,6 +20,64 @@ pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declares unstable items.
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! cfg_unstable {
|
||||||
|
($($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares Unix-specific items.
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! cfg_unix {
|
||||||
|
($($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(any(unix, feature = "docs"))]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares Windows-specific items.
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! cfg_windows {
|
||||||
|
($($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(any(windows, feature = "docs"))]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares items when the "docs" feature is enabled.
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! cfg_docs {
|
||||||
|
($($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = "docs")]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares items when the "docs" feature is disabled.
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! cfg_not_docs {
|
||||||
|
($($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(not(feature = "docs"))]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines an extension trait for a base trait.
|
/// Defines an extension trait for a base trait.
|
||||||
///
|
///
|
||||||
/// In generated docs, the base trait will contain methods from the extension trait. In actual
|
/// In generated docs, the base trait will contain methods from the extension trait. In actual
|
||||||
|
@ -29,7 +87,6 @@ pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
|
||||||
/// Inside invocations of this macro, we write a definitions that looks similar to the final
|
/// Inside invocations of this macro, we write a definitions that looks similar to the final
|
||||||
/// rendered docs, and the macro then generates all the boilerplate for us.
|
/// rendered docs, and the macro then generates all the boilerplate for us.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
|
||||||
macro_rules! extension_trait {
|
macro_rules! extension_trait {
|
||||||
(
|
(
|
||||||
// Interesting patterns:
|
// Interesting patterns:
|
||||||
|
@ -113,6 +170,12 @@ macro_rules! extension_trait {
|
||||||
// Handle the end of the token list.
|
// Handle the end of the token list.
|
||||||
(@doc ($($head:tt)*)) => { $($head)* };
|
(@doc ($($head:tt)*)) => { $($head)* };
|
||||||
(@ext ($($head:tt)*)) => { $($head)* };
|
(@ext ($($head:tt)*)) => { $($head)* };
|
||||||
}
|
|
||||||
|
|
||||||
pub use crate::extension_trait;
|
// Parse imports at the beginning of the macro.
|
||||||
|
($import:item $($tail:tt)*) => {
|
||||||
|
#[cfg(feature = "docs")]
|
||||||
|
$import
|
||||||
|
|
||||||
|
extension_trait!($($tail)*);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -48,13 +48,13 @@ fn test_buffered_writer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_buffered_writer_inner_into_inner_does_not_flush() {
|
fn test_buffered_writer_inner_into_inner_flushes() {
|
||||||
task::block_on(async {
|
task::block_on(async {
|
||||||
let mut w = BufWriter::with_capacity(3, Vec::new());
|
let mut w = BufWriter::with_capacity(3, Vec::new());
|
||||||
w.write(&[0, 1]).await.unwrap();
|
w.write(&[0, 1]).await.unwrap();
|
||||||
assert_eq!(*w.get_ref(), []);
|
assert_eq!(*w.get_ref(), []);
|
||||||
let w = w.into_inner().await.unwrap();
|
let w = w.into_inner().await.unwrap();
|
||||||
assert_eq!(w, []);
|
assert_eq!(w, [0, 1]);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
350
tests/channel.rs
Normal file
350
tests/channel.rs
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use async_std::sync::channel;
|
||||||
|
use async_std::task;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
fn ms(ms: u64) -> Duration {
|
||||||
|
Duration::from_millis(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(1);
|
||||||
|
|
||||||
|
s.send(7).await;
|
||||||
|
assert_eq!(r.recv().await, Some(7));
|
||||||
|
|
||||||
|
s.send(8).await;
|
||||||
|
assert_eq!(r.recv().await, Some(8));
|
||||||
|
|
||||||
|
drop(s);
|
||||||
|
assert_eq!(r.recv().await, None);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capacity() {
|
||||||
|
for i in 1..10 {
|
||||||
|
let (s, r) = channel::<()>(i);
|
||||||
|
assert_eq!(s.capacity(), i);
|
||||||
|
assert_eq!(r.capacity(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn len_empty_full() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(2);
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
|
assert_eq!(s.is_empty(), true);
|
||||||
|
assert_eq!(s.is_full(), false);
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
assert_eq!(r.is_empty(), true);
|
||||||
|
assert_eq!(r.is_full(), false);
|
||||||
|
|
||||||
|
s.send(()).await;
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 1);
|
||||||
|
assert_eq!(s.is_empty(), false);
|
||||||
|
assert_eq!(s.is_full(), false);
|
||||||
|
assert_eq!(r.len(), 1);
|
||||||
|
assert_eq!(r.is_empty(), false);
|
||||||
|
assert_eq!(r.is_full(), false);
|
||||||
|
|
||||||
|
s.send(()).await;
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 2);
|
||||||
|
assert_eq!(s.is_empty(), false);
|
||||||
|
assert_eq!(s.is_full(), true);
|
||||||
|
assert_eq!(r.len(), 2);
|
||||||
|
assert_eq!(r.is_empty(), false);
|
||||||
|
assert_eq!(r.is_full(), true);
|
||||||
|
|
||||||
|
r.recv().await;
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 1);
|
||||||
|
assert_eq!(s.is_empty(), false);
|
||||||
|
assert_eq!(s.is_full(), false);
|
||||||
|
assert_eq!(r.len(), 1);
|
||||||
|
assert_eq!(r.is_empty(), false);
|
||||||
|
assert_eq!(r.is_full(), false);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recv() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(100);
|
||||||
|
|
||||||
|
task::spawn(async move {
|
||||||
|
assert_eq!(r.recv().await, Some(7));
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
assert_eq!(r.recv().await, Some(8));
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
assert_eq!(r.recv().await, Some(9));
|
||||||
|
assert_eq!(r.recv().await, None);
|
||||||
|
});
|
||||||
|
|
||||||
|
task::sleep(ms(1500)).await;
|
||||||
|
s.send(7).await;
|
||||||
|
s.send(8).await;
|
||||||
|
s.send(9).await;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn send() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(1);
|
||||||
|
|
||||||
|
task::spawn(async move {
|
||||||
|
s.send(7).await;
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
s.send(8).await;
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
s.send(9).await;
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
s.send(10).await;
|
||||||
|
});
|
||||||
|
|
||||||
|
task::sleep(ms(1500)).await;
|
||||||
|
assert_eq!(r.recv().await, Some(7));
|
||||||
|
assert_eq!(r.recv().await, Some(8));
|
||||||
|
assert_eq!(r.recv().await, Some(9));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recv_after_disconnect() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(100);
|
||||||
|
|
||||||
|
s.send(1).await;
|
||||||
|
s.send(2).await;
|
||||||
|
s.send(3).await;
|
||||||
|
|
||||||
|
drop(s);
|
||||||
|
|
||||||
|
assert_eq!(r.recv().await, Some(1));
|
||||||
|
assert_eq!(r.recv().await, Some(2));
|
||||||
|
assert_eq!(r.recv().await, Some(3));
|
||||||
|
assert_eq!(r.recv().await, None);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn len() {
|
||||||
|
const COUNT: usize = 25_000;
|
||||||
|
const CAP: usize = 1000;
|
||||||
|
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(CAP);
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
|
||||||
|
for _ in 0..CAP / 10 {
|
||||||
|
for i in 0..50 {
|
||||||
|
s.send(i).await;
|
||||||
|
assert_eq!(s.len(), i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..50 {
|
||||||
|
r.recv().await;
|
||||||
|
assert_eq!(r.len(), 50 - i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
|
||||||
|
for i in 0..CAP {
|
||||||
|
s.send(i).await;
|
||||||
|
assert_eq!(s.len(), i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..CAP {
|
||||||
|
r.recv().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
|
||||||
|
let child = task::spawn({
|
||||||
|
let r = r.clone();
|
||||||
|
async move {
|
||||||
|
for i in 0..COUNT {
|
||||||
|
assert_eq!(r.recv().await, Some(i));
|
||||||
|
let len = r.len();
|
||||||
|
assert!(len <= CAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for i in 0..COUNT {
|
||||||
|
s.send(i).await;
|
||||||
|
let len = s.len();
|
||||||
|
assert!(len <= CAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
child.await;
|
||||||
|
|
||||||
|
assert_eq!(s.len(), 0);
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disconnect_wakes_receiver() {
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel::<()>(1);
|
||||||
|
|
||||||
|
let child = task::spawn(async move {
|
||||||
|
assert_eq!(r.recv().await, None);
|
||||||
|
});
|
||||||
|
|
||||||
|
task::sleep(ms(1000)).await;
|
||||||
|
drop(s);
|
||||||
|
|
||||||
|
child.await;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spsc() {
|
||||||
|
const COUNT: usize = 100_000;
|
||||||
|
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel(3);
|
||||||
|
|
||||||
|
let child = task::spawn(async move {
|
||||||
|
for i in 0..COUNT {
|
||||||
|
assert_eq!(r.recv().await, Some(i));
|
||||||
|
}
|
||||||
|
assert_eq!(r.recv().await, None);
|
||||||
|
});
|
||||||
|
|
||||||
|
for i in 0..COUNT {
|
||||||
|
s.send(i).await;
|
||||||
|
}
|
||||||
|
drop(s);
|
||||||
|
|
||||||
|
child.await;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mpmc() {
|
||||||
|
const COUNT: usize = 25_000;
|
||||||
|
const TASKS: usize = 4;
|
||||||
|
|
||||||
|
task::block_on(async {
|
||||||
|
let (s, r) = channel::<usize>(3);
|
||||||
|
let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
|
||||||
|
let v = Arc::new(v);
|
||||||
|
|
||||||
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
|
for _ in 0..TASKS {
|
||||||
|
let r = r.clone();
|
||||||
|
let v = v.clone();
|
||||||
|
tasks.push(task::spawn(async move {
|
||||||
|
for _ in 0..COUNT {
|
||||||
|
let n = r.recv().await.unwrap();
|
||||||
|
v[n].fetch_add(1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..TASKS {
|
||||||
|
let s = s.clone();
|
||||||
|
tasks.push(task::spawn(async move {
|
||||||
|
for i in 0..COUNT {
|
||||||
|
s.send(i).await;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for t in tasks {
|
||||||
|
t.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in v.iter() {
|
||||||
|
assert_eq!(c.load(Ordering::SeqCst), TASKS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn oneshot() {
|
||||||
|
const COUNT: usize = 10_000;
|
||||||
|
|
||||||
|
task::block_on(async {
|
||||||
|
for _ in 0..COUNT {
|
||||||
|
let (s, r) = channel(1);
|
||||||
|
|
||||||
|
let c1 = task::spawn(async move { r.recv().await.unwrap() });
|
||||||
|
let c2 = task::spawn(async move { s.send(0).await });
|
||||||
|
|
||||||
|
c1.await;
|
||||||
|
c2.await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn drops() {
|
||||||
|
const RUNS: usize = 100;
|
||||||
|
|
||||||
|
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct DropCounter;
|
||||||
|
|
||||||
|
impl Drop for DropCounter {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
for _ in 0..RUNS {
|
||||||
|
task::block_on(async {
|
||||||
|
let steps = rng.gen_range(0, 10_000);
|
||||||
|
let additional = rng.gen_range(0, 50);
|
||||||
|
|
||||||
|
DROPS.store(0, Ordering::SeqCst);
|
||||||
|
let (s, r) = channel::<DropCounter>(50);
|
||||||
|
|
||||||
|
let child = task::spawn({
|
||||||
|
let r = r.clone();
|
||||||
|
async move {
|
||||||
|
for _ in 0..steps {
|
||||||
|
r.recv().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..steps {
|
||||||
|
s.send(DropCounter).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.await;
|
||||||
|
|
||||||
|
for _ in 0..additional {
|
||||||
|
s.send(DropCounter).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(DROPS.load(Ordering::SeqCst), steps);
|
||||||
|
drop(s);
|
||||||
|
drop(r);
|
||||||
|
assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue