Merge branch 'master' into fs-stream-repeat-with

yoshuawuyts-patch-1
Yoshua Wuyts 5 years ago committed by GitHub
commit 822e4bc220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,20 +1,28 @@
on: pull_request
name: CI
on:
pull_request:
push:
branches:
- staging
- trying
jobs:
build_and_test:
name: Build and test on ${{ matrix.os }}
name: Build and test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
rust: [nightly]
steps:
- uses: actions/checkout@master
- name: Install nightly
- name: Install ${{ matrix.rust }}
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
toolchain: ${{ matrix.rust }}
override: true
- name: check
@ -41,12 +49,22 @@ jobs:
steps:
- uses: actions/checkout@master
- id: component
uses: actions-rs/components-nightly@v1
with:
component: rustfmt
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ steps.component.outputs.toolchain }}
override: true
- name: setup
run: |
rustup default nightly
rustup component add rustfmt
test -x $HOME/.cargo/bin/mdbook || ./ci/install-mdbook.sh
rustc --version
- name: mdbook
run: |
mdbook build docs
@ -54,4 +72,22 @@ jobs:
run: cargo fmt --all -- --check
- name: Docs
run: cargo doc --features docs,unstable
run: cargo doc --features docs
clippy_check:
name: Clippy check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- id: component
uses: actions-rs/components-nightly@v1
with:
component: clippy
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ steps.component.outputs.toolchain }}
override: true
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

@ -1,20 +0,0 @@
on: pull_request
name: Clippy check
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- id: component
uses: actions-rs/components-nightly@v1
with:
component: clippy
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ steps.component.outputs.toolchain }}
override: true
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

@ -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,unstable
- 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,59 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
## [Unreleased]
# [0.99.9] - 2019-10-08
This patch upgrades our `futures-rs` version, allowing us to build on the 1.39
beta. Additionally we've introduced `map` and `for_each` to `Stream`. And we've
added about a dozen new `FromStream` implementations for `std` types, bringing
us up to par with std's `FromIterator` implementations.
And finally we've added a new "unstable" `task::blocking` function which can be
used to convert blocking code into async code using a threadpool. We've been
using this internally for a while now to async-std to power our `fs` and
`net::SocketAddr` implementations. With this patch userland code now finally has
access to this too.
## Example
__Create a stream of tuples, and collect into a hashmap__
```rust
let a = stream::once(1u8);
let b = stream::once(0u8);
let s = a.zip(b);
let map: HashMap<u8, u8> = s.collect().await;
assert_eq!(map.get(&1), Some(&0u8));
```
__Spawn a blocking task on a dedicated threadpool__
```rust
task::blocking(async {
println!("long-running task here");
}).await;
```
## Added
- Added `stream::Stream::map`
- Added `stream::Stream::for_each`
- Added `stream::Stream::try_for_each`
- Added `task::blocking` as "unstable"
- Added `FromStream` for all `std::{option, collections, result, string, sync}` types.
- Added the `path` submodule as "unstable".
## Changed
- Updated `futures-preview` to `0.3.0-alpha.19`, allowing us to build on `rustc 1.39.0-beta`.
- As a consequence of this upgrade, all of our concrete stream implementations
now make use of `Stream::size_hint` to optimize internal allocations.
- We now use GitHub Actions through [actions-rs](https://github.com/actions-rs),
in addition to Travis CI. We intend to fully switch in the near future.
- Fixed a bug introduced in 0.99.6 where Unix Domain Listeners would sometimes become unresponsive.
- Updated our `sync::Barrier` docs to match std.
- Updated our `stream::FromStream` docs to match std's `FromIterator`.
# [0.99.8] - 2019-09-28
## Added
@ -130,7 +183,8 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
- Initial beta release
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.8...HEAD
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.9...HEAD
[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
[0.99.6]: https://github.com/async-rs/async-std/compare/v0.99.5...v0.99.6

@ -1,6 +1,6 @@
[package]
name = "async-std"
version = "0.99.8"
version = "0.99.9"
authors = [
"Stjepan Glavina <stjepang@gmail.com>",
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
@ -32,7 +32,7 @@ crossbeam-channel = "0.3.9"
crossbeam-deque = "0.7.1"
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"

@ -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 doc --features docs.rs --open
```
## Installation
Check out the [examples](examples). To run an example:
With [cargo add][cargo-add] installed run:
```sh
$ cargo add async-std
```
cargo 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>

@ -1 +1,7 @@
status = ["continuous-integration/travis-ci/push"]
status = [
"Build and test (ubuntu-latest, nightly)",
"Build and test (windows-latest, nightly)",
"Build and test (macOS-latest, nightly)",
"Checking fmt and docs",
"Clippy check",
]

@ -10,9 +10,9 @@ impl<T: Ord> Extend<T> for BinaryHeap<T> {
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let (lower_bound, _) = stream.size_hint();
//self.reserve(lower_bound);
self.reserve(stream.size_hint().0);
Box::pin(stream.for_each(move |item| self.push(item)))
}
}

@ -23,13 +23,12 @@ where
// hint lower bound if the map is empty. Otherwise reserve half the hint (rounded up), so
// the map will only resize twice in the worst case.
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let reserve = if self.is_empty() {
// stream.size_hint().0
//} else {
// (stream.size_hint().0 + 1) / 2
//};
//self.reserve(reserve);
let additional = if self.is_empty() {
stream.size_hint().0
} else {
(stream.size_hint().0 + 1) / 2
};
self.reserve(additional);
Box::pin(stream.for_each(move |(k, v)| {
self.insert(k, v);

@ -26,13 +26,12 @@ where
// hint lower bound if the map is empty. Otherwise reserve half the hint (rounded up), so
// the map will only resize twice in the worst case.
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let reserve = if self.is_empty() {
// stream.size_hint().0
//} else {
// (stream.size_hint().0 + 1) / 2
//};
//self.reserve(reserve);
let additional = if self.is_empty() {
stream.size_hint().0
} else {
(stream.size_hint().0 + 1) / 2
};
self.reserve(additional);
Box::pin(stream.for_each(move |item| {
self.insert(item);

@ -10,9 +10,6 @@ impl<T> Extend<T> for LinkedList<T> {
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let (lower_bound, _) = stream.size_hint();
//self.reserve(lower_bound);
Box::pin(stream.for_each(move |item| self.push_back(item)))
}
}

@ -10,9 +10,9 @@ impl<T> Extend<T> for VecDeque<T> {
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let (lower_bound, _) = stream.size_hint();
//self.reserve(lower_bound);
self.reserve(stream.size_hint().0);
Box::pin(stream.for_each(move |item| self.push_back(item)))
}
}

@ -1,6 +1,5 @@
use std::path::{Path, PathBuf};
use crate::io;
use crate::path::{Path, PathBuf};
use crate::task::blocking;
/// Returns the canonical form of a path.
@ -33,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) }).await
blocking::spawn(move || std::fs::canonicalize(&path).map(Into::into)).await
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Copies the contents and permissions of a file to a new location.
@ -42,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Creates a new directory.
@ -35,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Creates a new directory and all of its parents if they are missing.
@ -30,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,9 +1,9 @@
use std::path::Path;
use std::future::Future;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// A builder for creating directories with configurable options.
@ -14,7 +14,7 @@ use crate::task::blocking;
///
/// [`os::unix::fs::DirBuilderExt`]: ../os/unix/fs/trait.DirBuilderExt.html
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct DirBuilder {
/// Set to `true` if non-existent parent directories should be created.
recursive: bool,
@ -109,7 +109,7 @@ 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 }
}
}

@ -1,12 +1,12 @@
use std::ffi::OsString;
use std::fmt;
use std::path::PathBuf;
use std::sync::Arc;
use cfg_if::cfg_if;
use crate::fs::{FileType, Metadata};
use crate::io;
use crate::path::PathBuf;
use crate::task::blocking;
/// An entry in a directory.
@ -50,7 +50,7 @@ impl DirEntry {
/// # Ok(()) }) }
/// ```
pub fn path(&self) -> PathBuf {
self.0.path()
self.0.path().into()
}
/// Reads the metadata for this entry.
@ -89,7 +89,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 +127,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.

@ -3,7 +3,6 @@ use std::cmp;
use std::fmt;
use std::io::{Read as _, Seek as _, Write as _};
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
@ -13,6 +12,7 @@ use cfg_if::cfg_if;
use crate::fs::{Metadata, Permissions};
use crate::future;
use crate::io::{self, Read, Seek, SeekFrom, Write};
use crate::path::Path;
use crate::prelude::*;
use crate::task::{self, blocking, Context, Poll, Waker};
@ -97,7 +97,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 +132,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 +165,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 +201,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 +234,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 +253,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 +282,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
}
}
@ -702,7 +702,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 +811,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 +844,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,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Creates a hard link on the filesystem.
@ -33,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,8 +1,7 @@
use std::path::Path;
use cfg_if::cfg_if;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Reads metadata for a path.
@ -37,7 +36,7 @@ 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_if! {

@ -1,10 +1,10 @@
use std::path::Path;
use std::future::Future;
use cfg_if::cfg_if;
use crate::fs::File;
use crate::future::Future;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// A builder for opening files with configurable options.
@ -286,7 +286,13 @@ 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 }
}
}
impl Default for OpenOptions {
fn default() -> Self {
Self::new()
}
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Reads the entire contents of a file as raw bytes.
@ -37,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
}

@ -1,11 +1,11 @@
use std::path::Path;
use std::pin::Pin;
use crate::fs::DirEntry;
use crate::future::Future;
use crate::io;
use crate::path::Path;
use crate::stream::Stream;
use crate::task::{blocking, Context, Poll};
use crate::task::{blocking, Context, JoinHandle, Poll};
/// Returns a stream of entries in a directory.
///
@ -45,7 +45,7 @@ use crate::task::{blocking, Context, 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)
}
@ -71,7 +71,7 @@ pub struct ReadDir(State);
#[derive(Debug)]
enum State {
Idle(Option<std::fs::ReadDir>),
Busy(blocking::JoinHandle<(std::fs::ReadDir, Option<io::Result<std::fs::DirEntry>>)>),
Busy(JoinHandle<(std::fs::ReadDir, Option<io::Result<std::fs::DirEntry>>)>),
}
impl ReadDir {
@ -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)
}));

@ -1,6 +1,5 @@
use std::path::{Path, PathBuf};
use crate::io;
use crate::path::{Path, PathBuf};
use crate::task::blocking;
/// Reads a symbolic link and returns the path it points to.
@ -29,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) }).await
blocking::spawn(move || std::fs::read_link(path).map(Into::into)).await
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Reads the entire contents of a file as a string.
@ -38,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Removes an empty directory.
@ -30,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Removes a directory and all of its contents.
@ -30,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Removes a file.
@ -30,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Renames a file or directory to a new location.
@ -35,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
}

@ -1,7 +1,6 @@
use std::path::Path;
use crate::fs::Permissions;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Changes the permissions of a file or directory.
@ -33,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
}

@ -1,7 +1,6 @@
use std::path::Path;
use crate::fs::Metadata;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Reads metadata for a path without following symbolic links.
@ -35,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
}

@ -1,6 +1,5 @@
use std::path::Path;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Writes a slice of bytes as the new contents of a file.
@ -34,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,145 @@
use crate::utils::extension_trait;
cfg_if::cfg_if! {
if #[cfg(feature = "docs")] {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::task::{Context, Poll};
}
}
extension_trait! {
#[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(any(feature = "unstable", feature = "docs"))]
#[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
}
}

@ -42,25 +42,30 @@
//! | `future::try_select` | `Result<T, E>` | Return on first `Ok`, reject on last Err
#[doc(inline)]
pub use std::future::Future;
pub use async_macros::{join, try_join};
#[doc(inline)]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub use async_macros::{join, select, try_join, try_select};
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_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod timeout;
pub use timeout::{timeout, TimeoutError};
mod into_future;
pub use into_future::IntoFuture;
}
}

@ -9,7 +9,7 @@ use crate::task::{Context, Poll};
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use std::time::Duration;
///
@ -22,7 +22,7 @@ use crate::task::{Context, Poll};
/// let res: io::Result<()> = io::timeout(dur, fut).await;
/// assert!(res.is_err());
/// #
/// # }) }
/// # })
/// ```
pub async fn pending<T>() -> T {
let fut = Pending {

@ -10,7 +10,7 @@ use crate::task::{Context, Poll};
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::future;
/// use async_std::task::{Context, Poll};
@ -21,7 +21,7 @@ use crate::task::{Context, Poll};
///
/// assert_eq!(future::poll_fn(poll_greeting).await, "hello world");
/// #
/// # }) }
/// # })
/// ```
pub async fn poll_fn<F, T>(f: F) -> T
where

@ -7,13 +7,13 @@
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::future;
///
/// assert_eq!(future::ready(10).await, 10);
/// #
/// # }) }
/// # })
/// ```
pub async fn ready<T>(val: T) -> T {
val

@ -28,8 +28,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>,
@ -42,8 +40,6 @@ where
}
/// A future that times out after a duration of time.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
struct TimeoutFuture<F> {
future: F,
delay: Delay,
@ -69,8 +65,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: (),

@ -1,8 +1,11 @@
mod lines;
mod read_line;
mod read_until;
mod split;
pub use lines::Lines;
pub use split::Split;
use read_line::ReadLineFuture;
use read_until::ReadUntilFuture;
@ -41,7 +44,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.
@ -64,7 +67,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.
@ -226,6 +231,57 @@ extension_trait! {
read: 0,
}
}
#[doc = r#"
Returns a stream over the contents of this reader split on the byte `byte`.
The stream returned from this function will return instances of
[`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
the delimiter byte at the end.
This function will yield errors whenever [`read_until`] would have
also yielded an error.
[`io::Result`]: type.Result.html
[`Vec<u8>`]: ../vec/struct.Vec.html
[`read_until`]: #method.read_until
# Examples
[`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
this example, we use [`Cursor`] to iterate over all hyphen delimited
segments in a byte slice
[`Cursor`]: struct.Cursor.html
```
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::io;
let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
assert_eq!(split_iter.next().await, Some(b"lorem".to_vec()));
assert_eq!(split_iter.next().await, Some(b"ipsum".to_vec()));
assert_eq!(split_iter.next().await, Some(b"dolor".to_vec()));
assert_eq!(split_iter.next().await, None);
#
# Ok(()) }) }
```
"#]
fn split(self, byte: u8) -> Split<Self>
where
Self: Sized,
{
Split {
reader: self,
buf: Vec::new(),
delim: byte,
read: 0,
}
}
}
impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> {

@ -0,0 +1,46 @@
use std::mem;
use std::pin::Pin;
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,
}
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() {
return Poll::Ready(None);
}
if buf[buf.len() - 1] == *delim {
buf.pop();
}
Poll::Ready(Some(Ok(mem::replace(buf, vec![]))))
}
}

@ -1,10 +1,12 @@
use crate::task::{Context, Poll};
use futures_core::ready;
use futures_io::{AsyncSeek, AsyncWrite, SeekFrom};
use std::fmt;
use std::io;
use std::pin::Pin;
use futures_core::ready;
use crate::io::write::WriteExt;
use crate::io::{self, Seek, SeekFrom, Write};
use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024;
/// Wraps a writer and buffers its output.
@ -82,7 +84,10 @@ pub struct BufWriter<W> {
written: usize,
}
impl<W: AsyncWrite> BufWriter<W> {
#[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>);
@ -173,23 +178,35 @@ impl<W: AsyncWrite> BufWriter<W> {
&mut self.inner
}
// pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut W> {
// self.inner()
// }
/// Consumes BufWriter, returning the underlying writer
///
/// This method will not write leftover data, it will be lost.
/// For method that will attempt to write before returning the writer see [`poll_into_inner`]
///
/// [`poll_into_inner`]: #method.poll_into_inner
pub fn into_inner(self) -> W {
self.inner
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
///
/// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34251").await?);
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buf_writer.into_inner().await.unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>>
where
Self: Unpin,
{
match self.flush().await {
Err(e) => Err(IntoInnerError(self, e)),
Ok(()) => Ok(self.inner),
}
}
// pub fn poll_into_inner(self: Pin<&mut Self>, _cx: Context<'_>) -> Poll<io::Result<usize>> {
// unimplemented!("poll into inner method")
// }
/// Returns a reference to the internally buffered data.
///
@ -251,7 +268,7 @@ impl<W: AsyncWrite> BufWriter<W> {
}
}
impl<W: AsyncWrite> AsyncWrite for BufWriter<W> {
impl<W: Write> Write for BufWriter<W> {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -278,7 +295,7 @@ impl<W: AsyncWrite> AsyncWrite for BufWriter<W> {
}
}
impl<W: AsyncWrite + fmt::Debug> fmt::Debug for BufWriter<W> {
impl<W: Write + fmt::Debug> fmt::Debug for BufWriter<W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BufReader")
.field("writer", &self.inner)
@ -287,11 +304,10 @@ impl<W: AsyncWrite + fmt::Debug> fmt::Debug for BufWriter<W> {
}
}
impl<W: AsyncWrite + AsyncSeek> AsyncSeek for BufWriter<W> {
impl<W: Write + Seek> Seek for BufWriter<W> {
/// Seek to the offset, in bytes, in the underlying writer.
///
/// Seeking always writes out the internal buffer before seeking.
fn poll_seek(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -301,80 +317,3 @@ impl<W: AsyncWrite + AsyncSeek> AsyncSeek for BufWriter<W> {
self.inner().poll_seek(cx, pos)
}
}
mod tests {
#![allow(unused_imports)]
use super::BufWriter;
use crate::io::{self, SeekFrom};
use crate::prelude::*;
use crate::task;
#[test]
fn test_buffered_writer() {
task::block_on(async {
let inner = Vec::new();
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).await.unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).await.unwrap();
assert_eq!(writer.buffer(), [2]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).await.unwrap();
assert_eq!(writer.buffer(), [2, 3]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().await.unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).await.unwrap();
writer.write(&[5]).await.unwrap();
assert_eq!(writer.buffer(), [4, 5]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).await.unwrap();
assert_eq!(writer.buffer(), [6]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).await.unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).await.unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().await.unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
})
}
#[test]
fn test_buffered_writer_inner_into_inner_does_not_flush() {
task::block_on(async {
let mut w = BufWriter::with_capacity(3, Vec::new());
w.write(&[0, 1]).await.unwrap();
assert_eq!(*w.get_ref(), []);
let w = w.into_inner();
assert_eq!(w, []);
})
}
#[test]
fn test_buffered_writer_seek() {
task::block_on(async {
let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new()));
w.write_all(&[0, 1, 2, 3, 4, 5]).await.unwrap();
w.write_all(&[6, 7]).await.unwrap();
assert_eq!(w.seek(SeekFrom::Current(0)).await.ok(), Some(8));
assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
assert_eq!(w.seek(SeekFrom::Start(2)).await.ok(), Some(2));
})
}
}

@ -21,7 +21,6 @@ use crate::task::{Context, Poll};
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
/// [bytes]: https://doc.rust-lang.org/std/primitive.slice.html
/// [`File`]: struct.File.html
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Clone, Debug, Default)]
pub struct Cursor<T> {
inner: std::io::Cursor<T>,

@ -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
//!
//! 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;
//!
//! # 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(()) }) }
//! ```
//!
//! Read a line from the standard input:
//! 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::*;
//!
//! 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 {
//! #
//! 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};
@ -39,6 +288,10 @@ pub use stdout::{stdout, Stdout};
pub use timeout::timeout;
pub use write::Write;
// For use in the print macros.
#[doc(hidden)]
pub use stdio::{_eprint, _print};
pub mod prelude;
pub(crate) mod buf_read;
@ -55,5 +308,6 @@ mod repeat;
mod sink;
mod stderr;
mod stdin;
mod stdio;
mod stdout;
mod timeout;

@ -50,7 +50,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 +70,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.

@ -33,7 +33,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 +42,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 +72,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,
{

@ -5,7 +5,7 @@ use cfg_if::cfg_if;
use crate::future::Future;
use crate::io::{self, Write};
use crate::task::{blocking, Context, Poll};
use crate::task::{blocking, Context, JoinHandle, Poll};
/// Constructs a new handle to the standard error of the current process.
///
@ -56,7 +56,7 @@ enum State {
/// The stderr is blocked on an asynchronous operation.
///
/// Awaiting this operation will result in the new state of the stderr.
Busy(blocking::JoinHandle<State>),
Busy(JoinHandle<State>),
}
/// Inner representation of the asynchronous stderr.
@ -116,8 +116,8 @@ impl Write for Stderr {
inner.buf[..buf.len()].copy_from_slice(buf);
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
let res = std::io::Write::write(&mut inner.stderr, &mut inner.buf);
*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))
}));
@ -144,7 +144,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))

@ -5,7 +5,7 @@ use cfg_if::cfg_if;
use crate::future::{self, Future};
use crate::io::{self, Read};
use crate::task::{blocking, Context, Poll};
use crate::task::{blocking, Context, JoinHandle, Poll};
/// Constructs a new handle to the standard input of the current process.
///
@ -57,7 +57,7 @@ enum State {
/// The stdin is blocked on an asynchronous operation.
///
/// Awaiting this operation will result in the new state of the stdin.
Busy(blocking::JoinHandle<State>),
Busy(JoinHandle<State>),
}
/// Inner representation of the asynchronous stdin.
@ -119,7 +119,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));
@ -172,7 +172,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))

@ -0,0 +1,21 @@
//! Internal types for stdio.
//!
//! This module is a port of `libstd/io/stdio.rs`,and contains internal types for `print`/`eprint`.
use crate::io::{stderr, stdout};
use crate::prelude::*;
use std::fmt;
#[doc(hidden)]
pub async fn _print(args: fmt::Arguments<'_>) {
if let Err(e) = stdout().write_fmt(args).await {
panic!("failed printing to stdout: {}", e);
}
}
#[doc(hidden)]
pub async fn _eprint(args: fmt::Arguments<'_>) {
if let Err(e) = stderr().write_fmt(args).await {
panic!("failed printing to stderr: {}", e);
}
}

@ -5,7 +5,7 @@ use cfg_if::cfg_if;
use crate::future::Future;
use crate::io::{self, Write};
use crate::task::{blocking, Context, Poll};
use crate::task::{blocking, Context, JoinHandle, Poll};
/// Constructs a new handle to the standard output of the current process.
///
@ -56,7 +56,7 @@ enum State {
/// The stdout is blocked on an asynchronous operation.
///
/// Awaiting this operation will result in the new state of the stdout.
Busy(blocking::JoinHandle<State>),
Busy(JoinHandle<State>),
}
/// Inner representation of the asynchronous stdout.
@ -116,8 +116,8 @@ impl Write for Stdout {
inner.buf[..buf.len()].copy_from_slice(buf);
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
let res = std::io::Write::write(&mut inner.stdout, &mut inner.buf);
*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))
}));
@ -144,7 +144,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))

@ -1,6 +1,9 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use futures_timer::TryFutureExt;
use futures_timer::Delay;
use pin_utils::unsafe_pinned;
use crate::future::Future;
use crate::io;
@ -33,5 +36,48 @@ pub async fn timeout<F, T>(dur: Duration, f: F) -> io::Result<T>
where
F: Future<Output = io::Result<T>>,
{
f.timeout(dur).await
Timeout {
timeout: Delay::new(dur),
future: f,
}
.await
}
/// Future returned by the `FutureExt::timeout` method.
#[derive(Debug)]
pub struct Timeout<F, T>
where
F: Future<Output = io::Result<T>>,
{
future: F,
timeout: Delay,
}
impl<F, T> Timeout<F, T>
where
F: Future<Output = io::Result<T>>,
{
unsafe_pinned!(future: F);
unsafe_pinned!(timeout: Delay);
}
impl<F, T> Future for Timeout<F, T>
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().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());
Poll::Ready(err)
} else {
Poll::Pending
}
}
}

@ -1,11 +1,13 @@
mod flush;
mod write;
mod write_all;
mod write_fmt;
mod write_vectored;
use flush::FlushFuture;
use write::WriteFuture;
use write_all::WriteAllFuture;
use write_fmt::WriteFmtFuture;
use write_vectored::WriteVectoredFuture;
use cfg_if::cfg_if;
@ -13,12 +15,12 @@ use cfg_if::cfg_if;
use crate::io::IoSlice;
use crate::utils::extension_trait;
use crate::io;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::io;
use crate::task::{Context, Poll};
}
}
@ -47,7 +49,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.
"#]
@ -78,7 +80,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.
@ -197,6 +201,50 @@ extension_trait! {
{
WriteAllFuture { writer: self, buf }
}
#[doc = r#"
Writes a formatted string into this writer, returning any error encountered.
This method will continuously call [`write`] until there is no more data to be
written or an error is returned. This future will not resolve until the entire
buffer has been successfully written or such an error occurs.
[`write`]: #tymethod.write
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::io::prelude::*;
use async_std::fs::File;
let mut buffer = File::create("foo.txt").await?;
// this call
write!(buffer, "{:.*}", 2, 1.234567).await?;
// turns into this:
buffer.write_fmt(format_args!("{:.*}", 2, 1.234567)).await?;
#
# Ok(()) }) }
```
"#]
fn write_fmt<'a>(
&'a mut self,
fmt: std::fmt::Arguments<'_>,
) -> impl Future<Output = io::Result<()>> + 'a [WriteFmtFuture<'a, Self>]
where
Self: Unpin,
{
// In order to not have to implement an async version of `fmt` including private types
// and all, we convert `Arguments` to a `Result<Vec<u8>>` and pass that to the Future.
// Doing an owned conversion saves us from juggling references.
let mut string = String::new();
let res = std::fmt::write(&mut string, fmt)
.map(|_| string.into_bytes())
.map_err(|_| io::Error::new(io::ErrorKind::Other, "formatter error"));
WriteFmtFuture { writer: self, res: Some(res), buffer: None, amt: 0 }
}
}
impl<T: Write + Unpin + ?Sized> Write for Box<T> {

@ -0,0 +1,50 @@
use std::pin::Pin;
use crate::future::Future;
use crate::io::{self, Write};
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct WriteFmtFuture<'a, T: Unpin + ?Sized> {
pub(crate) writer: &'a mut T,
pub(crate) res: Option<io::Result<Vec<u8>>>,
pub(crate) buffer: Option<Vec<u8>>,
pub(crate) amt: u64,
}
impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Process the interal Result the first time we run.
if self.buffer.is_none() {
match self.res.take().unwrap() {
Err(err) => return Poll::Ready(Err(err)),
Ok(buffer) => self.buffer = Some(buffer),
};
}
// Get the types from the future.
let Self {
writer,
amt,
buffer,
..
} = &mut *self;
let mut buffer = buffer.as_mut().unwrap();
// Copy the data from the buffer into the writer until it's done.
loop {
if *amt == buffer.len() as u64 {
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))?;
if i == 0 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
*amt += i as u64;
}
}
}

@ -55,6 +55,7 @@ pub mod future;
pub mod io;
pub mod net;
pub mod os;
pub mod path;
pub mod prelude;
pub mod stream;
pub mod sync;
@ -64,6 +65,8 @@ 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;
mod unit;
mod vec;
@ -74,4 +77,10 @@ cfg_if! {
}
}
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};

@ -0,0 +1,163 @@
/// Prints to the standard output.
///
/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [`println!`]: macro.println.html
/// [flush]: io/trait.Write.html#tymethod.flush
/// [`eprint!`]: macro.eprint.html
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::io;
/// use async_std::print;
///
/// print!("this ").await;
/// print!("will ").await;
/// print!("be ").await;
/// print!("on ").await;
/// print!("the ").await;
/// print!("same ").await;
/// print!("line ").await;
///
/// io::stdout().flush().await.unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n").await;
///
/// io::stdout().flush().await.unwrap();
/// #
/// # })
/// ```
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)))
}
/// Prints to the standard output, with a newline.
///
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// [`format!`]: macro.format.html
/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
/// [`eprintln!`]: macro.eprintln.html
/// # Panics
///
/// Panics if writing to `io::stdout` fails.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// #
/// use async_std::println;
///
/// println!().await; // prints just a newline
/// println!("hello there!").await;
/// println!("format {} arguments", "some").await;
/// #
/// # })
/// ```
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)))
}
/// Prints to the standard error.
///
/// Equivalent to the [`print!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: io/struct.Stderr.html
/// [`print!`]: macro.print.html
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// #
/// use async_std::eprint;
///
/// eprint!("Error: Could not complete task").await;
/// #
/// # })
/// ```
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[macro_export]
macro_rules! eprint {
($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)))
}
/// Prints to the standard error, with a newline.
///
/// Equivalent to the [`println!`] macro, except that output goes to
/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: io/struct.Stderr.html
/// [`println!`]: macro.println.html
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// #
/// use async_std::eprintln;
///
/// eprintln!("Error: Could not complete task").await;
/// #
/// # })
/// ```
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[macro_export]
macro_rules! eprintln {
() => (async { $crate::eprint!("\n").await; });
($($arg:tt)*) => (
async {
$crate::io::_eprint(format_args!($($arg)*)).await;
}
);
}

@ -1,4 +1,4 @@
use std::marker::PhantomData;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::pin::Pin;
@ -7,30 +7,42 @@ use cfg_if::cfg_if;
use crate::future::Future;
use crate::io;
use crate::task::blocking;
use crate::task::{Context, Poll};
use crate::task::{blocking, Context, JoinHandle, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
macro_rules! ret {
($a:lifetime, $f:tt, $i:ty) => (ImplFuture<$a, io::Result<$i>>);
(impl Future<Output = $out:ty>, $fut:ty) => (ImplFuture<$out>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $i:ty) => ($f<$a, $i>);
(impl Future<Output = $out:ty>, $fut:ty) => ($fut);
}
}
}
/// A trait for objects which can be converted or resolved to one or more [`SocketAddr`] values.
/// Converts or resolves addresses to [`SocketAddr`] values.
///
/// This trait is an async version of [`std::net::ToSocketAddrs`].
///
/// [`std::net::ToSocketAddrs`]: https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html
/// [`SocketAddr`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html
/// [`SocketAddr`]: enum.SocketAddr.html
///
/// # Examples
///
/// ```
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::ToSocketAddrs;
///
/// let addr = "localhost:8080".to_socket_addrs().await?.next().unwrap();
/// println!("resolved: {:?}", addr);
/// #
/// # Ok(()) }) }
/// ```
pub trait ToSocketAddrs {
/// Returned iterator over socket addresses which this type may correspond to.
type Iter: Iterator<Item = SocketAddr>;
@ -41,28 +53,39 @@ pub trait ToSocketAddrs {
/// resolution performed.
///
/// Note that this function may block a backend thread while resolution is performed.
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter);
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
);
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub enum ToSocketAddrsFuture<'a, I> {
Phantom(PhantomData<&'a ()>),
Join(blocking::JoinHandle<io::Result<I>>),
Ready(Option<io::Result<I>>),
pub enum ToSocketAddrsFuture<I> {
Resolving(JoinHandle<io::Result<I>>),
Ready(io::Result<I>),
Done,
}
impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<'_, I> {
impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<I> {
type Output = io::Result<I>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match unsafe { self.get_unchecked_mut() } {
ToSocketAddrsFuture::Join(f) => Pin::new(&mut *f).poll(cx),
ToSocketAddrsFuture::Ready(res) => {
let res = res.take().expect("polled a completed future");
Poll::Ready(res)
let this = unsafe { self.get_unchecked_mut() };
let state = mem::replace(this, ToSocketAddrsFuture::Done);
match state {
ToSocketAddrsFuture::Resolving(mut task) => {
let poll = Pin::new(&mut task).poll(cx);
if poll.is_pending() {
*this = ToSocketAddrsFuture::Resolving(task);
}
_ => unreachable!(),
poll
}
ToSocketAddrsFuture::Ready(res) => Poll::Ready(res),
ToSocketAddrsFuture::Done => panic!("polled a completed future"),
}
}
}
@ -70,87 +93,157 @@ impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<'_, I> {
impl ToSocketAddrs for SocketAddr {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
ToSocketAddrsFuture::Ready(Ok(Some(*self).into_iter()))
}
}
impl ToSocketAddrs for SocketAddrV4 {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
SocketAddr::V4(*self).to_socket_addrs()
}
}
impl ToSocketAddrs for SocketAddrV6 {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
SocketAddr::V6(*self).to_socket_addrs()
}
}
impl ToSocketAddrs for (IpAddr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
let (ip, port) = *self;
match ip {
IpAddr::V4(a) => (a, port).to_socket_addrs(),
IpAddr::V6(a) => (a, port).to_socket_addrs(),
}
}
}
impl ToSocketAddrs for (Ipv4Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
let (ip, port) = *self;
SocketAddrV4::new(ip, port).to_socket_addrs()
}
}
impl ToSocketAddrs for (Ipv6Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
let (ip, port) = *self;
SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs()
}
}
impl ToSocketAddrs for (&str, u16) {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
let host = self.0.to_string();
let port = self.1;
let join = blocking::spawn(async move {
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
let (host, port) = *self;
if let Ok(addr) = host.parse::<Ipv4Addr>() {
let addr = SocketAddrV4::new(addr, port);
return ToSocketAddrsFuture::Ready(Ok(vec![SocketAddr::V4(addr)].into_iter()));
}
if let Ok(addr) = host.parse::<Ipv6Addr>() {
let addr = SocketAddrV6::new(addr, port, 0, 0);
return ToSocketAddrsFuture::Ready(Ok(vec![SocketAddr::V6(addr)].into_iter()));
}
let host = host.to_string();
let task = blocking::spawn(move || {
std::net::ToSocketAddrs::to_socket_addrs(&(host.as_str(), port))
});
ToSocketAddrsFuture::Join(join)
ToSocketAddrsFuture::Resolving(task)
}
}
impl ToSocketAddrs for str {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
let socket_addrs = self.to_string();
let join =
blocking::spawn(async move { std::net::ToSocketAddrs::to_socket_addrs(&socket_addrs) });
ToSocketAddrsFuture::Join(join)
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
if let Some(addr) = self.parse().ok() {
return ToSocketAddrsFuture::Ready(Ok(vec![addr].into_iter()));
}
let addr = self.to_string();
let task = blocking::spawn(move || std::net::ToSocketAddrs::to_socket_addrs(addr.as_str()));
ToSocketAddrsFuture::Resolving(task)
}
}
impl<'a> ToSocketAddrs for &'a [SocketAddr] {
type Iter = std::iter::Cloned<std::slice::Iter<'a, SocketAddr>>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrsFuture::Ready(Some(std::net::ToSocketAddrs::to_socket_addrs(self)))
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
ToSocketAddrsFuture::Ready(Ok(self.iter().cloned()))
}
}
impl<T: ToSocketAddrs + ?Sized> ToSocketAddrs for &T {
type Iter = T::Iter;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
(**self).to_socket_addrs()
}
}
@ -158,7 +251,12 @@ impl<T: ToSocketAddrs + ?Sized> ToSocketAddrs for &T {
impl ToSocketAddrs for String {
type Iter = std::vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
ToSocketAddrs::to_socket_addrs(self.as_str())
fn to_socket_addrs(
&self,
) -> ret!(
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
(&**self).to_socket_addrs()
}
}

@ -28,6 +28,11 @@
//! # }) }
//! ```
pub use std::net::AddrParseError;
pub use std::net::Shutdown;
pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
pub use addr::ToSocketAddrs;
pub use tcp::{Incoming, TcpListener, TcpStream};
pub use udp::UdpSocket;

@ -76,7 +76,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 {

@ -391,14 +391,14 @@ impl UdpSocket {
/// let mdns_addr = Ipv4Addr::new(224, 0, 0, 123);
///
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// socket.join_multicast_v4(&mdns_addr, &interface)?;
/// socket.join_multicast_v4(mdns_addr, interface)?;
/// #
/// # Ok(()) }) }
/// ```
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
self.watcher
.get_ref()
.join_multicast_v4(multiaddr, interface)
.join_multicast_v4(&multiaddr, &interface)
}
/// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type.
@ -435,10 +435,10 @@ impl UdpSocket {
/// For more information about this option, see [`join_multicast_v4`].
///
/// [`join_multicast_v4`]: #method.join_multicast_v4
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
self.watcher
.get_ref()
.leave_multicast_v4(multiaddr, interface)
.leave_multicast_v4(&multiaddr, &interface)
}
/// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.

@ -1,10 +1,9 @@
//! Unix-specific filesystem extensions.
use std::path::Path;
use cfg_if::cfg_if;
use crate::io;
use crate::path::Path;
use crate::task::blocking;
/// Creates a new symbolic link on the filesystem.
@ -29,7 +28,7 @@ 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! {

@ -2,7 +2,6 @@
use std::fmt;
use std::net::Shutdown;
use std::path::Path;
use mio_uds;
@ -11,6 +10,7 @@ use crate::future;
use crate::io;
use crate::net::driver::Watcher;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::Path;
use crate::task::blocking;
/// A Unix datagram socket.
@ -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))
}

@ -1,7 +1,6 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::path::Path;
use std::pin::Pin;
use mio_uds;
@ -12,6 +11,7 @@ use crate::future::{self, Future};
use crate::io;
use crate::net::driver::Watcher;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::Path;
use crate::stream::Stream;
use crate::task::{blocking, Context, Poll};
@ -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),
@ -93,11 +93,16 @@ impl UnixListener {
/// ```
pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
future::poll_fn(|cx| {
let res =
futures_core::ready!(self.watcher.poll_read_with(cx, |inner| inner.accept_std()));
let res = futures_core::ready!(self.watcher.poll_read_with(cx, |inner| {
match inner.accept_std() {
// Converting to `WouldBlock` so that the watcher will
// add the waker of this task to a list of readers.
Ok(None) => Err(io::ErrorKind::WouldBlock.into()),
res => res,
}
}));
match res? {
None => Poll::Pending,
Some((io, addr)) => {
let mio_stream = mio_uds::UnixStream::from_stream(io)?;
let stream = UnixStream {
@ -105,6 +110,8 @@ impl UnixListener {
};
Poll::Ready(Ok((stream, addr)))
}
// This should never happen since `None` is converted to `WouldBlock`
None => unreachable!(),
}
})
.await

@ -13,7 +13,8 @@ mod stream;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::fmt;
use std::path::Path;
use crate::path::Path;
/// An address associated with a Unix socket.
///
@ -65,9 +66,8 @@ cfg_if! {
/// With a pathname:
///
/// ```no_run
/// use std::path::Path;
///
/// use async_std::os::unix::net::UnixListener;
/// use async_std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;

@ -3,7 +3,6 @@
use std::fmt;
use std::io::{Read as _, Write as _};
use std::net::Shutdown;
use std::path::Path;
use std::pin::Pin;
use mio_uds;
@ -12,6 +11,7 @@ use super::SocketAddr;
use crate::io::{self, Read, Write};
use crate::net::driver::Watcher;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::Path;
use crate::task::{blocking, Context, Poll};
/// A Unix stream socket.
@ -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 {

@ -0,0 +1,39 @@
use std::iter::FusedIterator;
use crate::path::Path;
/// An iterator over [`Path`] and its ancestors.
///
/// This `struct` is created by the [`ancestors`] method on [`Path`].
/// See its documentation for more.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("/foo/bar");
///
/// for ancestor in path.ancestors() {
/// println!("{}", ancestor.display());
/// }
/// ```
///
/// [`ancestors`]: struct.Path.html#method.ancestors
/// [`Path`]: struct.Path.html
#[derive(Copy, Clone, Debug)]
pub struct Ancestors<'a> {
pub(crate) next: Option<&'a Path>,
}
impl<'a> Iterator for Ancestors<'a> {
type Item = &'a Path;
fn next(&mut self) -> Option<Self::Item> {
let next = self.next;
self.next = next.and_then(Path::parent);
next
}
}
impl FusedIterator for Ancestors<'_> {}

@ -0,0 +1,29 @@
//! Cross-platform path manipulation.
//!
//! This module is an async version of [`std::path`].
//!
//! [`std::path`]: https://doc.rust-lang.org/std/path/index.html
mod ancestors;
mod path;
mod pathbuf;
// Structs re-export
#[doc(inline)]
pub use std::path::{Components, Display, Iter, PrefixComponent, StripPrefixError};
// Enums re-export
#[doc(inline)]
pub use std::path::{Component, Prefix};
// Constants re-export
#[doc(inline)]
pub use std::path::MAIN_SEPARATOR;
// Functions re-export
#[doc(inline)]
pub use std::path::is_separator;
use ancestors::Ancestors;
pub use path::Path;
pub use pathbuf::PathBuf;

@ -0,0 +1,812 @@
use std::ffi::OsStr;
use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixError};
use crate::{fs, io};
/// This struct is an async version of [`std::path::Path`].
///
/// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
#[derive(Debug, PartialEq)]
pub struct Path {
inner: std::path::Path,
}
impl Path {
/// Directly wraps a string slice as a `Path` slice.
///
/// This is a cost-free conversion.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// Path::new("foo.txt");
/// ```
///
/// You can create `Path`s from `String`s, or even other `Path`s:
///
/// ```
/// use async_std::path::Path;
///
/// let string = String::from("foo.txt");
/// let from_string = Path::new(&string);
/// let from_path = Path::new(&from_string);
/// assert_eq!(from_string, from_path);
/// ```
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
unsafe { &*(std::path::Path::new(s) as *const std::path::Path as *const Path) }
}
/// Yields the underlying [`OsStr`] slice.
///
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn as_os_str(&self) -> &OsStr {
self.inner.as_os_str()
}
/// Yields a [`&str`] slice if the `Path` is valid unicode.
///
/// This conversion may entail doing a check for UTF-8 validity.
/// Note that validation is performed because non-UTF-8 strings are
/// perfectly valid for some OS.
///
/// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("foo.txt");
/// assert_eq!(path.to_str(), Some("foo.txt"));
/// ```
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
}
/// Converts a `Path` to a [`Cow<str>`].
///
/// Any non-Unicode sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
/// [`Cow<str>`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html
/// [U+FFFD]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
///
/// # Examples
///
/// Calling `to_string_lossy` on a `Path` with valid unicode:
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("foo.txt");
/// assert_eq!(path.to_string_lossy(), "foo.txt");
/// ```
///
/// Had `path` contained invalid unicode, the `to_string_lossy` call might
/// have returned `"fo<66>.txt"`.
pub fn to_string_lossy(&self) -> std::borrow::Cow<'_, str> {
self.inner.to_string_lossy()
}
/// Converts a `Path` to an owned [`PathBuf`].
///
/// [`PathBuf`]: struct.PathBuf.html
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let path_buf = Path::new("foo.txt").to_path_buf();
/// assert_eq!(path_buf, PathBuf::from("foo.txt"));
/// ```
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.inner.to_path_buf())
}
/// Returns `true` if the `Path` is absolute, i.e., if it is independent of
/// the current directory.
///
/// * On Unix, a path is absolute if it starts with the root, so
/// `is_absolute` and [`has_root`] are equivalent.
///
/// * On Windows, a path is absolute if it has a prefix and starts with the
/// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// assert!(!Path::new("foo.txt").is_absolute());
/// ```
///
/// [`has_root`]: #method.has_root
pub fn is_absolute(&self) -> bool {
self.inner.is_absolute()
}
/// Returns `true` if the `Path` is relative, i.e., not absolute.
///
/// See [`is_absolute`]'s documentation for more details.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// assert!(Path::new("foo.txt").is_relative());
/// ```
///
/// [`is_absolute`]: #method.is_absolute
pub fn is_relative(&self) -> bool {
self.inner.is_relative()
}
/// Returns `true` if the `Path` has a root.
///
/// * On Unix, a path has a root if it begins with `/`.
///
/// * On Windows, a path has a root if it:
/// * has no prefix and begins with a separator, e.g., `\windows`
/// * has a prefix followed by a separator, e.g., `c:\windows` but not `c:windows`
/// * has any non-disk prefix, e.g., `\\server\share`
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// assert!(Path::new("/etc/passwd").has_root());
/// ```
pub fn has_root(&self) -> bool {
self.inner.has_root()
}
/// Returns the `Path` without its final component, if there is one.
///
/// Returns [`None`] if the path terminates in a root or prefix.
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("/foo/bar");
/// let parent = path.parent().unwrap();
/// assert_eq!(parent, Path::new("/foo"));
///
/// let grand_parent = parent.parent().unwrap();
/// assert_eq!(grand_parent, Path::new("/"));
/// assert_eq!(grand_parent.parent(), None);
/// ```
pub fn parent(&self) -> Option<&Path> {
self.inner.parent().map(|p| p.into())
}
/// Produces an iterator over `Path` and its ancestors.
///
/// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
/// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
/// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
/// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
/// namely `&self`.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let mut ancestors = Path::new("/foo/bar").ancestors();
/// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar").into()));
/// assert_eq!(ancestors.next(), Some(Path::new("/foo").into()));
/// assert_eq!(ancestors.next(), Some(Path::new("/").into()));
/// assert_eq!(ancestors.next(), None);
/// ```
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html
/// [`parent`]: struct.Path.html#method.parent
pub fn ancestors(&self) -> Ancestors<'_> {
Ancestors { next: Some(&self) }
}
/// Returns the final component of the `Path`, if there is one.
///
/// If the path is a normal file, this is the file name. If it's the path of a directory, this
/// is the directory name.
///
/// Returns [`None`] if the path terminates in `..`.
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
/// use std::ffi::OsStr;
///
/// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
/// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
/// assert_eq!(None, Path::new("foo.txt/..").file_name());
/// assert_eq!(None, Path::new("/").file_name());
/// ```
pub fn file_name(&self) -> Option<&OsStr> {
self.inner.file_name()
}
/// Returns a path that, when joined onto `base`, yields `self`.
///
/// # Errors
///
/// If `base` is not a prefix of `self` (i.e., [`starts_with`]
/// returns `false`), returns [`Err`].
///
/// [`starts_with`]: #method.starts_with
/// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let path = Path::new("/test/haha/foo.txt");
///
/// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
/// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
/// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("test").is_ok(), false);
/// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
///
/// let prefix = PathBuf::from("/test/");
/// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
/// ```
pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError>
where
P: AsRef<Path>,
{
Ok(self.inner.strip_prefix(base.as_ref())?.into())
}
/// Determines whether `base` is a prefix of `self`.
///
/// Only considers whole path components to match.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("/etc/passwd");
///
/// assert!(path.starts_with("/etc"));
/// assert!(path.starts_with("/etc/"));
/// assert!(path.starts_with("/etc/passwd"));
/// assert!(path.starts_with("/etc/passwd/"));
///
/// assert!(!path.starts_with("/e"));
/// ```
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
self.inner.starts_with(base.as_ref())
}
/// Determines whether `child` is a suffix of `self`.
///
/// Only considers whole path components to match.
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("/etc/passwd");
///
/// assert!(path.ends_with("passwd"));
/// ```
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
self.inner.ends_with(child.as_ref())
}
/// Extracts the stem (non-extension) portion of [`self.file_name`].
///
/// [`self.file_name`]: struct.Path.html#method.file_name
///
/// The stem is:
///
/// * [`None`], if there is no file name;
/// * The entire file name if there is no embedded `.`;
/// * The entire file name if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name before the final `.`
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("foo.rs");
///
/// assert_eq!("foo", path.file_stem().unwrap());
/// ```
pub fn file_stem(&self) -> Option<&OsStr> {
self.inner.file_stem()
}
/// Extracts the extension of [`self.file_name`], if possible.
///
/// The extension is:
///
/// * [`None`], if there is no file name;
/// * [`None`], if there is no embedded `.`;
/// * [`None`], if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name after the final `.`
///
/// [`self.file_name`]: struct.Path.html#method.file_name
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("foo.rs");
///
/// assert_eq!("rs", path.extension().unwrap());
/// ```
pub fn extension(&self) -> Option<&OsStr> {
self.inner.extension()
}
/// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
///
/// See [`PathBuf::push`] for more details on what it means to adjoin a path.
///
/// [`PathBuf`]: struct.PathBuf.html
/// [`PathBuf::push`]: struct.PathBuf.html#method.push
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
/// ```
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
self.inner.join(path.as_ref()).into()
}
/// Creates an owned [`PathBuf`] like `self` but with the given file name.
///
/// See [`PathBuf::set_file_name`] for more details.
///
/// [`PathBuf`]: struct.PathBuf.html
/// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let path = Path::new("/tmp/foo.txt");
/// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
///
/// let path = Path::new("/tmp");
/// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
/// ```
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
self.inner.with_file_name(file_name).into()
}
/// Creates an owned [`PathBuf`] like `self` but with the given extension.
///
/// See [`PathBuf::set_extension`] for more details.
///
/// [`PathBuf`]: struct.PathBuf.html
/// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let path = Path::new("foo.rs");
/// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
/// ```
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
self.inner.with_extension(extension).into()
}
/// Produces an iterator over the [`Component`]s of the path.
///
/// When parsing the path, there is a small amount of normalization:
///
/// * Repeated separators are ignored, so `a/b` and `a//b` both have
/// `a` and `b` as components.
///
/// * Occurrences of `.` are normalized away, except if they are at the
/// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
/// `a/b` all have `a` and `b` as components, but `./a/b` starts with
/// an additional [`CurDir`] component.
///
/// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent.
///
/// Note that no other normalization takes place; in particular, `a/c`
/// and `a/b/../c` are distinct, to account for the possibility that `b`
/// is a symbolic link (so its parent isn't `a`).
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, Component};
/// use std::ffi::OsStr;
///
/// let mut components = Path::new("/tmp/foo.txt").components();
///
/// assert_eq!(components.next(), Some(Component::RootDir));
/// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
/// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
/// assert_eq!(components.next(), None)
/// ```
///
/// [`Component`]: enum.Component.html
/// [`CurDir`]: enum.Component.html#variant.CurDir
pub fn components(&self) -> Components<'_> {
self.inner.components()
}
/// Produces an iterator over the path's components viewed as [`OsStr`]
/// slices.
///
/// For more information about the particulars of how the path is separated
/// into components, see [`components`].
///
/// [`components`]: #method.components
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
///
/// # Examples
///
/// ```
/// use async_std::path::{self, Path};
/// use std::ffi::OsStr;
///
/// let mut it = Path::new("/tmp/foo.txt").iter();
/// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
/// assert_eq!(it.next(), Some(OsStr::new("tmp")));
/// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
/// assert_eq!(it.next(), None)
/// ```
pub fn iter(&self) -> Iter<'_> {
self.inner.iter()
}
/// Returns an object that implements [`Display`] for safely printing paths
/// that may contain non-Unicode data.
///
/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
///
/// # Examples
///
/// ```
/// use async_std::path::Path;
///
/// let path = Path::new("/tmp/foo.rs");
///
/// println!("{}", path.display());
/// ```
pub fn display(&self) -> Display<'_> {
self.inner.display()
}
/// Queries the file system to get information about a file, directory, etc.
///
/// This function will traverse symbolic links to query information about the
/// destination file.
///
/// This is an alias to [`fs::metadata`].
///
/// [`fs::metadata`]: ../fs/fn.metadata.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
///
/// let path = Path::new("/Minas/tirith");
/// let metadata = path.metadata().await.expect("metadata call failed");
/// println!("{:?}", metadata.file_type());
/// #
/// # Ok(()) }) }
/// ```
pub async fn metadata(&self) -> io::Result<fs::Metadata> {
fs::metadata(self).await
}
/// Queries the metadata about a file without following symlinks.
///
/// This is an alias to [`fs::symlink_metadata`].
///
/// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
///
/// let path = Path::new("/Minas/tirith");
/// let metadata = path.symlink_metadata().await.expect("symlink_metadata call failed");
/// println!("{:?}", metadata.file_type());
/// #
/// # Ok(()) }) }
/// ```
pub async fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
fs::symlink_metadata(self).await
}
/// Returns the canonical, absolute form of the path with all intermediate
/// components normalized and symbolic links resolved.
///
/// This is an alias to [`fs::canonicalize`].
///
/// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::{Path, PathBuf};
///
/// let path = Path::new("/foo/test/../test/bar.rs");
/// assert_eq!(path.canonicalize().await.unwrap(), PathBuf::from("/foo/test/bar.rs"));
/// #
/// # Ok(()) }) }
/// ```
pub async fn canonicalize(&self) -> io::Result<PathBuf> {
fs::canonicalize(self).await
}
/// Reads a symbolic link, returning the file that the link points to.
///
/// This is an alias to [`fs::read_link`].
///
/// [`fs::read_link`]: ../fs/fn.read_link.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
///
/// let path = Path::new("/laputa/sky_castle.rs");
/// let path_link = path.read_link().await.expect("read_link call failed");
/// #
/// # Ok(()) }) }
/// ```
pub async fn read_link(&self) -> io::Result<PathBuf> {
fs::read_link(self).await
}
/// Returns an iterator over the entries within a directory.
///
/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
/// errors may be encountered after an iterator is initially constructed.
///
/// This is an alias to [`fs::read_dir`].
///
/// [`io::Result`]: ../io/type.Result.html
/// [`DirEntry`]: ../fs/struct.DirEntry.html
/// [`fs::read_dir`]: ../fs/fn.read_dir.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
/// use async_std::fs;
/// use futures_util::stream::StreamExt;
///
/// let path = Path::new("/laputa");
/// let mut dir = fs::read_dir(&path).await.expect("read_dir call failed");
/// while let Some(res) = dir.next().await {
/// let entry = res?;
/// println!("{}", entry.file_name().to_string_lossy());
/// }
/// #
/// # Ok(()) }) }
/// ```
pub async fn read_dir(&self) -> io::Result<fs::ReadDir> {
fs::read_dir(self).await
}
/// Returns `true` if the path points at an existing entity.
///
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
/// If you cannot access the directory containing the file, e.g., because of a
/// permission error, this will return `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
/// assert_eq!(Path::new("does_not_exist.txt").exists().await, false);
/// #
/// # Ok(()) }) }
/// ```
///
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
/// check errors, call [fs::metadata].
///
/// [fs::metadata]: ../fs/fn.metadata.html
pub async fn exists(&self) -> bool {
fs::metadata(self).await.is_ok()
}
/// Returns `true` if the path exists on disk and is pointing at a regular file.
///
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
/// If you cannot access the directory containing the file, e.g., because of a
/// permission error, this will return `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
/// assert_eq!(Path::new("./is_a_directory/").is_file().await, false);
/// assert_eq!(Path::new("a_file.txt").is_file().await, true);
/// #
/// # Ok(()) }) }
/// ```
///
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
/// check errors, call [fs::metadata] and handle its Result. Then call
/// [fs::Metadata::is_file] if it was Ok.
///
/// [fs::metadata]: ../fs/fn.metadata.html
/// [fs::Metadata::is_file]: ../fs/struct.Metadata.html#method.is_file
pub async fn is_file(&self) -> bool {
fs::metadata(self)
.await
.map(|m| m.is_file())
.unwrap_or(false)
}
/// Returns `true` if the path exists on disk and is pointing at a directory.
///
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `false`.
///
/// If you cannot access the directory containing the file, e.g., because of a
/// permission error, this will return `false`.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::path::Path;
/// assert_eq!(Path::new("./is_a_directory/").is_dir().await, true);
/// assert_eq!(Path::new("a_file.txt").is_dir().await, false);
/// #
/// # Ok(()) }) }
/// ```
///
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
/// check errors, call [fs::metadata] and handle its Result. Then call
/// [fs::Metadata::is_dir] if it was Ok.
///
/// [fs::metadata]: ../fs/fn.metadata.html
/// [fs::Metadata::is_dir]: ../fs/struct.Metadata.html#method.is_dir
pub async fn is_dir(&self) -> bool {
fs::metadata(self)
.await
.map(|m| m.is_dir())
.unwrap_or(false)
}
/// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
/// allocating.
///
/// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
/// [`PathBuf`]: struct.PathBuf.html
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
let rw = Box::into_raw(self) as *mut std::path::Path;
let inner = unsafe { Box::from_raw(rw) };
inner.into_path_buf().into()
}
}
impl<'a> From<&'a std::path::Path> for &'a Path {
fn from(path: &'a std::path::Path) -> &'a Path {
&Path::new(path.as_os_str())
}
}
impl<'a> Into<&'a std::path::Path> for &'a Path {
fn into(self) -> &'a std::path::Path {
std::path::Path::new(&self.inner)
}
}
impl AsRef<std::path::Path> for Path {
fn as_ref(&self) -> &std::path::Path {
self.into()
}
}
impl AsRef<Path> for std::path::Path {
fn as_ref(&self) -> &Path {
self.into()
}
}
impl AsRef<Path> for Path {
fn as_ref(&self) -> &Path {
self
}
}
impl AsRef<OsStr> for Path {
fn as_ref(&self) -> &OsStr {
self.inner.as_ref()
}
}
impl AsRef<Path> for OsStr {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for str {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for String {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for std::path::PathBuf {
fn as_ref(&self) -> &Path {
Path::new(self.into())
}
}
impl std::borrow::ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> PathBuf {
self.to_path_buf()
}
}

@ -0,0 +1,235 @@
use std::ffi::{OsStr, OsString};
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)]
pub struct PathBuf {
inner: std::path::PathBuf,
}
impl PathBuf {
/// Allocates an empty `PathBuf`.
///
/// # Examples
///
/// ```
/// use async_std::path::PathBuf;
///
/// let path = PathBuf::new();
/// ```
pub fn new() -> PathBuf {
std::path::PathBuf::new().into()
}
/// Coerces to a [`Path`] slice.
///
/// [`Path`]: struct.Path.html
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let p = PathBuf::from("/test");
/// assert_eq!(Path::new("/test"), p.as_path());
/// ```
pub fn as_path(&self) -> &Path {
self.inner.as_path().into()
}
/// Extends `self` with `path`.
///
/// If `path` is absolute, it replaces the current path.
///
/// On Windows:
///
/// * if `path` has a root but no prefix (e.g., `\windows`), it
/// replaces everything except for the prefix (if any) of `self`.
/// * if `path` has a prefix but no root, it replaces `self`.
///
/// # Examples
///
/// Pushing a relative path extends the existing path:
///
/// ```
/// use async_std::path::PathBuf;
///
/// let mut path = PathBuf::from("/tmp");
/// path.push("file.bk");
/// assert_eq!(path, PathBuf::from("/tmp/file.bk"));
/// ```
///
/// Pushing an absolute path replaces the existing path:
///
/// ```
/// use async_std::path::PathBuf;
///
/// let mut path = PathBuf::from("/tmp");
/// path.push("/etc");
/// assert_eq!(path, PathBuf::from("/etc"));
/// ```
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
self.inner.push(path.as_ref())
}
/// Truncates `self` to [`self.parent`].
///
/// Returns `false` and does nothing if [`self.parent`] is [`None`].
/// Otherwise, returns `true`.
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`self.parent`]: struct.PathBuf.html#method.parent
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let mut p = PathBuf::from("/test/test.rs");
///
/// p.pop();
/// assert_eq!(Path::new("/test"), p.as_ref());
/// p.pop();
/// assert_eq!(Path::new("/"), p.as_ref());
/// ```
pub fn pop(&mut self) -> bool {
self.inner.pop()
}
/// Updates [`self.file_name`] to `file_name`.
///
/// If [`self.file_name`] was [`None`], this is equivalent to pushing
/// `file_name`.
///
/// Otherwise it is equivalent to calling [`pop`] and then pushing
/// `file_name`. The new path will be a sibling of the original path.
/// (That is, it will have the same parent.)
///
/// [`self.file_name`]: struct.PathBuf.html#method.file_name
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`pop`]: struct.PathBuf.html#method.pop
///
/// # Examples
///
/// ```
/// use async_std::path::PathBuf;
///
/// let mut buf = PathBuf::from("/");
/// assert!(buf.file_name() == None);
/// buf.set_file_name("bar");
/// assert!(buf == PathBuf::from("/bar"));
/// assert!(buf.file_name().is_some());
/// buf.set_file_name("baz.txt");
/// assert!(buf == PathBuf::from("/baz.txt"));
/// ```
pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
self.inner.set_file_name(file_name)
}
/// Updates [`self.extension`] to `extension`.
///
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
/// returns `true` and updates the extension otherwise.
///
/// If [`self.extension`] is [`None`], the extension is added; otherwise
/// it is replaced.
///
/// [`self.file_name`]: struct.PathBuf.html#method.file_name
/// [`self.extension`]: struct.PathBuf.html#method.extension
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// use async_std::path::{Path, PathBuf};
///
/// let mut p = PathBuf::from("/feel/the");
///
/// p.set_extension("force");
/// assert_eq!(Path::new("/feel/the.force"), p.as_path());
///
/// p.set_extension("dark_side");
/// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
/// ```
pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
self.inner.set_extension(extension)
}
/// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
///
/// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
///
/// # Examples
///
/// ```
/// use async_std::path::PathBuf;
///
/// let p = PathBuf::from("/the/head");
/// let os_str = p.into_os_string();
/// ```
pub fn into_os_string(self) -> OsString {
self.inner.into_os_string()
}
/// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
///
/// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
/// [`Path`]: struct.Path.html
pub fn into_boxed_path(self) -> Box<Path> {
let rw = Box::into_raw(self.inner.into_boxed_path()) as *mut Path;
unsafe { Box::from_raw(rw) }
}
}
impl std::ops::Deref for PathBuf {
type Target = Path;
fn deref(&self) -> &Path {
self.as_ref()
}
}
impl std::borrow::Borrow<Path> for PathBuf {
fn borrow(&self) -> &Path {
&**self
}
}
impl From<std::path::PathBuf> for PathBuf {
fn from(path: std::path::PathBuf) -> PathBuf {
PathBuf { inner: path }
}
}
impl Into<std::path::PathBuf> for PathBuf {
fn into(self) -> std::path::PathBuf {
self.inner.into()
}
}
impl From<OsString> for PathBuf {
fn from(path: OsString) -> PathBuf {
std::path::PathBuf::from(path).into()
}
}
impl From<&str> for PathBuf {
fn from(path: &str) -> PathBuf {
std::path::PathBuf::from(path).into()
}
}
impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
Path::new(&self.inner)
}
}
impl AsRef<std::path::Path> for PathBuf {
fn as_ref(&self) -> &std::path::Path {
self.inner.as_ref()
}
}

@ -11,6 +11,8 @@
//! use async_std::prelude::*;
//! ```
use cfg_if::cfg_if;
#[doc(no_inline)]
pub use crate::future::Future;
#[doc(no_inline)]
@ -21,11 +23,13 @@ pub use crate::io::Read as _;
pub use crate::io::Seek as _;
#[doc(no_inline)]
pub use crate::io::Write as _;
#[doc(hidden)]
#[doc(no_inline)]
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)]
@ -36,3 +40,13 @@ pub use crate::io::seek::SeekExt as _;
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;
}
}

@ -0,0 +1,14 @@
//! A module for working with processes.
//!
//! This module is mostly concerned with spawning and interacting with child processes, but it also
//! provides abort and exit for terminating the current process.
//!
//! This is an async version of [`std::process`].
//!
//! [`std::process`]: https://doc.rust-lang.org/std/process/index.html
// Re-export structs.
pub use std::process::{ExitStatus, Output};
// Re-export functions.
pub use std::process::{abort, exit, id};

@ -9,7 +9,7 @@ use crate::task::{Context, Poll};
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::stream;
@ -18,7 +18,7 @@ use crate::task::{Context, Poll};
///
/// assert_eq!(s.next().await, None);
/// #
/// # }) }
/// # })
/// ```
pub fn empty<T>() -> Empty<T> {
Empty {

@ -0,0 +1,120 @@
pub use crate::stream::Stream;
/// A stream that knows its exact length.
///
/// Many [`Stream`]s don't know how many times they will iterate, but some do.
/// If a stream knows how many times it can iterate, providing access to
/// that information can be useful. For example, if you want to iterate
/// backwards, a good start is to know where the end is.
///
/// When implementing an `ExactSizeStream`, you must also implement
/// [`Stream`]. When doing so, the implementation of [`size_hint`] *must*
/// return the exact size of the stream.
///
/// [`Stream`]: trait.Stream.html
/// [`size_hint`]: trait.Stream.html#method.size_hint
///
/// The [`len`] method has a default implementation, so you usually shouldn't
/// implement it. However, you may be able to provide a more performant
/// implementation than the default, so overriding it in this case makes sense.
///
/// [`len`]: #method.len
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// // a finite range knows exactly how many times it will iterate
/// let five = 0..5;
///
/// assert_eq!(5, five.len());
/// ```
///
/// In the [module level docs][moddocs], we implemented an [`Stream`],
/// `Counter`. Let's implement `ExactSizeStream` for it as well:
///
/// [moddocs]: index.html
///
/// ```
/// # use std::task::{Context, Poll};
/// # use std::pin::Pin;
/// # use async_std::prelude::*;
/// # struct Counter {
/// # count: usize,
/// # }
/// # impl Counter {
/// # fn new() -> Counter {
/// # Counter { count: 0 }
/// # }
/// # }
/// # impl Stream for Counter {
/// # type Item = usize;
/// # fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
/// # self.count += 1;
/// # if self.count < 6 {
/// # Poll::Ready(Some(self.count))
/// # } else {
/// # Poll::Ready(None)
/// # }
/// # }
/// # }
/// # fn main() { async_std::task::block_on(async {
/// #
/// impl ExactSizeStream for Counter {
/// // We can easily calculate the remaining number of iterations.
/// fn len(&self) -> usize {
/// 5 - self.count
/// }
/// }
///
/// // And now we can use it!
///
/// let counter = Counter::new();
///
/// assert_eq!(5, counter.len());
/// # });
/// # }
/// ```
#[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.
///
/// This method has a default implementation, so you usually should not
/// implement it directly. However, if you can provide a more efficient
/// implementation, you can do so. See the [trait-level] docs for an
/// example.
///
/// This function has the same safety guarantees as the [`size_hint`]
/// function.
///
/// [trait-level]: trait.ExactSizeStream.html
/// [`size_hint`]: trait.Stream.html#method.size_hint
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// // a finite range knows exactly how many times it will iterate
/// let five = 0..5;
///
/// assert_eq!(5, five.len());
/// ```
fn len(&self) -> usize {
let (lower, upper) = self.size_hint();
// Note: This assertion is overly defensive, but it checks the invariant
// guaranteed by the trait. If this trait were rust-internal,
// we could use debug_assert!; assert_eq! will check all Rust user
// implementations too.
assert_eq!(upper, Some(lower));
lower
}
}
impl<I: ExactSizeStream + ?Sized + Unpin> ExactSizeStream for &mut I {
fn len(&self) -> usize {
(**self).len()
}
}

@ -0,0 +1,100 @@
use std::marker::PhantomData;
use std::pin::Pin;
use crate::future::Future;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// 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,
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
///
/// ```
/// # fn main() { 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> FromFn<F, Fut, T> {
pin_utils::unsafe_unpinned!(f: F);
pin_utils::unsafe_pinned!(future: Option<Fut>);
}
impl<F, Fut, T> Stream for FromFn<F, Fut, T>
where
F: FnMut() -> Fut,
Fut: Future<Output = Option<T>>,
{
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop {
match &self.future {
Some(_) => {
let next =
futures_core::ready!(self.as_mut().future().as_pin_mut().unwrap().poll(cx));
self.as_mut().future().set(None);
return Poll::Ready(next);
}
None => {
let fut = (self.as_mut().f())();
self.as_mut().future().set(Some(fut));
}
}
}
}
}

@ -9,6 +9,102 @@ use std::pin::Pin;
///
/// See also: [`IntoStream`].
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use crate::async_std::stream::FromStream;
/// use async_std::prelude::*;
/// use async_std::stream;
///
/// let five_fives = stream::repeat(5).take(5);
///
/// let v = Vec::from_stream(five_fives).await;
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// # Ok(()) }) }
/// ```
///
/// Using `collect` to implicitly use `FromStream`
///
///```
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::prelude::*;
/// use async_std::stream;
/// let five_fives = stream::repeat(5).take(5);
///
/// let v: Vec<i32> = five_fives.collect().await;
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// #
/// # Ok(()) }) }
///```
///
/// Implementing `FromStream` for your type:
///
/// ```
/// use async_std::prelude::*;
/// use async_std::stream::{Extend, FromStream, IntoStream};
/// use async_std::stream;
/// use std::pin::Pin;
///
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
/// fn new() -> MyCollection {
/// MyCollection(Vec::new())
/// }
///
/// fn add(&mut self, elem: i32) {
/// self.0.push(elem);
/// }
/// }
///
/// // and we'll implement FromIterator
/// impl FromStream<i32> for MyCollection {
/// fn from_stream<'a, S: IntoStream<Item = i32> + 'a>(
/// stream: S,
/// ) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> {
/// let stream = stream.into_stream();
///
/// Box::pin(async move {
/// let mut c = MyCollection::new();
///
/// let mut v = vec![];
/// v.stream_extend(stream).await;
///
/// for i in v {
/// c.add(i);
/// }
/// c
/// })
/// }
/// }
///
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// // Now we can make a new stream...
/// let stream = stream::repeat(5).take(5);
///
/// // ...and make a MyCollection out of it
/// let c = MyCollection::from_stream(stream).await;
///
/// assert_eq!(c.0, vec![5, 5, 5, 5, 5]);
///
/// // collect works too!
///
/// let stream = stream::repeat(5).take(5);
/// let c: MyCollection = stream.collect().await;
///
/// assert_eq!(c.0, vec![5, 5, 5, 5, 5]);
/// # Ok(()) }) }
///```
///
/// [`IntoStream`]: trait.IntoStream.html
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
@ -20,9 +116,17 @@ pub trait FromStream<T> {
/// Basic usage:
///
/// ```
/// // use async_std::stream::FromStream;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use crate::async_std::stream::FromStream;
/// use async_std::prelude::*;
/// use async_std::stream;
///
/// let five_fives = stream::repeat(5).take(5);
///
/// let v = Vec::from_stream(five_fives).await;
///
/// // let _five_fives = async_std::stream::repeat(5).take(5);
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// # Ok(()) }) }
/// ```
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,

@ -0,0 +1,21 @@
use crate::stream::Stream;
/// A stream that always continues to yield `None` when exhausted.
///
/// Calling next on a fused stream that has returned `None` once is guaranteed
/// to return [`None`] again. This trait should be implemented by all streams
/// that behave this way because it allows optimizing [`Stream::fuse`].
///
/// Note: In general, you should not use `FusedStream` in generic bounds if
/// you need a fused stream. Instead, you should just call [`Stream::fuse`]
/// on the stream. If the stream is already fused, the additional [`Fuse`]
/// wrapper will be a no-op with no performance penalty.
///
/// [`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_attr(feature = "docs", doc(cfg(unstable)))]
pub trait FusedStream: Stream {}
impl<S: FusedStream + ?Sized + Unpin> FusedStream for &mut S {}

@ -0,0 +1,199 @@
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 pin_utils::unsafe_pinned;
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(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[doc(inline)]
pub fn interval(dur: Duration) -> Interval {
Interval {
delay: Delay::new(dur),
interval: dur,
}
}
/// A stream representing notifications at fixed interval
///
#[derive(Debug)]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[doc(inline)]
pub struct Interval {
delay: Delay,
interval: Duration,
}
impl Interval {
unsafe_pinned!(delay: Delay);
}
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)
);
}
}

@ -1,4 +1,4 @@
//! Asynchronous iteration.
//! Composable asynchronous iteration.
//!
//! This module is an async version of [`std::iter`].
//!
@ -7,7 +7,7 @@
//! # Examples
//!
//! ```
//! # fn main() { async_std::task::block_on(async {
//! # async_std::task::block_on(async {
//! #
//! use async_std::prelude::*;
//! use async_std::stream;
@ -18,20 +18,24 @@
//! assert_eq!(v, 9);
//! }
//! #
//! # }) }
//! # })
//! ```
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, Zip};
pub use stream::{
Chain, Filter, Fuse, Inspect, Scan, Skip, SkipWhile, StepBy, Stream, Take, TakeWhile, Zip,
};
pub(crate) mod stream;
mod empty;
mod from_fn;
mod once;
mod repeat;
mod repeat_with;
@ -39,17 +43,25 @@ mod repeat_with;
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
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 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 sum::Sum;
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[doc(inline)]
pub use async_macros::{join_stream as join, JoinStream as Join};
pub use stream::Merge;
}
}

@ -8,7 +8,7 @@ use crate::task::{Context, Poll};
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::stream;
@ -18,7 +18,7 @@ use crate::task::{Context, Poll};
/// assert_eq!(s.next().await, Some(7));
/// assert_eq!(s.next().await, None);
/// #
/// # }) }
/// # })
/// ```
pub fn once<T>(t: T) -> Once<T> {
Once { value: Some(t) }

@ -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_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
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>;
}

@ -8,7 +8,7 @@ use crate::task::{Context, Poll};
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::stream;
@ -18,7 +18,7 @@ use crate::task::{Context, Poll};
/// assert_eq!(s.next().await, Some(7));
/// assert_eq!(s.next().await, Some(7));
/// #
/// # }) }
/// # })
/// ```
pub fn repeat<T>(item: T) -> Repeat<T>
where

@ -0,0 +1,91 @@
use std::cmp::Ordering;
use std::pin::Pin;
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 using `Ord`.
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct CmpFuture<L: Stream, R: Stream> {
l: Fuse<L>,
r: Fuse<R>,
l_cache: Option<L::Item>,
r_cache: Option<R::Item>,
}
impl<L: Stream, R: Stream> CmpFuture<L, R> {
pin_utils::unsafe_pinned!(l: Fuse<L>);
pin_utils::unsafe_pinned!(r: Fuse<R>);
pin_utils::unsafe_unpinned!(l_cache: Option<L::Item>);
pin_utils::unsafe_unpinned!(r_cache: Option<R::Item>);
pub(super) fn new(l: L, r: R) -> Self {
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(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
// 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();
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 !self.l.done && self.as_mut().l_cache.is_none() {
let l_next = futures_core::ready!(self.as_mut().l().poll_next(cx));
if let Some(item) = l_next {
*self.as_mut().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 let Some(item) = r_next {
*self.as_mut().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();
let result = l_value.cmp(&r_value);
if let Ordering::Equal = result {
// Reset cache to prepare for next comparison
*self.as_mut().l_cache() = None;
*self.as_mut().r_cache() = None;
} else {
// Return non equal value
return Poll::Ready(result);
}
}
}
}
}

@ -36,13 +36,11 @@ where
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
match next {
Some(v) => match (self.as_mut().predicate())(&v) {
true => Poll::Ready(Some(v)),
false => {
Some(v) if (self.as_mut().predicate())(&v) => Poll::Ready(Some(v)),
Some(_) => {
cx.waker().wake_by_ref();
Poll::Pending
}
},
None => Poll::Ready(None),
}
}

@ -36,13 +36,11 @@ where
let item = futures_core::ready!(Pin::new(&mut *self.stream).poll_next(cx));
match item {
Some(v) => match (&mut self.p)(&v) {
true => Poll::Ready(Some(v)),
false => {
Some(v) if (&mut self.p)(&v) => Poll::Ready(Some(v)),
Some(_) => {
cx.waker().wake_by_ref();
Poll::Pending
}
},
None => Poll::Ready(None),
}
}

@ -0,0 +1,47 @@
use std::cmp::Ordering;
use std::pin::Pin;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
// 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> {
partial_cmp: PartialCmpFuture<L, R>,
}
impl<L: Stream, R: Stream> GeFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
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 + Sized,
R: Stream + Sized,
L::Item: PartialOrd<R::Item>,
{
type Output = bool;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
match result {
Some(Ordering::Greater) | Some(Ordering::Equal) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,47 @@
use std::cmp::Ordering;
use std::pin::Pin;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
// 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> {
partial_cmp: PartialCmpFuture<L, R>,
}
impl<L: Stream, R: Stream> GtFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
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(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
match result {
Some(Ordering::Greater) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,42 @@
use std::pin::Pin;
use crate::future::Future;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct LastFuture<S, T> {
stream: S,
last: Option<T>,
}
impl<S, T> LastFuture<S, T> {
pin_utils::unsafe_pinned!(stream: S);
pin_utils::unsafe_unpinned!(last: Option<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(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
match next {
Some(new) => {
cx.waker().wake_by_ref();
*self.as_mut().last() = Some(new);
Poll::Pending
}
None => Poll::Ready(self.last),
}
}
}

@ -0,0 +1,47 @@
use std::cmp::Ordering;
use std::pin::Pin;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// 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> {
partial_cmp: PartialCmpFuture<L, R>,
}
impl<L: Stream, R: Stream> LeFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
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(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
match result {
Some(Ordering::Less) | Some(Ordering::Equal) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,47 @@
use std::cmp::Ordering;
use std::pin::Pin;
use super::partial_cmp::PartialCmpFuture;
use crate::future::Future;
use crate::prelude::*;
use crate::stream::Stream;
use crate::task::{Context, Poll};
// 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> {
partial_cmp: PartialCmpFuture<L, R>,
}
impl<L: Stream, R: Stream> LtFuture<L, R>
where
L::Item: PartialOrd<R::Item>,
{
pin_utils::unsafe_pinned!(partial_cmp: PartialCmpFuture<L, R>);
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(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = futures_core::ready!(self.as_mut().partial_cmp().poll(cx));
match result {
Some(Ordering::Less) => Poll::Ready(true),
_ => Poll::Ready(false),
}
}
}

@ -0,0 +1,44 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::Stream;
/// 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(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Debug)]
pub struct Merge<L, R> {
left: L,
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 }
}
}
impl<L, R, T> Stream for Merge<L, R>
where
L: Stream<Item = T> + Unpin,
R: Stream<Item = T> + Unpin,
{
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) {
// 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)
}
}
}

@ -7,7 +7,7 @@
//! # Examples
//!
//! ```
//! # fn main() { async_std::task::block_on(async {
//! # async_std::task::block_on(async {
//! #
//! use async_std::prelude::*;
//! use async_std::stream;
@ -18,12 +18,13 @@
//! assert_eq!(v, 9);
//! }
//! #
//! # }) }
//! # })
//! ```
mod all;
mod any;
mod chain;
mod cmp;
mod enumerate;
mod filter;
mod filter_map;
@ -32,30 +33,46 @@ 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;
mod nth;
mod partial_cmp;
mod scan;
mod skip;
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;
@ -68,6 +85,7 @@ pub use skip::Skip;
pub use skip_while::SkipWhile;
pub use step_by::StepBy;
pub use take::Take;
pub use take_while::TakeWhile;
pub use zip::Zip;
use std::cmp::Ordering;
@ -87,10 +105,14 @@ cfg_if! {
cfg_if! {
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod merge;
use std::pin::Pin;
use crate::future::Future;
use crate::stream::FromStream;
pub use merge::Merge;
}
}
@ -114,7 +136,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.
"#]
@ -172,7 +194,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.
@ -235,6 +259,35 @@ extension_trait! {
}
}
#[doc = r#"
Creates a stream that yields elements based on a predicate.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use std::collections::VecDeque;
use async_std::prelude::*;
let s: VecDeque<usize> = vec![1, 2, 3, 4].into_iter().collect();
let mut s = s.take_while(|x| x < &3 );
assert_eq!(s.next().await, Some(1));
assert_eq!(s.next().await, Some(2));
assert_eq!(s.next().await, None);
#
# }) }
"#]
fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P, Self::Item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
TakeWhile::new(self, predicate)
}
#[doc = r#"
Creates a stream that yields each `step`th element.
@ -405,6 +458,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
@ -993,6 +1094,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.
@ -1147,6 +1288,264 @@ extension_trait! {
{
FromStream::from_stream(self)
}
#[doc = r#"
Combines multiple streams into a single stream of all their outputs.
Items are yielded as soon as they're received, and the stream continues yield until both
streams have been exhausted.
# Examples
```
# async_std::task::block_on(async {
use async_std::prelude::*;
use async_std::stream;
let a = stream::once(1u8);
let b = stream::once(2u8);
let c = stream::once(3u8);
let mut s = a.merge(b).merge(c);
assert_eq!(s.next().await, Some(1u8));
assert_eq!(s.next().await, Some(2u8));
assert_eq!(s.next().await, Some(3u8));
assert_eq!(s.next().await, None);
# });
```
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn merge<U>(self, other: U) -> Merge<Self, U>
where
Self: Sized,
U: Stream<Item = Self::Item> + Sized,
{
Merge::new(self, other)
}
#[doc = r#"
Lexicographically compares the elements of this `Stream` with those
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]);
let s4 = VecDeque::from(vec![1, 2, 4]);
assert_eq!(s1.clone().partial_cmp(s1.clone()).await, Some(Ordering::Equal));
assert_eq!(s1.clone().partial_cmp(s2.clone()).await, Some(Ordering::Less));
assert_eq!(s2.clone().partial_cmp(s1.clone()).await, Some(Ordering::Greater));
assert_eq!(s3.clone().partial_cmp(s4.clone()).await, Some(Ordering::Less));
assert_eq!(s4.clone().partial_cmp(s3.clone()).await, Some(Ordering::Greater));
#
# }) }
```
"#]
fn partial_cmp<S>(
self,
other: S
) -> impl Future<Output = Option<Ordering>> [PartialCmpFuture<Self, S>]
where
Self: Sized + Stream,
S: Stream,
<Self as Stream>::Item: PartialOrd<S::Item>,
{
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> {

@ -0,0 +1,92 @@
use std::cmp::Ordering;
use std::pin::Pin;
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>,
}
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(),
r: r.fuse(),
l_cache: None,
r_cache: None,
}
}
}
impl<L: Stream, R: Stream> Future for PartialCmpFuture<L, R>
where
L: Stream + Sized,
R: Stream + Sized,
L::Item: PartialOrd<R::Item>,
{
type Output = Option<Ordering>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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();
if l_complete && r_complete {
return Poll::Ready(Some(Ordering::Equal));
} else if l_complete {
return Poll::Ready(Some(Ordering::Less));
} else if r_complete {
return Poll::Ready(Some(Ordering::Greater));
}
// 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 let Some(item) = l_next {
*self.as_mut().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 let Some(item) = r_next {
*self.as_mut().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();
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;
} else {
// Return non equal value
return Poll::Ready(result);
}
}
}
}
}

@ -38,13 +38,12 @@ where
match next {
Some(v) => match self.as_mut().predicate() {
Some(p) => match p(&v) {
true => (),
false => {
Some(p) => {
if !p(&v) {
*self.as_mut().predicate() = None;
return Poll::Ready(Some(v));
}
},
}
None => return Poll::Ready(Some(v)),
},
None => return Poll::Ready(None),

@ -0,0 +1,47 @@
use std::marker::PhantomData;
use std::pin::Pin;
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A stream that yields elements based on a predicate.
#[derive(Debug)]
pub struct TakeWhile<S, P, T> {
stream: S,
predicate: P,
__t: PhantomData<T>,
}
impl<S, P, T> TakeWhile<S, P, T> {
pin_utils::unsafe_pinned!(stream: S);
pin_utils::unsafe_unpinned!(predicate: P);
pub(super) fn new(stream: S, predicate: P) -> Self {
TakeWhile {
stream,
predicate,
__t: PhantomData,
}
}
}
impl<S, P> Stream for TakeWhile<S, P, S::Item>
where
S: Stream,
P: FnMut(&S::Item) -> bool,
{
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));
match next {
Some(v) if (self.as_mut().predicate())(&v) => Poll::Ready(Some(v)),
Some(_) => {
cx.waker().wake_by_ref();
Poll::Pending
}
None => Poll::Ready(None),
}
}
}

@ -0,0 +1,59 @@
use std::marker::PhantomData;
use std::pin::Pin;
use crate::future::Future;
use crate::stream::Stream;
use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct TryFoldFuture<S, F, T> {
stream: S,
f: F,
acc: Option<T>,
__t: PhantomData<T>,
}
impl<S, F, T> TryFoldFuture<S, F, T> {
pin_utils::unsafe_pinned!(stream: S);
pin_utils::unsafe_unpinned!(f: F);
pin_utils::unsafe_unpinned!(acc: Option<T>);
pub(super) fn new(stream: S, init: T, f: F) -> Self {
TryFoldFuture {
stream,
f,
acc: Some(init),
__t: PhantomData,
}
}
}
impl<S, F, T, E> Future for TryFoldFuture<S, F, T>
where
S: Stream + Sized,
F: FnMut(T, S::Item) -> Result<T, E>,
{
type Output = Result<T, E>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
match next {
Some(v) => {
let old = self.as_mut().acc().take().unwrap();
let new = (self.as_mut().f())(old, v);
match new {
Ok(o) => {
*self.as_mut().acc() = Some(o);
}
Err(e) => return Poll::Ready(Err(e)),
}
}
None => return Poll::Ready(Ok(self.as_mut().acc().take().unwrap())),
}
}
}
}

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

@ -10,9 +10,8 @@ impl Extend<char> for String {
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
// let (lower_bound, _) = stream.size_hint();
// self.reserve(lower_bound);
self.reserve(stream.size_hint().0);
Box::pin(stream.for_each(move |c| self.push(c)))
}

@ -157,7 +157,7 @@ impl Barrier {
drop(lock);
while local_gen == generation_id && count < self.n {
let (g, c) = wait.recv().await.expect("sender hasn not been closed");
let (g, c) = wait.recv().await.expect("sender has not been closed");
generation_id = g;
count = c;
}

@ -9,7 +9,7 @@
//! Spawn a task that updates an integer protected by a mutex:
//!
//! ```
//! # fn main() { async_std::task::block_on(async {
//! # async_std::task::block_on(async {
//! #
//! use std::sync::Arc;
//!
@ -26,7 +26,7 @@
//!
//! assert_eq!(*m1.lock().await, 1);
//! #
//! # }) }
//! # })
//! ```
#[doc(inline)]

@ -10,7 +10,7 @@ use crate::future::Future;
use crate::task::{Context, Poll, Waker};
/// Set if the mutex is locked.
const LOCK: usize = 1 << 0;
const LOCK: usize = 1;
/// Set if there are tasks blocked on the mutex.
const BLOCKED: usize = 1 << 1;
@ -24,7 +24,7 @@ const BLOCKED: usize = 1 << 1;
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use std::sync::Arc;
///
@ -46,7 +46,7 @@ const BLOCKED: usize = 1 << 1;
/// }
/// assert_eq!(*m.lock().await, 10);
/// #
/// # }) }
/// # })
/// ```
pub struct Mutex<T> {
state: AtomicUsize,
@ -82,7 +82,7 @@ impl<T> Mutex<T> {
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use std::sync::Arc;
///
@ -99,7 +99,7 @@ impl<T> Mutex<T> {
///
/// assert_eq!(*m2.lock().await, 20);
/// #
/// # }) }
/// # })
/// ```
pub async fn lock(&self) -> MutexGuard<'_, T> {
pub struct LockFuture<'a, T> {
@ -196,7 +196,7 @@ impl<T> Mutex<T> {
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use std::sync::Arc;
///
@ -217,7 +217,7 @@ impl<T> Mutex<T> {
///
/// assert_eq!(*m2.lock().await, 20);
/// #
/// # }) }
/// # })
/// ```
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
if self.state.fetch_or(LOCK, Ordering::Acquire) & LOCK == 0 {
@ -249,7 +249,7 @@ impl<T> Mutex<T> {
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// # async_std::task::block_on(async {
/// #
/// use async_std::sync::Mutex;
///
@ -257,7 +257,7 @@ impl<T> Mutex<T> {
/// *mutex.get_mut() = 10;
/// assert_eq!(*mutex.lock().await, 10);
/// #
/// # }) }
/// # })
/// ```
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }

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

Loading…
Cancel
Save