Merge branch 'master' into add_stdin_lock

poc-serde-support
k-nasa 5 years ago
commit 48b255897e

@ -11,6 +11,8 @@ jobs:
build_and_test:
name: Build and test
runs-on: ${{ matrix.os }}
env:
RUSTFLAGS: -Dwarnings
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
@ -29,7 +31,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: check
args: --all --benches --bins --examples --tests
args: --all --bins --examples
- name: check unstable
uses: actions-rs/cargo@v1
@ -41,11 +43,13 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --all --doc --features unstable
args: --all --features unstable
check_fmt_and_docs:
name: Checking fmt and docs
runs-on: ubuntu-latest
env:
RUSTFLAGS: -Dwarnings
steps:
- uses: actions/checkout@master
@ -77,6 +81,9 @@ jobs:
clippy_check:
name: Clippy check
runs-on: ubuntu-latest
# TODO: There is a lot of warnings
# env:
# RUSTFLAGS: -Dwarnings
steps:
- uses: actions/checkout@v1
- id: component

@ -1,68 +0,0 @@
language: rust
env:
- RUSTFLAGS="-D warnings"
# Cache the whole `~/.cargo` directory to keep `~/cargo/.crates.toml`.
cache:
directories:
- /home/travis/.cargo
# Don't cache the cargo registry because it's too big.
before_cache:
- rm -rf /home/travis/.cargo/registry
branches:
only:
- master
- staging
- trying
matrix:
fast_finish: true
include:
- rust: nightly
os: linux
- rust: nightly
os: osx
osx_image: xcode9.2
- rust: nightly-x86_64-pc-windows-msvc
os: windows
- name: fmt
rust: nightly
os: linux
before_script: |
if ! rustup component add rustfmt; then
target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustfmt`;
echo "'rustfmt' is unavailable on the toolchain 'nightly', use the toolchain 'nightly-$target' instead";
rustup toolchain install nightly-$target;
rustup default nightly-$target;
rustup component add rustfmt;
fi
script:
- cargo fmt --all -- --check
- name: docs
rust: nightly
os: linux
script:
- cargo doc --features docs
- name: book
rust: nightly
os: linux
before_script:
- test -x $HOME/.cargo/bin/mdbook || ./ci/install-mdbook.sh
- cargo build # to find 'extern crate async_std' by `mdbook test`
script:
- mdbook build docs
- mdbook test -L ./target/debug/deps docs
script:
- cargo check --all --benches --bins --examples --tests
- cargo check --features unstable --all --benches --bins --examples --tests
- cargo test --all --doc --features unstable

@ -7,6 +7,104 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
## [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
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
[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.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

@ -1,6 +1,6 @@
[package]
name = "async-std"
version = "0.99.9"
version = "0.99.10"
authors = [
"Stjepan Glavina <stjepang@gmail.com>",
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
@ -21,18 +21,18 @@ features = ["docs"]
rustdoc-args = ["--cfg", "feature=\"docs\""]
[features]
docs = ["broadcaster"]
docs = ["unstable"]
unstable = ["broadcaster"]
[dependencies]
async-macros = "1.0.0"
async-task = "1.0.0"
cfg-if = "0.1.9"
crossbeam-channel = "0.3.9"
crossbeam-deque = "0.7.1"
crossbeam-utils = "0.6.6"
futures-core-preview = "=0.3.0-alpha.19"
futures-io-preview = "=0.3.0-alpha.19"
futures-timer = "0.4.0"
futures-timer = "1.0.2"
lazy_static = "1.4.0"
log = { version = "0.4.8", features = ["kv_unstable"] }
memchr = "2.2.1"
@ -43,9 +43,11 @@ pin-utils = "0.1.0-alpha.4"
slab = "0.4.2"
kv-log-macro = "1.0.4"
broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] }
pin-project-lite = "0.1"
[dev-dependencies]
femme = "1.2.0"
rand = "0.7.2"
# surf = "1.0.2"
tempdir = "0.3.7"
futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] }

@ -1,41 +1,78 @@
# Async version of the Rust standard library
[![Build Status](https://travis-ci.com/async-rs/async-std.svg?branch=master)](https://travis-ci.com/async-rs/async-std)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/async-rs/async-std)
[![Cargo](https://img.shields.io/crates/v/async-std.svg)](https://crates.io/crates/async-std)
[![Documentation](https://docs.rs/async-std/badge.svg)](https://docs.rs/async-std)
[![chat](https://img.shields.io/discord/598880689856970762.svg?logo=discord)](https://discord.gg/JvZeVNe)
This crate provides an async version of [`std`]. It provides all the interfaces you
are used to, but in an async version and ready for Rust's `async`/`await` syntax.
<h1 align="center">async-std</h1>
<div align="center">
<strong>
Async version of the Rust standard library
</strong>
</div>
<br />
<div align="center">
<!-- Crates version -->
<a href="https://crates.io/crates/async-std">
<img src="https://img.shields.io/crates/v/async-std.svg?style=flat-square"
alt="Crates.io version" />
</a>
<!-- Downloads -->
<a href="https://crates.io/crates/async-std">
<img src="https://img.shields.io/crates/d/async-std.svg?style=flat-square"
alt="Download" />
</a>
<!-- docs.rs docs -->
<a href="https://docs.rs/async-std">
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
alt="docs.rs docs" />
</a>
<a href="https://discord.gg/JvZeVNe">
<img src="https://img.shields.io/discord/598880689856970762.svg?logo=discord&style=flat-square"
alt="chat" />
</a>
</div>
<div align="center">
<h3>
<a href="https://docs.rs/async-std">
API Docs
</a>
<span> | </span>
<a href="https://book.async.rs">
Book
</a>
<span> | </span>
<a href="https://github.com/async-rs/async-std/releases">
Releases
</a>
<span> | </span>
<a href="https://async.rs/contribute">
Contributing
</a>
</h3>
</div>
<br/>
This crate provides an async version of [`std`]. It provides all the interfaces
you are used to, but in an async version and ready for Rust's `async`/`await`
syntax.
[`std`]: https://doc.rust-lang.org/std/index.html
## Documentation
## Features
`async-std` comes with [extensive API documentation][docs] and a [book][book].
- __Modern:__ Built from the ground up for `std::future` and `async/await` with
blazing fast compilation times.
- __Fast:__ Our robust allocator and threadpool designs provide ultra-high
throughput with predictably low latency.
- __Intuitive:__ Complete parity with the stdlib means you only need to learn
APIs once.
- __Clear:__ [Detailed documentation][docs] and [accessible guides][book] mean
using async Rust was never easier.
[docs]: https://docs.rs/async-std
[book]: https://book.async.rs
## Quickstart
Add the following lines to your `Cargo.toml`:
```toml
[dependencies]
async-std = "0.99"
```
Or use [cargo add][cargo-add] if you have it installed:
```sh
$ cargo add async-std
```
[cargo-add]: https://github.com/killercup/cargo-edit
## Hello world
## Examples
```rust
use async_std::task;
@ -47,96 +84,48 @@ fn main() {
}
```
## Low-Friction Sockets with Built-In Timeouts
```rust
use std::time::Duration;
use async_std::{
prelude::*,
task,
io,
net::TcpStream,
};
async fn get() -> io::Result<Vec<u8>> {
let mut stream = TcpStream::connect("example.com:80").await?;
stream.write_all(b"GET /index.html HTTP/1.0\r\n\r\n").await?;
let mut buf = vec![];
io::timeout(Duration::from_secs(5), async {
stream.read_to_end(&mut buf).await?;
Ok(buf)
}).await
}
fn main() {
task::block_on(async {
let raw_response = get().await.expect("request");
let response = String::from_utf8(raw_response)
.expect("utf8 conversion");
println!("received: {}", response);
});
}
```
## Features
`async-std` is strongly commited to following semver. This means your code won't
break unless _you_ decide to upgrade.
However every now and then we come up with something that we think will work
_great_ for `async-std`, and we want to provide a sneak-peek so you can try it
out. This is what we call _"unstable"_ features. You can try out the unstable
features by enabling the `unstable` feature in your `Cargo.toml` file:
```toml
[dependencies.async-std]
version = "0.99"
features = ["unstable"]
```
Just be careful when using these features, as they may change between
versions.
More examples, including networking and file access, can be found in our
[`examples`] directory.
## Take a look around
[`examples`]: https://github.com/async-rs/async-std/tree/master/examples
Clone the repo:
## Philosophy
```
git clone git@github.com:async-rs/async-std.git && cd async-std
```
We believe Async Rust should be as easy to pick up as Sync Rust. We also believe
that the best API is the one you already know. And finally, we believe that
providing an asynchronous counterpart to the standard library is the best way
stdlib provides a reliable basis for both performance and productivity.
Generate docs:
Async-std is the embodiment of that vision. It combines single-allocation task
creation, with an adaptive lock-free executor, threadpool and network driver to
create a smooth system that processes work at a high pace with low latency,
using Rust's familiar stdlib API.
```
cargo +nightly doc --features docs --open
```
## Installation
Check out the [examples](examples). To run an example:
With [cargo add][cargo-add] installed run:
```sh
$ cargo add async-std
```
cargo +nightly run --example hello-world
```
## Contributing
See [our contribution document][contribution].
We also provide a set of "unstable" features with async-std. See the [features
documentation] on how to enable them.
[contribution]: https://async.rs/contribute
[cargo-add]: https://github.com/killercup/cargo-edit
[features documentation]: https://docs.rs/async-std/#features
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
<sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>
#### Contribution
<br/>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
</sub>

@ -32,5 +32,5 @@ use crate::task::blocking;
/// ```
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::canonicalize(&path).map(Into::into) }).await
blocking::spawn(move || std::fs::canonicalize(&path).map(Into::into)).await
}

@ -41,5 +41,5 @@ use crate::task::blocking;
pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::copy(&from, &to) }).await
blocking::spawn(move || std::fs::copy(&from, &to)).await
}

@ -34,5 +34,5 @@ use crate::task::blocking;
/// ```
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::create_dir(path) }).await
blocking::spawn(move || std::fs::create_dir(path)).await
}

@ -29,5 +29,5 @@ use crate::task::blocking;
/// ```
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::create_dir_all(path) }).await
blocking::spawn(move || std::fs::create_dir_all(path)).await
}

@ -1,6 +1,5 @@
use cfg_if::cfg_if;
use std::future::Future;
use crate::future::Future;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
@ -108,26 +107,17 @@ impl DirBuilder {
}
let path = path.as_ref().to_owned();
async move { blocking::spawn(async move { builder.create(path) }).await }
async move { blocking::spawn(move || builder.create(path)).await }
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::DirBuilderExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::DirBuilderExt;
}
}
cfg_unix! {
use crate::os::unix::fs::DirBuilderExt;
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);
self
}
impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);
self
}
}
}

@ -2,8 +2,6 @@ use std::ffi::OsString;
use std::fmt;
use std::sync::Arc;
use cfg_if::cfg_if;
use crate::fs::{FileType, Metadata};
use crate::io;
use crate::path::PathBuf;
@ -89,7 +87,7 @@ impl DirEntry {
/// ```
pub async fn metadata(&self) -> io::Result<Metadata> {
let inner = self.0.clone();
blocking::spawn(async move { inner.metadata() }).await
blocking::spawn(move || inner.metadata()).await
}
/// Reads the file type for this entry.
@ -127,7 +125,7 @@ impl DirEntry {
/// ```
pub async fn file_type(&self) -> io::Result<FileType> {
let inner = self.0.clone();
blocking::spawn(async move { inner.file_type() }).await
blocking::spawn(move || inner.file_type()).await
}
/// Returns the bare name of this entry without the leading path.
@ -160,21 +158,12 @@ impl fmt::Debug for DirEntry {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::DirEntryExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::DirEntryExt;
}
}
cfg_unix! {
use crate::os::unix::fs::DirEntryExt;
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl DirEntryExt for DirEntry {
fn ino(&self) -> u64 {
self.0.ino()
}
impl DirEntryExt for DirEntry {
fn ino(&self) -> u64 {
self.0.ino()
}
}
}

@ -7,8 +7,6 @@ use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use cfg_if::cfg_if;
use crate::fs::{Metadata, Permissions};
use crate::future;
use crate::io::{self, Read, Seek, SeekFrom, Write};
@ -97,7 +95,7 @@ impl File {
/// ```
pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
let file = blocking::spawn(async move { std::fs::File::open(&path) }).await?;
let file = blocking::spawn(move || std::fs::File::open(&path)).await?;
Ok(file.into())
}
@ -132,7 +130,7 @@ impl File {
/// ```
pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
let file = blocking::spawn(async move { std::fs::File::create(&path) }).await?;
let file = blocking::spawn(move || std::fs::File::create(&path)).await?;
Ok(file.into())
}
@ -165,7 +163,7 @@ impl File {
})
.await?;
blocking::spawn(async move { state.file.sync_all() }).await
blocking::spawn(move || state.file.sync_all()).await
}
/// Synchronizes OS-internal buffered contents to disk.
@ -201,7 +199,7 @@ impl File {
})
.await?;
blocking::spawn(async move { state.file.sync_data() }).await
blocking::spawn(move || state.file.sync_data()).await
}
/// Truncates or extends the file.
@ -234,7 +232,7 @@ impl File {
})
.await?;
blocking::spawn(async move { state.file.set_len(size) }).await
blocking::spawn(move || state.file.set_len(size)).await
}
/// Reads the file's metadata.
@ -253,7 +251,7 @@ impl File {
/// ```
pub async fn metadata(&self) -> io::Result<Metadata> {
let file = self.file.clone();
blocking::spawn(async move { file.metadata() }).await
blocking::spawn(move || file.metadata()).await
}
/// Changes the permissions on the file.
@ -282,7 +280,7 @@ impl File {
/// ```
pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
let file = self.file.clone();
blocking::spawn(async move { file.set_permissions(perm) }).await
blocking::spawn(move || file.set_permissions(perm)).await
}
}
@ -401,67 +399,54 @@ impl From<std::fs::File> for File {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(fd: RawFd) -> File {
std::fs::File::from_raw_fd(fd).into()
}
impl FromRawFd for File {
unsafe fn from_raw_fd(fd: RawFd) -> File {
std::fs::File::from_raw_fd(fd).into()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_fd()
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.file.as_raw_handle()
}
cfg_windows! {
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.file.as_raw_handle()
}
}
impl FromRawHandle for File {
unsafe fn from_raw_handle(handle: RawHandle) -> File {
std::fs::File::from_raw_handle(handle).into()
}
impl FromRawHandle for File {
unsafe fn from_raw_handle(handle: RawHandle) -> File {
std::fs::File::from_raw_handle(handle).into()
}
}
impl IntoRawHandle for File {
fn into_raw_handle(self) -> RawHandle {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_handle()
}
impl IntoRawHandle for File {
fn into_raw_handle(self) -> RawHandle {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_handle()
}
}
}
@ -702,7 +687,7 @@ impl LockGuard<State> {
self.register(cx);
// Start a read operation asynchronously.
blocking::spawn(async move {
blocking::spawn(move || {
// Read some data from the file into the cache.
let res = {
let State { file, cache, .. } = &mut *self;
@ -811,7 +796,7 @@ impl LockGuard<State> {
self.register(cx);
// Start a write operation asynchronously.
blocking::spawn(async move {
blocking::spawn(move || {
match (&*self.file).write_all(&self.cache) {
Ok(_) => {
// Switch to idle mode.
@ -844,7 +829,7 @@ impl LockGuard<State> {
self.register(cx);
// Start a flush operation asynchronously.
blocking::spawn(async move {
blocking::spawn(move || {
match (&*self.file).flush() {
Ok(()) => {
// Mark the file as flushed.

@ -1,86 +1,84 @@
use cfg_if::cfg_if;
cfg_not_docs! {
pub use std::fs::FileType;
}
cfg_docs! {
/// The type of a file or directory.
///
/// A file type is returned by [`Metadata::file_type`].
///
/// Note that file types are mutually exclusive, i.e. at most one of methods [`is_dir`],
/// [`is_file`], and [`is_symlink`] can return `true`.
///
/// This type is a re-export of [`std::fs::FileType`].
///
/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`is_symlink`]: #method.is_symlink
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType {
_private: (),
}
cfg_if! {
if #[cfg(feature = "docs")] {
/// The type of a file or directory.
impl FileType {
/// Returns `true` if this file type represents a regular directory.
///
/// A file type is returned by [`Metadata::file_type`].
/// If this file type represents a symbolic link, this method returns `false`.
///
/// Note that file types are mutually exclusive, i.e. at most one of methods [`is_dir`],
/// [`is_file`], and [`is_symlink`] can return `true`.
/// # Examples
///
/// This type is a re-export of [`std::fs::FileType`].
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`is_symlink`]: #method.is_symlink
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType {
_private: (),
/// let file_type = fs::metadata(".").await?.file_type();
/// println!("{:?}", file_type.is_dir());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_dir(&self) -> bool {
unimplemented!()
}
impl FileType {
/// Returns `true` if this file type represents a regular directory.
///
/// If this file type represents a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata(".").await?.file_type();
/// println!("{:?}", file_type.is_dir());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_dir(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this file type represents a regular file.
///
/// If this file type represents a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata("a.txt").await?.file_type();
/// println!("{:?}", file_type.is_file());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_file(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this file type represents a regular file.
///
/// If this file type represents a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata("a.txt").await?.file_type();
/// println!("{:?}", file_type.is_file());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_file(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this file type represents a symbolic link.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata("a.txt").await?.file_type();
/// println!("{:?}", file_type.is_symlink());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_symlink(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this file type represents a symbolic link.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata("a.txt").await?.file_type();
/// println!("{:?}", file_type.is_symlink());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_symlink(&self) -> bool {
unimplemented!()
}
} else {
pub use std::fs::FileType;
}
}

@ -32,5 +32,5 @@ use crate::task::blocking;
pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::hard_link(&from, &to) }).await
blocking::spawn(move || std::fs::hard_link(&from, &to)).await
}

@ -1,5 +1,3 @@
use cfg_if::cfg_if;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
@ -36,196 +34,196 @@ use crate::task::blocking;
/// ```
pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::metadata(path) }).await
blocking::spawn(move || std::fs::metadata(path)).await
}
cfg_not_docs! {
pub use std::fs::Metadata;
}
cfg_if! {
if #[cfg(feature = "docs")] {
use std::time::SystemTime;
cfg_docs! {
use std::time::SystemTime;
use crate::fs::{FileType, Permissions};
use crate::fs::{FileType, Permissions};
/// Metadata for a file or directory.
/// Metadata for a file or directory.
///
/// Metadata is returned by [`metadata`] and [`symlink_metadata`].
///
/// This type is a re-export of [`std::fs::Metadata`].
///
/// [`metadata`]: fn.metadata.html
/// [`symlink_metadata`]: fn.symlink_metadata.html
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
#[derive(Clone, Debug)]
pub struct Metadata {
_private: (),
}
impl Metadata {
/// Returns the file type from this metadata.
///
/// Metadata is returned by [`metadata`] and [`symlink_metadata`].
/// # Examples
///
/// This type is a re-export of [`std::fs::Metadata`].
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// [`metadata`]: fn.metadata.html
/// [`symlink_metadata`]: fn.symlink_metadata.html
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
#[derive(Clone, Debug)]
pub struct Metadata {
_private: (),
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.file_type());
/// #
/// # Ok(()) }) }
/// ```
pub fn file_type(&self) -> FileType {
unimplemented!()
}
impl Metadata {
/// Returns the file type from this metadata.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.file_type());
/// #
/// # Ok(()) }) }
/// ```
pub fn file_type(&self) -> FileType {
unimplemented!()
}
/// Returns `true` if this metadata is for a regular directory.
///
/// If this metadata is for a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata(".").await?;
/// println!("{:?}", metadata.is_dir());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_dir(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this metadata is for a regular directory.
///
/// If this metadata is for a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata(".").await?;
/// println!("{:?}", metadata.is_dir());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_dir(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this metadata is for a regular file.
///
/// If this metadata is for a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.is_file());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_file(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this metadata is for a regular file.
///
/// If this metadata is for a symbolic link, this method returns `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.is_file());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_file(&self) -> bool {
unimplemented!()
}
/// Returns the file size in bytes.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{}", metadata.len());
/// #
/// # Ok(()) }) }
/// ```
pub fn len(&self) -> u64 {
unimplemented!()
}
/// Returns the file size in bytes.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{}", metadata.len());
/// #
/// # Ok(()) }) }
/// ```
pub fn len(&self) -> u64 {
unimplemented!()
}
/// Returns the permissions from this metadata.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.permissions());
/// #
/// # Ok(()) }) }
/// ```
pub fn permissions(&self) -> Permissions {
unimplemented!()
}
/// Returns the permissions from this metadata.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.permissions());
/// #
/// # Ok(()) }) }
/// ```
pub fn permissions(&self) -> Permissions {
unimplemented!()
}
/// Returns the last modification time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.modified());
/// #
/// # Ok(()) }) }
/// ```
pub fn modified(&self) -> io::Result<SystemTime> {
unimplemented!()
}
/// Returns the last modification time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.modified());
/// #
/// # Ok(()) }) }
/// ```
pub fn modified(&self) -> io::Result<SystemTime> {
unimplemented!()
}
/// Returns the last access time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.accessed());
/// #
/// # Ok(()) }) }
/// ```
pub fn accessed(&self) -> io::Result<SystemTime> {
unimplemented!()
}
/// Returns the last access time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.accessed());
/// #
/// # Ok(()) }) }
/// ```
pub fn accessed(&self) -> io::Result<SystemTime> {
unimplemented!()
}
/// Returns the creation time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.created());
/// #
/// # Ok(()) }) }
/// ```
pub fn created(&self) -> io::Result<SystemTime> {
unimplemented!()
}
/// Returns the creation time.
///
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.created());
/// #
/// # Ok(()) }) }
/// ```
pub fn created(&self) -> io::Result<SystemTime> {
unimplemented!()
}
} else {
pub use std::fs::Metadata;
}
}

@ -1,7 +1,6 @@
use cfg_if::cfg_if;
use std::future::Future;
use crate::fs::File;
use crate::future::Future;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
@ -285,7 +284,7 @@ impl OpenOptions {
pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
let path = path.as_ref().to_owned();
let options = self.0.clone();
async move { blocking::spawn(async move { options.open(path).map(|f| f.into()) }).await }
async move { blocking::spawn(move || options.open(path).map(|f| f.into())).await }
}
}
@ -295,27 +294,18 @@ impl Default for OpenOptions {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::OpenOptionsExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::OpenOptionsExt;
}
}
cfg_unix! {
use crate::os::unix::fs::OpenOptionsExt;
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut Self {
self.0.mode(mode);
self
}
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut Self {
self.0.mode(mode);
self
}
fn custom_flags(&mut self, flags: i32) -> &mut Self {
self.0.custom_flags(flags);
self
}
fn custom_flags(&mut self, flags: i32) -> &mut Self {
self.0.custom_flags(flags);
self
}
}
}

@ -1,58 +1,56 @@
use cfg_if::cfg_if;
cfg_not_docs! {
pub use std::fs::Permissions;
}
cfg_docs! {
/// A set of permissions on a file or directory.
///
/// This type is a re-export of [`std::fs::Permissions`].
///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Permissions {
_private: (),
}
cfg_if! {
if #[cfg(feature = "docs")] {
/// A set of permissions on a file or directory.
impl Permissions {
/// Returns the read-only flag.
///
/// This type is a re-export of [`std::fs::Permissions`].
/// # Examples
///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Permissions {
_private: (),
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let perm = fs::metadata("a.txt").await?.permissions();
/// println!("{:?}", perm.readonly());
/// #
/// # Ok(()) }) }
/// ```
pub fn readonly(&self) -> bool {
unimplemented!()
}
impl Permissions {
/// Returns the read-only flag.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let perm = fs::metadata("a.txt").await?.permissions();
/// println!("{:?}", perm.readonly());
/// #
/// # Ok(()) }) }
/// ```
pub fn readonly(&self) -> bool {
unimplemented!()
}
/// Configures the read-only flag.
///
/// [`fs::set_permissions`]: fn.set_permissions.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let mut perm = fs::metadata("a.txt").await?.permissions();
/// perm.set_readonly(true);
/// fs::set_permissions("a.txt", perm).await?;
/// #
/// # Ok(()) }) }
/// ```
pub fn set_readonly(&mut self, readonly: bool) {
unimplemented!()
}
/// Configures the read-only flag.
///
/// [`fs::set_permissions`]: fn.set_permissions.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let mut perm = fs::metadata("a.txt").await?.permissions();
/// perm.set_readonly(true);
/// fs::set_permissions("a.txt", perm).await?;
/// #
/// # Ok(()) }) }
/// ```
pub fn set_readonly(&mut self, readonly: bool) {
unimplemented!()
}
} else {
pub use std::fs::Permissions;
}
}

@ -36,5 +36,5 @@ use crate::task::blocking;
/// ```
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read(path) }).await
blocking::spawn(move || std::fs::read(path)).await
}

@ -45,7 +45,7 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
/// ```
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_dir(path) })
blocking::spawn(move || std::fs::read_dir(path))
.await
.map(ReadDir::new)
}
@ -91,7 +91,7 @@ impl Stream for ReadDir {
let mut inner = opt.take().unwrap();
// Start the operation asynchronously.
self.0 = State::Busy(blocking::spawn(async move {
self.0 = State::Busy(blocking::spawn(move || {
let next = inner.next();
(inner, next)
}));

@ -28,5 +28,5 @@ use crate::task::blocking;
/// ```
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_link(path).map(Into::into) }).await
blocking::spawn(move || std::fs::read_link(path).map(Into::into)).await
}

@ -37,5 +37,5 @@ use crate::task::blocking;
/// ```
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_to_string(path) }).await
blocking::spawn(move || std::fs::read_to_string(path)).await
}

@ -29,5 +29,5 @@ use crate::task::blocking;
/// ```
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_dir(path) }).await
blocking::spawn(move || std::fs::remove_dir(path)).await
}

@ -29,5 +29,5 @@ use crate::task::blocking;
/// ```
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_dir_all(path) }).await
blocking::spawn(move || std::fs::remove_dir_all(path)).await
}

@ -29,5 +29,5 @@ use crate::task::blocking;
/// ```
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_file(path) }).await
blocking::spawn(move || std::fs::remove_file(path)).await
}

@ -34,5 +34,5 @@ use crate::task::blocking;
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::rename(&from, &to) }).await
blocking::spawn(move || std::fs::rename(&from, &to)).await
}

@ -32,5 +32,5 @@ use crate::task::blocking;
/// ```
pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::set_permissions(path, perm) }).await
blocking::spawn(move || std::fs::set_permissions(path, perm)).await
}

@ -34,5 +34,5 @@ use crate::task::blocking;
/// ```
pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::symlink_metadata(path) }).await
blocking::spawn(move || std::fs::symlink_metadata(path)).await
}

@ -33,5 +33,5 @@ use crate::task::blocking;
pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
let path = path.as_ref().to_owned();
let contents = contents.as_ref().to_owned();
blocking::spawn(async move { std::fs::write(path, contents) }).await
blocking::spawn(move || std::fs::write(path, contents)).await
}

@ -0,0 +1,139 @@
extension_trait! {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::task::{Context, Poll};
#[doc = r#"
A future represents an asynchronous computation.
A future is a value that may not have finished computing yet. This kind of
"asynchronous value" makes it possible for a thread to continue doing useful
work while it waits for the value to become available.
# The `poll` method
The core method of future, `poll`, *attempts* to resolve the future into a
final value. This method does not block if the value is not ready. Instead,
the current task is scheduled to be woken up when it's possible to make
further progress by `poll`ing again. The `context` passed to the `poll`
method can provide a [`Waker`], which is a handle for waking up the current
task.
When using a future, you generally won't call `poll` directly, but instead
`.await` the value.
[`Waker`]: ../task/struct.Waker.html
"#]
pub trait Future {
#[doc = r#"
The type of value produced on completion.
"#]
type Output;
#[doc = r#"
Attempt to resolve the future to a final value, registering
the current task for wakeup if the value is not yet available.
# Return value
This function returns:
- [`Poll::Pending`] if the future is not ready yet
- [`Poll::Ready(val)`] with the result `val` of this future if it
finished successfully.
Once a future has finished, clients should not `poll` it again.
When a future is not ready yet, `poll` returns `Poll::Pending` and
stores a clone of the [`Waker`] copied from the current [`Context`].
This [`Waker`] is then woken once the future can make progress.
For example, a future waiting for a socket to become
readable would call `.clone()` on the [`Waker`] and store it.
When a signal arrives elsewhere indicating that the socket is readable,
[`Waker::wake`] is called and the socket future's task is awoken.
Once a task has been woken up, it should attempt to `poll` the future
again, which may or may not produce a final value.
Note that on multiple calls to `poll`, only the [`Waker`] from the
[`Context`] passed to the most recent call should be scheduled to
receive a wakeup.
# Runtime characteristics
Futures alone are *inert*; they must be *actively* `poll`ed to make
progress, meaning that each time the current task is woken up, it should
actively re-`poll` pending futures that it still has an interest in.
The `poll` function is not called repeatedly in a tight loop -- instead,
it should only be called when the future indicates that it is ready to
make progress (by calling `wake()`). If you're familiar with the
`poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
typically do *not* suffer the same problems of "all wakeups must poll
all events"; they are more like `epoll(4)`.
An implementation of `poll` should strive to return quickly, and should
not block. Returning quickly prevents unnecessarily clogging up
threads or event loops. If it is known ahead of time that a call to
`poll` may end up taking awhile, the work should be offloaded to a
thread pool (or something similar) to ensure that `poll` can return
quickly.
# Panics
Once a future has completed (returned `Ready` from `poll`), calling its
`poll` method again may panic, block forever, or cause other kinds of
problems; the `Future` trait places no requirements on the effects of
such a call. However, as the `poll` method is not marked `unsafe`,
Rust's usual rules apply: calls must never cause undefined behavior
(memory corruption, incorrect use of `unsafe` functions, or the like),
regardless of the future's state.
[`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
[`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
[`Context`]: ../task/struct.Context.html
[`Waker`]: ../task/struct.Waker.html
[`Waker::wake`]: ../task/struct.Waker.html#method.wake
"#]
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
}
pub trait FutureExt: std::future::Future {
}
impl<F: Future + Unpin + ?Sized> Future for Box<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<F: Future + Unpin + ?Sized> Future for &mut F {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> Future for Pin<P>
where
P: DerefMut + Unpin,
<P as Deref>::Target: Future,
{
type Output = <<P as Deref>::Target as Future>::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<F: Future> Future for std::panic::AssertUnwindSafe<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
}

@ -0,0 +1,54 @@
use crate::future::Future;
/// Convert a type into a `Future`.
///
/// # Examples
///
/// ```
/// use async_std::future::{Future, IntoFuture};
/// use async_std::io;
/// use async_std::pin::Pin;
///
/// struct Client;
///
/// impl Client {
/// pub async fn send(self) -> io::Result<()> {
/// // Send a request
/// Ok(())
/// }
/// }
///
/// impl IntoFuture for Client {
/// type Output = io::Result<()>;
///
/// type Future = Pin<Box<dyn Future<Output = Self::Output>>>;
///
/// fn into_future(self) -> Self::Future {
/// Box::pin(async {
/// self.send().await
/// })
/// }
/// }
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait IntoFuture {
/// The type of value produced on completion.
type Output;
/// Which kind of future are we turning this into?
type Future: Future<Output = Self::Output>;
/// Create a future from a value
fn into_future(self) -> Self::Future;
}
impl<T: Future> IntoFuture for T {
type Output = T::Output;
type Future = T;
fn into_future(self) -> Self::Future {
self
}
}

@ -41,29 +41,25 @@
//! | `future::select` | `Result<T, E>` | Return on first value
//! | `future::try_select` | `Result<T, E>` | Return on first `Ok`, reject on last Err
#[doc(inline)]
pub use std::future::Future;
#[doc(inline)]
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 pending::pending;
pub use poll_fn::poll_fn;
pub use ready::ready;
pub use timeout::{timeout, TimeoutError};
pub(crate) mod future;
mod pending;
mod poll_fn;
mod ready;
mod timeout;
cfg_unstable! {
#[doc(inline)]
pub use async_macros::{select, try_select};
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod timeout;
pub use timeout::{timeout, TimeoutError};
}
pub use into_future::IntoFuture;
mod into_future;
}

@ -4,6 +4,7 @@ use std::pin::Pin;
use std::time::Duration;
use futures_timer::Delay;
use pin_project_lite::pin_project;
use crate::future::Future;
use crate::task::{Context, Poll};
@ -28,8 +29,6 @@ use crate::task::{Context, Poll};
/// #
/// # Ok(()) }) }
/// ```
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError>
where
F: Future<Output = T>,
@ -41,26 +40,24 @@ where
f.await
}
/// A future that times out after a duration of time.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
struct TimeoutFuture<F> {
future: F,
delay: Delay,
}
impl<F> TimeoutFuture<F> {
pin_utils::unsafe_pinned!(future: F);
pin_utils::unsafe_pinned!(delay: Delay);
pin_project! {
/// A future that times out after a duration of time.
struct TimeoutFuture<F> {
#[pin]
future: F,
#[pin]
delay: Delay,
}
}
impl<F: Future> Future for TimeoutFuture<F> {
type Output = Result<F::Output, TimeoutError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().future().poll(cx) {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this.future.poll(cx) {
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::Pending => Poll::Pending,
},
@ -69,8 +66,6 @@ impl<F: Future> Future for TimeoutFuture<F> {
}
/// An error returned when a future times out.
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TimeoutError {
_private: (),

@ -2,50 +2,55 @@ use std::mem;
use std::pin::Pin;
use std::str;
use pin_project_lite::pin_project;
use super::read_until_internal;
use crate::io::{self, BufRead};
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A stream of lines in a byte stream.
///
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
///
/// This type is an async version of [`std::io::Lines`].
///
/// [`lines`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
#[derive(Debug)]
pub struct Lines<R> {
pub(crate) reader: R,
pub(crate) buf: String,
pub(crate) bytes: Vec<u8>,
pub(crate) read: usize,
pin_project! {
/// A stream of lines in a byte stream.
///
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
///
/// This type is an async version of [`std::io::Lines`].
///
/// [`lines`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
#[derive(Debug)]
pub struct Lines<R> {
#[pin]
pub(crate) reader: R,
pub(crate) buf: String,
pub(crate) bytes: Vec<u8>,
pub(crate) read: usize,
}
}
impl<R: BufRead> Stream for Lines<R> {
type Item = io::Result<String>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Self {
reader,
buf,
bytes,
read,
} = unsafe { self.get_unchecked_mut() };
let reader = unsafe { Pin::new_unchecked(reader) };
let n = futures_core::ready!(read_line_internal(reader, cx, buf, bytes, read))?;
if n == 0 && buf.is_empty() {
let this = self.project();
let n = futures_core::ready!(read_line_internal(
this.reader,
cx,
this.buf,
this.bytes,
this.read
))?;
if n == 0 && this.buf.is_empty() {
return Poll::Ready(None);
}
if buf.ends_with('\n') {
buf.pop();
if buf.ends_with('\r') {
buf.pop();
if this.buf.ends_with('\n') {
this.buf.pop();
if this.buf.ends_with('\r') {
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::pin::Pin;
use cfg_if::cfg_if;
use crate::io;
use crate::task::{Context, Poll};
use crate::utils::extension_trait;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut};
}
}
extension_trait! {
use std::ops::{Deref, DerefMut};
#[doc = r#"
Allows reading from a buffered byte stream.
@ -44,7 +37,7 @@ extension_trait! {
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
[provided methods]: #provided-methods
"#]
pub trait BufRead [BufReadExt: futures_io::AsyncBufRead] {
pub trait BufRead {
#[doc = r#"
Returns the contents of the internal buffer, filling it with more data from the
inner reader if it is empty.
@ -67,7 +60,9 @@ extension_trait! {
should no longer be returned in calls to `read`.
"#]
fn consume(self: Pin<&mut Self>, amt: usize);
}
pub trait BufReadExt: futures_io::AsyncBufRead {
#[doc = r#"
Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.

@ -1,46 +1,51 @@
use std::mem;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::read_until_internal;
use crate::io::{self, BufRead};
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// 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 type is an async version of [`std::io::Split`].
///
/// [`split`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
#[derive(Debug)]
pub struct Split<R> {
pub(crate) reader: R,
pub(crate) buf: Vec<u8>,
pub(crate) read: usize,
pub(crate) delim: u8,
pin_project! {
/// 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 type is an async version of [`std::io::Split`].
///
/// [`split`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
#[derive(Debug)]
pub struct Split<R> {
#[pin]
pub(crate) reader: R,
pub(crate) buf: Vec<u8>,
pub(crate) read: usize,
pub(crate) delim: u8,
}
}
impl<R: BufRead> Stream for Split<R> {
type Item = io::Result<Vec<u8>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Self {
reader,
buf,
read,
delim,
} = unsafe { self.get_unchecked_mut() };
let reader = unsafe { Pin::new_unchecked(reader) };
let n = futures_core::ready!(read_until_internal(reader, cx, *delim, buf, read))?;
if n == 0 && buf.is_empty() {
let this = self.project();
let n = futures_core::ready!(read_until_internal(
this.reader,
cx,
*this.delim,
this.buf,
this.read
))?;
if n == 0 && this.buf.is_empty() {
return Poll::Ready(None);
}
if buf[buf.len() - 1] == *delim {
buf.pop();
if this.buf[this.buf.len() - 1] == *this.delim {
this.buf.pop();
}
Poll::Ready(Some(Ok(mem::replace(buf, vec![]))))
Poll::Ready(Some(Ok(mem::replace(this.buf, vec![]))))
}
}

@ -2,51 +2,56 @@ use std::io::{IoSliceMut, Read as _};
use std::pin::Pin;
use std::{cmp, fmt};
use pin_project_lite::pin_project;
use crate::io::{self, BufRead, Read, Seek, SeekFrom};
use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024;
/// Adds buffering to any reader.
///
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
/// performs large, infrequent reads on the underlying [`Read`] and maintains an in-memory buffer
/// of the incoming byte stream.
///
/// `BufReader` can improve the speed of programs that make *small* and *repeated* read calls to
/// the same file or network socket. It does not help when reading very large amounts at once, or
/// reading just one or a few times. It also provides no advantage when reading from a source that
/// is already in memory, like a `Vec<u8>`.
///
/// When the `BufReader` is dropped, the contents of its buffer will be discarded. Creating
/// multiple instances of a `BufReader` on the same stream can cause data loss.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`Read`]: trait.Read.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
/// use async_std::prelude::*;
///
/// let mut file = BufReader::new(File::open("a.txt").await?);
///
/// let mut line = String::new();
/// file.read_line(&mut line).await?;
/// #
/// # Ok(()) }) }
/// ```
pub struct BufReader<R> {
inner: R,
buf: Box<[u8]>,
pos: usize,
cap: usize,
pin_project! {
/// Adds buffering to any reader.
///
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
/// performs large, infrequent reads on the underlying [`Read`] and maintains an in-memory buffer
/// of the incoming byte stream.
///
/// `BufReader` can improve the speed of programs that make *small* and *repeated* read calls to
/// the same file or network socket. It does not help when reading very large amounts at once, or
/// reading just one or a few times. It also provides no advantage when reading from a source that
/// is already in memory, like a `Vec<u8>`.
///
/// When the `BufReader` is dropped, the contents of its buffer will be discarded. Creating
/// multiple instances of a `BufReader` on the same stream can cause data loss.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`Read`]: trait.Read.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
/// use async_std::prelude::*;
///
/// let mut file = BufReader::new(File::open("a.txt").await?);
///
/// let mut line = String::new();
/// file.read_line(&mut line).await?;
/// #
/// # Ok(()) }) }
/// ```
pub struct BufReader<R> {
#[pin]
inner: R,
buf: Box<[u8]>,
pos: usize,
cap: usize,
}
}
impl<R: io::Read> BufReader<R> {
@ -95,10 +100,6 @@ impl<R: io::Read> 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.
///
/// It is inadvisable to directly read from the underlying reader.
@ -141,6 +142,13 @@ impl<R> BufReader<R> {
&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.
///
/// 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.
#[inline]
fn discard_buffer(mut self: Pin<&mut Self>) {
*self.as_mut().pos() = 0;
*self.cap() = 0;
fn discard_buffer(self: Pin<&mut Self>) {
let this = self.project();
*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
// entirely.
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();
return Poll::Ready(res);
}
@ -218,7 +227,8 @@ impl<R: Read> Read for BufReader<R> {
) -> Poll<io::Result<usize>> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
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();
return Poll::Ready(res);
}
@ -234,28 +244,23 @@ impl<R: Read> BufRead for BufReader<R> {
self: Pin<&'a mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<&'a [u8]>> {
let Self {
inner,
buf,
cap,
pos,
} = unsafe { self.get_unchecked_mut() };
let mut inner = unsafe { Pin::new_unchecked(inner) };
let mut this = self.project();
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
// Branch using `>=` instead of the more correct `==`
// to tell the compiler that the pos..cap slice is always valid.
if *pos >= *cap {
debug_assert!(*pos == *cap);
*cap = futures_core::ready!(inner.as_mut().poll_read(cx, buf))?;
*pos = 0;
if *this.pos >= *this.cap {
debug_assert!(*this.pos == *this.cap);
*this.cap = futures_core::ready!(this.inner.as_mut().poll_read(cx, this.buf))?;
*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) {
*self.as_mut().pos() = cmp::min(self.pos + amt, self.cap);
fn consume(self: Pin<&mut Self>, amt: usize) {
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) {
result = futures_core::ready!(
self.as_mut()
.inner()
.get_pin_mut()
.poll_seek(cx, SeekFrom::Current(offset))
)?;
} else {
// seek backwards by our remainder, and then by the offset
futures_core::ready!(
self.as_mut()
.inner()
.get_pin_mut()
.poll_seek(cx, SeekFrom::Current(-remainder))
)?;
self.as_mut().discard_buffer();
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 {
// 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();
Poll::Ready(Ok(result))

@ -2,6 +2,7 @@ use std::fmt;
use std::pin::Pin;
use futures_core::ready;
use pin_project_lite::pin_project;
use crate::io::write::WriteExt;
use crate::io::{self, Seek, SeekFrom, Write};
@ -9,88 +10,88 @@ use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024;
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
/// implements [`Write`]. For example, every call to
/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
/// writer in large, infrequent batches.
///
/// `BufWriter` can improve the speed of programs that make *small* and
/// *repeated* write calls to the same file or network socket. It does not
/// help when writing very large amounts at once, or writing just one or a few
/// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`.
///
/// When the `BufWriter` is dropped, the contents of its buffer will be written
/// out. However, any errors that happen in the process of flushing the buffer
/// when the writer is dropped will be ignored. Code that wishes to handle such
/// errors must manually call [`flush`] before the writer is dropped.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
/// Let's write the numbers one through ten to a [`TcpStream`]:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").await?;
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
///
/// Because we're not buffering, we write each one in turn, incurring the
/// overhead of a system call per byte written. We can fix this with a
/// `BufWriter`:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?);
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// };
/// #
/// # Ok(()) }) }
/// ```
///
/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
/// together by the buffer, and will all be written out in one system call when
/// the `stream` is dropped.
///
/// [`Write`]: trait.Write.html
/// [`TcpStream::write`]: ../net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../net/struct.TcpStream.html
/// [`flush`]: trait.Write.html#tymethod.flush
pub struct BufWriter<W> {
inner: W,
buf: Vec<u8>,
written: usize,
pin_project! {
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
/// implements [`Write`]. For example, every call to
/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
/// writer in large, infrequent batches.
///
/// `BufWriter` can improve the speed of programs that make *small* and
/// *repeated* write calls to the same file or network socket. It does not
/// help when writing very large amounts at once, or writing just one or a few
/// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`.
///
/// When the `BufWriter` is dropped, the contents of its buffer will be written
/// out. However, any errors that happen in the process of flushing the buffer
/// when the writer is dropped will be ignored. Code that wishes to handle such
/// errors must manually call [`flush`] before the writer is dropped.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
/// Let's write the numbers one through ten to a [`TcpStream`]:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").await?;
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
///
/// Because we're not buffering, we write each one in turn, incurring the
/// overhead of a system call per byte written. We can fix this with a
/// `BufWriter`:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?);
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// };
/// #
/// # Ok(()) }) }
/// ```
///
/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
/// together by the buffer, and will all be written out in one system call when
/// the `stream` is dropped.
///
/// [`Write`]: trait.Write.html
/// [`TcpStream::write`]: ../net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../net/struct.TcpStream.html
/// [`flush`]: trait.Write.html#tymethod.flush
pub struct BufWriter<W> {
#[pin]
inner: W,
buf: Vec<u8>,
written: usize,
}
}
#[derive(Debug)]
pub struct IntoInnerError<W>(W, std::io::Error);
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,
/// but may change in the future.
///
@ -178,6 +179,13 @@ impl<W: Write> BufWriter<W> {
&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
///
/// This method will not write leftover data, it will be lost.
@ -234,16 +242,15 @@ impl<W: Write> BufWriter<W> {
///
/// [`LineWriter`]: struct.LineWriter.html
fn poll_flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let Self {
inner,
buf,
written,
} = unsafe { Pin::get_unchecked_mut(self) };
let mut inner = unsafe { Pin::new_unchecked(inner) };
let len = buf.len();
let mut this = self.project();
let len = this.buf.len();
let mut ret = Ok(());
while *written < len {
match inner.as_mut().poll_write(cx, &buf[*written..]) {
while *this.written < len {
match this
.inner
.as_mut()
.poll_write(cx, &this.buf[*this.written..])
{
Poll::Ready(Ok(0)) => {
ret = Err(io::Error::new(
io::ErrorKind::WriteZero,
@ -251,7 +258,7 @@ impl<W: Write> BufWriter<W> {
));
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(e)) => {
ret = Err(e);
@ -260,10 +267,10 @@ impl<W: Write> BufWriter<W> {
Poll::Pending => return Poll::Pending,
}
}
if *written > 0 {
buf.drain(..*written);
if *this.written > 0 {
this.buf.drain(..*this.written);
}
*written = 0;
*this.written = 0;
Poll::Ready(ret)
}
}
@ -278,20 +285,20 @@ impl<W: Write> Write for BufWriter<W> {
ready!(self.as_mut().poll_flush_buf(cx))?;
}
if buf.len() >= self.buf.capacity() {
self.inner().poll_write(cx, buf)
self.get_pin_mut().poll_write(cx, buf)
} 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<()>> {
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<()>> {
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,
) -> Poll<io::Result<u64>> {
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 pin_project_lite::pin_project;
use crate::future::Future;
use crate::io::{self, BufRead, BufReader, Read, Write};
use crate::task::{Context, Poll};
@ -46,47 +48,38 @@ where
R: Read + Unpin + ?Sized,
W: Write + Unpin + ?Sized,
{
pub struct CopyFuture<'a, R, W: ?Sized> {
reader: R,
writer: &'a mut W,
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,
)
}
pin_project! {
struct CopyFuture<R, W> {
#[pin]
reader: R,
#[pin]
writer: W,
amt: u64,
}
}
impl<R, W> Future for CopyFuture<'_, R, W>
impl<R, W> Future for CopyFuture<R, W>
where
R: BufRead,
W: Write + Unpin + ?Sized,
W: Write + Unpin,
{
type Output = io::Result<u64>;
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 {
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() {
futures_core::ready!(writer.as_mut().poll_flush(cx))?;
return Poll::Ready(Ok(*amt));
futures_core::ready!(this.writer.as_mut().poll_flush(cx))?;
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 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
*amt += i as u64;
reader.as_mut().consume(i);
*this.amt += i as u64;
this.reader.as_mut().consume(i);
}
}
}

@ -1,24 +1,273 @@
//! Basic input and output.
//! Traits, helpers, and type definitions for core I/O functionality.
//!
//! The `async_std::io` module contains a number of common things you'll need
//! when doing input and output. The most core part of this module is
//! the [`Read`] and [`Write`] traits, which provide the
//! most general interface for reading and writing input and output.
//!
//! This module is an async version of [`std::io`].
//!
//! [`std::io`]: https://doc.rust-lang.org/std/io/index.html
//!
//! # Examples
//! # Read and Write
//!
//! Read a line from the standard input:
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
//! [`File`]s:
//!
//! ```no_run
//! use async_std::prelude::*;
//! use async_std::fs::File;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut f = File::open("foo.txt").await?;
//! let mut buffer = [0; 10];
//!
//! // read up to 10 bytes
//! let n = f.read(&mut buffer).await?;
//!
//! println!("The bytes: {:?}", &buffer[..n]);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
//! of 'a type that implements the [`Read`] trait'. Much easier!
//!
//! ## Seek and BufRead
//!
//! Beyond that, there are two important traits that are provided: [`Seek`]
//! and [`BufRead`]. Both of these build on top of a reader to control
//! how the reading happens. [`Seek`] lets you control where the next byte is
//! coming from:
//!
//! ```no_run
//! use async_std::io::prelude::*;
//! use async_std::io::SeekFrom;
//! use async_std::fs::File;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut f = File::open("foo.txt").await?;
//! let mut buffer = [0; 10];
//!
//! // skip to the last 10 bytes of the file
//! f.seek(SeekFrom::End(-10)).await?;
//!
//! // read up to 10 bytes
//! let n = f.read(&mut buffer).await?;
//!
//! println!("The bytes: {:?}", &buffer[..n]);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
//! to show it off, we'll need to talk about buffers in general. Keep reading!
//!
//! ## BufReader and BufWriter
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
//! readers and writers. The wrapper uses a buffer, reducing the number of
//! calls and providing nicer methods for accessing exactly what you want.
//!
//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
//! methods to any reader:
//!
//! ```no_run
//! use async_std::io::prelude::*;
//! use async_std::io::BufReader;
//! use async_std::fs::File;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let f = File::open("foo.txt").await?;
//! let mut reader = BufReader::new(f);
//! let mut buffer = String::new();
//!
//! // read a line into buffer
//! reader.read_line(&mut buffer).await?;
//!
//! println!("{}", buffer);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
//! to [`write`][`Write::write`]:
//!
//! ```no_run
//! use async_std::io::prelude::*;
//! use async_std::io::BufWriter;
//! use async_std::fs::File;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let f = File::create("foo.txt").await?;
//! {
//! let mut writer = BufWriter::new(f);
//!
//! // write a byte to the buffer
//! writer.write(&[42]).await?;
//!
//! } // the buffer is flushed once writer goes out of scope
//! #
//! # Ok(()) }) }
//! ```
//!
//! ## Standard input and output
//!
//! A very common source of input is standard input:
//!
//! ```no_run
//! use async_std::io;
//!
//! let stdin = io::stdin();
//! let mut line = String::new();
//! stdin.read_line(&mut line).await?;
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await?;
//!
//! println!("You typed: {}", input.trim());
//! #
//! # Ok(()) }) }
//! ```
//!
//! Note that you cannot use the [`?` operator] in functions that do not return
//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`]
//! or `match` on the return value to catch any possible errors:
//!
//! ```no_run
//! use async_std::io;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await.unwrap();
//! #
//! # Ok(()) }) }
//! ```
//!
//! And a very common source of output is standard output:
//!
//! ```no_run
//! use async_std::io;
//! use async_std::io::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! io::stdout().write(&[42]).await?;
//! #
//! # Ok(()) }) }
//! ```
//!
//! Of course, using [`io::stdout`] directly is less common than something like
//! [`println!`].
//!
//! ## Iterator types
//!
//! A large number of the structures provided by `std::io` are for various
//! ways of iterating over I/O. For example, [`Lines`] is used to split over
//! lines:
//!
//! ```no_run
//! use async_std::prelude::*;
//! use async_std::io::BufReader;
//! use async_std::fs::File;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let f = File::open("foo.txt").await?;
//! let reader = BufReader::new(f);
//!
//! let mut lines = reader.lines();
//! while let Some(line) = lines.next().await {
//! println!("{}", line?);
//! }
//! #
//! # Ok(()) }) }
//! ```
//!
//! ## Functions
//!
//! There are a number of [functions][functions-list] that offer access to various
//! features. For example, we can use three of these functions to copy everything
//! from standard input to standard output:
//!
//! ```no_run
//! use async_std::io;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! io::copy(&mut io::stdin(), &mut io::stdout()).await?;
//! #
//! # Ok(()) }) }
//! ```
//!
//! [functions-list]: #functions-1
//!
//! ## io::Result
//!
//! Last, but certainly not least, is [`io::Result`]. This type is used
//! as the return type of many `std::io` functions that can cause an error, and
//! can be returned from your own functions as well. Many of the examples in this
//! module use the [`?` operator]:
//!
//! ```
//! #![allow(dead_code)]
//! use async_std::io;
//!
//! async fn read_input() -> io::Result<()> {
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await?;
//!
//! println!("You typed: {}", input.trim());
//!
//! Ok(())
//! }
//! ```
//!
//! The return type of `read_input`, [`io::Result<()>`][`io::Result`], is a very
//! common type for functions which don't have a 'real' return value, but do want to
//! return errors if they happen. In this case, the only purpose of this function is
//! to read the line and print it, so we use `()`.
//!
//! ## Platform-specific behavior
//!
//! Many I/O functions throughout the standard library are documented to indicate
//! what various library or syscalls they are delegated to. This is done to help
//! applications both understand what's happening under the hood as well as investigate
//! any possibly unclear semantics. Note, however, that this is informative, not a binding
//! contract. The implementation of many of these functions are subject to change over
//! time and may call fewer or more syscalls/library functions.
//!
//! [`Read`]: trait.Read.html
//! [`Write`]: trait.Write.html
//! [`Seek`]: trait.Seek.html
//! [`BufRead`]: trait.BufRead.html
//! [`File`]: ../fs/struct.File.html
//! [`TcpStream`]: ../net/struct.TcpStream.html
//! [`Vec<T>`]: ../vec/struct.Vec.html
//! [`BufReader`]: struct.BufReader.html
//! [`BufWriter`]: struct.BufWriter.html
//! [`Write::write`]: trait.Write.html#tymethod.write
//! [`io::stdout`]: fn.stdout.html
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
//! [`?` operator]: https://doc.rust-lang.org/stable/book/appendix-02-operators.html
//! [`Read::read`]: trait.Read.html#tymethod.read
//! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
//! [`.unwrap()`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap
#[doc(inline)]
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};

@ -1,20 +1,25 @@
use crate::io::IoSliceMut;
use std::fmt;
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};
/// Adaptor to chain together two readers.
///
/// This struct is generally created by calling [`chain`] on a reader.
/// Please see the documentation of [`chain`] for more details.
///
/// [`chain`]: trait.Read.html#method.chain
pub struct Chain<T, U> {
pub(crate) first: T,
pub(crate) second: U,
pub(crate) done_first: bool,
pin_project! {
/// Adaptor to chain together two readers.
///
/// This struct is generally created by calling [`chain`] on a reader.
/// Please see the documentation of [`chain`] for more details.
///
/// [`chain`]: trait.Read.html#method.chain
pub struct Chain<T, U> {
#[pin]
pub(crate) first: T,
#[pin]
pub(crate) second: U,
pub(crate) done_first: bool,
}
}
impl<T, U> Chain<T, U> {
@ -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(
mut self: Pin<&mut Self>,
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
if !self.done_first {
let rd = Pin::new(&mut self.first);
match futures_core::ready!(rd.poll_read(cx, buf)) {
Ok(0) if !buf.is_empty() => self.done_first = true,
let this = self.project();
if !*this.done_first {
match futures_core::ready!(this.first.poll_read(cx, buf)) {
Ok(0) if !buf.is_empty() => *this.done_first = true,
Ok(n) => return Poll::Ready(Ok(n)),
Err(err) => return Poll::Ready(Err(err)),
}
}
let rd = Pin::new(&mut self.second);
rd.poll_read(cx, buf)
this.second.poll_read(cx, buf)
}
fn poll_read_vectored(
mut self: Pin<&mut Self>,
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
if !self.done_first {
let rd = Pin::new(&mut self.first);
match futures_core::ready!(rd.poll_read_vectored(cx, bufs)) {
Ok(0) if !bufs.is_empty() => self.done_first = true,
let this = self.project();
if !*this.done_first {
match futures_core::ready!(this.first.poll_read_vectored(cx, bufs)) {
Ok(0) if !bufs.is_empty() => *this.done_first = true,
Ok(n) => return Poll::Ready(Ok(n)),
Err(err) => return Poll::Ready(Err(err)),
}
}
let rd = Pin::new(&mut self.second);
rd.poll_read_vectored(cx, bufs)
this.second.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]>> {
let Self {
first,
second,
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)) {
let this = self.project();
if !*this.done_first {
match futures_core::ready!(this.first.poll_fill_buf(cx)) {
Ok(buf) if buf.is_empty() => {
*done_first = true;
*this.done_first = true;
}
Ok(buf) => return Poll::Ready(Ok(buf)),
Err(err) => return Poll::Ready(Err(err)),
}
}
let second = unsafe { Pin::new_unchecked(second) };
second.poll_fill_buf(cx)
this.second.poll_fill_buf(cx)
}
fn consume(mut self: Pin<&mut Self>, amt: usize) {
if !self.done_first {
let rd = Pin::new(&mut self.first);
rd.consume(amt)
fn consume(self: Pin<&mut Self>, amt: usize) {
let this = self.project();
if !*this.done_first {
this.first.consume(amt)
} else {
let rd = Pin::new(&mut self.second);
rd.consume(amt)
this.second.consume(amt)
}
}
}

@ -13,23 +13,17 @@ use read_to_end::{read_to_end_internal, ReadToEndFuture};
use read_to_string::ReadToStringFuture;
use read_vectored::ReadVectoredFuture;
use cfg_if::cfg_if;
use std::mem;
use crate::io::IoSliceMut;
use crate::utils::extension_trait;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
extension_trait! {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::io;
use crate::task::{Context, Poll};
}
}
use crate::io;
use crate::task::{Context, Poll};
extension_trait! {
#[doc = r#"
Allows reading from a byte stream.
@ -50,7 +44,7 @@ extension_trait! {
[`poll_read`]: #tymethod.poll_read
[`poll_read_vectored`]: #method.poll_read_vectored
"#]
pub trait Read [ReadExt: futures_io::AsyncRead] {
pub trait Read {
#[doc = r#"
Attempt to read from the `AsyncRead` into `buf`.
"#]
@ -70,7 +64,9 @@ extension_trait! {
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
}
pub trait ReadExt: futures_io::AsyncRead {
#[doc = r#"
Reads some bytes from the byte stream.

@ -1,19 +1,24 @@
use std::cmp;
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::io::{self, BufRead, Read};
use crate::task::{Context, Poll};
/// Reader adaptor which limits the bytes read from an underlying reader.
///
/// This struct is generally created by calling [`take`] on a reader.
/// Please see the documentation of [`take`] for more details.
///
/// [`take`]: trait.Read.html#method.take
#[derive(Debug)]
pub struct Take<T> {
pub(crate) inner: T,
pub(crate) limit: u64,
pin_project! {
/// Reader adaptor which limits the bytes read from an underlying reader.
///
/// This struct is generally created by calling [`take`] on a reader.
/// Please see the documentation of [`take`] for more details.
///
/// [`take`]: trait.Read.html#method.take
#[derive(Debug)]
pub struct Take<T> {
#[pin]
pub(crate) inner: T,
pub(crate) limit: u64,
}
}
impl<T> Take<T> {
@ -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`.
fn poll_read(
mut self: Pin<&mut Self>,
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let Self { inner, limit } = &mut *self;
take_read_internal(Pin::new(inner), cx, buf, limit)
let this = self.project();
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]>> {
let Self { inner, limit } = unsafe { self.get_unchecked_mut() };
let inner = unsafe { Pin::new_unchecked(inner) };
let this = self.project();
if *limit == 0 {
if *this.limit == 0 {
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) => {
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]))
}
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
let amt = cmp::min(amt as u64, self.limit) as usize;
self.limit -= amt as u64;
let amt = cmp::min(amt as u64, *this.limit) as usize;
*this.limit -= amt as u64;
let rd = Pin::new(&mut self.inner);
rd.consume(amt);
this.inner.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::{self, SeekFrom};
use crate::task::{Context, Poll};
use crate::utils::extension_trait;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut};
}
}
use crate::io::SeekFrom;
extension_trait! {
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use crate::io;
use crate::task::{Context, Poll};
#[doc = r#"
Allows seeking through a byte stream.
@ -33,7 +30,7 @@ extension_trait! {
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
[provided methods]: #provided-methods
"#]
pub trait Seek [SeekExt: futures_io::AsyncSeek] {
pub trait Seek {
#[doc = r#"
Attempt to seek to an offset, in bytes, in a stream.
"#]
@ -42,7 +39,9 @@ extension_trait! {
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>>;
}
pub trait SeekExt: futures_io::AsyncSeek {
#[doc = r#"
Seeks to a new position in a byte stream.
@ -70,7 +69,7 @@ extension_trait! {
fn seek(
&mut self,
pos: SeekFrom,
) -> impl Future<Output = io::Result<u64>> [SeekFuture<'_, Self>]
) -> impl Future<Output = io::Result<u64>> + '_ [SeekFuture<'_, Self>]
where
Self: Unpin,
{
@ -112,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)
}
}

@ -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)
}
}

@ -2,8 +2,6 @@ use lazy_static::lazy_static;
use std::pin::Pin;
use std::sync::Mutex;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io::{self, Write};
use crate::task::{blocking, Context, JoinHandle, Poll};
@ -146,7 +144,7 @@ impl Write for Stderr {
inner.buf[..buf.len()].copy_from_slice(buf);
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
let res = std::io::Write::write(&mut inner.stderr, &inner.buf);
inner.last_op = Some(Operation::Write(res));
State::Idle(Some(inner))
@ -174,7 +172,7 @@ impl Write for Stderr {
let mut inner = opt.take().unwrap();
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
let res = std::io::Write::flush(&mut inner.stderr);
inner.last_op = Some(Operation::Flush(res));
State::Idle(Some(inner))
@ -192,35 +190,22 @@ impl Write for Stderr {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stderr {
fn as_raw_fd(&self) -> RawFd {
std::io::stderr().as_raw_fd()
}
impl AsRawFd for Stderr {
fn as_raw_fd(&self) -> RawFd {
std::io::stderr().as_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stderr {
fn as_raw_handle(&self) -> RawHandle {
std::io::stderr().as_raw_handle()
}
cfg_windows! {
use crate::os::windows::io::{AsRawHandle, RawHandle};
impl AsRawHandle for Stderr {
fn as_raw_handle(&self) -> RawHandle {
std::io::stderr().as_raw_handle()
}
}
}

@ -2,8 +2,6 @@ use lazy_static::lazy_static;
use std::pin::Pin;
use std::sync::Mutex;
use cfg_if::cfg_if;
use crate::future::{self, Future};
use crate::io::{self, Read};
use crate::task::{blocking, Context, JoinHandle, Poll};
@ -125,7 +123,7 @@ impl Stdin {
let mut inner = opt.take().unwrap();
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
inner.line.clear();
let res = inner.stdin.read_line(&mut inner.line);
inner.last_op = Some(Operation::ReadLine(res));
@ -167,7 +165,7 @@ impl Stdin {
static ref STDIN: std::io::Stdin = std::io::stdin();
}
blocking::spawn(async { StdinLock(STDIN.lock()) }).await
blocking::spawn(move || { StdinLock(STDIN.lock()) }).await
}
}
@ -207,7 +205,7 @@ impl Read for Stdin {
}
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
let res = std::io::Read::read(&mut inner.stdin, &mut inner.buf);
inner.last_op = Some(Operation::Read(res));
State::Idle(Some(inner))
@ -221,35 +219,22 @@ impl Read for Stdin {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stdin {
fn as_raw_fd(&self) -> RawFd {
std::io::stdin().as_raw_fd()
}
impl AsRawFd for Stdin {
fn as_raw_fd(&self) -> RawFd {
std::io::stdin().as_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stdin {
fn as_raw_handle(&self) -> RawHandle {
std::io::stdin().as_raw_handle()
}
cfg_windows! {
use crate::os::windows::io::{AsRawHandle, RawHandle};
impl AsRawHandle for Stdin {
fn as_raw_handle(&self) -> RawHandle {
std::io::stdin().as_raw_handle()
}
}
}

@ -2,8 +2,6 @@ use lazy_static::lazy_static;
use std::pin::Pin;
use std::sync::Mutex;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io::{self, Write};
use crate::task::{blocking, Context, JoinHandle, Poll};
@ -146,7 +144,7 @@ impl Write for Stdout {
inner.buf[..buf.len()].copy_from_slice(buf);
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
let res = std::io::Write::write(&mut inner.stdout, &inner.buf);
inner.last_op = Some(Operation::Write(res));
State::Idle(Some(inner))
@ -174,7 +172,7 @@ impl Write for Stdout {
let mut inner = opt.take().unwrap();
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
*state = State::Busy(blocking::spawn(move || {
let res = std::io::Write::flush(&mut inner.stdout);
inner.last_op = Some(Operation::Flush(res));
State::Idle(Some(inner))
@ -192,35 +190,22 @@ impl Write for Stdout {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stdout {
fn as_raw_fd(&self) -> RawFd {
std::io::stdout().as_raw_fd()
}
impl AsRawFd for Stdout {
fn as_raw_fd(&self) -> RawFd {
std::io::stdout().as_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stdout {
fn as_raw_handle(&self) -> RawHandle {
std::io::stdout().as_raw_handle()
}
cfg_windows! {
use crate::os::windows::io::{AsRawHandle, RawHandle};
impl AsRawHandle for Stdout {
fn as_raw_handle(&self) -> RawHandle {
std::io::stdout().as_raw_handle()
}
}
}

@ -2,8 +2,8 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use futures_core::future::TryFuture;
use futures_timer::Delay;
use pin_project_lite::pin_project;
use crate::future::Future;
use crate::io;
@ -36,45 +36,42 @@ pub async fn timeout<F, T>(dur: Duration, f: F) -> io::Result<T>
where
F: Future<Output = io::Result<T>>,
{
let f = TimeoutFuture {
Timeout {
timeout: Delay::new(dur),
future: f,
};
f.await
}
// Future returned by the [`io::timeout`](./fn.timeout.html) function.
#[derive(Debug)]
pub struct TimeoutFuture<F, T>
where
F: Future<Output = io::Result<T>>,
{
future: F,
timeout: Delay,
}
.await
}
impl<F, T> TimeoutFuture<F, T>
where
F: Future<Output = io::Result<T>>,
{
pin_utils::unsafe_pinned!(future: F);
pin_utils::unsafe_pinned!(timeout: Delay);
pin_project! {
/// Future returned by the `FutureExt::timeout` method.
#[derive(Debug)]
pub struct Timeout<F, T>
where
F: Future<Output = io::Result<T>>,
{
#[pin]
future: F,
#[pin]
timeout: Delay,
}
}
impl<F, T> Future for TimeoutFuture<F, T>
impl<F, T> Future for Timeout<F, T>
where
F: Future<Output = io::Result<T>>,
{
type Output = io::Result<T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().future().try_poll(cx) {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this.future.poll(cx) {
Poll::Pending => {}
other => return other,
}
if self.timeout().poll(cx).is_ready() {
let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out").into());
if this.timeout.poll(cx).is_ready() {
let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out"));
Poll::Ready(err)
} else {
Poll::Pending

@ -10,22 +10,14 @@ use write_all::WriteAllFuture;
use write_fmt::WriteFmtFuture;
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;
extension_trait! {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
cfg_if! {
if #[cfg(feature = "docs")] {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::task::{Context, Poll};
}
}
use crate::task::{Context, Poll};
extension_trait! {
#[doc = r#"
Allows writing to a byte stream.
@ -49,7 +41,7 @@ extension_trait! {
[`poll_flush`]: #tymethod.poll_flush
[`poll_close`]: #tymethod.poll_close
"#]
pub trait Write [WriteExt: futures_io::AsyncWrite] {
pub trait Write {
#[doc = r#"
Attempt to write bytes from `buf` into the object.
"#]
@ -80,7 +72,9 @@ extension_trait! {
Attempt to close the object.
"#]
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
}
pub trait WriteExt: futures_io::AsyncWrite {
#[doc = r#"
Writes some bytes into the byte stream.

@ -32,7 +32,7 @@ impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
buffer,
..
} = &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.
loop {
@ -40,7 +40,7 @@ impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?;
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 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}

@ -48,7 +48,8 @@
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
#![recursion_limit = "1024"]
use cfg_if::cfg_if;
#[macro_use]
mod utils;
pub mod fs;
pub mod future;
@ -61,26 +62,19 @@ pub mod stream;
pub mod sync;
pub mod task;
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub mod pin;
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub mod process;
cfg_unstable! {
pub mod pin;
pub mod process;
mod unit;
mod vec;
mod result;
mod option;
mod string;
mod collections;
}
mod unit;
mod vec;
mod result;
mod option;
mod string;
mod collections;
#[doc(inline)]
pub use std::{write, writeln};
}
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)))]
#[macro_export]
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)))]
#[macro_export]
macro_rules! println {
() => ($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.
@ -116,7 +119,7 @@ macro_rules! println {
/// #
/// # })
/// ```
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[macro_export]
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)))]
#[macro_export]
macro_rules! eprintln {
@ -158,6 +161,7 @@ macro_rules! eprintln {
($($arg:tt)*) => (
async {
$crate::io::_eprint(format_args!($($arg)*)).await;
$crate::io::_eprint(format_args!("\n")).await;
}
);
}

@ -3,24 +3,22 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::pin::Pin;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io;
use crate::task::{blocking, Context, JoinHandle, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
cfg_not_docs! {
macro_rules! ret {
(impl Future<Output = $out:ty>, $fut:ty) => ($fut);
}
}
cfg_docs! {
#[doc(hidden)]
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
macro_rules! ret {
(impl Future<Output = $out:ty>, $fut:ty) => (ImplFuture<$out>);
}
} else {
macro_rules! ret {
(impl Future<Output = $out:ty>, $fut:ty) => ($fut);
}
macro_rules! ret {
(impl Future<Output = $out:ty>, $fut:ty) => (ImplFuture<$out>);
}
}
@ -196,7 +194,7 @@ impl ToSocketAddrs for (&str, u16) {
}
let host = host.to_string();
let task = blocking::spawn(async move {
let task = blocking::spawn(move || {
std::net::ToSocketAddrs::to_socket_addrs(&(host.as_str(), port))
});
ToSocketAddrsFuture::Resolving(task)
@ -212,13 +210,12 @@ impl ToSocketAddrs for str {
impl Future<Output = 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()));
}
let addr = self.to_string();
let task =
blocking::spawn(async move { std::net::ToSocketAddrs::to_socket_addrs(addr.as_str()) });
let task = blocking::spawn(move || std::net::ToSocketAddrs::to_socket_addrs(addr.as_str()));
ToSocketAddrsFuture::Resolving(task)
}
}

@ -1,13 +1,10 @@
use std::net::SocketAddr;
use std::pin::Pin;
use cfg_if::cfg_if;
use super::TcpStream;
use crate::future::{self, Future};
use crate::io;
use crate::net::driver::Watcher;
use crate::net::ToSocketAddrs;
use crate::net::{TcpStream, ToSocketAddrs};
use crate::stream::Stream;
use crate::task::{Context, Poll};
@ -213,59 +210,46 @@ impl From<std::net::TcpListener> for TcpListener {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
}
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
std::net::TcpListener::from_raw_fd(fd).into()
}
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
std::net::TcpListener::from_raw_fd(fd).into()
}
}
impl IntoRawFd for TcpListener {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
impl IntoRawFd for TcpListener {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
// impl AsRawSocket for TcpListener {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpListener {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
// net::TcpListener::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}
cfg_windows! {
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for TcpListener {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpListener {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
// net::TcpListener::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -2,8 +2,6 @@ use std::io::{IoSlice, IoSliceMut, Read as _, Write as _};
use std::net::SocketAddr;
use std::pin::Pin;
use cfg_if::cfg_if;
use crate::future;
use crate::io::{self, Read, Write};
use crate::net::driver::Watcher;
@ -76,7 +74,7 @@ impl TcpStream {
let mut last_err = None;
for addr in addrs.to_socket_addrs().await? {
let res = blocking::spawn(async move {
let res = blocking::spawn(move || {
let std_stream = std::net::TcpStream::connect(addr)?;
let mio_stream = mio::net::TcpStream::from_stream(std_stream)?;
Ok(TcpStream {
@ -367,59 +365,46 @@ impl From<std::net::TcpStream> for TcpStream {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
impl AsRawFd for TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
}
impl FromRawFd for TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
std::net::TcpStream::from_raw_fd(fd).into()
}
impl FromRawFd for TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
std::net::TcpStream::from_raw_fd(fd).into()
}
}
impl IntoRawFd for TcpStream {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
impl IntoRawFd for TcpStream {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
// impl AsRawSocket for TcpStream {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpStream {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpStream {
// net::TcpStream::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}
cfg_windows! {
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for TcpStream {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpStream {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpStream {
// net::TcpStream::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -1,7 +1,5 @@
use std::io;
use std::net::SocketAddr;
use cfg_if::cfg_if;
use std::net::{Ipv4Addr, Ipv6Addr};
use crate::future;
@ -463,61 +461,46 @@ impl From<std::net::UdpSocket> for UdpSocket {
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
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_unix! {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
impl AsRawFd for UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.watcher.get_ref().as_raw_fd()
}
}
impl FromRawFd for UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
std::net::UdpSocket::from_raw_fd(fd).into()
}
impl FromRawFd for UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
std::net::UdpSocket::from_raw_fd(fd).into()
}
}
impl IntoRawFd for UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
impl IntoRawFd for UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_inner().into_raw_fd()
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
// use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
//
// impl AsRawSocket for UdpSocket {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for UdpSocket {
// unsafe fn from_raw_socket(handle: RawSocket) -> UdpSocket {
// net::UdpSocket::from_raw_socket(handle).into()
// }
// }
//
// impl IntoRawSocket for UdpSocket {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}
cfg_windows! {
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for UdpSocket {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for UdpSocket {
// unsafe fn from_raw_socket(handle: RawSocket) -> UdpSocket {
// net::UdpSocket::from_raw_socket(handle).into()
// }
// }
//
// impl IntoRawSocket for UdpSocket {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -1,9 +1,9 @@
//! OS-specific extensions.
#[cfg(any(unix, feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
pub mod unix;
cfg_unix! {
pub mod unix;
}
#[cfg(any(windows, feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
pub mod windows;
cfg_windows! {
pub mod windows;
}

@ -1,7 +1,5 @@
//! Unix-specific filesystem extensions.
use cfg_if::cfg_if;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
@ -28,46 +26,46 @@ use crate::task::blocking;
pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
blocking::spawn(async move { std::os::unix::fs::symlink(&src, &dst) }).await
blocking::spawn(move || std::os::unix::fs::symlink(&src, &dst)).await
}
cfg_if! {
if #[cfg(feature = "docs")] {
/// Unix-specific extensions to `DirBuilder`.
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// `0o777`.
fn mode(&mut self, mode: u32) -> &mut Self;
}
cfg_not_docs! {
pub use std::os::unix::fs::{DirBuilderExt, DirEntryExt, OpenOptionsExt};
}
/// Unix-specific extension methods for `DirEntry`.
pub trait DirEntryExt {
/// Returns the underlying `d_ino` field in the contained `dirent`
/// structure.
fn ino(&self) -> u64;
}
cfg_docs! {
/// Unix-specific extensions to `DirBuilder`.
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// `0o777`.
fn mode(&mut self, mode: u32) -> &mut Self;
}
/// Unix-specific extension methods for `DirEntry`.
pub trait DirEntryExt {
/// Returns the underlying `d_ino` field in the contained `dirent`
/// structure.
fn ino(&self) -> u64;
}
/// Unix-specific extensions to `OpenOptions`.
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
fn mode(&mut self, mode: u32) -> &mut Self;
/// Unix-specific extensions to `OpenOptions`.
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
fn mode(&mut self, mode: u32) -> &mut Self;
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
} else {
pub use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt};
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
}

@ -1,56 +1,54 @@
//! 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! {
if #[cfg(feature = "docs")] {
/// Raw file descriptors.
pub type RawFd = std::os::raw::c_int;
cfg_docs! {
/// Raw file descriptors.
pub type RawFd = std::os::raw::c_int;
/// A trait to extract the raw unix file descriptor from an underlying
/// object.
/// A trait to extract the raw unix file descriptor from an underlying
/// object.
///
/// This is only available on unix platforms and must be imported in order
/// to call the method. Windows platforms have a corresponding `AsRawHandle`
/// and `AsRawSocket` set of traits.
pub trait AsRawFd {
/// Extracts the raw file descriptor.
///
/// This is only available on unix platforms and must be imported in order
/// to call the method. Windows platforms have a corresponding `AsRawHandle`
/// and `AsRawSocket` set of traits.
pub trait AsRawFd {
/// Extracts the raw file descriptor.
///
/// This method does **not** pass ownership of the raw file descriptor
/// to the caller. The descriptor is only guaranteed to be valid while
/// the original object has not yet been destroyed.
fn as_raw_fd(&self) -> RawFd;
}
/// This method does **not** pass ownership of the raw file descriptor
/// to the caller. The descriptor is only guaranteed to be valid while
/// the original object has not yet been destroyed.
fn as_raw_fd(&self) -> RawFd;
}
/// A trait to express the ability to construct an object from a raw file
/// A trait to express the ability to construct an object from a raw file
/// descriptor.
pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// it when the object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// it when the object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// This function **transfers ownership** of the underlying file descriptor
/// to the caller. Callers are then the unique owners of the file descriptor
/// and must close the descriptor once it's no longer needed.
fn into_raw_fd(self) -> RawFd;
}
} else {
pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// This function **transfers ownership** of the underlying file descriptor
/// to the caller. Callers are then the unique owners of the file descriptor
/// and must close the descriptor once it's no longer needed.
fn into_raw_fd(self) -> RawFd;
}
}

@ -67,7 +67,7 @@ impl UnixDatagram {
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
let path = path.as_ref().to_owned();
let socket = blocking::spawn(async move { mio_uds::UnixDatagram::bind(path) }).await?;
let socket = blocking::spawn(move || mio_uds::UnixDatagram::bind(path)).await?;
Ok(UnixDatagram::new(socket))
}

@ -68,7 +68,7 @@ impl UnixListener {
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
let path = path.as_ref().to_owned();
let listener = blocking::spawn(async move { mio_uds::UnixListener::bind(path) }).await?;
let listener = blocking::spawn(move || mio_uds::UnixListener::bind(path)).await?;
Ok(UnixListener {
watcher: Watcher::new(listener),

@ -1,7 +1,5 @@
//! Unix-specific networking extensions.
use cfg_if::cfg_if;
pub use datagram::UnixDatagram;
pub use listener::{Incoming, UnixListener};
pub use stream::UnixStream;
@ -10,90 +8,90 @@ mod datagram;
mod listener;
mod stream;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::fmt;
cfg_not_docs! {
pub use std::os::unix::net::SocketAddr;
}
cfg_docs! {
use std::fmt;
use crate::path::Path;
use crate::path::Path;
/// An address associated with a Unix socket.
///
/// # Examples
///
/// ```
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// ```
#[derive(Clone)]
pub struct SocketAddr {
_private: (),
}
/// An address associated with a Unix socket.
impl SocketAddr {
/// Returns `true` if the address is unnamed.
///
/// # Examples
///
/// ```
/// A named address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), false);
/// ```
#[derive(Clone)]
pub struct SocketAddr {
_private: (),
///
/// An unnamed address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), true);
/// ```
pub fn is_unnamed(&self) -> bool {
unreachable!("this impl only appears in the rendered docs")
}
impl SocketAddr {
/// Returns `true` if the address is unnamed.
///
/// # Examples
///
/// A named address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), false);
/// ```
///
/// An unnamed address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), true);
/// ```
pub fn is_unnamed(&self) -> bool {
unreachable!("this impl only appears in the rendered docs")
}
/// Returns the contents of this address if it is a `pathname` address.
///
/// # Examples
///
/// With a pathname:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
/// use async_std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/socket")));
/// ```
///
/// Without a pathname:
///
/// ```
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), None);
/// ```
pub fn as_pathname(&self) -> Option<&Path> {
unreachable!("this impl only appears in the rendered docs")
}
/// Returns the contents of this address if it is a `pathname` address.
///
/// # Examples
///
/// With a pathname:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
/// use async_std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/socket")));
/// ```
///
/// Without a pathname:
///
/// ```
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), None);
/// ```
pub fn as_pathname(&self) -> Option<&Path> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!("this impl only appears in the rendered docs")
}
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!("this impl only appears in the rendered docs")
}
} else {
pub use std::os::unix::net::SocketAddr;
}
}

@ -58,7 +58,7 @@ impl UnixStream {
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
let path = path.as_ref().to_owned();
blocking::spawn(async move {
blocking::spawn(move || {
let std_stream = std::os::unix::net::UnixStream::connect(path)?;
let mio_stream = mio_uds::UnixStream::from_stream(std_stream)?;
Ok(UnixStream {

@ -1,50 +1,48 @@
//! 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! {
if #[cfg(feature = "docs")] {
/// Raw HANDLEs.
pub type RawHandle = *mut std::os::raw::c_void;
cfg_docs! {
/// Raw HANDLEs.
pub type RawHandle = *mut std::os::raw::c_void;
/// Raw SOCKETs.
pub type RawSocket = u64;
/// Raw SOCKETs.
pub type RawSocket = u64;
/// Extracts raw handles.
pub trait AsRawHandle {
/// Extracts the raw handle, without taking any ownership.
fn as_raw_handle(&self) -> RawHandle;
}
/// Extracts raw handles.
pub trait AsRawHandle {
/// Extracts the raw handle, without taking any ownership.
fn as_raw_handle(&self) -> RawHandle;
}
/// Construct I/O objects from raw handles.
pub trait FromRawHandle {
/// Constructs a new I/O object from the specified raw handle.
///
/// This function will **consume ownership** of the handle given,
/// passing responsibility for closing the handle to the returned
/// object.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}
/// Construct I/O objects from raw handles.
pub trait FromRawHandle {
/// Constructs a new I/O object from the specified raw handle.
///
/// This function will **consume ownership** of the handle given,
/// passing responsibility for closing the handle to the returned
/// object.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `HANDLE`.
pub trait IntoRawHandle {
/// Consumes this object, returning the raw underlying handle.
///
/// This function **transfers ownership** of the underlying handle to the
/// caller. Callers are then the unique owners of the handle and must close
/// it once it's no longer needed.
fn into_raw_handle(self) -> RawHandle;
}
} else {
pub use std::os::windows::io::{
AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, RawSocket,
};
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `HANDLE`.
pub trait IntoRawHandle {
/// Consumes this object, returning the raw underlying handle.
///
/// This function **transfers ownership** of the underlying handle to the
/// caller. Callers are then the unique owners of the handle and must close
/// it once it's no longer needed.
fn into_raw_handle(self) -> RawHandle;
}
}

@ -799,7 +799,7 @@ impl AsRef<Path> for String {
impl AsRef<Path> for std::path::PathBuf {
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`].
///
/// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Default)]
pub struct PathBuf {
inner: std::path::PathBuf,
}
@ -206,7 +206,7 @@ impl From<std::path::PathBuf> for PathBuf {
impl Into<std::path::PathBuf> for PathBuf {
fn into(self) -> std::path::PathBuf {
self.inner.into()
self.inner
}
}

@ -11,8 +11,6 @@
//! use async_std::prelude::*;
//! ```
use cfg_if::cfg_if;
#[doc(no_inline)]
pub use crate::future::Future;
#[doc(no_inline)]
@ -28,6 +26,8 @@ pub use crate::stream::Stream;
#[doc(no_inline)]
pub use crate::task_local;
#[doc(hidden)]
pub use crate::future::future::FutureExt as _;
#[doc(hidden)]
pub use crate::io::buf_read::BufReadExt as _;
#[doc(hidden)]
@ -39,12 +39,9 @@ pub use crate::io::write::WriteExt as _;
#[doc(hidden)]
pub use crate::stream::stream::StreamExt as _;
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
#[doc(no_inline)]
pub use crate::stream::DoubleEndedStream;
#[doc(no_inline)]
pub use crate::stream::ExactSizeStream;
}
cfg_unstable! {
#[doc(no_inline)]
pub use crate::stream::DoubleEndedStream;
#[doc(no_inline)]
pub use crate::stream::ExactSizeStream;
}

@ -10,8 +10,8 @@ use std::task::{Context, Poll};
/// `Item`s from the back, as well as the front.
///
/// [`Stream`]: trait.Stream.html
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub trait DoubleEndedStream: 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 {
/// // We can easily calculate the remaining number of iterations.
@ -74,10 +74,9 @@ pub use crate::stream::Stream;
///
/// assert_eq!(5, counter.len());
/// # });
/// # }
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub trait ExactSizeStream: Stream {
/// Returns the exact number of times the stream will iterate.
///

@ -14,7 +14,7 @@ use crate::stream::IntoStream;
/// ## Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::stream::{self, Extend};
@ -25,8 +25,9 @@ use crate::stream::IntoStream;
///
/// assert_eq!(v, vec![1, 2, 3, 3, 3]);
/// #
/// # }) }
/// # })
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait Extend<A> {
/// Extends a collection with the contents of a stream.

@ -0,0 +1,97 @@
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 yields elements by calling a closure.
///
/// This stream is constructed by [`from_fn`] function.
///
/// [`from_fn`]: fn.from_fn.html
#[derive(Debug)]
pub struct FromFn<F, Fut, T> {
f: F,
#[pin]
future: Option<Fut>,
__t: PhantomData<T>,
}
}
/// Creates a new stream where to produce each new element a provided closure is called.
///
/// This allows creating a custom stream with any behaviour without using the more verbose
/// syntax of creating a dedicated type and implementing a `Stream` trait for it.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::sync::Mutex;
/// use std::sync::Arc;
/// use async_std::stream;
///
/// let count = Arc::new(Mutex::new(0u8));
/// let s = stream::from_fn(|| {
/// let count = Arc::clone(&count);
///
/// async move {
/// *count.lock().await += 1;
///
/// if *count.lock().await > 3 {
/// None
/// } else {
/// Some(*count.lock().await)
/// }
/// }
/// });
///
/// pin_utils::pin_mut!(s);
/// assert_eq!(s.next().await, Some(1));
/// assert_eq!(s.next().await, Some(2));
/// assert_eq!(s.next().await, Some(3));
/// assert_eq!(s.next().await, None);
/// #
/// # })
/// ```
pub fn from_fn<T, F, Fut>(f: F) -> FromFn<F, Fut, T>
where
F: FnMut() -> Fut,
Fut: Future<Output = Option<T>>,
{
FromFn {
f,
future: None,
__t: PhantomData,
}
}
impl<F, Fut, T> Stream for FromFn<F, Fut, T>
where
F: FnMut() -> Fut,
Fut: Future<Output = Option<T>>,
{
type Item = T;
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 next =
futures_core::ready!(this.future.as_mut().as_pin_mut().unwrap().poll(cx));
this.future.set(None);
return Poll::Ready(next);
} else {
let fut = (this.f)();
this.future.set(Some(fut));
}
}
}
}

@ -106,8 +106,8 @@ use std::pin::Pin;
///```
///
/// [`IntoStream`]: trait.IntoStream.html
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub trait FromStream<T> {
/// 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
/// [`Stream::fuse`]: trait.Stream.html#method.fuse
/// [`Fuse`]: struct.Fuse.html
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait FusedStream: Stream {}

@ -0,0 +1,192 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_timer::Delay;
/// Creates a new stream that yields at a set interval.
///
/// The stream first yields after `dur`, and continues to yield every
/// `dur` after that. The stream accounts for time elapsed between calls, and
/// will adjust accordingly to prevent time skews.
///
/// Each interval may be slightly longer than the specified duration, but never
/// less.
///
/// Note that intervals are not intended for high resolution timers, but rather
/// they will likely fire some granularity after the exact instant that they're
/// otherwise indicated to fire at.
///
/// See also: [`task::sleep`].
///
/// [`task::sleep`]: ../task/fn.sleep.html
///
/// # Examples
///
/// Basic example:
///
/// ```no_run
/// use async_std::prelude::*;
/// use async_std::stream;
/// use std::time::Duration;
///
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// let mut interval = stream::interval(Duration::from_secs(4));
/// while let Some(_) = interval.next().await {
/// println!("prints every four seconds");
/// }
/// #
/// # Ok(()) }) }
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub fn interval(dur: Duration) -> Interval {
Interval {
delay: Delay::new(dur),
interval: dur,
}
}
/// A stream representing notifications at fixed interval
///
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Debug)]
pub struct Interval {
delay: Delay,
interval: Duration,
}
impl Stream for Interval {
type 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() {
return Poll::Pending;
}
let when = Instant::now();
let next = next_interval(when, Instant::now(), self.interval);
self.delay.reset(next);
Poll::Ready(Some(()))
}
}
/// Converts Duration object to raw nanoseconds if possible
///
/// This is useful to divide intervals.
///
/// While technically for large duration it's impossible to represent any
/// duration as nanoseconds, the largest duration we can represent is about
/// 427_000 years. Large enough for any interval we would use or calculate in
/// tokio.
fn duration_to_nanos(dur: Duration) -> Option<u64> {
dur.as_secs()
.checked_mul(1_000_000_000)
.and_then(|v| v.checked_add(u64::from(dur.subsec_nanos())))
}
fn next_interval(prev: Instant, now: Instant, interval: Duration) -> Instant {
let new = prev + interval;
if new > now {
return new;
}
let spent_ns = duration_to_nanos(now.duration_since(prev)).expect("interval should be expired");
let interval_ns =
duration_to_nanos(interval).expect("interval is less that 427 thousand years");
let mult = spent_ns / interval_ns + 1;
assert!(
mult < (1 << 32),
"can't skip more than 4 billion intervals of {:?} \
(trying to skip {})",
interval,
mult
);
prev + interval * (mult as u32)
}
#[cfg(test)]
mod test {
use super::next_interval;
use std::time::{Duration, Instant};
struct Timeline(Instant);
impl Timeline {
fn new() -> Timeline {
Timeline(Instant::now())
}
fn at(&self, millis: u64) -> Instant {
self.0 + Duration::from_millis(millis)
}
fn at_ns(&self, sec: u64, nanos: u32) -> Instant {
self.0 + Duration::new(sec, nanos)
}
}
fn dur(millis: u64) -> Duration {
Duration::from_millis(millis)
}
// The math around Instant/Duration isn't 100% precise due to rounding
// errors, see #249 for more info
fn almost_eq(a: Instant, b: Instant) -> bool {
if a == b {
true
} else if a > b {
a - b < Duration::from_millis(1)
} else {
b - a < Duration::from_millis(1)
}
}
#[test]
fn norm_next() {
let tm = Timeline::new();
assert!(almost_eq(
next_interval(tm.at(1), tm.at(2), dur(10)),
tm.at(11)
));
assert!(almost_eq(
next_interval(tm.at(7777), tm.at(7788), dur(100)),
tm.at(7877)
));
assert!(almost_eq(
next_interval(tm.at(1), tm.at(1000), dur(2100)),
tm.at(2101)
));
}
#[test]
fn fast_forward() {
let tm = Timeline::new();
assert!(almost_eq(
next_interval(tm.at(1), tm.at(1000), dur(10)),
tm.at(1001)
));
assert!(almost_eq(
next_interval(tm.at(7777), tm.at(8888), dur(100)),
tm.at(8977)
));
assert!(almost_eq(
next_interval(tm.at(1), tm.at(10000), dur(2100)),
tm.at(10501)
));
}
/// TODO: this test actually should be successful, but since we can't
/// multiply Duration on anything larger than u32 easily we decided
/// to allow it to fail for now
#[test]
#[should_panic(expected = "can't skip more than 4 billion intervals")]
fn large_skip() {
let tm = Timeline::new();
assert_eq!(
next_interval(tm.at_ns(0, 1), tm.at_ns(25, 0), Duration::new(0, 2)),
tm.at_ns(25, 1)
);
}
}

@ -13,8 +13,8 @@ use crate::stream::Stream;
/// See also: [`FromStream`].
///
/// [`FromStream`]: trait.FromStream.html
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub trait IntoStream {
/// The type of the elements being iterated over.
type Item;

@ -1,4 +1,4 @@
//! Asynchronous iteration.
//! Composable asynchronous iteration.
//!
//! This module is an async version of [`std::iter`].
//!
@ -21,11 +21,11 @@
//! # })
//! ```
use cfg_if::cfg_if;
pub use empty::{empty, Empty};
pub use from_fn::{from_fn, FromFn};
pub use once::{once, Once};
pub use repeat::{repeat, Repeat};
pub use repeat_with::{repeat_with, RepeatWith};
pub use stream::{
Chain, Filter, Fuse, Inspect, Scan, Skip, SkipWhile, StepBy, Stream, Take, TakeWhile, Zip,
};
@ -33,25 +33,30 @@ pub use stream::{
pub(crate) mod stream;
mod empty;
mod from_fn;
mod once;
mod repeat;
mod repeat_with;
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod double_ended_stream;
mod exact_size_stream;
mod fused_stream;
mod extend;
mod from_stream;
mod into_stream;
pub use double_ended_stream::DoubleEndedStream;
pub use exact_size_stream::ExactSizeStream;
pub use extend::Extend;
pub use from_stream::FromStream;
pub use into_stream::IntoStream;
pub use fused_stream::FusedStream;
cfg_unstable! {
mod double_ended_stream;
mod exact_size_stream;
mod extend;
mod from_stream;
mod fused_stream;
mod interval;
mod into_stream;
mod product;
mod sum;
pub use stream::Merge;
}
pub use double_ended_stream::DoubleEndedStream;
pub use exact_size_stream::ExactSizeStream;
pub use extend::Extend;
pub use from_stream::FromStream;
pub use fused_stream::FusedStream;
pub use interval::{interval, Interval};
pub use into_stream::IntoStream;
pub use product::Product;
pub use stream::Merge;
pub use sum::Sum;
}

@ -1,5 +1,7 @@
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
@ -24,20 +26,22 @@ pub fn once<T>(t: T) -> Once<T> {
Once { value: Some(t) }
}
/// A stream that yields a single item.
///
/// This stream is constructed by the [`once`] function.
///
/// [`once`]: fn.once.html
#[derive(Debug)]
pub struct Once<T> {
value: Option<T>,
pin_project! {
/// A stream that yields a single item.
///
/// This stream is constructed by the [`once`] function.
///
/// [`once`]: fn.once.html
#[derive(Debug)]
pub struct Once<T> {
value: Option<T>,
}
}
impl<T: Unpin> Stream for Once<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
Poll::Ready(self.value.take())
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
Poll::Ready(self.project().value.take())
}
}

@ -0,0 +1,23 @@
use crate::future::Future;
use crate::stream::Stream;
/// Trait to represent types that can be created by productming up a stream.
///
/// This trait is used to implement the [`product`] method on streams. Types which
/// implement the trait can be generated by the [`product`] method. Like
/// [`FromStream`] this trait should rarely be called directly and instead
/// interacted with through [`Stream::product`].
///
/// [`product`]: trait.Product.html#tymethod.product
/// [`FromStream`]: trait.FromStream.html
/// [`Stream::product`]: trait.Stream.html#method.product
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait Product<A = Self>: Sized {
/// Method which takes a stream and generates `Self` from the elements by
/// multiplying the items.
fn product<S, F>(stream: S) -> F
where
S: Stream<Item = A>,
F: Future<Output = Self>;
}

@ -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 pin_project_lite::pin_project;
use super::fuse::Fuse;
use crate::prelude::*;
use crate::task::{Context, Poll};
/// Chains two streams one after another.
#[derive(Debug)]
pub struct Chain<S, U> {
first: Fuse<S>,
second: Fuse<U>,
pin_project! {
/// Chains two streams one after another.
#[derive(Debug)]
pub struct Chain<S, U> {
#[pin]
first: Fuse<S>,
#[pin]
second: Fuse<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 {
Chain {
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> {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
if !self.first.done {
let next = futures_core::ready!(self.as_mut().first().poll_next(cx));
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut this = self.project();
if !this.first.done {
let next = futures_core::ready!(this.first.as_mut().poll_next(cx));
if let Some(next) = next {
return Poll::Ready(Some(next));
}
}
if !self.second.done {
let next = futures_core::ready!(self.as_mut().second().poll_next(cx));
if !this.second.done {
let next = futures_core::ready!(this.second.as_mut().poll_next(cx));
if let Some(next) = next {
return Poll::Ready(Some(next));
}
}
if self.first.done && self.second.done {
if this.first.done && this.second.done {
return Poll::Ready(None);
}

@ -0,0 +1,93 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::fuse::Fuse;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
// Lexicographically compares the elements of this `Stream` with those
// of another using `Ord`.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct CmpFuture<L: Stream, R: Stream> {
#[pin]
l: Fuse<L>,
#[pin]
r: Fuse<R>,
l_cache: Option<L::Item>,
r_cache: Option<R::Item>,
}
}
impl<L: Stream, R: Stream> CmpFuture<L, R> {
pub(super) fn new(l: L, r: R) -> Self {
CmpFuture {
l: l.fuse(),
r: r.fuse(),
l_cache: None,
r_cache: None,
}
}
}
impl<L: Stream, R: Stream> Future for CmpFuture<L, R>
where
L: Stream + Sized,
R: Stream<Item = L::Item> + Sized,
L::Item: Ord,
{
type Output = Ordering;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
loop {
// Stream that completes earliest can be considered Less, etc
let l_complete = this.l.done && this.l_cache.is_none();
let r_complete = this.r.done && this.r_cache.is_none();
if l_complete && r_complete {
return Poll::Ready(Ordering::Equal);
} else if l_complete {
return Poll::Ready(Ordering::Less);
} else if r_complete {
return Poll::Ready(Ordering::Greater);
}
// Get next value if possible and necesary
if !this.l.done && this.l_cache.is_none() {
let l_next = futures_core::ready!(this.l.as_mut().poll_next(cx));
if let Some(item) = l_next {
*this.l_cache = Some(item);
}
}
if !this.r.done && this.r_cache.is_none() {
let r_next = futures_core::ready!(this.r.as_mut().poll_next(cx));
if let Some(item) = r_next {
*this.r_cache = Some(item);
}
}
// Compare if both values are available.
if this.l_cache.is_some() && this.r_cache.is_some() {
let l_value = this.l_cache.take().unwrap();
let r_value = this.r_cache.take().unwrap();
let result = l_value.cmp(&r_value);
if let Ordering::Equal = result {
// Reset cache to prepare for next comparison
*this.l_cache = None;
*this.r_cache = None;
} else {
// Return non equal value
return Poll::Ready(result);
}
}
}
}
}

@ -1,19 +1,21 @@
use crate::task::{Context, Poll};
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct Enumerate<S> {
stream: S,
i: usize,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct Enumerate<S> {
#[pin]
stream: S,
i: usize,
}
}
impl<S> Enumerate<S> {
pin_utils::unsafe_pinned!(stream: S);
pin_utils::unsafe_unpinned!(i: usize);
pub(super) fn new(stream: S) -> Self {
Enumerate { stream, i: 0 }
}
@ -25,13 +27,14 @@ where
{
type Item = (usize, S::Item);
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let next = futures_core::ready!(this.stream.poll_next(cx));
match next {
Some(v) => {
let ret = (self.i, v);
*self.as_mut().i() += 1;
let ret = (*this.i, v);
*this.i += 1;
Poll::Ready(Some(ret))
}
None => Poll::Ready(None),

@ -1,21 +1,23 @@
use std::marker::PhantomData;
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A stream to filter elements of another stream with a predicate.
#[derive(Debug)]
pub struct Filter<S, P, T> {
stream: S,
predicate: P,
__t: PhantomData<T>,
pin_project! {
/// A stream to filter elements of another stream with a predicate.
#[derive(Debug)]
pub struct Filter<S, P, T> {
#[pin]
stream: S,
predicate: P,
__t: PhantomData<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 {
Filter {
stream,
@ -32,11 +34,12 @@ where
{
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let next = futures_core::ready!(this.stream.poll_next(cx));
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(_) => {
cx.waker().wake_by_ref();
Poll::Pending

@ -2,21 +2,23 @@ use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use crate::stream::Stream;
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FilterMap<S, F, T, B> {
stream: S,
f: F,
__from: PhantomData<T>,
__to: PhantomData<B>,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FilterMap<S, F, T, B> {
#[pin]
stream: S,
f: F,
__from: PhantomData<T>,
__to: PhantomData<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 {
FilterMap {
stream,
@ -34,10 +36,11 @@ where
{
type Item = B;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let next = futures_core::ready!(this.stream.poll_next(cx));
match next {
Some(v) => match (self.as_mut().f())(v) {
Some(v) => match (this.f)(v) {
Some(b) => Poll::Ready(Some(b)),
None => {
cx.waker().wake_by_ref();

@ -1,24 +1,25 @@
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};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FoldFuture<S, F, T, B> {
stream: S,
f: F,
acc: Option<B>,
__t: PhantomData<T>,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FoldFuture<S, F, T, B> {
#[pin]
stream: S,
f: F,
acc: Option<B>,
__t: PhantomData<T>,
}
}
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 {
FoldFuture {
stream,
@ -36,17 +37,18 @@ where
{
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 {
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 {
Some(v) => {
let old = self.as_mut().acc().take().unwrap();
let new = (self.as_mut().f())(old, v);
*self.as_mut().acc() = Some(new);
let old = this.acc.take().unwrap();
let new = (this.f)(old, v);
*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::pin::Pin;
use pin_project_lite::pin_project;
use crate::future::Future;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ForEachFuture<S, F, T> {
stream: S,
f: F,
__t: PhantomData<T>,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ForEachFuture<S, F, T> {
#[pin]
stream: S,
f: F,
__t: PhantomData<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 {
ForEachFuture {
stream,
@ -33,12 +35,13 @@ where
{
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 {
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 {
Some(v) => (self.as_mut().f())(v),
Some(v) => (this.f)(v),
None => return Poll::Ready(()),
}
}

@ -1,33 +1,32 @@
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// 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`.
#[derive(Clone, Debug)]
pub struct Fuse<S> {
pub(crate) stream: S,
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);
pin_project! {
/// 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`.
#[derive(Clone, Debug)]
pub struct Fuse<S> {
#[pin]
pub(crate) stream: S,
pub(crate) done: bool,
}
}
impl<S: Stream> Stream for Fuse<S> {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
if self.done {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
let this = self.project();
if *this.done {
Poll::Ready(None)
} 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() {
*self.as_mut().done() = true;
*this.done = true;
}
Poll::Ready(next)
}

@ -0,0 +1,50 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
// Determines if the elements of this `Stream` are lexicographically
// greater than or equal to those of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct GeFuture<L: Stream, R: Stream> {
#[pin]
partial_cmp: PartialCmpFuture<L, R>,
}
}
impl<L: Stream, R: Stream> GeFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pub(super) fn new(l: L, r: R) -> Self {
GeFuture {
partial_cmp: l.partial_cmp(r),
}
}
}
impl<L: Stream, R: Stream> Future for GeFuture<L, R>
where
L: Stream,
R: Stream,
L::Item: PartialOrd<R::Item>,
{
type Output = bool;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
match result {
Some(Ordering::Greater) | Some(Ordering::Equal) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,50 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
// Determines if the elements of this `Stream` are lexicographically
// greater than those of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct GtFuture<L: Stream, R: Stream> {
#[pin]
partial_cmp: PartialCmpFuture<L, R>,
}
}
impl<L: Stream, R: Stream> GtFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pub(super) fn new(l: L, r: R) -> Self {
GtFuture {
partial_cmp: l.partial_cmp(r),
}
}
}
impl<L: Stream, R: Stream> Future for GtFuture<L, R>
where
L: Stream + Sized,
R: Stream + Sized,
L::Item: PartialOrd<R::Item>,
{
type Output = bool;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
match result {
Some(Ordering::Greater) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -1,21 +1,23 @@
use std::marker::PhantomData;
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A stream that does something with each element of another stream.
#[derive(Debug)]
pub struct Inspect<S, F, T> {
stream: S,
f: F,
__t: PhantomData<T>,
pin_project! {
/// A stream that does something with each element of another stream.
#[derive(Debug)]
pub struct Inspect<S, F, T> {
#[pin]
stream: S,
f: F,
__t: PhantomData<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 {
Inspect {
stream,
@ -32,11 +34,12 @@ where
{
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut this = self.project();
let next = futures_core::ready!(this.stream.as_mut().poll_next(cx));
Poll::Ready(next.and_then(|x| {
(self.as_mut().f())(&x);
(this.f)(&x);
Some(x)
}))
}

@ -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),
}
}
}

@ -0,0 +1,50 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
/// Determines if the elements of this `Stream` are lexicographically
/// less or equal to those of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct LeFuture<L: Stream, R: Stream> {
#[pin]
partial_cmp: PartialCmpFuture<L, R>,
}
}
impl<L: Stream, R: Stream> LeFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pub(super) fn new(l: L, r: R) -> Self {
LeFuture {
partial_cmp: l.partial_cmp(r),
}
}
}
impl<L: Stream, R: Stream> Future for LeFuture<L, R>
where
L: Stream + Sized,
R: Stream + Sized,
L::Item: PartialOrd<R::Item>,
{
type Output = bool;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
match result {
Some(Ordering::Less) | Some(Ordering::Equal) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,50 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
// Determines if the elements of this `Stream` are lexicographically
// less than those of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct LtFuture<L: Stream, R: Stream> {
#[pin]
partial_cmp: PartialCmpFuture<L, R>,
}
}
impl<L: Stream, R: Stream> LtFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pub(super) fn new(l: L, r: R) -> Self {
LtFuture {
partial_cmp: l.partial_cmp(r),
}
}
}
impl<L: Stream, R: Stream> Future for LtFuture<L, R>
where
L: Stream + Sized,
R: Stream + Sized,
L::Item: PartialOrd<R::Item>,
{
type Output = bool;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.project().partial_cmp.poll(cx));
match result {
Some(Ordering::Less) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -1,22 +1,24 @@
use std::marker::PhantomData;
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct Map<S, F, T, B> {
stream: S,
f: F,
__from: PhantomData<T>,
__to: PhantomData<B>,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct Map<S, F, T, B> {
#[pin]
stream: S,
f: F,
__from: PhantomData<T>,
__to: PhantomData<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 {
Map {
stream,
@ -34,8 +36,9 @@ where
{
type Item = B;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
Poll::Ready(next.map(self.as_mut().f()))
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let next = futures_core::ready!(this.stream.poll_next(cx));
Poll::Ready(next.map(this.f))
}
}

@ -2,20 +2,25 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::Stream;
use pin_project_lite::pin_project;
/// A stream that merges two other streams into a single stream.
///
/// This stream is returned by [`Stream::merge`].
///
/// [`Stream::merge`]: trait.Stream.html#method.merge
#[derive(Debug)]
pub struct Merge<L, R> {
left: L,
right: R,
pin_project! {
/// A stream that merges two other streams into a single stream.
///
/// This stream is returned by [`Stream::merge`].
///
/// [`Stream::merge`]: trait.Stream.html#method.merge
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Debug)]
pub struct Merge<L, R> {
#[pin]
left: L,
#[pin]
right: R,
}
}
impl<L, R> Unpin for Merge<L, R> {}
impl<L, R> Merge<L, R> {
pub(crate) fn new(left: L, right: R) -> Self {
Self { left, right }
@ -24,19 +29,20 @@ impl<L, R> Merge<L, R> {
impl<L, R, T> Stream for Merge<L, R>
where
L: Stream<Item = T> + Unpin,
R: Stream<Item = T> + Unpin,
L: Stream<Item = T>,
R: Stream<Item = T>,
{
type Item = T;
fn poll_next(mut 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) {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
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
// again to check the progress of the second stream.
cx.waker().wake_by_ref();
Poll::Ready(Some(item))
} else {
Pin::new(&mut self.right).poll_next(cx)
this.right.poll_next(cx)
}
}
}

@ -1,23 +1,24 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::future::Future;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct MinByFuture<S, F, T> {
stream: S,
compare: F,
min: Option<T>,
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct MinByFuture<S, F, T> {
#[pin]
stream: S,
compare: F,
min: Option<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 {
MinByFuture {
stream,
@ -35,22 +36,23 @@ where
{
type Output = Option<S::Item>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
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();
match self.as_mut().min().take() {
None => *self.as_mut().min() = Some(new),
Some(old) => match (&mut self.as_mut().compare())(&new, &old) {
Ordering::Less => *self.as_mut().min() = Some(new),
_ => *self.as_mut().min() = Some(old),
match this.min.take() {
None => *this.min = Some(new),
Some(old) => match (this.compare)(&new, &old) {
Ordering::Less => *this.min = Some(new),
_ => *this.min = Some(old),
},
}
Poll::Pending
}
None => Poll::Ready(self.min),
None => Poll::Ready(*this.min),
}
}
}

@ -24,6 +24,7 @@
mod all;
mod any;
mod chain;
mod cmp;
mod enumerate;
mod filter;
mod filter_map;
@ -32,7 +33,12 @@ mod find_map;
mod fold;
mod for_each;
mod fuse;
mod ge;
mod gt;
mod inspect;
mod last;
mod le;
mod lt;
mod map;
mod min_by;
mod next;
@ -44,21 +50,29 @@ mod skip_while;
mod step_by;
mod take;
mod take_while;
mod try_fold;
mod try_for_each;
mod zip;
use all::AllFuture;
use any::AnyFuture;
use cmp::CmpFuture;
use enumerate::Enumerate;
use filter_map::FilterMap;
use find::FindFuture;
use find_map::FindMapFuture;
use fold::FoldFuture;
use for_each::ForEachFuture;
use ge::GeFuture;
use gt::GtFuture;
use last::LastFuture;
use le::LeFuture;
use lt::LtFuture;
use min_by::MinByFuture;
use next::NextFuture;
use nth::NthFuture;
use partial_cmp::PartialCmpFuture;
use try_fold::TryFoldFuture;
use try_for_each::TryForEeachFuture;
pub use chain::Chain;
@ -77,32 +91,22 @@ pub use zip::Zip;
use std::cmp::Ordering;
use std::marker::PhantomData;
use cfg_if::cfg_if;
cfg_unstable! {
use std::pin::Pin;
use crate::utils::extension_trait;
use crate::future::Future;
use crate::stream::FromStream;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut};
pub use merge::Merge;
use crate::task::{Context, Poll};
}
mod merge;
}
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod merge;
use std::pin::Pin;
extension_trait! {
use std::ops::{Deref, DerefMut};
use crate::future::Future;
use crate::stream::FromStream;
use crate::task::{Context, Poll};
pub use merge::Merge;
}
}
extension_trait! {
#[doc = r#"
An asynchronous stream of values.
@ -122,7 +126,7 @@ extension_trait! {
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/stream/trait.Stream.html
[provided methods]: #provided-methods
"#]
pub trait Stream [StreamExt: futures_core::stream::Stream] {
pub trait Stream {
#[doc = r#"
The type of items yielded by this stream.
"#]
@ -180,7 +184,9 @@ extension_trait! {
```
"#]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
}
pub trait StreamExt: futures_core::stream::Stream {
#[doc = r#"
Advances the stream and returns the next value.
@ -442,6 +448,54 @@ extension_trait! {
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#"
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
@ -1030,6 +1084,46 @@ extension_trait! {
Skip::new(self, n)
}
#[doc = r#"
A combinator that applies a function as long as it returns successfully, producing a single, final value.
Immediately returns the error when the function returns unsuccessfully.
# Examples
Basic usage:
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
let s: VecDeque<usize> = vec![1, 2, 3].into_iter().collect();
let sum = s.try_fold(0, |acc, v| {
if (acc+v) % 2 == 1 {
Ok(v+3)
} else {
Err("fail")
}
}).await;
assert_eq!(sum, Err("fail"));
#
# }) }
```
"#]
fn try_fold<B, F, T, E>(
self,
init: T,
f: F,
) -> impl Future<Output = Result<T, E>> [TryFoldFuture<Self, F, T>]
where
Self: Sized,
F: FnMut(B, Self::Item) -> Result<T, E>,
{
TryFoldFuture::new(self, init, f)
}
#[doc = r#"
Applies a falliable function to each element in a stream, stopping at first error and returning it.
@ -1172,7 +1266,7 @@ extension_trait! {
[`stream`]: trait.Stream.html#tymethod.next
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead (TODO)"]
fn collect<'a, B>(
@ -1211,7 +1305,7 @@ extension_trait! {
# });
```
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn merge<U>(self, other: U) -> Merge<Self, U>
where
@ -1226,12 +1320,15 @@ extension_trait! {
of another.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
use std::cmp::Ordering;
let s1 = VecDeque::from(vec![1]);
let s2 = VecDeque::from(vec![1, 2]);
let s3 = VecDeque::from(vec![1, 2, 3]);
@ -1256,6 +1353,189 @@ extension_trait! {
{
PartialCmpFuture::new(self, other)
}
#[doc = r#"
Lexicographically compares the elements of this `Stream` with those
of another using 'Ord'.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
use std::cmp::Ordering;
let s1 = VecDeque::from(vec![1]);
let s2 = VecDeque::from(vec![1, 2]);
let s3 = VecDeque::from(vec![1, 2, 3]);
let s4 = VecDeque::from(vec![1, 2, 4]);
assert_eq!(s1.clone().cmp(s1.clone()).await, Ordering::Equal);
assert_eq!(s1.clone().cmp(s2.clone()).await, Ordering::Less);
assert_eq!(s2.clone().cmp(s1.clone()).await, Ordering::Greater);
assert_eq!(s3.clone().cmp(s4.clone()).await, Ordering::Less);
assert_eq!(s4.clone().cmp(s3.clone()).await, Ordering::Greater);
#
# }) }
```
"#]
fn cmp<S>(
self,
other: S
) -> impl Future<Output = Ordering> [CmpFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: Ord
{
CmpFuture::new(self, other)
}
#[doc = r#"
Determines if the elements of this `Stream` are lexicographically
greater than or equal to those of another.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
let single: VecDeque<isize> = vec![1].into_iter().collect();
let single_gt: VecDeque<isize> = vec![10].into_iter().collect();
let multi: VecDeque<isize> = vec![1,2].into_iter().collect();
let multi_gt: VecDeque<isize> = vec![1,5].into_iter().collect();
assert_eq!(single.clone().ge(single.clone()).await, true);
assert_eq!(single_gt.clone().ge(single.clone()).await, true);
assert_eq!(multi.clone().ge(single_gt.clone()).await, false);
assert_eq!(multi_gt.clone().ge(multi.clone()).await, true);
#
# }) }
```
"#]
fn ge<S>(
self,
other: S
) -> impl Future<Output = bool> [GeFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: PartialOrd<S::Item>,
{
GeFuture::new(self, other)
}
#[doc = r#"
Determines if the elements of this `Stream` are lexicographically
greater than those of another.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
let single = VecDeque::from(vec![1]);
let single_gt = VecDeque::from(vec![10]);
let multi = VecDeque::from(vec![1,2]);
let multi_gt = VecDeque::from(vec![1,5]);
assert_eq!(single.clone().gt(single.clone()).await, false);
assert_eq!(single_gt.clone().gt(single.clone()).await, true);
assert_eq!(multi.clone().gt(single_gt.clone()).await, false);
assert_eq!(multi_gt.clone().gt(multi.clone()).await, true);
#
# }) }
```
"#]
fn gt<S>(
self,
other: S
) -> impl Future<Output = bool> [GtFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: PartialOrd<S::Item>,
{
GtFuture::new(self, other)
}
#[doc = r#"
Determines if the elements of this `Stream` are lexicographically
less or equal to those of another.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
let single = VecDeque::from(vec![1]);
let single_gt = VecDeque::from(vec![10]);
let multi = VecDeque::from(vec![1,2]);
let multi_gt = VecDeque::from(vec![1,5]);
assert_eq!(single.clone().le(single.clone()).await, true);
assert_eq!(single.clone().le(single_gt.clone()).await, true);
assert_eq!(multi.clone().le(single_gt.clone()).await, true);
assert_eq!(multi_gt.clone().le(multi.clone()).await, false);
#
# }) }
```
"#]
fn le<S>(
self,
other: S
) -> impl Future<Output = bool> [LeFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: PartialOrd<S::Item>,
{
LeFuture::new(self, other)
}
#[doc = r#"
Determines if the elements of this `Stream` are lexicographically
less than those of another.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use std::collections::VecDeque;
let single = VecDeque::from(vec![1]);
let single_gt = VecDeque::from(vec![10]);
let multi = VecDeque::from(vec![1,2]);
let multi_gt = VecDeque::from(vec![1,5]);
assert_eq!(single.clone().lt(single.clone()).await, false);
assert_eq!(single.clone().lt(single_gt.clone()).await, true);
assert_eq!(multi.clone().lt(single_gt.clone()).await, true);
assert_eq!(multi_gt.clone().lt(multi.clone()).await, false);
#
# }) }
```
"#]
fn lt<S>(
self,
other: S
) -> impl Future<Output = bool> [LtFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: PartialOrd<S::Item>,
{
LtFuture::new(self, other)
}
}
impl<S: Stream + Unpin + ?Sized> Stream for Box<S> {

@ -1,29 +1,30 @@
use std::cmp::Ordering;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::fuse::Fuse;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
// Lexicographically compares the elements of this `Stream` with those
// of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct PartialCmpFuture<L: Stream, R: Stream> {
l: Fuse<L>,
r: Fuse<R>,
l_cache: Option<L::Item>,
r_cache: Option<R::Item>,
pin_project! {
// Lexicographically compares the elements of this `Stream` with those
// of another.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct PartialCmpFuture<L: Stream, R: Stream> {
#[pin]
l: Fuse<L>,
#[pin]
r: Fuse<R>,
l_cache: Option<L::Item>,
r_cache: Option<R::Item>,
}
}
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 {
PartialCmpFuture {
l: l.fuse(),
@ -42,12 +43,13 @@ where
{
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 {
// Short circuit logic
// Stream that completes earliest can be considered Less, etc
let l_complete = self.l.done && self.as_mut().l_cache.is_none();
let r_complete = self.r.done && self.as_mut().r_cache.is_none();
let l_complete = this.l.done && this.l_cache.is_none();
let r_complete = this.r.done && this.r_cache.is_none();
if l_complete && r_complete {
return Poll::Ready(Some(Ordering::Equal));
@ -58,30 +60,30 @@ where
}
// Get next value if possible and necesary
if !self.l.done && self.as_mut().l_cache.is_none() {
let l_next = futures_core::ready!(self.as_mut().l().poll_next(cx));
if !this.l.done && this.l_cache.is_none() {
let l_next = futures_core::ready!(this.l.as_mut().poll_next(cx));
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() {
let r_next = futures_core::ready!(self.as_mut().r().poll_next(cx));
if !this.r.done && this.r_cache.is_none() {
let r_next = futures_core::ready!(this.r.as_mut().poll_next(cx));
if let Some(item) = r_next {
*self.as_mut().r_cache() = Some(item);
*this.r_cache = Some(item);
}
}
// Compare if both values are available.
if self.as_mut().l_cache.is_some() && self.as_mut().r_cache.is_some() {
let l_value = self.as_mut().l_cache().take().unwrap();
let r_value = self.as_mut().r_cache().take().unwrap();
if this.l_cache.is_some() && this.r_cache.is_some() {
let l_value = this.l_cache.as_mut().take().unwrap();
let r_value = this.r_cache.as_mut().take().unwrap();
let result = l_value.partial_cmp(&r_value);
if let Some(Ordering::Equal) = result {
// Reset cache to prepare for next comparison
*self.as_mut().l_cache() = None;
*self.as_mut().r_cache() = None;
*this.l_cache = None;
*this.r_cache = None;
} else {
// Return non equal value
return Poll::Ready(result);

@ -1,13 +1,18 @@
use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A stream to maintain state while polling another stream.
#[derive(Debug)]
pub struct Scan<S, St, F> {
stream: S,
state_f: (St, F),
pin_project! {
/// A stream to maintain state while polling another stream.
#[derive(Debug)]
pub struct Scan<S, St, F> {
#[pin]
stream: S,
state_f: (St, F),
}
}
impl<S, St, F> Scan<S, St, F> {
@ -17,13 +22,8 @@ impl<S, St, F> Scan<S, St, 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>
where
S: Stream,
@ -31,11 +31,12 @@ where
{
type Item = B;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<B>> {
let poll_result = self.as_mut().stream().poll_next(cx);
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<B>> {
let mut this = self.project();
let poll_result = this.stream.as_mut().poll_next(cx);
poll_result.map(|item| {
item.and_then(|item| {
let (state, f) = self.as_mut().state_f();
let (state, f) = this.state_f;
f(state, item)
})
})

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save