Compare commits

..

2 Commits

Author SHA1 Message Date
Yoshua Wuyts 2378a68b50
cargo fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b1d2b8ac86
add mutex benches vs std + parking_lot
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago

@ -1,3 +0,0 @@
Our contribution policy can be found at [async.rs/contribute][policy].
[policy]: https://async.rs/contribute/

@ -4,7 +4,6 @@ on:
pull_request:
push:
branches:
- master
- staging
- trying
@ -29,24 +28,6 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- name: Cache cargo registry
uses: actions/cache@v2
with:
path: ~/.cargo/registry
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-registry-${{ hashFiles('**/Cargo.toml') }}
- name: Cache cargo index
uses: actions/cache@v2
with:
path: ~/.cargo/git
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-index-${{ hashFiles('**/Cargo.toml') }}
- name: Cache cargo build
uses: actions/cache@v2
with:
path: target
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-build-target-${{ hashFiles('**/Cargo.toml') }}
- name: check
uses: actions-rs/cargo@v1
with:
@ -58,15 +39,6 @@ jobs:
with:
command: check
args: --features unstable --all --bins --examples --tests
- name: check wasm
uses: actions-rs/cargo@v1
with:
command: check
target: wasm32-unknown-unknown
override: true
args: --features unstable --all --bins --tests
- name: check bench
uses: actions-rs/cargo@v1
if: matrix.rust == 'nightly'
@ -90,69 +62,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --all --features "unstable attributes"
build__with_no_std:
name: Build with no-std
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: setup
run: |
rustup default nightly
rustup target add thumbv7m-none-eabi
- name: check no_std
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features --features alloc --target thumbv7m-none-eabi -Z avoid-dev-deps
check_tokio_02_feature:
name: Check tokio02 feature
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: check tokio02
uses: actions-rs/cargo@v1
with:
command: check
args: --all --features tokio02
cross:
name: Cross compile
runs-on: ubuntu-latest
strategy:
matrix:
target:
- i686-unknown-linux-gnu
- powerpc-unknown-linux-gnu
- powerpc64-unknown-linux-gnu
- mips-unknown-linux-gnu
- arm-linux-androideabi
steps:
- uses: actions/checkout@master
- name: Install nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
- name: Install cross
run: cargo install cross
- name: check
run: cross check --all --target ${{ matrix.target }}
- name: check unstable
run: cross check --all --features unstable --target ${{ matrix.target }}
- name: test
run: cross test --all --features unstable --target ${{ matrix.target }}
args: --all --features unstable
check_fmt_and_docs:
name: Checking fmt and docs
@ -181,3 +91,15 @@ jobs:
- name: Docs
run: cargo doc --features docs
# clippy_check:
# name: Clippy check
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v1
# - name: Install rust
# run: rustup update beta && rustup default beta
# - name: Install clippy
# run: rustup component add clippy
# - name: clippy
# run: cargo clippy --all --features unstable

@ -7,310 +7,6 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
## [Unreleased]
# [1.6.2] - 2020-06-19
## Added
- Add `UdpSocket::peer_addr` ([#816](https://github.com/async-rs/async-std/pull/816))
## Changed
## Fixed
- Ensure the reactor is running for sockets and timers ([#819](https://github.com/async-rs/async-std/pull/819)).
- Avoid excessive polling in `flatten` and `flat_map` ([#701](https://github.com/async-rs/async-std/pull/701))
# [1.6.1] - 2020-06-11
## Added
- Added `tokio02` feature flag, to allow compatability usage with tokio@0.2 ([#804](https://github.com/async-rs/async-std/pull/804)).
## Changed
- Removed unstable `stdio` lock methods, due to their unsoundness ([#807](https://github.com/async-rs/async-std/pull/807)).
## Fixed
- Fixed wrong slice index for file reading ([#802](https://github.com/async-rs/async-std/pull/802)).
- Fixed recursive calls to `block_on` ([#799](https://github.com/async-rs/async-std/pull/799)) and ([#809](https://github.com/async-rs/async-std/pull/809)).
- Remove `default` feature requirement for the `unstable` feature ([#806](https://github.com/async-rs/async-std/pull/806)).
# [1.6.0] - 2020-05-22
See `1.6.0-beta.1` and `1.6.0-beta.2`.
# [1.6.0-beta.2] - 2020-05-19
## Added
- Added an environment variable to configure the thread pool size of the runtime. ([#774](https://github.com/async-rs/async-std/pull/774))
- Implement `Clone` for `UnixStream` ([#772](https://github.com/async-rs/async-std/pull/772))
## Changed
- For `wasm`, switched underlying `Timer` implementation to [`futures-timer`](https://github.com/async-rs/futures-timer). ([#776](https://github.com/async-rs/async-std/pull/776))
## Fixed
- Use `smol::block_on` to handle drop of `File`, avoiding nested executor panic. ([#768](https://github.com/async-rs/async-std/pull/768))
# [1.6.0-beta.1] - 2020-05-07
## Added
- Added `task::spawn_local`. ([#757](https://github.com/async-rs/async-std/pull/757))
- Added out of the box support for `wasm`. ([#757](https://github.com/async-rs/async-std/pull/757))
- Added `JoinHandle::cancel` ([#757](https://github.com/async-rs/async-std/pull/757))
- Added `sync::Condvar` ([#369](https://github.com/async-rs/async-std/pull/369))
- Added `sync::Sender::try_send` and `sync::Receiver::try_recv` ([#585](https://github.com/async-rs/async-std/pull/585))
- Added `no_std` support for `task`, `future` and `stream` ([#680](https://github.com/async-rs/async-std/pull/680))
## Changed
- Switched underlying runtime to [`smol`](https://github.com/stjepang/smol/). ([#757](https://github.com/async-rs/async-std/pull/757))
- Switched implementation of `sync::Barrier` to use `sync::Condvar` like `std` does. ([#581](https://github.com/async-rs/async-std/pull/581))
## Fixed
- Allow compilation on 32 bit targets, by using `AtomicUsize` for `TaskId`. ([#756](https://github.com/async-rs/async-std/pull/756))
# [1.5.0] - 2020-02-03
[API Documentation](https://docs.rs/async-std/1.5.0/async-std)
This patch includes various quality of life improvements to async-std.
Including improved performance, stability, and the addition of various
`Clone` impls that replace the use of `Arc` in many cases.
## Added
- Added links to various ecosystem projects from the README ([#660](https://github.com/async-rs/async-std/pull/660))
- Added an example on `FromStream` for `Result<T, E>` ([#643](https://github.com/async-rs/async-std/pull/643))
- Added `stream::pending` as "unstable" ([#615](https://github.com/async-rs/async-std/pull/615))
- Added an example of `stream::timeout` to document the error flow ([#675](https://github.com/async-rs/async-std/pull/675))
- Implement `Clone` for `DirEntry` ([#682](https://github.com/async-rs/async-std/pull/682))
- Implement `Clone` for `TcpStream` ([#689](https://github.com/async-rs/async-std/pull/689))
## Changed
- Removed internal comment on `stream::Interval` ([#645](https://github.com/async-rs/async-std/pull/645))
- The "unstable" feature can now be used without requiring the "default" feature ([#647](https://github.com/async-rs/async-std/pull/647))
- Removed unnecessary trait bound on `stream::FlatMap` ([#651](https://github.com/async-rs/async-std/pull/651))
- Updated the "broadcaster" dependency used by "unstable" to `1.0.0` ([#681](https://github.com/async-rs/async-std/pull/681))
- Updated `async-task` to 1.2.1 ([#676](https://github.com/async-rs/async-std/pull/676))
- `task::block_on` now parks after a single poll, improving performance in many cases ([#684](https://github.com/async-rs/async-std/pull/684))
- Improved reading flow of the "client" part of the async-std tutorial ([#550](https://github.com/async-rs/async-std/pull/550))
- Use `take_while` instead of `scan` in `impl` of `Product`, `Sum` and `FromStream` ([#667](https://github.com/async-rs/async-std/pull/667))
- `TcpStream::connect` no longer uses a thread from the threadpool, improving performance ([#687](https://github.com/async-rs/async-std/pull/687))
## Fixed
- Fixed crate documentation typo ([#655](https://github.com/async-rs/async-std/pull/655))
- Fixed documentation for `UdpSocket::recv` ([#648](https://github.com/async-rs/async-std/pull/648))
- Fixed documentation for `UdpSocket::send` ([#671](https://github.com/async-rs/async-std/pull/671))
- Fixed typo in stream documentation ([#650](https://github.com/async-rs/async-std/pull/650))
- Fixed typo on `sync::JoinHandle` documentation ([#659](https://github.com/async-rs/async-std/pull/659))
- Removed use of `std::error::Error::description` which failed CI ([#661](https://github.com/async-rs/async-std/pull/662))
- Removed the use of rustfmt's unstable `format_code_in_doc_comments` option which failed CI ([#685](https://github.com/async-rs/async-std/pull/685))
- Fixed a code typo in the `task::sleep` example ([#688](https://github.com/async-rs/async-std/pull/688))
# [1.4.0] - 2019-12-20
[API Documentation](https://docs.rs/async-std/1.4.0/async-std)
This patch adds `Future::timeout`, providing a method counterpart to the
`future::timeout` free function. And includes several bug fixes around missing
APIs. Notably we're not shipping our new executor yet, first announced [on our
blog](https://async.rs/blog/stop-worrying-about-blocking-the-new-async-std-runtime/).
## Examples
```rust
use async_std::prelude::*;
use async_std::future;
use std::time::Duration;
let fut = future::pending::<()>(); // This future will never resolve.
let res = fut.timeout(Duration::from_millis(100)).await;
assert!(res.is_err()); // The future timed out, returning an err.
```
## Added
- Added `Future::timeout` as "unstable" [(#600)](https://github.com/async-rs/async-std/pull/600)
## Fixes
- Fixed a doc test and enabled it on CI [(#597)](https://github.com/async-rs/async-std/pull/597)
- Fixed a rendering issue with the `stream` submodule documentation [(#621)](https://github.com/async-rs/async-std/pull/621)
- `Write::write_fmt`'s future is now correctly marked as `#[must_use]` [(#628)](https://github.com/async-rs/async-std/pull/628)
- Fixed the missing `io::Bytes` export [(#633)](https://github.com/async-rs/async-std/pull/633)
- Fixed the missing `io::Chain` export [(#633)](https://github.com/async-rs/async-std/pull/633)
- Fixed the missing `io::Take` export [(#633)](https://github.com/async-rs/async-std/pull/633)
# [1.3.0] - 2019-12-12
[API Documentation](https://docs.rs/async-std/1.3.0/async-std)
This patch introduces `Stream::delay`, more methods on `DoubleEndedStream`,
and improves compile times. `Stream::delay` is a new API that's similar to
[`task::sleep`](https://docs.rs/async-std/1.2.0/async_std/task/fn.sleep.html),
but can be passed as part of as stream, rather than as a separate block. This is
useful for examples, or when manually debugging race conditions.
## Examples
```rust
let start = Instant::now();
let mut s = stream::from_iter(vec![0u8, 1]).delay(Duration::from_millis(200));
// The first time will take more than 200ms due to delay.
s.next().await;
assert!(start.elapsed().as_millis() >= 200);
// There will be no delay after the first time.
s.next().await;
assert!(start.elapsed().as_millis() <= 210);
```
## Added
- Added `Stream::delay` as "unstable" [(#309)](https://github.com/async-rs/async-std/pull/309)
- Added `DoubleEndedStream::next_back` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::nth_back` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::rfind` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::rfold` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::try_rfold` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- `stream::Once` now implements `DoubleEndedStream` [(#562)](https://github.com/async-rs/async-std/pull/562)
- `stream::FromIter` now implements `DoubleEndedStream` [(#562)](https://github.com/async-rs/async-std/pull/562)
## Changed
- Removed our dependency on `async-macros`, speeding up compilation [(#610)](https://github.com/async-rs/async-std/pull/610)
## Fixes
- Fixed a link in the task docs [(#598)](https://github.com/async-rs/async-std/pull/598)
- Fixed the `UdpSocket::recv` example [(#603)](https://github.com/async-rs/async-std/pull/603)
- Fixed a link to `task::block_on` [(#608)](https://github.com/async-rs/async-std/pull/608)
- Fixed an incorrect API mention in `task::Builder` [(#612)](https://github.com/async-rs/async-std/pull/612)
- Fixed leftover mentions of `futures-preview` [(#595)](https://github.com/async-rs/async-std/pull/595)
- Fixed a typo in the tutorial [(#614)](https://github.com/async-rs/async-std/pull/614)
- `<TcpStream as Write>::poll_close` now closes the write half of the stream [(#618)](https://github.com/async-rs/async-std/pull/618)
# [1.2.0] - 2019-11-27
[API Documentation](https://docs.rs/async-std/1.2.0/async-std)
This patch includes some minor quality-of-life improvements, introduces a
new `Stream::unzip` API, and adds verbose errors to our networking types.
This means if you can't connect to a socket, you'll never have to wonder again
*which* address it was you couldn't connect to, instead of having to go through
the motions to debug what the address was.
## Example
Unzip a stream of tuples into two collections:
```rust
use async_std::prelude::*;
use async_std::stream;
let s = stream::from_iter(vec![(1,2), (3,4)]);
let (left, right): (Vec<_>, Vec<_>) = s.unzip().await;
assert_eq!(left, [1, 3]);
assert_eq!(right, [2, 4]);
```
## Added
- Added `Stream::unzip` as "unstable".
- Added verbose errors to the networking types.
## Changed
- Enabled CI on master branch.
- `Future::join` and `Future::try_join` can now join futures with different
output types.
## Fixed
- Fixed the docs and `Debug` output of `BufWriter`.
- Fixed a bug in `Stream::throttle` that made it consume too much CPU.
# [1.1.0] - 2019-11-21
[API Documentation](https://docs.rs/async-std/1.1.0/async-std)
This patch introduces a faster scheduler algorithm, `Stream::throttle`, and
stabilizes `task::yield_now`. Additionally we're introducing several more stream
APIs, bringing us to almost complete parity with the standard library.
Furthermore our `path` submodule now returns more context in errors. So if
opening a file fails, async-std will tell you *which* file was failed to open,
making it easier to write and debug programs.
## Examples
```rust
let start = Instant::now();
let mut s = stream::interval(Duration::from_millis(5))
.throttle(Duration::from_millis(10))
.take(2);
s.next().await;
assert!(start.elapsed().as_millis() >= 5);
s.next().await;
assert!(start.elapsed().as_millis() >= 15);
s.next().await;
assert!(start.elapsed().as_millis() >= 25);
```
## Added
- Added `Stream::throttle` as "unstable".
- Added `Stream::count` as "unstable".
- Added `Stream::max` as "unstable".
- Added `Stream::successors` as "unstable".
- Added `Stream::by_ref` as "unstable".
- Added `Stream::partition` as "unstable".
- Added contextual errors to the `path` submodule.
- Added `os::windows::symlink_dir` as "unstable".
- Added `os::windows::symlink_file` as "unstable".
- Stabilized `task::yield_now`.
## Fixes
- We now ignore seek errors when rolling back failed `read` calls on `File`.
- Fixed a bug where `Stream::max_by_key` was returning the wrong result.
- Fixed a bug where `Stream::min_by_key` was returning the wrong result.
## Changed
- Applied various fixes to the tutorial.
- Fixed an issue with Clippy.
- Optimized an internal code generation macro, improving compilation speeds.
- Removed an `Unpin` bound from `stream::Once`.
- Removed various extra internal uses of `pin_mut!`.
- Simplified `Stream::any` and `Stream::all`'s internals.
- The `surf` example is now enabled again.
- Tweaked some streams internals.
- Updated `futures-timer` to 2.0.0, improving compilation speed.
- Upgraded `async-macros` to 2.0.0.
- `Stream::merge` now uses randomized ordering to reduce overall latency.
- The scheduler is now more efficient by keeping a slot for the next task to
run. This is similar to Go's scheduler, and Tokio's scheduler.
- Fixed the documentation of the `channel` types to link back to the `channel`
function.
# [1.0.1] - 2019-11-12
[API Documentation](https://docs.rs/async-std/1.0.1/async-std)
@ -746,17 +442,7 @@ task::blocking(async {
- Initial beta release
[Unreleased]: https://github.com/async-rs/async-std/compare/v1.6.2...HEAD
[1.6.2]: https://github.com/async-rs/async-std/compare/v1.6.1...v1.6.2
[1.6.1]: https://github.com/async-rs/async-std/compare/v1.6.0...v1.6.1
[1.6.0]: https://github.com/async-rs/async-std/compare/v1.5.0...v1.6.0
[1.6.0-beta.2]: https://github.com/async-rs/async-std/compare/v1.6.0-beta.1...v1.6.0-beta.2
[1.6.0-beta.1]: https://github.com/async-rs/async-std/compare/v1.5.0...v1.6.0-beta.1
[1.5.0]: https://github.com/async-rs/async-std/compare/v1.4.0...v1.5.0
[1.4.0]: https://github.com/async-rs/async-std/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/async-rs/async-std/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/async-rs/async-std/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/async-rs/async-std/compare/v1.0.1...v1.1.0
[Unreleased]: https://github.com/async-rs/async-std/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/async-rs/async-std/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/async-rs/async-std/compare/v0.99.12...v1.0.0
[0.99.12]: https://github.com/async-rs/async-std/compare/v0.99.11...v0.99.12

@ -1,10 +1,9 @@
[package]
name = "async-std"
version = "1.6.2"
version = "1.0.1"
authors = [
"Stjepan Glavina <stjepang@gmail.com>",
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
"Friedel Ziegelmayer <me@dignifiedquire.com>",
"Contributors to async-std",
]
edition = "2018"
@ -25,74 +24,60 @@ rustdoc-args = ["--cfg", "feature=\"docs\""]
default = [
"std",
"async-task",
"crossbeam-channel",
"crossbeam-deque",
"futures-timer",
"kv-log-macro",
"log",
"mio",
"mio-uds",
"num_cpus",
"pin-project-lite",
"smol",
]
docs = ["attributes", "unstable", "default"]
unstable = [
"std",
"futures-timer",
]
docs = ["attributes", "unstable"]
unstable = ["default", "broadcaster"]
attributes = ["async-attributes"]
std = [
"alloc",
"async-macros",
"crossbeam-utils",
"futures-core/std",
"futures-core",
"futures-io",
"memchr",
"once_cell",
"pin-project-lite",
"pin-utils",
"slab",
"wasm-bindgen-futures",
"futures-channel",
"async-mutex",
]
alloc = [
"futures-core/alloc",
"pin-project-lite",
]
tokio02 = ["smol/tokio02"]
[dependencies]
async-attributes = { version = "1.1.1", optional = true }
async-task = { version = "3.0.0", optional = true }
async-mutex = { version = "1.1.3", optional = true }
crossbeam-utils = { version = "0.7.2", optional = true }
futures-core = { version = "0.3.4", optional = true, default-features = false }
futures-io = { version = "0.3.4", optional = true }
kv-log-macro = { version = "1.0.6", optional = true }
async-attributes = { version = "1.1.0", optional = true }
async-macros = { version = "2.0.0", optional = true }
async-task = { version = "1.0.0", optional = true }
broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] }
crossbeam-channel = { version = "0.3.9", optional = true }
crossbeam-deque = { version = "0.7.1", optional = true }
crossbeam-utils = { version = "0.6.6", optional = true }
futures-core = { version = "0.3.0", optional = true }
futures-io = { version = "0.3.0", optional = true }
futures-timer = { version = "2.0.0", optional = true }
kv-log-macro = { version = "1.0.4", optional = true }
log = { version = "0.4.8", features = ["kv_unstable"], optional = true }
memchr = { version = "2.3.3", optional = true }
num_cpus = { version = "1.12.0", optional = true }
once_cell = { version = "1.3.1", optional = true }
pin-project-lite = { version = "0.1.4", optional = true }
memchr = { version = "2.2.1", optional = true }
mio = { version = "0.6.19", optional = true }
mio-uds = { version = "0.6.7", optional = true }
num_cpus = { version = "1.10.1", optional = true }
once_cell = { version = "1.2.0", optional = true }
pin-project-lite = { version = "0.1", optional = true }
pin-utils = { version = "0.1.0-alpha.4", optional = true }
slab = { version = "0.4.2", optional = true }
futures-timer = { version = "3.0.2", optional = true }
# Devdepencency, but they are not allowed to be optional :/
surf = { version = "1.0.3", optional = true }
[target.'cfg(not(target_os = "unknown"))'.dependencies]
smol = { version = "0.1.17", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
futures-timer = { version = "3.0.2", optional = true, features = ["wasm-bindgen"] }
wasm-bindgen-futures = { version = "0.4.10", optional = true }
futures-channel = { version = "0.3.4", optional = true }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.10"
[dev-dependencies]
femme = "1.3.0"
rand = "0.7.3"
femme = "1.2.0"
futures = "0.3.0"
parking_lot = "0.9.0"
rand = "0.7.2"
surf = "1.0.3"
tempdir = "0.3.7"
futures = "0.3.4"
rand_xorshift = "0.2.0"
[[test]]
name = "stream"
@ -101,7 +86,3 @@ required-features = ["unstable"]
[[example]]
name = "tcp-ipv4-and-6-echo"
required-features = ["unstable"]
[[example]]
name = "surf-web"
required-features = ["surf"]

@ -8,11 +8,6 @@
<br />
<div align="center">
<!-- CI status -->
<a href="https://github.com/async-rs/async-std/actions">
<img src="https://github.com/async-rs/async-std/workflows/CI/badge.svg"
alt="CI Status" />
</a>
<!-- Crates version -->
<a href="https://crates.io/crates/async-std">
<img src="https://img.shields.io/crates/v/async-std.svg?style=flat-square"
@ -82,22 +77,17 @@ syntax.
```rust
use async_std::task;
async fn say_hello() {
println!("Hello, world!");
}
fn main() {
task::block_on(say_hello())
task::block_on(async {
println!("Hello, world!");
})
}
```
More examples, including networking and file access, can be found in our
[`examples`] directory and in our [documentation].
[`examples`] directory.
[`examples`]: https://github.com/async-rs/async-std/tree/master/examples
[documentation]: https://docs.rs/async-std#examples
[`task::block_on`]: https://docs.rs/async-std/*/async_std/task/fn.block_on.html
[`"attributes"` feature]: https://docs.rs/async-std/#features
## Philosophy
@ -125,24 +115,6 @@ documentation] on how to enable them.
[cargo-add]: https://github.com/killercup/cargo-edit
[features documentation]: https://docs.rs/async-std/#features
## Ecosystem
* [async-tls](https://crates.io/crates/async-tls) — Async TLS/SSL streams using **Rustls**.
* [async-native-tls](https://crates.io/crates/async-native-tls) — **Native TLS** for Async. Native TLS for futures and async-std.
* [async-tungstenite](https://crates.io/crates/async-tungstenite) — Asynchronous **WebSockets** for async-std, tokio, gio and any std Futures runtime.
* [Tide](https://crates.io/crates/tide) — Serve the web. A modular **web framework** built around async/await.
* [SQLx](https://crates.io/crates/sqlx) — The Rust **SQL** Toolkit. SQLx is a 100% safe Rust library for Postgres and MySQL with compile-time checked queries.
* [Surf](https://crates.io/crates/surf) — Surf the web. Surf is a friendly **HTTP client** built for casual Rustaceans and veterans alike.
* [Xactor](https://crates.io/crates/xactor) — Xactor is a rust actors framework based on async-std.
* [async-graphql](https://crates.io/crates/async-graphql) — A GraphQL server library implemented in rust, with full support for async/await.
## License
<sup>

@ -1,40 +1,125 @@
#![feature(test)]
extern crate test;
mod async_std {
extern crate test;
use async_std::sync::{Arc, Mutex};
use async_std::task;
use test::Bencher;
use async_std::sync::{Arc, Mutex};
use async_std::task;
use test::Bencher;
#[bench]
fn create(b: &mut Bencher) {
b.iter(|| Mutex::new(()));
}
#[bench]
fn create(b: &mut Bencher) {
b.iter(|| Mutex::new(()));
}
#[bench]
fn contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(10, 1000)));
}
#[bench]
fn no_contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(1, 10000)));
}
async fn run(task: usize, iter: usize) {
let m = Arc::new(Mutex::new(()));
let mut tasks = Vec::new();
#[bench]
fn contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(10, 1000)));
for _ in 0..task {
let m = m.clone();
tasks.push(task::spawn(async move {
for _ in 0..iter {
let _ = m.lock().await;
}
}));
}
for t in tasks {
t.await;
}
}
}
#[bench]
fn no_contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(1, 10000)));
mod std {
extern crate test;
use std::sync::{Arc, Mutex};
use std::thread;
use test::Bencher;
#[bench]
fn create(b: &mut Bencher) {
b.iter(|| Mutex::new(()));
}
#[bench]
fn contention(b: &mut Bencher) {
b.iter(|| run(10, 1000));
}
#[bench]
fn no_contention(b: &mut Bencher) {
b.iter(|| run(1, 10000));
}
fn run(thread: usize, iter: usize) {
let m = Arc::new(Mutex::new(()));
let mut threads = Vec::new();
for _ in 0..thread {
let m = m.clone();
threads.push(thread::spawn(move || {
for _ in 0..iter {
let _ = m.lock().unwrap();
}
}));
}
for t in threads {
t.join().unwrap();
}
}
}
async fn run(task: usize, iter: usize) {
let m = Arc::new(Mutex::new(()));
let mut tasks = Vec::new();
mod parking_lot {
extern crate test;
use parking_lot::Mutex;
use std::sync::Arc;
use std::thread;
use test::Bencher;
for _ in 0..task {
let m = m.clone();
tasks.push(task::spawn(async move {
for _ in 0..iter {
let _ = m.lock().await;
}
}));
#[bench]
fn create(b: &mut Bencher) {
b.iter(|| Mutex::new(()));
}
for t in tasks {
t.await;
#[bench]
fn contention(b: &mut Bencher) {
b.iter(|| run(10, 1000));
}
#[bench]
fn no_contention(b: &mut Bencher) {
b.iter(|| run(1, 10000));
}
fn run(thread: usize, iter: usize) {
let m = Arc::new(Mutex::new(()));
let mut threads = Vec::new();
for _ in 0..thread {
let m = m.clone();
threads.push(thread::spawn(move || {
for _ in 0..iter {
let _ = m.lock();
}
}));
}
for t in threads {
t.join().unwrap();
}
}
}

@ -19,9 +19,8 @@
- [Clean Shutdown](./tutorial/clean_shutdown.md)
- [Handling Disconnection](./tutorial/handling_disconnection.md)
- [Implementing a Client](./tutorial/implementing_a_client.md)
- [Async Patterns](./patterns.md)
- [TODO: Async Patterns](./patterns.md)
- [TODO: Collected Small Patterns](./patterns/small-patterns.md)
- [Production-Ready Accept Loop](./patterns/accept-loop.md)
- [Security practices](./security/index.md)
- [Security Disclosures and Policy](./security/policy.md)
- [Glossary](./glossary.md)

@ -4,13 +4,13 @@ Rust has two kinds of types commonly referred to as `Future`:
- the first is `std::future::Future` from Rusts [standard library](https://doc.rust-lang.org/std/future/trait.Future.html).
- the second is `futures::future::Future` from the [futures-rs crate](https://docs.rs/futures/0.3/futures/prelude/trait.Future.html).
- the second is `futures::future::Future` from the [futures-rs crate](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html), currently released as `futures-preview`.
The future defined in the [futures-rs](https://docs.rs/futures/0.3/futures/prelude/trait.Future.html) crate was the original implementation of the type. To enable the `async/await` syntax, the core Future trait was moved into Rusts standard library and became `std::future::Future`. In some sense, the `std::future::Future` can be seen as a minimal subset of `futures::future::Future`.
The future defined in the [futures-rs](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html) crate was the original implementation of the type. To enable the `async/await` syntax, the core Future trait was moved into Rusts standard library and became `std::future::Future`. In some sense, the `std::future::Future` can be seen as a minimal subset of `futures::future::Future`.
It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called [`FuturesExt`](https://docs.rs/futures/0.3/futures/future/trait.FutureExt.html). From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features.
It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called [`FuturesExt`](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/future/trait.FutureExt.html). From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features.
In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can actively opt into the extensions provided by the `futures` crate by adding it to your `Cargo.toml` and importing `FuturesExt`.
In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can actively opt into the extensions provided by the `futures-preview` crate by adding it to your `Cargo.toml` and importing `FuturesExt`.
## Interfaces and Stability

@ -1,266 +0,0 @@
# Production-Ready Accept Loop
A production-ready accept loop needs the following things:
1. Handling errors
2. Limiting the number of simultanteous connections to avoid deny-of-service
(DoS) attacks
## Handling errors
There are two kinds of errors in an accept loop:
1. Per-connection errors. The system uses them to notify that there was a
connection in the queue and it's dropped by the peer. Subsequent connections
can be already queued so next connection must be accepted immediately.
2. Resource shortages. When these are encountered it doesn't make sense to
accept the next socket immediately. But the listener stays active, so you server
should try to accept socket later.
Here is the example of a per-connection error (printed in normal and debug mode):
```
Error: Connection reset by peer (os error 104)
Error: Os { code: 104, kind: ConnectionReset, message: "Connection reset by peer" }
```
And the following is the most common example of a resource shortage error:
```
Error: Too many open files (os error 24)
Error: Os { code: 24, kind: Other, message: "Too many open files" }
```
### Testing Application
To test your application for these errors try the following (this works
on unixes only).
Lower limits and start the application:
```
$ ulimit -n 100
$ cargo run --example your_app
Compiling your_app v0.1.0 (/work)
Finished dev [unoptimized + debuginfo] target(s) in 5.47s
Running `target/debug/examples/your_app`
Server is listening on: http://127.0.0.1:1234
```
Then in another console run the [`wrk`] benchmark tool:
```
$ wrk -c 1000 http://127.0.0.1:1234
Running 10s test @ http://localhost:8080/
2 threads and 1000 connections
$ telnet localhost 1234
Trying ::1...
Connected to localhost.
```
Important is to check the following things:
1. The application doesn't crash on error (but may log errors, see below)
2. It's possible to connect to the application again once load is stopped
(few seconds after `wrk`). This is what `telnet` does in example above,
make sure it prints `Connected to <hostname>`.
3. The `Too many open files` error is logged in the appropriate log. This
requires to set "maximum number of simultaneous connections" parameter (see
below) of your application to a value greater then `100` for this example.
4. Check CPU usage of the app while doing a test. It should not occupy 100%
of a single CPU core (it's unlikely that you can exhaust CPU by 1000
connections in Rust, so this means error handling is not right).
#### Testing non-HTTP applications
If it's possible, use the appropriate benchmark tool and set the appropriate
number of connections. For example `redis-benchmark` has a `-c` parameter for
that, if you implement redis protocol.
Alternatively, can still use `wrk`, just make sure that connection is not
immediately closed. If it is, put a temporary timeout before handing
the connection to the protocol handler, like this:
```rust,edition2018
# extern crate async_std;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
#async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
# let listener = TcpListener::bind(addr).await?;
# let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
task::spawn(async {
task::sleep(Duration::from_secs(10)).await; // 1
connection_loop(stream).await;
});
}
# Ok(())
# }
```
1. Make sure the sleep coroutine is inside the spawned task, not in the loop.
[`wrk`]: https://github.com/wg/wrk
### Handling Errors Manually
Here is how basic accept loop could look like:
```rust,edition2018
# extern crate async_std;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener.incoming();
while let Some(result) = incoming.next().await {
let stream = match stream {
Err(ref e) if is_connection_error(e) => continue, // 1
Err(e) => {
eprintln!("Error: {}. Pausing for 500ms."); // 3
task::sleep(Duration::from_millis(500)).await; // 2
continue;
}
Ok(s) => s,
};
// body
}
Ok(())
}
```
1. Ignore per-connection errors.
2. Sleep and continue on resource shortage.
3. It's important to log the message, because these errors commonly mean the
misconfiguration of the system and are helpful for operations people running
the application.
Be sure to [test your application](#testing-application).
### External Crates
The crate [`async-listen`] has a helper to achieve this task:
```rust,edition2018
# extern crate async_std;
# extern crate async_listen;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
use async_listen::{ListenExt, error_hint};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener
.incoming()
.log_warnings(log_accept_error) // 1
.handle_errors(Duration::from_millis(500));
while let Some(socket) = incoming.next().await { // 2
// body
}
Ok(())
}
fn log_accept_error(e: &io::Error) {
eprintln!("Error: {}. Listener paused for 0.5s. {}", e, error_hint(e)) // 3
}
```
1. Logs resource shortages (`async-listen` calls them warnings). If you use
`log` crate or any other in your app this should go to the log.
2. Stream yields sockets without `Result` wrapper after `handle_errors` because
all errors are already handled.
3. Together with the error we print a hint, which explains some errors for end
users. For example, it recommends increasing open file limit and gives
a link.
[`async-listen`]: https://crates.io/crates/async-listen/
Be sure to [test your application](#testing-application).
## Connections Limit
Even if you've applied everything described in
[Handling Errors](#handling-errors) section, there is still a problem.
Let's imagine you have a server that needs to open a file to process
client request. At some point, you might encounter the following situation:
1. There are as many client connection as max file descriptors allowed for
the application.
2. Listener gets `Too many open files` error so it sleeps.
3. Some client sends a request via the previously open connection.
4. Opening a file to serve request fails, because of the same
`Too many open files` error, until some other client drops a connection.
There are many more possible situations, this is just a small illustation that
limiting number of connections is very useful. Generally, it's one of the ways
to control resources used by a server and avoiding some kinds of deny of
service (DoS) attacks.
### `async-listen` crate
Limiting maximum number of simultaneous connections with [`async-listen`]
looks like the following:
```rust,edition2018
# extern crate async_std;
# extern crate async_listen;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
use async_listen::{ListenExt, Token, error_hint};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener
.incoming()
.log_warnings(log_accept_error)
.handle_errors(Duration::from_millis(500)) // 1
.backpressure(100);
while let Some((token, socket)) = incoming.next().await { // 2
task::spawn(async move {
connection_loop(&token, stream).await; // 3
});
}
Ok(())
}
async fn connection_loop(_token: &Token, stream: TcpStream) { // 4
// ...
}
# fn log_accept_error(e: &io::Error) {
# eprintln!("Error: {}. Listener paused for 0.5s. {}", e, error_hint(e));
# }
```
1. We need to handle errors first, because [`backpressure`] helper expects
stream of `TcpStream` rather than `Result`.
2. The token yielded by a new stream is what is counted by backpressure helper.
I.e. if you drop a token, new connection can be established.
3. We give the connection loop a reference to token to bind token's lifetime to
the lifetime of the connection.
4. The token itsellf in the function can be ignored, hence `_token`
[`backpressure`]: https://docs.rs/async-listen/0.1.2/async_listen/trait.ListenExt.html#method.backpressure
Be sure to [test this behavior](#testing-application).

@ -6,13 +6,13 @@ At this point, we only need to start the broker to get a fully-functioning (in t
# extern crate async_std;
# extern crate futures;
use async_std::{
io::BufReader,
io::{self, BufReader},
net::{TcpListener, TcpStream, ToSocketAddrs},
prelude::*,
task,
};
use futures::channel::mpsc;
use futures::sink::SinkExt;
use futures::SinkExt;
use std::{
collections::hash_map::{HashMap, Entry},
sync::Arc,

@ -30,7 +30,7 @@ Let's add waiting to the server:
# task,
# };
# use futures::channel::mpsc;
# use futures::sink::SinkExt;
# use futures::SinkExt;
# use std::{
# collections::hash_map::{HashMap, Entry},
# sync::Arc,
@ -163,7 +163,7 @@ And to the broker:
# task,
# };
# use futures::channel::mpsc;
# use futures::sink::SinkExt;
# use futures::SinkExt;
# use std::{
# collections::hash_map::{HashMap, Entry},
# sync::Arc,

@ -2,12 +2,12 @@
## Connecting Readers and Writers
So how do we make sure that messages read in `connection_loop` flow into the relevant `connection_writer_loop`?
We should somehow maintain a `peers: HashMap<String, Sender<String>>` map which allows a client to find destination channels.
We should somehow maintain an `peers: HashMap<String, Sender<String>>` map which allows a client to find destination channels.
However, this map would be a bit of shared mutable state, so we'll have to wrap an `RwLock` over it and answer tough questions of what should happen if the client joins at the same moment as it receives a message.
One trick to make reasoning about state simpler comes from the actor model.
We can create a dedicated broker task which owns the `peers` map and communicates with other tasks using channels.
By hiding `peers` inside such an "actor" task, we remove the need for mutexes and also make the serialization point explicit.
We can create a dedicated broker tasks which owns the `peers` map and communicates with other tasks by channels.
By hiding `peers` inside such an "actor" task, we remove the need for mutxes and also make serialization point explicit.
The order of events "Bob sends message to Alice" and "Alice joins" is determined by the order of the corresponding events in the broker's event queue.
```rust,edition2018
@ -92,9 +92,9 @@ async fn broker_loop(mut events: Receiver<Event>) -> Result<()> {
}
```
1. The broker task should handle two types of events: a message or an arrival of a new peer.
2. The internal state of the broker is a `HashMap`.
1. Broker should handle two types of events: a message or an arrival of a new peer.
2. Internal state of the broker is a `HashMap`.
Note how we don't need a `Mutex` here and can confidently say, at each iteration of the broker's loop, what is the current set of peers
3. To handle a message, we send it over a channel to each destination
4. To handle a new peer, we first register it in the peer's map ...
4. To handle new peer, we first register it in the peer's map ...
5. ... and then spawn a dedicated task to actually write the messages to the socket.

@ -22,7 +22,7 @@ First, let's add a shutdown channel to the `connection_loop`:
# extern crate futures;
# use async_std::net::TcpStream;
# use futures::channel::mpsc;
# use futures::sink::SinkExt;
# use futures::SinkExt;
# use std::sync::Arc;
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
@ -60,8 +60,8 @@ async fn connection_loop(mut broker: Sender<Event>, stream: Arc<TcpStream>) -> R
}
```
1. To enforce that no messages are sent along the shutdown channel, we use an uninhabited type.
2. We pass the shutdown channel to the writer task.
1. To enforce that no messages are send along the shutdown channel, we use an uninhabited type.
2. We pass the shutdown channel to the writer task
3. In the reader, we create a `_shutdown_sender` whose only purpose is to get dropped.
In the `connection_writer_loop`, we now need to choose between shutdown and message channels.
@ -71,12 +71,14 @@ We use the `select` macro for this purpose:
# extern crate async_std;
# extern crate futures;
# use async_std::{net::TcpStream, prelude::*};
# use futures::channel::mpsc;
use futures::channel::mpsc;
use futures::{select, FutureExt};
# use std::sync::Arc;
# type Receiver<T> = mpsc::UnboundedReceiver<T>;
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
# type Sender<T> = mpsc::UnboundedSender<T>;
# #[derive(Debug)]
# enum Void {} // 1
@ -110,7 +112,7 @@ async fn connection_writer_loop(
Another problem is that between the moment we detect disconnection in `connection_writer_loop` and the moment when we actually remove the peer from the `peers` map, new messages might be pushed into the peer's channel.
To not lose these messages completely, we'll return the messages channel back to the broker.
This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and makes the broker itself infallible.
This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and makes the broker itself infailable.
## Final Code
@ -126,8 +128,7 @@ use async_std::{
task,
};
use futures::channel::mpsc;
use futures::sink::SinkExt;
use futures::{select, FutureExt};
use futures::{select, FutureExt, SinkExt};
use std::{
collections::hash_map::{Entry, HashMap},
future::Future,

@ -1,16 +1,18 @@
## Implementing a client
Since the protocol is line-based, implementing a client for the chat is straightforward:
Let's now implement the client for the chat.
Because the protocol is line-based, the implementation is pretty straightforward:
* Lines read from stdin should be sent over the socket.
* Lines read from the socket should be echoed to stdout.
Although async does not significantly affect client performance (as unlike the server, the client interacts solely with one user and only needs limited concurrency), async is still useful for managing concurrency!
The client has to read from stdin and the socket *simultaneously*.
Programming this with threads is cumbersome, especially when implementing a clean shutdown.
With async, the `select!` macro is all that is needed.
Unlike the server, the client needs only limited concurrency, as it interacts with only a single user.
For this reason, async doesn't bring a lot of performance benefits in this case.
However, async is still useful for managing concurrency!
Specifically, the client should *simultaneously* read from stdin and from the socket.
Programming this with threads is cumbersome, especially when implementing clean shutdown.
With async, we can just use the `select!` macro.
```rust,edition2018
# extern crate async_std;

@ -1,14 +1,11 @@
# Tutorial: Writing a chat
Nothing is simpler than creating a chat server, right?
Not quite, chat servers expose you to all the fun of asynchronous programming:
Nothing is as simple as a chat server, right? Not quite, chat servers
already expose you to all the fun of asynchronous programming: how
do you handle clients connecting concurrently. How do you handle them disconnecting?
How will the server handle clients connecting concurrently?
How do you distribute the messages?
How will it handle them disconnecting?
How will it distribute the messages?
This tutorial explains how to write a chat server in `async-std`.
In this tutorial, we will show you how to write one in `async-std`.
You can also find the tutorial in [our repository](https://github.com/async-rs/async-std/blob/master/examples/a-chat).

@ -10,18 +10,14 @@ We need to:
```rust,edition2018
# extern crate async_std;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# io::BufReader,
# net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*,
# task,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
use async_std::{
io::BufReader,
net::TcpStream,
};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener.incoming();
@ -50,7 +46,7 @@ async fn connection_loop(stream: TcpStream) -> Result<()> {
Some(idx) => (&line[..idx], line[idx + 1 ..].trim()),
};
let dest: Vec<String> = dest.split(',').map(|name| name.trim().to_string()).collect();
let msg: String = msg.to_string();
let msg: String = msg.trim().to_string();
}
Ok(())
}
@ -111,7 +107,7 @@ We can "fix" it by waiting for the task to be joined, like this:
#
# async move |stream| {
let handle = task::spawn(connection_loop(stream));
handle.await?
handle.await
# };
```
@ -134,7 +130,7 @@ So let's use a helper function for this:
# };
fn spawn_and_log_error<F>(fut: F) -> task::JoinHandle<()>
where
F: Future<Output = Result<()>> + Send + 'static,
F: Future<Output = io::Result<()>> + Send + 'static,
{
task::spawn(async move {
if let Err(e) = fut.await {

@ -14,9 +14,8 @@ use async_std::task;
async fn process(stream: TcpStream) -> io::Result<()> {
println!("Accepted from: {}", stream.peer_addr()?);
let mut reader = stream.clone();
let mut writer = stream;
io::copy(&mut reader, &mut writer).await?;
let (reader, writer) = &mut (&stream, &stream);
io::copy(reader, writer).await?;
Ok(())
}

@ -15,9 +15,8 @@ use async_std::task;
async fn process(stream: TcpStream) -> io::Result<()> {
println!("Accepted from: {}", stream.peer_addr()?);
let mut reader = stream.clone();
let mut writer = stream;
io::copy(&mut reader, &mut writer).await?;
let (reader, writer) = &mut (&stream, &stream);
io::copy(reader, writer).await?;
Ok(())
}

@ -1 +1,2 @@
version = "Two"
format_code_in_doc_comments = true

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, IntoStream};
impl<T: Ord + Send> stream::Extend<T> for BinaryHeap<T> {
impl<T: Ord> stream::Extend<T> for BinaryHeap<T> {
fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
self.reserve(stream.size_hint().0);

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Ord + Send> FromStream<T> for BinaryHeap<T> {
impl<T: Ord> FromStream<T> for BinaryHeap<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, IntoStream};
impl<K: Ord + Send, V: Send> stream::Extend<(K, V)> for BTreeMap<K, V> {
impl<K: Ord, V> stream::Extend<(K, V)> for BTreeMap<K, V> {
fn extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
Box::pin(stream.into_stream().for_each(move |(k, v)| {
self.insert(k, v);
}))

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<K: Ord + Send, V: Send> FromStream<(K, V)> for BTreeMap<K, V> {
impl<K: Ord, V> FromStream<(K, V)> for BTreeMap<K, V> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, IntoStream};
impl<T: Ord + Send> stream::Extend<T> for BTreeSet<T> {
impl<T: Ord> stream::Extend<T> for BTreeSet<T> {
fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
Box::pin(stream.into_stream().for_each(move |item| {
self.insert(item);
}))

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Ord + Send> FromStream<T> for BTreeSet<T> {
impl<T: Ord> FromStream<T> for BTreeSet<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -7,17 +7,13 @@ use crate::stream::{self, IntoStream};
impl<K, V, H> stream::Extend<(K, V)> for HashMap<K, V, H>
where
K: Eq + Hash + Send,
V: Send,
H: BuildHasher + Default + Send,
K: Eq + Hash,
H: BuildHasher + Default,
{
fn extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
// The following is adapted from the hashbrown source code:

@ -7,17 +7,13 @@ use crate::stream::{self, FromStream, IntoStream};
impl<K, V, H> FromStream<(K, V)> for HashMap<K, V, H>
where
K: Eq + Hash + Send,
H: BuildHasher + Default + Send,
V: Send,
K: Eq + Hash,
H: BuildHasher + Default,
{
#[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -7,16 +7,13 @@ use crate::stream::{self, IntoStream};
impl<T, H> stream::Extend<T> for HashSet<T, H>
where
T: Eq + Hash + Send,
H: BuildHasher + Default + Send,
T: Eq + Hash,
H: BuildHasher + Default,
{
fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
// The Extend impl for HashSet in the standard library delegates to the internal HashMap.
// Thus, this impl is just a copy of the async Extend impl for HashMap in this crate.

@ -7,16 +7,13 @@ use crate::stream::{self, FromStream, IntoStream};
impl<T, H> FromStream<T> for HashSet<T, H>
where
T: Eq + Hash + Send,
H: BuildHasher + Default + Send,
T: Eq + Hash,
H: BuildHasher + Default,
{
#[inline]
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, IntoStream};
impl<T: Send> stream::Extend<T> for LinkedList<T> {
impl<T> stream::Extend<T> for LinkedList<T> {
fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
Box::pin(stream.for_each(move |item| self.push_back(item)))
}

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Send> FromStream<T> for LinkedList<T> {
impl<T> FromStream<T> for LinkedList<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, IntoStream};
impl<T: Send> stream::Extend<T> for VecDeque<T> {
impl<T> stream::Extend<T> for VecDeque<T> {
fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
self.reserve(stream.size_hint().0);

@ -4,14 +4,11 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Send> FromStream<T> for VecDeque<T> {
impl<T> FromStream<T> for VecDeque<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -1,7 +1,6 @@
use crate::io;
use crate::path::{Path, PathBuf};
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Returns the canonical form of a path.
///
@ -33,10 +32,5 @@ use crate::utils::Context as _;
/// ```
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::canonicalize(&path)
.map(Into::into)
.context(|| format!("could not canonicalize `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::canonicalize(&path).map(Into::into)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Copies the contents and permissions of a file to a new location.
///
@ -42,9 +41,5 @@ use crate::utils::Context as _;
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();
spawn_blocking(move || {
std::fs::copy(&from, &to)
.context(|| format!("could not copy `{}` to `{}`", from.display(), to.display()))
})
.await
spawn_blocking(move || std::fs::copy(&from, &to)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a new directory.
///
@ -35,9 +34,5 @@ use crate::utils::Context as _;
/// ```
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::create_dir(&path)
.context(|| format!("could not create directory `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::create_dir(path)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a new directory and all of its parents if they are missing.
///
@ -30,9 +29,5 @@ use crate::utils::Context as _;
/// ```
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::create_dir_all(&path)
.context(|| format!("could not create directory path `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::create_dir_all(path)).await
}

@ -158,12 +158,6 @@ impl fmt::Debug for DirEntry {
}
}
impl Clone for DirEntry {
fn clone(&self) -> Self {
DirEntry(self.0.clone())
}
}
cfg_unix! {
use crate::os::unix::fs::DirEntryExt;

@ -12,8 +12,7 @@ use crate::future;
use crate::io::{self, Read, Seek, SeekFrom, Write};
use crate::path::Path;
use crate::prelude::*;
use crate::task::{spawn_blocking, Context, Poll, Waker};
use crate::utils::Context as _;
use crate::task::{self, spawn_blocking, Context, Poll, Waker};
/// An open file on the filesystem.
///
@ -113,10 +112,7 @@ impl File {
/// ```
pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
let file = spawn_blocking(move || {
std::fs::File::open(&path).context(|| format!("could not open `{}`", path.display()))
})
.await?;
let file = spawn_blocking(move || std::fs::File::open(&path)).await?;
Ok(File::new(file, true))
}
@ -151,11 +147,7 @@ impl File {
/// ```
pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
let file = spawn_blocking(move || {
std::fs::File::create(&path)
.context(|| format!("could not create `{}`", path.display()))
})
.await?;
let file = spawn_blocking(move || std::fs::File::create(&path)).await?;
Ok(File::new(file, true))
}
@ -315,7 +307,7 @@ impl Drop for File {
// non-blocking fashion, but our only other option here is losing data remaining in the
// write cache. Good task schedulers should be resilient to occasional blocking hiccups in
// file destructors so we don't expect this to be a common problem in practice.
let _ = smol::block_on(self.flush());
let _ = task::block_on(self.flush());
}
}
@ -673,7 +665,7 @@ impl LockGuard<State> {
if available > 0 || self.cache.is_empty() {
// Copy data from the cache into the buffer.
let n = cmp::min(available, buf.len());
buf[..n].copy_from_slice(&self.cache[start..(start + n)]);
buf[..n].copy_from_slice(&self.cache[start..n]);
// Move the read cursor forward.
self.mode = Mode::Reading(start + n);
@ -741,10 +733,7 @@ impl LockGuard<State> {
if n > 0 {
// Seek `n` bytes backwards. This call should not block because it only changes
// the internal offset into the file and doesn't touch the actual file on disk.
//
// We ignore errors here because special files like `/dev/random` are not
// seekable.
let _ = (&*self.file).seek(SeekFrom::Current(-(n as i64)));
(&*self.file).seek(SeekFrom::Current(-(n as i64)))?;
}
// Switch to idle mode.
@ -867,15 +856,3 @@ impl LockGuard<State> {
Poll::Ready(Ok(()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn async_file_drop() {
crate::task::block_on(async move {
File::open(file!()).await.unwrap();
});
}
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a hard link on the filesystem.
///
@ -33,14 +32,5 @@ use crate::utils::Context as _;
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();
spawn_blocking(move || {
std::fs::hard_link(&from, &to).context(|| {
format!(
"could not create a hard link from `{}` to `{}`",
from.display(),
to.display()
)
})
})
.await
spawn_blocking(move || std::fs::hard_link(&from, &to)).await
}

@ -3,13 +3,11 @@
//! This module is an async version of [`std::fs`].
//!
//! [`os::unix::fs`]: ../os/unix/fs/index.html
//! [`os::windows::fs`]: ../os/windows/fs/index.html
//! [`std::fs`]: https://doc.rust-lang.org/std/fs/index.html
//!
//! # Platform-specific extensions
//!
//! * Unix: use the [`os::unix::fs`] module.
//! * Windows: use the [`os::windows::fs`] module.
//!
//! # Examples
//!

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads the entire contents of a file as raw bytes.
///
@ -37,8 +36,5 @@ use crate::utils::Context as _;
/// ```
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::read(&path).context(|| format!("could not read file `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::read(path)).await
}

@ -1,12 +1,11 @@
use std::future::Future;
use std::pin::Pin;
use std::future::Future;
use crate::fs::DirEntry;
use crate::io;
use crate::path::Path;
use crate::stream::Stream;
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
use crate::utils::Context as _;
/// Returns a stream of entries in a directory.
///
@ -46,12 +45,9 @@ use crate::utils::Context as _;
/// ```
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::read_dir(&path)
.context(|| format!("could not read directory `{}`", path.display()))
})
.await
.map(ReadDir::new)
spawn_blocking(move || std::fs::read_dir(path))
.await
.map(ReadDir::new)
}
/// A stream of entries in a directory.

@ -1,7 +1,6 @@
use crate::io;
use crate::path::{Path, PathBuf};
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads a symbolic link and returns the path it points to.
///
@ -29,10 +28,5 @@ use crate::utils::Context as _;
/// ```
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::read_link(&path)
.map(Into::into)
.context(|| format!("could not read link `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::read_link(path).map(Into::into)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads the entire contents of a file as a string.
///
@ -38,9 +37,5 @@ use crate::utils::Context as _;
/// ```
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::read_to_string(&path)
.context(|| format!("could not read file `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::read_to_string(path)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes an empty directory.
///
@ -30,9 +29,5 @@ use crate::utils::Context as _;
/// ```
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::remove_dir(&path)
.context(|| format!("could not remove directory `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::remove_dir(path)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes a directory and all of its contents.
///
@ -30,9 +29,5 @@ use crate::utils::Context as _;
/// ```
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::remove_dir_all(&path)
.context(|| format!("could not remove directory `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::remove_dir_all(path)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes a file.
///
@ -30,9 +29,5 @@ use crate::utils::Context as _;
/// ```
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
spawn_blocking(move || {
std::fs::remove_file(&path)
.context(|| format!("could not remove file `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::remove_file(path)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Renames a file or directory to a new location.
///
@ -35,14 +34,5 @@ use crate::utils::Context as _;
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();
spawn_blocking(move || {
std::fs::rename(&from, &to).context(|| {
format!(
"could not rename `{}` to `{}`",
from.display(),
to.display()
)
})
})
.await
spawn_blocking(move || std::fs::rename(&from, &to)).await
}

@ -1,7 +1,6 @@
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Writes a slice of bytes as the new contents of a file.
///
@ -34,9 +33,5 @@ use crate::utils::Context as _;
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();
spawn_blocking(move || {
std::fs::write(&path, contents)
.context(|| format!("could not write to file `{}`", path.display()))
})
.await
spawn_blocking(move || std::fs::write(path, contents)).await
}

@ -2,10 +2,10 @@ use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use futures_timer::Delay;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use crate::utils::{timer_after, Timer};
pin_project! {
#[doc(hidden)]
@ -14,13 +14,13 @@ pin_project! {
#[pin]
future: F,
#[pin]
delay: Timer,
delay: Delay,
}
}
impl<F> DelayFuture<F> {
pub fn new(future: F, dur: Duration) -> DelayFuture<F> {
let delay = timer_after(dur);
let delay = Delay::new(dur);
DelayFuture { future, delay }
}

@ -1,6 +1,6 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use async_macros::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
@ -12,7 +12,7 @@ pin_project! {
pub struct Join<L, R>
where
L: Future,
R: Future,
R: Future<Output = L::Output>
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
@ -22,7 +22,7 @@ pin_project! {
impl<L, R> Join<L, R>
where
L: Future,
R: Future,
R: Future<Output = L::Output>,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
@ -35,7 +35,7 @@ where
impl<L, R> Future for Join<L, R>
where
L: Future,
R: Future,
R: Future<Output = L::Output>,
{
type Output = (L::Output, R::Output);
@ -45,14 +45,16 @@ where
let mut left = this.left;
let mut right = this.right;
let is_left_ready = Future::poll(Pin::new(&mut left), cx).is_ready();
if is_left_ready && right.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
if Future::poll(Pin::new(&mut left), cx).is_ready() {
if right.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
}
}
let is_right_ready = Future::poll(Pin::new(&mut right), cx).is_ready();
if is_right_ready && left.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
if Future::poll(Pin::new(&mut right), cx).is_ready() {
if left.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
}
}
Poll::Pending

@ -7,6 +7,7 @@ cfg_unstable! {
mod try_join;
use std::time::Duration;
use delay::DelayFuture;
use flatten::FlattenFuture;
use crate::future::IntoFuture;
@ -16,13 +17,9 @@ cfg_unstable! {
use try_join::TryJoin;
}
cfg_unstable_default! {
use crate::future::timeout::TimeoutFuture;
}
extension_trait! {
use core::pin::Pin;
use core::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::task::{Context, Poll};
@ -136,7 +133,7 @@ extension_trait! {
[`Future`]: ../future/trait.Future.html
"#]
pub trait FutureExt: core::future::Future {
pub trait FutureExt: std::future::Future {
/// Returns a Future that delays execution for a specified time.
///
/// # Examples
@ -151,7 +148,7 @@ extension_trait! {
/// dbg!(a.await);
/// # })
/// ```
#[cfg(feature = "unstable")]
#[cfg(all(feature = "default", feature = "unstable"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn delay(self, dur: Duration) -> impl Future<Output = Self::Output> [DelayFuture<Self>]
where
@ -292,10 +289,10 @@ extension_trait! {
use async_std::future;
let a = future::ready(1u8);
let b = future::ready(2u16);
let b = future::ready(2u8);
let f = a.join(b);
assert_eq!(f.await, (1u8, 2u16));
assert_eq!(f.await, (1u8, 2u8));
# });
```
"#]
@ -307,7 +304,7 @@ extension_trait! {
) -> impl Future<Output = (<Self as std::future::Future>::Output, <F as std::future::Future>::Output)> [Join<Self, F>]
where
Self: std::future::Future + Sized,
F: std::future::Future,
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
{
Join::new(self, other)
}
@ -331,67 +328,33 @@ extension_trait! {
use async_std::prelude::*;
use async_std::future;
let a = future::ready(Err::<u8, &str>("Error"));
let a = future::ready(Err("Error"));
let b = future::ready(Ok(1u8));
let f = a.try_join(b);
assert_eq!(f.await, Err("Error"));
let a = future::ready(Ok::<u8, String>(1u8));
let b = future::ready(Ok::<u16, String>(2u16));
let b = future::ready(Ok::<u8, String>(2u8));
let f = a.try_join(b);
assert_eq!(f.await, Ok((1u8, 2u16)));
assert_eq!(f.await, Ok((1u8, 2u8)));
#
# Ok(()) }) }
```
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn try_join<F, A, B, E>(
fn try_join<F, T, E>(
self,
other: F
) -> impl Future<Output = Result<(A, B), E>> [TryJoin<Self, F>]
) -> impl Future<Output = Result<(T, T), E>> [TryJoin<Self, F>]
where
Self: std::future::Future<Output = Result<A, E>> + Sized,
F: std::future::Future<Output = Result<B, E>>,
Self: std::future::Future<Output = Result<T, E>> + Sized,
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
{
TryJoin::new(self, other)
}
#[doc = r#"
Waits for both the future and a timeout, if the timeout completes before
the future, it returns an TimeoutError.
# Example
```
# async_std::task::block_on(async {
#
use std::time::Duration;
use async_std::prelude::*;
use async_std::future;
let fut = future::ready(0);
let dur = Duration::from_millis(100);
let res = fut.timeout(dur).await;
assert!(res.is_ok());
let fut = future::pending::<()>();
let dur = Duration::from_millis(100);
let res = fut.timeout(dur).await;
assert!(res.is_err())
#
# });
```
"#]
#[cfg(any(all(feature = "default", feature = "unstable"), feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn timeout(self, dur: Duration) -> impl Future<Output = Self::Output> [TimeoutFuture<Self>]
where Self: Sized
{
TimeoutFuture::new(self, dur)
}
}
impl<F: Future + Unpin + ?Sized> Future for Box<F> {

@ -1,7 +1,7 @@
use std::future::Future;
use std::pin::Pin;
use crate::future::MaybeDone;
use async_macros::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};

@ -1,6 +1,6 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use async_macros::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
@ -12,7 +12,7 @@ pin_project! {
pub struct TryJoin<L, R>
where
L: Future,
R: Future,
R: Future<Output = L::Output>
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
@ -22,7 +22,7 @@ pin_project! {
impl<L, R> TryJoin<L, R>
where
L: Future,
R: Future,
R: Future<Output = L::Output>,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
@ -32,12 +32,12 @@ where
}
}
impl<L, R, A, B, E> Future for TryJoin<L, R>
impl<L, R, T, E> Future for TryJoin<L, R>
where
L: Future<Output = Result<A, E>>,
R: Future<Output = Result<B, E>>,
L: Future<Output = Result<T, E>>,
R: Future<Output = L::Output>,
{
type Output = Result<(A, B), E>;
type Output = Result<(T, T), E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();

@ -1,6 +1,6 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use async_macros::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};

@ -1,79 +0,0 @@
//! A type that wraps a future to keep track of its completion status.
//!
//! This implementation was taken from the original `macro_rules` `join/try_join`
//! macros in the `futures-preview` crate.
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::ready;
/// A future that may have completed.
#[derive(Debug)]
pub(crate) enum MaybeDone<Fut: Future> {
/// A not-yet-completed future
Future(Fut),
/// The output of the completed future
Done(Fut::Output),
/// The empty variant after the result of a [`MaybeDone`] has been
/// taken using the [`take`](MaybeDone::take) method.
Gone,
}
impl<Fut: Future> MaybeDone<Fut> {
/// Create a new instance of `MaybeDone`.
pub(crate) fn new(future: Fut) -> MaybeDone<Fut> {
Self::Future(future)
}
/// Returns an [`Option`] containing a reference to the output of the future.
/// The output of this method will be [`Some`] if and only if the inner
/// future has been completed and [`take`](MaybeDone::take)
/// has not yet been called.
#[inline]
pub(crate) fn output(self: Pin<&Self>) -> Option<&Fut::Output> {
let this = self.get_ref();
match this {
MaybeDone::Done(res) => Some(res),
_ => None,
}
}
/// Attempt to take the output of a `MaybeDone` without driving it
/// towards completion.
#[inline]
pub(crate) fn take(self: Pin<&mut Self>) -> Option<Fut::Output> {
unsafe {
let this = self.get_unchecked_mut();
match this {
MaybeDone::Done(_) => {}
MaybeDone::Future(_) | MaybeDone::Gone => return None,
};
if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) {
Some(output)
} else {
unreachable!()
}
}
}
}
impl<Fut: Future> Future for MaybeDone<Fut> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = unsafe {
match Pin::as_mut(&mut self).get_unchecked_mut() {
MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)),
MaybeDone::Done(_) => return Poll::Ready(()),
MaybeDone::Gone => panic!("MaybeDone polled after value taken"),
}
};
self.set(MaybeDone::Done(res));
Poll::Ready(())
}
}

@ -46,29 +46,22 @@
//! [`Future::race`]: trait.Future.html#method.race
//! [`Future::try_race`]: trait.Future.html#method.try_race
cfg_alloc! {
pub use future::Future;
pub(crate) mod future;
}
pub use future::Future;
pub use pending::pending;
pub use poll_fn::poll_fn;
pub use ready::ready;
cfg_std! {
pub use pending::pending;
pub use poll_fn::poll_fn;
pub use ready::ready;
pub(crate) mod future;
mod pending;
mod poll_fn;
mod ready;
mod pending;
mod poll_fn;
mod ready;
cfg_default! {
pub use timeout::{timeout, TimeoutError};
mod timeout;
}
#[cfg(any(feature = "unstable", feature = "default"))]
pub use timeout::{timeout, TimeoutError};
#[cfg(any(feature = "unstable", feature = "default"))]
mod timeout;
cfg_unstable! {
pub use into_future::IntoFuture;
pub(crate) use maybe_done::MaybeDone;
mod into_future;
mod maybe_done;
}

@ -1,13 +1,13 @@
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use std::future::Future;
use futures_timer::Delay;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use crate::utils::{timer_after, Timer};
/// Awaits a future or times out after a duration of time.
///
@ -33,26 +33,20 @@ pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError>
where
F: Future<Output = T>,
{
TimeoutFuture::new(f, dur).await
let f = TimeoutFuture {
future: f,
delay: Delay::new(dur),
};
f.await
}
pin_project! {
/// A future that times out after a duration of time.
pub struct TimeoutFuture<F> {
struct TimeoutFuture<F> {
#[pin]
future: F,
#[pin]
delay: Timer,
}
}
impl<F> TimeoutFuture<F> {
#[allow(dead_code)]
pub(super) fn new(future: F, dur: Duration) -> TimeoutFuture<F> {
TimeoutFuture {
future,
delay: timer_after(dur),
}
delay: Delay,
}
}

@ -29,12 +29,12 @@ extension_trait! {
```
# #[allow(unused_imports)]
use async_std::io::prelude::*;
use async_std::prelude::*;
```
[`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
[`futures::io::AsyncBufRead`]:
https://docs.rs/futures/0.3/futures/io/trait.AsyncBufRead.html
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
[provided methods]: #provided-methods
[`BufReadExt`]: ../io/prelude/trait.BufReadExt.html
[prelude]: ../prelude/index.html

@ -4,9 +4,11 @@ use std::{cmp, fmt};
use pin_project_lite::pin_project;
use crate::io::{self, BufRead, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
use crate::io::{self, BufRead, Read, Seek, SeekFrom};
use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024;
pin_project! {
/// Adds buffering to any reader.
///
@ -70,7 +72,7 @@ impl<R: io::Read> BufReader<R> {
/// # Ok(()) }) }
/// ```
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
BufReader::with_capacity(DEFAULT_CAPACITY, inner)
}
/// Creates a new buffered reader with the specified capacity.

@ -4,9 +4,11 @@ use std::pin::Pin;
use pin_project_lite::pin_project;
use crate::io::write::WriteExt;
use crate::io::{self, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE};
use crate::io::{self, Seek, SeekFrom, Write};
use crate::task::{Context, Poll, ready};
const DEFAULT_CAPACITY: usize = 8 * 1024;
pin_project! {
/// Wraps a writer and buffers its output.
///
@ -22,14 +24,14 @@ pin_project! {
/// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`.
///
/// Unlike the `BufWriter` type in `std`, this type does not write out the
/// contents of its buffer when it is dropped. Therefore, it is absolutely
/// critical that users explicitly flush the buffer before dropping a
/// `BufWriter`.
/// When the `BufWriter` is dropped, the contents of its buffer will be written
/// out. However, any errors that happen in the process of flushing the buffer
/// when the writer is dropped will be ignored. Code that wishes to handle such
/// errors must manually call [`flush`] before the writer is dropped.
///
/// This type is an async version of [`std::io::BufWriter`].
/// This type is an async version of [`std::io::BufReader`].
///
/// [`std::io::BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
@ -61,13 +63,10 @@ pin_project! {
/// use async_std::prelude::*;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?);
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// };
///
/// stream.flush().await?;
/// #
/// # Ok(()) }) }
/// ```
@ -88,32 +87,8 @@ pin_project! {
}
}
/// An error returned by `into_inner` which combines an error that
/// happened while writing out the buffer, and the buffered writer object
/// which may be used to recover from the condition.
///
/// # 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 = match buf_writer.into_inner().await {
/// Ok(s) => s,
/// Err(e) => {
/// // Here, e is an IntoInnerError
/// panic!("An error occurred");
/// }
/// };
/// #
/// # Ok(()) }) }
///```
#[derive(Debug)]
pub struct IntoInnerError<W>(W, crate::io::Error);
pub struct IntoInnerError<W>(W, std::io::Error);
impl<W: Write> BufWriter<W> {
/// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
@ -132,7 +107,7 @@ impl<W: Write> BufWriter<W> {
/// # Ok(()) }) }
/// ```
pub fn new(inner: W) -> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
BufWriter::with_capacity(DEFAULT_CAPACITY, inner)
}
/// Creates a new `BufWriter` with the specified buffer capacity.
@ -328,7 +303,7 @@ impl<W: Write> Write 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("BufWriter")
f.debug_struct("BufReader")
.field("writer", &self.inner)
.field("buf", &self.buf)
.finish()

@ -1,11 +1,10 @@
use std::future::Future;
use std::pin::Pin;
use std::future::Future;
use pin_project_lite::pin_project;
use crate::io::{self, BufRead, BufReader, Read, Write};
use crate::task::{Context, Poll};
use crate::utils::Context as _;
/// Copies the entire contents of a reader into a writer.
///
@ -91,7 +90,7 @@ where
writer,
amt: 0,
};
future.await.context(|| String::from("io::copy failed"))
future.await
}
/// Copies the entire contents of a reader into a writer.
@ -178,5 +177,5 @@ where
writer,
amt: 0,
};
future.await.context(|| String::from("io::copy failed"))
future.await
}

@ -105,8 +105,8 @@
//!
//! ```no_run
//! use async_std::fs::File;
//! use async_std::io::prelude::*;
//! use async_std::io::BufWriter;
//! use async_std::io::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
@ -116,8 +116,8 @@
//!
//! // write a byte to the buffer
//! writer.write(&[42]).await?;
//!
//! } // the buffer is flushed once writer goes out of scope
//! //
//! #
//! # Ok(()) }) }
//! ```
@ -269,19 +269,17 @@
//! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
//! [`.unwrap()`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
cfg_std! {
#[doc(inline)]
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
pub use buf_read::{BufRead, Lines, Split};
pub use buf_read::{BufRead, Lines};
pub use buf_reader::BufReader;
pub use buf_writer::{BufWriter, IntoInnerError};
pub use buf_writer::BufWriter;
pub use copy::copy;
pub use cursor::Cursor;
pub use empty::{empty, Empty};
pub use read::*;
pub use read::Read;
pub use repeat::{repeat, Repeat};
pub use seek::Seek;
pub use sink::{sink, Sink};
@ -293,7 +291,6 @@ cfg_std! {
pub(crate) mod read;
pub(crate) mod seek;
pub(crate) mod write;
pub(crate) mod utils;
mod buf_reader;
mod buf_writer;
@ -307,24 +304,22 @@ cfg_std! {
cfg_default! {
// For use in the print macros.
#[doc(hidden)]
#[cfg(not(target_os = "unknown"))]
pub use stdio::{_eprint, _print};
#[cfg(not(target_os = "unknown"))]
pub use stderr::{stderr, Stderr};
#[cfg(not(target_os = "unknown"))]
pub use stdin::{stdin, Stdin};
#[cfg(not(target_os = "unknown"))]
pub use stdout::{stdout, Stdout};
pub use timeout::timeout;
mod timeout;
#[cfg(not(target_os = "unknown"))]
mod stderr;
#[cfg(not(target_os = "unknown"))]
mod stdin;
#[cfg(not(target_os = "unknown"))]
mod stdio;
#[cfg(not(target_os = "unknown"))]
mod stdout;
}
cfg_unstable! {
pub use stderr::StderrLock;
pub use stdin::StdinLock;
pub use stdout::StdoutLock;
}

@ -32,7 +32,7 @@ impl<T: Read + Unpin> Stream for Bytes<T> {
}
}
#[cfg(all(test, default))]
#[cfg(test)]
mod tests {
use crate::io;
use crate::prelude::*;

@ -165,7 +165,7 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
}
}
#[cfg(all(test, default))]
#[cfg(test)]
mod tests {
use crate::io;
use crate::prelude::*;

@ -17,10 +17,6 @@ use std::mem;
use crate::io::IoSliceMut;
pub use bytes::Bytes;
pub use chain::Chain;
pub use take::Take;
extension_trait! {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
@ -44,7 +40,7 @@ extension_trait! {
[`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
[`futures::io::AsyncRead`]:
https://docs.rs/futures/0.3/futures/io/trait.AsyncRead.html
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
[`poll_read`]: #tymethod.poll_read
[`poll_read_vectored`]: #method.poll_read_vectored
[`ReadExt`]: ../io/prelude/trait.ReadExt.html
@ -305,11 +301,11 @@ extension_trait! {
# Ok(()) }) }
```
"#]
fn take(self, limit: u64) -> Take<Self>
fn take(self, limit: u64) -> take::Take<Self>
where
Self: Sized,
{
Take { inner: self, limit }
take::Take { inner: self, limit }
}
#[doc = r#"
@ -381,8 +377,8 @@ extension_trait! {
# Ok(()) }) }
```
"#]
fn bytes(self) -> Bytes<Self> where Self: Sized {
Bytes { inner: self }
fn bytes(self) -> bytes::Bytes<Self> where Self: Sized {
bytes::Bytes { inner: self }
}
#[doc = r#"
@ -417,8 +413,8 @@ extension_trait! {
# Ok(()) }) }
```
"#]
fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized {
Chain { first: self, second: next, done_first: false }
fn chain<R: Read>(self, next: R) -> chain::Chain<Self, R> where Self: Sized {
chain::Chain { first: self, second: next, done_first: false }
}
}
@ -477,13 +473,13 @@ unsafe fn initialize<R: futures_io::AsyncRead>(_reader: &R, buf: &mut [u8]) {
std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len())
}
#[cfg(all(test, not(target_os = "unknown")))]
#[cfg(test)]
mod tests {
use crate::io;
use crate::prelude::*;
#[test]
fn test_read_by_ref() {
fn test_read_by_ref() -> io::Result<()> {
crate::task::block_on(async {
let mut f = io::Cursor::new(vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8]);
let mut buffer = Vec::new();
@ -493,13 +489,14 @@ mod tests {
let reference = f.by_ref();
// read at most 5 bytes
assert_eq!(reference.take(5).read_to_end(&mut buffer).await.unwrap(), 5);
assert_eq!(reference.take(5).read_to_end(&mut buffer).await?, 5);
assert_eq!(&buffer, &[0, 1, 2, 3, 4])
} // drop our &mut reference so we can use f again
// original file still usable, read the rest
assert_eq!(f.read_to_end(&mut other_buffer).await.unwrap(), 4);
assert_eq!(f.read_to_end(&mut other_buffer).await?, 4);
assert_eq!(&other_buffer, &[5, 6, 7, 8]);
});
Ok(())
})
}
}

@ -218,7 +218,7 @@ impl<T: BufRead> BufRead for Take<T> {
}
}
#[cfg(all(test, not(target_os = "unknown")))]
#[cfg(test)]
mod tests {
use crate::io;
use crate::prelude::*;

@ -27,7 +27,7 @@ extension_trait! {
[`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
[`futures::io::AsyncSeek`]:
https://docs.rs/futures/0.3/futures/io/trait.AsyncSeek.html
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
[provided methods]: #provided-methods
[`SeekExt`]: ../io/prelude/trait.SeekExt.html
[prelude]: ../prelude/index.html

@ -5,6 +5,11 @@ use std::future::Future;
use crate::io::{self, Write};
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
cfg_unstable! {
use once_cell::sync::Lazy;
use std::io::Write as _;
}
/// Constructs a new handle to the standard error of the current process.
///
/// This function is an async version of [`std::io::stderr`].
@ -53,6 +58,22 @@ pub fn stderr() -> Stderr {
#[derive(Debug)]
pub struct Stderr(Mutex<State>);
/// A locked reference to the Stderr handle.
///
/// This handle implements the [`Write`] traits, and is constructed via the [`Stderr::lock`]
/// method.
///
/// [`Write`]: trait.Read.html
/// [`Stderr::lock`]: struct.Stderr.html#method.lock
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Debug)]
pub struct StderrLock<'a>(std::io::StderrLock<'a>);
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
unsafe impl Send for StderrLock<'_> {}
/// The state of the asynchronous stderr.
///
/// The stderr can be either idle or busy performing an asynchronous operation.
@ -87,14 +108,42 @@ enum Operation {
Flush(io::Result<()>),
}
impl Stderr {
/// Locks this handle to the standard error stream, returning a writable guard.
///
/// The lock is released when the returned lock goes out of scope. The returned guard also implements the Write trait for writing data.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::io;
/// use async_std::prelude::*;
///
/// let stderr = io::stderr();
/// let mut handle = stderr.lock().await;
///
/// handle.write_all(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub async fn lock(&self) -> StderrLock<'static> {
static STDERR: Lazy<std::io::Stderr> = Lazy::new(std::io::stderr);
spawn_blocking(move || StderrLock(STDERR.lock())).await
}
}
impl Write for Stderr {
fn poll_write(
self: Pin<&mut Self>,
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let mut state_guard = self.0.lock().unwrap();
let state = &mut *state_guard;
let state = &mut *self.0.lock().unwrap();
loop {
match state {
@ -138,9 +187,8 @@ impl Write for Stderr {
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let mut state_guard = self.0.lock().unwrap();
let state = &mut *state_guard;
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let state = &mut *self.0.lock().unwrap();
loop {
match state {
@ -191,3 +239,23 @@ cfg_windows! {
}
}
}
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
impl io::Write for StderrLock<'_> {
fn poll_write(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(self.0.write(buf))
}
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(self.0.flush())
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.poll_flush(cx)
}
}

@ -1,11 +1,15 @@
use std::future::Future;
use std::pin::Pin;
use std::sync::Mutex;
use std::future::Future;
use crate::future;
use crate::io::{self, Read};
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
use crate::utils::Context as _;
cfg_unstable! {
use once_cell::sync::Lazy;
use std::io::Read as _;
}
/// Constructs a new handle to the standard input of the current process.
///
@ -56,6 +60,21 @@ pub fn stdin() -> Stdin {
#[derive(Debug)]
pub struct Stdin(Mutex<State>);
/// A locked reference to the Stdin handle.
///
/// This handle implements the [`Read`] traits, and is constructed via the [`Stdin::lock`] method.
///
/// [`Read`]: trait.Read.html
/// [`Stdin::lock`]: struct.Stdin.html#method.lock
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(feature = "unstable")]
#[derive(Debug)]
pub struct StdinLock<'a>(std::io::StdinLock<'a>);
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
unsafe impl Send for StdinLock<'_> {}
/// The state of the asynchronous stdin.
///
/// The stdin can be either idle or busy performing an asynchronous operation.
@ -143,18 +162,45 @@ impl Stdin {
}
})
.await
.context(|| String::from("could not read line on stdin"))
}
/// Locks this handle to the standard input stream, returning a readable guard.
///
/// The lock is released when the returned lock goes out of scope. The returned guard also implements the Read trait for accessing the underlying data.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::io;
/// use async_std::prelude::*;
///
/// let mut buffer = String::new();
///
/// let stdin = io::stdin();
/// let mut handle = stdin.lock().await;
///
/// handle.read_to_string(&mut buffer).await?;
/// #
/// # Ok(()) }) }
/// ```
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub async fn lock(&self) -> StdinLock<'static> {
static STDIN: Lazy<std::io::Stdin> = Lazy::new(std::io::stdin);
spawn_blocking(move || StdinLock(STDIN.lock())).await
}
}
impl Read for Stdin {
fn poll_read(
self: Pin<&mut Self>,
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let mut state_guard = self.0.lock().unwrap();
let state = &mut *state_guard;
let state = &mut *self.0.lock().unwrap();
loop {
match state {
@ -217,3 +263,15 @@ cfg_windows! {
}
}
}
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
impl Read for StdinLock<'_> {
fn poll_read(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(self.0.read(buf))
}
}

@ -5,6 +5,11 @@ use std::future::Future;
use crate::io::{self, Write};
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
cfg_unstable! {
use once_cell::sync::Lazy;
use std::io::Write as _;
}
/// Constructs a new handle to the standard output of the current process.
///
/// This function is an async version of [`std::io::stdout`].
@ -53,6 +58,22 @@ pub fn stdout() -> Stdout {
#[derive(Debug)]
pub struct Stdout(Mutex<State>);
/// A locked reference to the Stderr handle.
///
/// This handle implements the [`Write`] traits, and is constructed via the [`Stdout::lock`]
/// method.
///
/// [`Write`]: trait.Read.html
/// [`Stdout::lock`]: struct.Stdout.html#method.lock
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[derive(Debug)]
pub struct StdoutLock<'a>(std::io::StdoutLock<'a>);
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
unsafe impl Send for StdoutLock<'_> {}
/// The state of the asynchronous stdout.
///
/// The stdout can be either idle or busy performing an asynchronous operation.
@ -87,14 +108,42 @@ enum Operation {
Flush(io::Result<()>),
}
impl Stdout {
/// Locks this handle to the standard error stream, returning a writable guard.
///
/// The lock is released when the returned lock goes out of scope. The returned guard also implements the Write trait for writing data.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::io;
/// use async_std::prelude::*;
///
/// let stdout = io::stdout();
/// let mut handle = stdout.lock().await;
///
/// handle.write_all(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub async fn lock(&self) -> StdoutLock<'static> {
static STDOUT: Lazy<std::io::Stdout> = Lazy::new(std::io::stdout);
spawn_blocking(move || StdoutLock(STDOUT.lock())).await
}
}
impl Write for Stdout {
fn poll_write(
self: Pin<&mut Self>,
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let mut state_guard = self.0.lock().unwrap();
let state = &mut *state_guard;
let state = &mut *self.0.lock().unwrap();
loop {
match state {
@ -138,9 +187,8 @@ impl Write for Stdout {
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let mut state_guard = self.0.lock().unwrap();
let state = &mut *state_guard;
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let state = &mut *self.0.lock().unwrap();
loop {
match state {
@ -191,3 +239,23 @@ cfg_windows! {
}
}
}
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
impl Write for StdoutLock<'_> {
fn poll_write(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(self.0.write(buf))
}
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(self.0.flush())
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.poll_flush(cx)
}
}

@ -1,12 +1,12 @@
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use std::future::Future;
use futures_timer::Delay;
use pin_project_lite::pin_project;
use crate::io;
use crate::utils::{timer_after, Timer};
/// Awaits an I/O future or times out after a duration of time.
///
@ -37,7 +37,7 @@ where
F: Future<Output = io::Result<T>>,
{
Timeout {
timeout: timer_after(dur),
timeout: Delay::new(dur),
future: f,
}
.await
@ -53,7 +53,7 @@ pin_project! {
#[pin]
future: F,
#[pin]
timeout: Timer,
timeout: Delay,
}
}

@ -1,42 +0,0 @@
use crate::utils::Context;
use std::{error::Error as StdError, fmt, io};
/// Wrap `std::io::Error` with additional message
///
/// Keeps the original error kind and stores the original I/O error as `source`.
impl<T> Context for Result<T, std::io::Error> {
fn context(self, message: impl Fn() -> String) -> Self {
self.map_err(|e| VerboseError::wrap(e, message()))
}
}
#[derive(Debug)]
pub(crate) struct VerboseError {
source: io::Error,
message: String,
}
impl VerboseError {
pub(crate) fn wrap(source: io::Error, message: impl Into<String>) -> io::Error {
io::Error::new(
source.kind(),
VerboseError {
source,
message: message.into(),
},
)
}
}
impl fmt::Display for VerboseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl StdError for VerboseError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.source)
}
}

@ -35,7 +35,7 @@ extension_trait! {
[`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
[`futures::io::AsyncWrite`]:
https://docs.rs/futures/0.3/futures/io/trait.AsyncWrite.html
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
[`poll_write`]: #tymethod.poll_write
[`poll_write_vectored`]: #method.poll_write_vectored
[`poll_flush`]: #tymethod.poll_flush

@ -6,7 +6,6 @@ use crate::task::{Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
#[must_use]
pub struct WriteFmtFuture<'a, T: Unpin + ?Sized> {
pub(crate) writer: &'a mut T,
pub(crate) res: Option<io::Result<Vec<u8>>>,

@ -47,7 +47,7 @@
//! encouraged to read it. The `async-std` source is generally high
//! quality and a peek behind the curtains is often enlightening.
//!
//! Modules in this crate are organized in the same way as in `std`, except blocking
//! Modules in this crate are organized in the same way as in `async-std`, except blocking
//! functions have been replaced with async functions and threads have been replaced with
//! lightweight tasks.
//!
@ -131,61 +131,18 @@
//!
//! # Examples
//!
//! All examples require the [`"attributes"` feature](#features) to be enabled.
//! This feature is not enabled by default because it significantly impacts
//! compile times. See [`task::block_on`] for an alternative way to start
//! executing tasks.
//! Spawn a task and block the current thread on its result:
//!
//! Call an async function from the main function:
//!
#![cfg_attr(feature = "attributes", doc = "```")]
#![cfg_attr(not(feature = "attributes"), doc = "```ignore")]
//! async fn say_hello() {
//! println!("Hello, world!");
//! }
//!
//! #[async_std::main]
//! async fn main() {
//! say_hello().await;
//! }
//! ```
//! use async_std::task;
//!
//! Await two futures concurrently, and return a tuple of their output:
//!
#![cfg_attr(feature = "attributes", doc = "```")]
#![cfg_attr(not(feature = "attributes"), doc = "```ignore")]
//! use async_std::prelude::*;
//!
//! #[async_std::main]
//! async fn main() {
//! let a = async { 1u8 };
//! let b = async { 2u8 };
//! assert_eq!(a.join(b).await, (1u8, 2u8))
//! fn main() {
//! task::block_on(async {
//! println!("Hello, world!");
//! })
//! }
//! ```
//!
//! Create a UDP server that echoes back each received message to the sender:
//!
#![cfg_attr(feature = "attributes", doc = "```no_run")]
#![cfg_attr(not(feature = "attributes"), doc = "```ignore")]
//! use async_std::net::UdpSocket;
//!
//! #[async_std::main]
//! async fn main() -> std::io::Result<()> {
//! let socket = UdpSocket::bind("127.0.0.1:8080").await?;
//! println!("Listening on {}", socket.local_addr()?);
//!
//! let mut buf = vec![0u8; 1024];
//!
//! loop {
//! let (recv, peer) = socket.recv_from(&mut buf).await?;
//! let sent = socket.send_to(&buf[..recv], &peer).await?;
//! println!("Sent {} out of {} bytes to {}", sent, recv, peer);
//! }
//! }
//! ```
//! [`task::block_on`]: task/fn.block_on.html
//!
//! # Features
//!
//! Items marked with
@ -197,7 +154,7 @@
//!
//! ```toml
//! [dependencies.async-std]
//! version = "1.6.2"
//! version = "1.0.0"
//! features = ["unstable"]
//! ```
//!
@ -210,55 +167,20 @@
//!
//! ```toml
//! [dependencies.async-std]
//! version = "1.6.2"
//! version = "1.0.0"
//! features = ["attributes"]
//! ```
//!
//! Compatibility with the `tokio` runtime is possible using the `tokio02`
//! Cargo feature:
//!
//! ```toml
//! [dependencies.async-std]
//! version = "1.6.2"
//! features = ["tokio02"]
//! ```
//!
//! Additionally it's possible to only use the core traits and combinators by
//! only enabling the `std` Cargo feature:
//!
//! ```toml
//! [dependencies.async-std]
//! version = "1.6.2"
//! version = "1.0.0"
//! default-features = false
//! features = ["std"]
//! ```
//!
//! And to use async-std on `no_std` targets that only support `alloc` only
//! enable the `alloc` Cargo feature:
//!
//! ```toml
//! [dependencies.async-std]
//! version = "1.6.2"
//! default-features = false
//! features = ["alloc"]
//! ```
//!
//! # Runtime configuration
//!
//! Several environment variables are available to tune the async-std
//! runtime:
//!
//! * `ASYNC_STD_THREAD_COUNT`: The number of threads that the
//! async-std runtime will start. By default, this is one per logical
//! cpu as reported by the [num_cpus](num_cpus) crate, which may be
//! different than the number of physical cpus. Async-std _will panic_
//! if this is set to any value other than a positive integer.
//! * `ASYNC_STD_THREAD_NAME`: The name that async-std's runtime
//! threads report to the operating system. The default value is
//! `"async-std/runtime"`.
//!
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "docs", feature(doc_cfg))]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![allow(clippy::mutex_atomic, clippy::module_inception)]
@ -267,8 +189,6 @@
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
#![recursion_limit = "2048"]
extern crate alloc;
#[macro_use]
mod utils;
@ -280,31 +200,24 @@ pub use async_attributes::{main, test};
#[cfg(feature = "std")]
mod macros;
cfg_alloc! {
pub mod task;
pub mod future;
pub mod stream;
}
cfg_std! {
pub mod future;
pub mod io;
pub mod os;
pub mod prelude;
pub mod stream;
pub mod sync;
pub mod task;
}
cfg_default! {
#[cfg(not(target_os = "unknown"))]
pub mod fs;
pub mod path;
pub mod net;
#[cfg(not(target_os = "unknown"))]
pub(crate) mod rt;
}
cfg_unstable! {
pub mod pin;
#[cfg(not(target_os = "unknown"))]
pub mod process;
mod unit;
@ -313,9 +226,7 @@ cfg_unstable! {
mod option;
mod string;
mod collections;
}
cfg_unstable_default! {
#[doc(inline)]
pub use std::{write, writeln};
}

@ -1,12 +1,11 @@
use std::future::Future;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::pin::Pin;
use std::future::Future;
use crate::io;
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
use crate::utils::Context as ErrorContext;
cfg_not_docs! {
macro_rules! ret {
@ -68,18 +67,6 @@ pub enum ToSocketAddrsFuture<I> {
Done,
}
/// Wrap `std::io::Error` with additional message
///
/// Keeps the original error kind and stores the original I/O error as `source`.
impl<T> ErrorContext for ToSocketAddrsFuture<T> {
fn context(self, message: impl Fn() -> String) -> Self {
match self {
ToSocketAddrsFuture::Ready(res) => ToSocketAddrsFuture::Ready(res.context(message)),
x => x,
}
}
}
impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<I> {
type Output = io::Result<I>;
@ -123,9 +110,7 @@ impl ToSocketAddrs for SocketAddrV4 {
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
SocketAddr::V4(*self)
.to_socket_addrs()
.context(|| format!("could not resolve address `{}`", self))
SocketAddr::V4(*self).to_socket_addrs()
}
}
@ -138,9 +123,7 @@ impl ToSocketAddrs for SocketAddrV6 {
impl Future<Output = Self::Iter>,
ToSocketAddrsFuture<Self::Iter>
) {
SocketAddr::V6(*self)
.to_socket_addrs()
.context(|| format!("could not resolve address `{}`", self))
SocketAddr::V6(*self).to_socket_addrs()
}
}
@ -212,9 +195,7 @@ impl ToSocketAddrs for (&str, u16) {
let host = host.to_string();
let task = spawn_blocking(move || {
let addr = (host.as_str(), port);
std::net::ToSocketAddrs::to_socket_addrs(&addr)
.context(|| format!("could not resolve address `{:?}`", addr))
std::net::ToSocketAddrs::to_socket_addrs(&(host.as_str(), port))
});
ToSocketAddrsFuture::Resolving(task)
}
@ -234,10 +215,7 @@ impl ToSocketAddrs for str {
}
let addr = self.to_string();
let task = spawn_blocking(move || {
std::net::ToSocketAddrs::to_socket_addrs(addr.as_str())
.context(|| format!("could not resolve address `{:?}`", addr))
});
let task = spawn_blocking(move || std::net::ToSocketAddrs::to_socket_addrs(addr.as_str()));
ToSocketAddrsFuture::Resolving(task)
}
}

@ -0,0 +1,315 @@
use std::fmt;
use std::sync::{Arc, Mutex};
use mio::{self, Evented};
use once_cell::sync::Lazy;
use slab::Slab;
use crate::io;
use crate::task::{Context, Poll, Waker};
use crate::utils::abort_on_panic;
/// Data associated with a registered I/O handle.
#[derive(Debug)]
struct Entry {
/// A unique identifier.
token: mio::Token,
/// Tasks that are blocked on reading from this I/O handle.
readers: Mutex<Vec<Waker>>,
/// Thasks that are blocked on writing to this I/O handle.
writers: Mutex<Vec<Waker>>,
}
/// The state of a networking driver.
struct Reactor {
/// A mio instance that polls for new events.
poller: mio::Poll,
/// A collection of registered I/O handles.
entries: Mutex<Slab<Arc<Entry>>>,
/// Dummy I/O handle that is only used to wake up the polling thread.
notify_reg: (mio::Registration, mio::SetReadiness),
/// An identifier for the notification handle.
notify_token: mio::Token,
}
impl Reactor {
/// Creates a new reactor for polling I/O events.
fn new() -> io::Result<Reactor> {
let poller = mio::Poll::new()?;
let notify_reg = mio::Registration::new2();
let mut reactor = Reactor {
poller,
entries: Mutex::new(Slab::new()),
notify_reg,
notify_token: mio::Token(0),
};
// Register a dummy I/O handle for waking up the polling thread.
let entry = reactor.register(&reactor.notify_reg.0)?;
reactor.notify_token = entry.token;
Ok(reactor)
}
/// Registers an I/O event source and returns its associated entry.
fn register(&self, source: &dyn Evented) -> io::Result<Arc<Entry>> {
let mut entries = self.entries.lock().unwrap();
// Reserve a vacant spot in the slab and use its key as the token value.
let vacant = entries.vacant_entry();
let token = mio::Token(vacant.key());
// Allocate an entry and insert it into the slab.
let entry = Arc::new(Entry {
token,
readers: Mutex::new(Vec::new()),
writers: Mutex::new(Vec::new()),
});
vacant.insert(entry.clone());
// Register the I/O event source in the poller.
let interest = mio::Ready::all();
let opts = mio::PollOpt::edge();
self.poller.register(source, token, interest, opts)?;
Ok(entry)
}
/// Deregisters an I/O event source associated with an entry.
fn deregister(&self, source: &dyn Evented, entry: &Entry) -> io::Result<()> {
// Deregister the I/O object from the mio instance.
self.poller.deregister(source)?;
// Remove the entry associated with the I/O object.
self.entries.lock().unwrap().remove(entry.token.0);
Ok(())
}
// fn notify(&self) {
// self.notify_reg
// .1
// .set_readiness(mio::Ready::readable())
// .unwrap();
// }
}
/// The state of the global networking driver.
static REACTOR: Lazy<Reactor> = Lazy::new(|| {
// Spawn a thread that waits on the poller for new events and wakes up tasks blocked on I/O
// handles.
std::thread::Builder::new()
.name("async-std/net".to_string())
.spawn(move || {
// If the driver thread panics, there's not much we can do. It is not a
// recoverable error and there is no place to propagate it into so we just abort.
abort_on_panic(|| {
main_loop().expect("async networking thread has panicked");
})
})
.expect("cannot start a thread driving blocking tasks");
Reactor::new().expect("cannot initialize reactor")
});
/// Waits on the poller for new events and wakes up tasks blocked on I/O handles.
fn main_loop() -> io::Result<()> {
let reactor = &REACTOR;
let mut events = mio::Events::with_capacity(1000);
loop {
// Block on the poller until at least one new event comes in.
reactor.poller.poll(&mut events, None)?;
// Lock the entire entry table while we're processing new events.
let entries = reactor.entries.lock().unwrap();
for event in events.iter() {
let token = event.token();
if token == reactor.notify_token {
// If this is the notification token, we just need the notification state.
reactor.notify_reg.1.set_readiness(mio::Ready::empty())?;
} else {
// Otherwise, look for the entry associated with this token.
if let Some(entry) = entries.get(token.0) {
// Set the readiness flags from this I/O event.
let readiness = event.readiness();
// Wake up reader tasks blocked on this I/O handle.
if !(readiness & reader_interests()).is_empty() {
for w in entry.readers.lock().unwrap().drain(..) {
w.wake();
}
}
// Wake up writer tasks blocked on this I/O handle.
if !(readiness & writer_interests()).is_empty() {
for w in entry.writers.lock().unwrap().drain(..) {
w.wake();
}
}
}
}
}
}
}
/// An I/O handle powered by the networking driver.
///
/// This handle wraps an I/O event source and exposes a "futurized" interface on top of it,
/// implementing traits `AsyncRead` and `AsyncWrite`.
pub struct Watcher<T: Evented> {
/// Data associated with the I/O handle.
entry: Arc<Entry>,
/// The I/O event source.
source: Option<T>,
}
impl<T: Evented> Watcher<T> {
/// Creates a new I/O handle.
///
/// The provided I/O event source will be kept registered inside the reactor's poller for the
/// lifetime of the returned I/O handle.
pub fn new(source: T) -> Watcher<T> {
Watcher {
entry: REACTOR
.register(&source)
.expect("cannot register an I/O event source"),
source: Some(source),
}
}
/// Returns a reference to the inner I/O event source.
pub fn get_ref(&self) -> &T {
self.source.as_ref().unwrap()
}
/// Polls the inner I/O source for a non-blocking read operation.
///
/// If the operation returns an error of the `io::ErrorKind::WouldBlock` kind, the current task
/// will be registered for wakeup when the I/O source becomes readable.
pub fn poll_read_with<'a, F, R>(&'a self, cx: &mut Context<'_>, mut f: F) -> Poll<io::Result<R>>
where
F: FnMut(&'a T) -> io::Result<R>,
{
// If the operation isn't blocked, return its result.
match f(self.source.as_ref().unwrap()) {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
res => return Poll::Ready(res),
}
// Lock the waker list.
let mut list = self.entry.readers.lock().unwrap();
// Try running the operation again.
match f(self.source.as_ref().unwrap()) {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
res => return Poll::Ready(res),
}
// Register the task if it isn't registered already.
if list.iter().all(|w| !w.will_wake(cx.waker())) {
list.push(cx.waker().clone());
}
Poll::Pending
}
/// Polls the inner I/O source for a non-blocking write operation.
///
/// If the operation returns an error of the `io::ErrorKind::WouldBlock` kind, the current task
/// will be registered for wakeup when the I/O source becomes writable.
pub fn poll_write_with<'a, F, R>(
&'a self,
cx: &mut Context<'_>,
mut f: F,
) -> Poll<io::Result<R>>
where
F: FnMut(&'a T) -> io::Result<R>,
{
// If the operation isn't blocked, return its result.
match f(self.source.as_ref().unwrap()) {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
res => return Poll::Ready(res),
}
// Lock the waker list.
let mut list = self.entry.writers.lock().unwrap();
// Try running the operation again.
match f(self.source.as_ref().unwrap()) {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
res => return Poll::Ready(res),
}
// Register the task if it isn't registered already.
if list.iter().all(|w| !w.will_wake(cx.waker())) {
list.push(cx.waker().clone());
}
Poll::Pending
}
/// Deregisters and returns the inner I/O source.
///
/// This method is typically used to convert `Watcher`s to raw file descriptors/handles.
#[allow(dead_code)]
pub fn into_inner(mut self) -> T {
let source = self.source.take().unwrap();
REACTOR
.deregister(&source, &self.entry)
.expect("cannot deregister I/O event source");
source
}
}
impl<T: Evented> Drop for Watcher<T> {
fn drop(&mut self) {
if let Some(ref source) = self.source {
REACTOR
.deregister(source, &self.entry)
.expect("cannot deregister I/O event source");
}
}
}
impl<T: Evented + fmt::Debug> fmt::Debug for Watcher<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Watcher")
.field("entry", &self.entry)
.field("source", &self.source)
.finish()
}
}
/// Returns a mask containing flags that interest tasks reading from I/O handles.
#[inline]
fn reader_interests() -> mio::Ready {
mio::Ready::all() - mio::Ready::writable()
}
/// Returns a mask containing flags that interest tasks writing into I/O handles.
#[inline]
fn writer_interests() -> mio::Ready {
mio::Ready::writable() | hup()
}
/// Returns a flag containing the hangup status.
#[inline]
fn hup() -> mio::Ready {
#[cfg(unix)]
let ready = mio::unix::UnixReady::hup().into();
#[cfg(not(unix))]
let ready = mio::Ready::empty();
ready
}

@ -61,16 +61,11 @@ pub use std::net::Shutdown;
pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
#[cfg(not(target_os = "unknown"))]
pub use addr::ToSocketAddrs;
#[cfg(not(target_os = "unknown"))]
pub use tcp::{Incoming, TcpListener, TcpStream};
#[cfg(not(target_os = "unknown"))]
pub use udp::UdpSocket;
#[cfg(not(target_os = "unknown"))]
mod addr;
#[cfg(not(target_os = "unknown"))]
pub(crate) mod driver;
mod tcp;
#[cfg(not(target_os = "unknown"))]
mod udp;

@ -1,13 +1,12 @@
use std::future::Future;
use std::net::SocketAddr;
use std::future::Future;
use std::pin::Pin;
use smol::Async;
use crate::future;
use crate::io;
use crate::net::driver::Watcher;
use crate::net::{TcpStream, ToSocketAddrs};
use crate::stream::Stream;
use crate::sync::Arc;
use crate::task::{Context, Poll};
/// A TCP socket server, listening for connections.
@ -49,7 +48,7 @@ use crate::task::{Context, Poll};
/// ```
#[derive(Debug)]
pub struct TcpListener {
watcher: Async<std::net::TcpListener>,
watcher: Watcher<mio::net::TcpListener>,
}
impl TcpListener {
@ -75,15 +74,14 @@ impl TcpListener {
///
/// [`local_addr`]: #method.local_addr
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpListener> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let mut last_err = None;
let addrs = addrs.to_socket_addrs().await?;
for addr in addrs {
match Async::<std::net::TcpListener>::bind(&addr) {
Ok(listener) => {
return Ok(TcpListener { watcher: listener });
for addr in addrs.to_socket_addrs().await? {
match mio::net::TcpListener::bind(&addr) {
Ok(mio_listener) => {
return Ok(TcpListener {
watcher: Watcher::new(mio_listener),
});
}
Err(err) => last_err = Some(err),
}
@ -114,9 +112,13 @@ impl TcpListener {
/// # Ok(()) }) }
/// ```
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (stream, addr) = self.watcher.accept().await?;
let (io, addr) =
future::poll_fn(|cx| self.watcher.poll_read_with(cx, |inner| inner.accept_std()))
.await?;
let mio_stream = mio::net::TcpStream::from_stream(io)?;
let stream = TcpStream {
watcher: Arc::new(stream),
watcher: Watcher::new(mio_stream),
};
Ok((stream, addr))
}
@ -202,10 +204,9 @@ impl<'a> Stream for Incoming<'a> {
impl From<std::net::TcpListener> for TcpListener {
/// Converts a `std::net::TcpListener` into its asynchronous equivalent.
fn from(listener: std::net::TcpListener) -> TcpListener {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let mio_listener = mio::net::TcpListener::from_std(listener).unwrap();
TcpListener {
watcher: Async::new(listener).expect("TcpListener is known to be good"),
watcher: Watcher::new(mio_listener),
}
}
}
@ -227,31 +228,29 @@ cfg_unix! {
impl IntoRawFd for TcpListener {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}
}
cfg_windows! {
use crate::os::windows::io::{
AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket,
};
impl AsRawSocket for TcpListener {
fn as_raw_socket(&self) -> RawSocket {
self.watcher.as_raw_socket()
}
}
impl FromRawSocket for TcpListener {
unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
std::net::TcpListener::from_raw_socket(handle).into()
}
}
impl IntoRawSocket for TcpListener {
fn into_raw_socket(self) -> RawSocket {
self.watcher.into_raw_socket()
}
}
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for TcpListener {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpListener {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
// net::TcpListener::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -1,13 +1,12 @@
use std::io::{IoSlice, IoSliceMut};
use std::io::{IoSlice, IoSliceMut, Read as _, Write as _};
use std::net::SocketAddr;
use std::pin::Pin;
use smol::Async;
use crate::future;
use crate::io::{self, Read, Write};
use crate::net::driver::Watcher;
use crate::net::ToSocketAddrs;
use crate::sync::Arc;
use crate::task::{Context, Poll};
use crate::task::{spawn_blocking, Context, Poll};
/// A TCP stream between a local and a remote socket.
///
@ -23,9 +22,9 @@ use crate::task::{Context, Poll};
/// [`connect`]: struct.TcpStream.html#method.connect
/// [accepting]: struct.TcpListener.html#method.accept
/// [listener]: struct.TcpListener.html
/// [`AsyncRead`]: https://docs.rs/futures/0.3/futures/io/trait.AsyncRead.html
/// [`AsyncWrite`]: https://docs.rs/futures/0.3/futures/io/trait.AsyncWrite.html
/// [`futures::io`]: https://docs.rs/futures/0.3/futures/io/index.html
/// [`AsyncRead`]: https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
/// [`AsyncWrite`]: https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
/// [`futures::io`]: https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/index.html
/// [`shutdown`]: struct.TcpStream.html#method.shutdown
/// [`std::net::TcpStream`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html
///
@ -45,9 +44,9 @@ use crate::task::{Context, Poll};
/// #
/// # Ok(()) }) }
/// ```
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct TcpStream {
pub(super) watcher: Arc<Async<std::net::TcpStream>>,
pub(super) watcher: Watcher<mio::net::TcpStream>,
}
impl TcpStream {
@ -71,22 +70,21 @@ impl TcpStream {
/// # Ok(()) }) }
/// ```
pub async fn connect<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpStream> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let mut last_err = None;
let addrs = addrs.to_socket_addrs().await?;
for addr in addrs {
match Async::<std::net::TcpStream>::connect(&addr).await {
Ok(stream) => {
return Ok(TcpStream {
watcher: Arc::new(stream),
});
}
Err(e) => {
last_err = Some(e);
continue;
}
for addr in addrs.to_socket_addrs().await? {
let res = spawn_blocking(move || {
let std_stream = std::net::TcpStream::connect(addr)?;
let mio_stream = mio::net::TcpStream::from_stream(std_stream)?;
Ok(TcpStream {
watcher: Watcher::new(mio_stream),
})
})
.await;
match res {
Ok(stream) => return Ok(stream),
Err(err) => last_err = Some(err),
}
}
@ -204,7 +202,7 @@ impl TcpStream {
/// # Ok(()) }) }
/// ```
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.watcher.peek(buf).await
future::poll_fn(|cx| self.watcher.poll_read_with(cx, |inner| inner.peek(buf))).await
}
/// Gets the value of the `TCP_NODELAY` option on this socket.
@ -307,7 +305,7 @@ impl Read for &TcpStream {
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self.watcher).poll_read(cx, buf)
self.watcher.poll_read_with(cx, |mut inner| inner.read(buf))
}
}
@ -343,25 +341,25 @@ impl Write for &TcpStream {
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self.watcher).poll_write(cx, buf)
self.watcher
.poll_write_with(cx, |mut inner| inner.write(buf))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self.watcher).poll_flush(cx)
self.watcher.poll_write_with(cx, |mut inner| inner.flush())
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self.watcher).poll_close(cx)
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
impl From<std::net::TcpStream> for TcpStream {
/// Converts a `std::net::TcpStream` into its asynchronous equivalent.
fn from(stream: std::net::TcpStream) -> TcpStream {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let mio_stream = mio::net::TcpStream::from_stream(stream).unwrap();
TcpStream {
watcher: Arc::new(Async::new(stream).expect("TcpStream is known to be good")),
watcher: Watcher::new(mio_stream),
}
}
}
@ -383,37 +381,29 @@ cfg_unix! {
impl IntoRawFd for TcpStream {
fn into_raw_fd(self) -> RawFd {
// TODO(stjepang): This does not mean `RawFd` is now the sole owner of the file
// descriptor because it's possible that there are other clones of this `TcpStream`
// using it at the same time. We should probably document that behavior.
self.as_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}
}
cfg_windows! {
use crate::os::windows::io::{
RawSocket, AsRawSocket, FromRawSocket, IntoRawSocket
};
impl AsRawSocket for TcpStream {
fn as_raw_socket(&self) -> RawSocket {
self.watcher.get_ref().as_raw_socket()
}
}
impl FromRawSocket for TcpStream {
unsafe fn from_raw_socket(handle: RawSocket) -> TcpStream {
std::net::TcpStream::from_raw_socket(handle).into()
}
}
impl IntoRawSocket for TcpStream {
fn into_raw_socket(self) -> RawSocket {
// TODO(stjepang): This does not mean `RawFd` is now the sole owner of the file
// descriptor because it's possible that there are other clones of this `TcpStream`
// using it at the same time. We should probably document that behavior.
self.as_raw_socket()
}
}
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for TcpStream {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpStream {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpStream {
// net::TcpStream::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -2,10 +2,9 @@ use std::io;
use std::net::SocketAddr;
use std::net::{Ipv4Addr, Ipv6Addr};
use smol::Async;
use crate::future;
use crate::net::driver::Watcher;
use crate::net::ToSocketAddrs;
use crate::utils::Context as _;
/// A UDP socket.
///
@ -45,7 +44,7 @@ use crate::utils::Context as _;
/// ```
#[derive(Debug)]
pub struct UdpSocket {
watcher: Async<std::net::UdpSocket>,
watcher: Watcher<mio::net::UdpSocket>,
}
impl UdpSocket {
@ -67,16 +66,15 @@ impl UdpSocket {
/// #
/// # Ok(()) }) }
/// ```
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<UdpSocket> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
let mut last_err = None;
let addrs = addrs.to_socket_addrs().await?;
for addr in addrs {
match Async::<std::net::UdpSocket>::bind(&addr) {
Ok(socket) => {
return Ok(UdpSocket { watcher: socket });
for addr in addr.to_socket_addrs().await? {
match mio::net::UdpSocket::bind(&addr) {
Ok(mio_socket) => {
return Ok(UdpSocket {
watcher: Watcher::new(mio_socket),
});
}
Err(err) => last_err = Some(err),
}
@ -90,32 +88,6 @@ impl UdpSocket {
}))
}
/// Returns the peer address that this listener is connected to.
///
/// This can be useful, for example, when connect to port 0 to figure out which port was
/// actually connected.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// let socket1 = UdpSocket::bind("127.0.0.1:0").await?;
/// let socket2 = UdpSocket::bind("127.0.0.1:0").await?;
/// socket1.connect(socket2.local_addr()?).await?;
/// let addr = socket1.peer_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.watcher
.get_ref()
.peer_addr()
.context(|| String::from("could not get peer address"))
}
/// Returns the local address that this listener is bound to.
///
/// This can be useful, for example, when binding to port 0 to figure out which port was
@ -126,7 +98,7 @@ impl UdpSocket {
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
/// use async_std::net::UdpSocket;
///
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// let addr = socket.local_addr()?;
@ -134,10 +106,7 @@ impl UdpSocket {
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.watcher
.get_ref()
.local_addr()
.context(|| String::from("could not get local address"))
self.watcher.get_ref().local_addr()
}
/// Sends data on the socket to the given address.
@ -177,10 +146,11 @@ impl UdpSocket {
}
};
self.watcher
.send_to(buf, addr)
.await
.context(|| format!("could not send packet to {}", addr))
future::poll_fn(|cx| {
self.watcher
.poll_write_with(cx, |inner| inner.send_to(buf, &addr))
})
.await
}
/// Receives data from the socket.
@ -203,7 +173,11 @@ impl UdpSocket {
/// # Ok(()) }) }
/// ```
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.watcher.recv_from(buf).await
future::poll_fn(|cx| {
self.watcher
.poll_read_with(cx, |inner| inner.recv_from(buf))
})
.await
}
/// Connects the UDP socket to a remote address.
@ -221,7 +195,7 @@ impl UdpSocket {
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
/// use async_std::net::UdpSocket;
///
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// socket.connect("127.0.0.1:8080").await?;
@ -230,12 +204,8 @@ impl UdpSocket {
/// ```
pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> io::Result<()> {
let mut last_err = None;
let addrs = addrs
.to_socket_addrs()
.await
.context(|| String::from("could not resolve addresses"))?;
for addr in addrs {
for addr in addrs.to_socket_addrs().await? {
// TODO(stjepang): connect on the blocking pool
match self.watcher.get_ref().connect(addr) {
Ok(()) => return Ok(()),
@ -251,12 +221,9 @@ impl UdpSocket {
}))
}
/// Sends data on the socket to the remote address to which it is connected.
///
/// The [`connect`] method will connect this socket to a remote address.
/// This method will fail if the socket is not connected.
/// Sends data on the socket to the given address.
///
/// [`connect`]: #method.connect
/// On success, returns the number of bytes written.
///
/// # Examples
///
@ -265,21 +232,28 @@ impl UdpSocket {
/// #
/// use async_std::net::UdpSocket;
///
/// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
/// socket.connect("127.0.0.1:8080").await?;
/// let bytes = socket.send(b"Hi there!").await?;
/// const THE_MERCHANT_OF_VENICE: &[u8] = b"
/// If you prick us, do we not bleed?
/// If you tickle us, do we not laugh?
/// If you poison us, do we not die?
/// And if you wrong us, shall we not revenge?
/// ";
///
/// println!("Sent {} bytes", bytes);
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
///
/// let addr = "127.0.0.1:7878";
/// let sent = socket.send_to(THE_MERCHANT_OF_VENICE, &addr).await?;
/// println!("Sent {} bytes to {}", sent, addr);
/// #
/// # Ok(()) }) }
/// ```
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.watcher.send(buf).await
future::poll_fn(|cx| self.watcher.poll_write_with(cx, |inner| inner.send(buf))).await
}
/// Receives data from the socket.
///
/// On success, returns the number of bytes read.
/// On success, returns the number of bytes read and the origin.
///
/// # Examples
///
@ -289,16 +263,15 @@ impl UdpSocket {
/// use async_std::net::UdpSocket;
///
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// socket.connect("127.0.0.1:8080").await?;
///
/// let mut buf = vec![0; 1024];
/// let n = socket.recv(&mut buf).await?;
/// println!("Received {} bytes", n);
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// println!("Received {} bytes from {}", n, peer);
/// #
/// # Ok(()) }) }
/// ```
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.watcher.recv(buf).await
future::poll_fn(|cx| self.watcher.poll_read_with(cx, |inner| inner.recv(buf))).await
}
/// Gets the value of the `SO_BROADCAST` option for this socket.
@ -442,7 +415,7 @@ impl UdpSocket {
/// use async_std::net::UdpSocket;
///
/// let socket_addr = SocketAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into(), 0);
/// let mdns_addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0x0123);
/// let mdns_addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0x0123) ;
/// let socket = UdpSocket::bind(&socket_addr).await?;
///
/// socket.join_multicast_v6(&mdns_addr, 0)?;
@ -481,10 +454,9 @@ impl UdpSocket {
impl From<std::net::UdpSocket> for UdpSocket {
/// Converts a `std::net::UdpSocket` into its asynchronous equivalent.
fn from(socket: std::net::UdpSocket) -> UdpSocket {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let mio_socket = mio::net::UdpSocket::from_socket(socket).unwrap();
UdpSocket {
watcher: Async::new(socket).expect("UdpSocket is known to be good"),
watcher: Watcher::new(mio_socket),
}
}
}
@ -506,31 +478,29 @@ cfg_unix! {
impl IntoRawFd for UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}
}
cfg_windows! {
use crate::os::windows::io::{
RawSocket, AsRawSocket, IntoRawSocket, FromRawSocket
};
impl AsRawSocket for UdpSocket {
fn as_raw_socket(&self) -> RawSocket {
self.watcher.get_ref().as_raw_socket()
}
}
impl FromRawSocket for UdpSocket {
unsafe fn from_raw_socket(handle: RawSocket) -> UdpSocket {
std::net::UdpSocket::from_raw_socket(handle).into()
}
}
impl IntoRawSocket for UdpSocket {
fn into_raw_socket(self) -> RawSocket {
self.watcher.into_raw_socket()
}
}
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
//
// impl AsRawSocket for UdpSocket {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for UdpSocket {
// unsafe fn from_raw_socket(handle: RawSocket) -> UdpSocket {
// net::UdpSocket::from_raw_socket(handle).into()
// }
// }
//
// impl IntoRawSocket for UdpSocket {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}

@ -2,9 +2,8 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{FromStream, IntoStream};
use std::convert::identity;
impl<T: Send, V> FromStream<Option<T>> for Option<V>
impl<T, V> FromStream<Option<T>> for Option<V>
where
V: FromStream<T>,
{
@ -14,29 +13,28 @@ where
#[inline]
fn from_stream<'a, S: IntoStream<Item = Option<T>> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut found_none = false;
let mut found_error = false;
let out: V = stream
.take_while(|elem| {
elem.is_some() || {
found_none = true;
// Stop processing the stream on `None`
false
.scan((), |_, elem| {
match elem {
Some(elem) => Some(elem),
None => {
found_error = true;
// Stop processing the stream on error
None
}
}
})
.filter_map(identity)
.collect()
.await;
if found_none { None } else { Some(out) }
if found_error { None } else { Some(out) }
})
}
}

@ -1,8 +1,7 @@
use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{Product, Stream};
use std::convert::identity;
use crate::stream::{Stream, Product};
impl<T, U> Product<Option<U>> for Option<T>
where
@ -37,27 +36,29 @@ where
```
"#]
fn product<'a, S>(stream: S) -> Pin<Box<dyn Future<Output = Option<T>> + 'a>>
where
S: Stream<Item = Option<U>> + 'a,
where S: Stream<Item = Option<U>> + 'a
{
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut found_none = false;
let out = <T as Product<U>>::product(
stream
.take_while(|elem| {
elem.is_some() || {
let out = <T as Product<U>>::product(stream
.scan((), |_, elem| {
match elem {
Some(elem) => Some(elem),
None => {
found_none = true;
// Stop processing the stream on `None`
false
// Stop processing the stream on error
None
}
})
.filter_map(identity),
)
.await;
}
})).await;
if found_none { None } else { Some(out) }
if found_none {
None
} else {
Some(out)
}
})
}
}

@ -2,7 +2,6 @@ use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{Stream, Sum};
use std::convert::identity;
impl<T, U> Sum<Option<U>> for Option<T>
where
@ -32,27 +31,29 @@ where
```
"#]
fn sum<'a, S>(stream: S) -> Pin<Box<dyn Future<Output = Option<T>> + 'a>>
where
S: Stream<Item = Option<U>> + 'a,
where S: Stream<Item = Option<U>> + 'a
{
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut found_none = false;
let out = <T as Sum<U>>::sum(
stream
.take_while(|elem| {
elem.is_some() || {
let out = <T as Sum<U>>::sum(stream
.scan((), |_, elem| {
match elem {
Some(elem) => Some(elem),
None => {
found_none = true;
// Stop processing the stream on `None`
false
// Stop processing the stream on error
None
}
})
.filter_map(identity),
)
.await;
}
})).await;
if found_none { None } else { Some(out) }
if found_none {
None
} else {
Some(out)
}
})
}
}

@ -2,14 +2,16 @@
use std::fmt;
use std::net::Shutdown;
use std::os::unix::net::UnixDatagram as StdUnixDatagram;
use smol::Async;
use mio_uds;
use super::SocketAddr;
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::spawn_blocking;
/// A Unix datagram socket.
///
@ -40,15 +42,13 @@ use crate::path::Path;
/// # Ok(()) }) }
/// ```
pub struct UnixDatagram {
watcher: Async<StdUnixDatagram>,
watcher: Watcher<mio_uds::UnixDatagram>,
}
impl UnixDatagram {
fn new(socket: StdUnixDatagram) -> UnixDatagram {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
fn new(socket: mio_uds::UnixDatagram) -> UnixDatagram {
UnixDatagram {
watcher: Async::new(socket).expect("UnixDatagram is known to be good"),
watcher: Watcher::new(socket),
}
}
@ -66,11 +66,9 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let path = path.as_ref().to_owned();
let socket = Async::<StdUnixDatagram>::bind(path)?;
Ok(UnixDatagram { watcher: socket })
let socket = spawn_blocking(move || mio_uds::UnixDatagram::bind(path)).await?;
Ok(UnixDatagram::new(socket))
}
/// Creates a Unix datagram which is not bound to any address.
@ -87,7 +85,7 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub fn unbound() -> io::Result<UnixDatagram> {
let socket = StdUnixDatagram::unbound()?;
let socket = mio_uds::UnixDatagram::unbound()?;
Ok(UnixDatagram::new(socket))
}
@ -107,7 +105,7 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
let (a, b) = StdUnixDatagram::pair()?;
let (a, b) = mio_uds::UnixDatagram::pair()?;
let a = UnixDatagram::new(a);
let b = UnixDatagram::new(b);
Ok((a, b))
@ -199,7 +197,11 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.watcher.recv_from(buf).await
future::poll_fn(|cx| {
self.watcher
.poll_read_with(cx, |inner| inner.recv_from(buf))
})
.await
}
/// Receives data from the socket.
@ -220,7 +222,7 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.watcher.recv(buf).await
future::poll_fn(|cx| self.watcher.poll_read_with(cx, |inner| inner.recv(buf))).await
}
/// Sends data on the socket to the specified address.
@ -240,7 +242,11 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub async fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
self.watcher.send_to(buf, path.as_ref()).await
future::poll_fn(|cx| {
self.watcher
.poll_write_with(cx, |inner| inner.send_to(buf, path.as_ref()))
})
.await
}
/// Sends data on the socket to the socket's peer.
@ -261,7 +267,7 @@ impl UnixDatagram {
/// # Ok(()) }) }
/// ```
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.watcher.send(buf).await
future::poll_fn(|cx| self.watcher.poll_write_with(cx, |inner| inner.send(buf))).await
}
/// Shut down the read, write, or both halves of this connection.
@ -306,35 +312,31 @@ impl fmt::Debug for UnixDatagram {
}
}
impl From<StdUnixDatagram> for UnixDatagram {
impl From<std::os::unix::net::UnixDatagram> for UnixDatagram {
/// Converts a `std::os::unix::net::UnixDatagram` into its asynchronous equivalent.
fn from(datagram: StdUnixDatagram) -> UnixDatagram {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
fn from(datagram: std::os::unix::net::UnixDatagram) -> UnixDatagram {
let mio_datagram = mio_uds::UnixDatagram::from_datagram(datagram).unwrap();
UnixDatagram {
watcher: Async::new(datagram).expect("UnixDatagram is known to be good"),
watcher: Watcher::new(mio_datagram),
}
}
}
impl AsRawFd for UnixDatagram {
fn as_raw_fd(&self) -> RawFd {
self.watcher.as_raw_fd()
self.watcher.get_ref().as_raw_fd()
}
}
impl FromRawFd for UnixDatagram {
unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let raw = StdUnixDatagram::from_raw_fd(fd);
let datagram = Async::<StdUnixDatagram>::new(raw).expect("invalid file descriptor");
UnixDatagram { watcher: datagram }
let datagram = std::os::unix::net::UnixDatagram::from_raw_fd(fd);
datagram.into()
}
}
impl IntoRawFd for UnixDatagram {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}

@ -1,20 +1,20 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::future::Future;
use std::os::unix::net::UnixListener as StdUnixListener;
use std::pin::Pin;
use std::future::Future;
use smol::Async;
use mio_uds;
use super::SocketAddr;
use super::UnixStream;
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::stream::Stream;
use crate::sync::Arc;
use crate::task::{Context, Poll};
use crate::task::{spawn_blocking, Context, Poll};
/// A Unix domain socket server, listening for connections.
///
@ -50,7 +50,7 @@ use crate::task::{Context, Poll};
/// # Ok(()) }) }
/// ```
pub struct UnixListener {
watcher: Async<StdUnixListener>,
watcher: Watcher<mio_uds::UnixListener>,
}
impl UnixListener {
@ -68,12 +68,12 @@ impl UnixListener {
/// # Ok(()) }) }
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let path = path.as_ref().to_owned();
let listener = Async::<StdUnixListener>::bind(path)?;
let listener = spawn_blocking(move || mio_uds::UnixListener::bind(path)).await?;
Ok(UnixListener { watcher: listener })
Ok(UnixListener {
watcher: Watcher::new(listener),
})
}
/// Accepts a new incoming connection to this listener.
@ -93,14 +93,29 @@ impl UnixListener {
/// # Ok(()) }) }
/// ```
pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
let (stream, addr) = self.watcher.accept().await?;
Ok((
UnixStream {
watcher: Arc::new(stream),
},
addr,
))
future::poll_fn(|cx| {
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? {
Some((io, addr)) => {
let mio_stream = mio_uds::UnixStream::from_stream(io)?;
let stream = UnixStream {
watcher: Watcher::new(mio_stream),
};
Poll::Ready(Ok((stream, addr)))
}
// This should never happen since `None` is converted to `WouldBlock`
None => unreachable!(),
}
})
.await
}
/// Returns a stream of incoming connections.
@ -191,20 +206,19 @@ impl Stream for Incoming<'_> {
}
}
impl From<StdUnixListener> for UnixListener {
impl From<std::os::unix::net::UnixListener> for UnixListener {
/// Converts a `std::os::unix::net::UnixListener` into its asynchronous equivalent.
fn from(listener: StdUnixListener) -> UnixListener {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
fn from(listener: std::os::unix::net::UnixListener) -> UnixListener {
let mio_listener = mio_uds::UnixListener::from_listener(listener).unwrap();
UnixListener {
watcher: Async::new(listener).expect("UnixListener is known to be good"),
watcher: Watcher::new(mio_listener),
}
}
}
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.watcher.as_raw_fd()
self.watcher.get_ref().as_raw_fd()
}
}
@ -217,6 +231,6 @@ impl FromRawFd for UnixListener {
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> RawFd {
self.watcher.into_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}

@ -1,18 +1,18 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::io::{Read as _, Write as _};
use std::net::Shutdown;
use std::os::unix::net::UnixStream as StdUnixStream;
use std::pin::Pin;
use smol::Async;
use mio_uds;
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::sync::Arc;
use crate::task::{Context, Poll};
use crate::task::{spawn_blocking, Context, Poll};
/// A Unix stream socket.
///
@ -37,9 +37,8 @@ use crate::task::{Context, Poll};
/// #
/// # Ok(()) }) }
/// ```
#[derive(Clone)]
pub struct UnixStream {
pub(super) watcher: Arc<Async<StdUnixStream>>,
pub(super) watcher: Watcher<mio_uds::UnixStream>,
}
impl UnixStream {
@ -57,12 +56,16 @@ impl UnixStream {
/// # Ok(()) }) }
/// ```
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let path = path.as_ref().to_owned();
let stream = Arc::new(Async::<StdUnixStream>::connect(path).await?);
Ok(UnixStream { watcher: stream })
spawn_blocking(move || {
let std_stream = std::os::unix::net::UnixStream::connect(path)?;
let mio_stream = mio_uds::UnixStream::from_stream(std_stream)?;
Ok(UnixStream {
watcher: Watcher::new(mio_stream),
})
})
.await
}
/// Creates an unnamed pair of connected sockets.
@ -81,14 +84,12 @@ impl UnixStream {
/// # Ok(()) }) }
/// ```
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let (a, b) = Async::<StdUnixStream>::pair()?;
let (a, b) = mio_uds::UnixStream::pair()?;
let a = UnixStream {
watcher: Arc::new(a),
watcher: Watcher::new(a),
};
let b = UnixStream {
watcher: Arc::new(b),
watcher: Watcher::new(b),
};
Ok((a, b))
}
@ -168,7 +169,7 @@ impl Read for &UnixStream {
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self.watcher).poll_read(cx, buf)
self.watcher.poll_read_with(cx, |mut inner| inner.read(buf))
}
}
@ -196,15 +197,16 @@ impl Write for &UnixStream {
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self.watcher).poll_write(cx, buf)
self.watcher
.poll_write_with(cx, |mut inner| inner.write(buf))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self.watcher).poll_flush(cx)
self.watcher.poll_write_with(cx, |mut inner| inner.flush())
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self.watcher).poll_close(cx)
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
@ -225,21 +227,19 @@ impl fmt::Debug for UnixStream {
}
}
impl From<StdUnixStream> for UnixStream {
impl From<std::os::unix::net::UnixStream> for UnixStream {
/// Converts a `std::os::unix::net::UnixStream` into its asynchronous equivalent.
fn from(stream: StdUnixStream) -> UnixStream {
once_cell::sync::Lazy::force(&crate::rt::RUNTIME);
let stream = Async::new(stream).expect("UnixStream is known to be good");
fn from(stream: std::os::unix::net::UnixStream) -> UnixStream {
let mio_stream = mio_uds::UnixStream::from_stream(stream).unwrap();
UnixStream {
watcher: Arc::new(stream),
watcher: Watcher::new(mio_stream),
}
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.watcher.as_raw_fd()
self.watcher.get_ref().as_raw_fd()
}
}
@ -252,6 +252,6 @@ impl FromRawFd for UnixStream {
impl IntoRawFd for UnixStream {
fn into_raw_fd(self) -> RawFd {
self.as_raw_fd()
self.watcher.into_inner().into_raw_fd()
}
}

@ -1,55 +0,0 @@
//! Windows-specific filesystem extensions.
use crate::io;
use crate::path::Path;
use crate::task::spawn_blocking;
/// Creates a new directory symbolic link on the filesystem.
///
/// The `dst` path will be a directory symbolic link pointing to the `src` path.
///
/// This function is an async version of [`std::os::windows::fs::symlink_dir`].
///
/// [`std::os::windows::fs::symlink_dir`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::windows::fs::symlink_dir;
///
/// symlink_dir("a", "b").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn symlink_dir<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();
spawn_blocking(move || std::os::windows::fs::symlink_dir(&src, &dst)).await
}
/// Creates a new file symbolic link on the filesystem.
///
/// The `dst` path will be a file symbolic link pointing to the `src` path.
///
/// This function is an async version of [`std::os::windows::fs::symlink_file`].
///
/// [`std::os::windows::fs::symlink_file`]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::windows::fs::symlink_file;
///
/// symlink_file("a.txt", "b.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn symlink_file<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();
spawn_blocking(move || std::os::windows::fs::symlink_file(&src, &dst)).await
}

@ -2,8 +2,7 @@
cfg_not_docs! {
pub use std::os::windows::io::{
AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle,
AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket,
AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, RawSocket,
};
}
@ -46,33 +45,4 @@ cfg_docs! {
/// it once it's no longer needed.
fn into_raw_handle(self) -> RawHandle;
}
/// Creates I/O objects from raw sockets.
pub trait FromRawSocket {
/// Creates a new I/O object from the given raw socket.
///
/// This function will consume ownership of the socket provided and it will be closed when the returned object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned have the contract that they are the sole owner of the
/// file descriptor they are wrapping. Usage of this function could accidentally allow violating this contract which can cause
/// memory unsafety in code that relies on it being true.
unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}
/// Extracts raw sockets.
pub trait AsRawSocket {
/// Extracts the underlying raw socket from this object.
fn as_raw_socket(&self) -> RawSocket;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw `SOCKET`.
pub trait IntoRawSocket {
/// Consumes this object, returning the raw underlying socket.
///
/// This function **transfers ownership** of the underlying socket to the
/// caller. Callers are then the unique owners of the socket and must close
/// it once it's no longer needed.
fn into_raw_socket(self) -> RawSocket;
}
}

@ -3,7 +3,3 @@
cfg_std! {
pub mod io;
}
cfg_unstable! {
pub mod fs;
}

@ -4,9 +4,9 @@ use std::ffi::{OsStr, OsString};
use std::rc::Rc;
use std::sync::Arc;
use crate::fs;
use crate::io;
use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixError};
#[cfg(not(target_os = "unknown"))]
use crate::{fs, io};
/// A slice of a path.
///
@ -584,7 +584,6 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn metadata(&self) -> io::Result<fs::Metadata> {
fs::metadata(self).await
}
@ -608,7 +607,6 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
fs::symlink_metadata(self).await
}
@ -634,7 +632,6 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn canonicalize(&self) -> io::Result<PathBuf> {
fs::canonicalize(self).await
}
@ -657,7 +654,6 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn read_link(&self) -> io::Result<PathBuf> {
fs::read_link(self).await
}
@ -692,7 +688,6 @@ impl Path {
/// #
/// # Ok(()) }) }
/// ```
#[cfg(not(target_os = "unknown"))]
pub async fn read_dir(&self) -> io::Result<fs::ReadDir> {
fs::read_dir(self).await
}
@ -722,7 +717,6 @@ impl Path {
/// check errors, call [fs::metadata].
///
/// [fs::metadata]: ../fs/fn.metadata.html
#[cfg(not(target_os = "unknown"))]
pub async fn exists(&self) -> bool {
fs::metadata(self).await.is_ok()
}
@ -755,7 +749,6 @@ impl Path {
///
/// [fs::metadata]: ../fs/fn.metadata.html
/// [fs::Metadata::is_file]: ../fs/struct.Metadata.html#method.is_file
#[cfg(not(target_os = "unknown"))]
pub async fn is_file(&self) -> bool {
fs::metadata(self)
.await
@ -792,7 +785,6 @@ impl Path {
///
/// [fs::metadata]: ../fs/fn.metadata.html
/// [fs::Metadata::is_dir]: ../fs/struct.Metadata.html#method.is_dir
#[cfg(not(target_os = "unknown"))]
pub async fn is_dir(&self) -> bool {
fs::metadata(self)
.await

@ -323,10 +323,7 @@ impl<P: AsRef<Path>> stream::Extend<P> for PathBuf {
fn extend<'a, S: IntoStream<Item = P> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {
@ -340,14 +337,11 @@ impl<P: AsRef<Path>> stream::Extend<P> for PathBuf {
}
#[cfg(feature = "unstable")]
impl<'b, P: AsRef<Path> + 'b + Send> FromStream<P> for PathBuf {
impl<'b, P: AsRef<Path> + 'b> FromStream<P> for PathBuf {
#[inline]
fn from_stream<'a, S: IntoStream<Item = P> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {

@ -5,68 +5,38 @@ use crate::stream::{FromStream, IntoStream};
impl<T, E, V> FromStream<Result<T, E>> for Result<V, E>
where
T: Send,
E: Send,
V: FromStream<T>,
{
/// Takes each element in the stream: if it is an `Err`, no further
/// elements are taken, and the `Err` is returned. Should no `Err`
/// occur, a container with the values of each `Result` is returned.
///
/// # Examples
///
/// ```
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::prelude::*;
/// use async_std::stream;
///
/// let v = stream::from_iter(vec![1, 2]);
/// let res: Result<Vec<u32>, &'static str> = v.map(|x: u32|
/// x.checked_add(1).ok_or("Overflow!")
/// ).collect().await;
/// assert_eq!(res, Ok(vec![2, 3]));
/// #
/// # }) }
/// ```
#[inline]
fn from_stream<'a, S: IntoStream<Item = Result<T, E>> + 'a>(
stream: S,
) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
let stream = stream.into_stream();
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut is_error = false;
let mut found_error = None;
let out: V = stream
.take_while(|elem| {
// Stop processing the stream on `Err`
!is_error
&& (elem.is_ok() || {
is_error = true;
// Capture first `Err`
true
})
})
.filter_map(|elem| match elem {
Ok(value) => Some(value),
Err(err) => {
found_error = Some(err);
None
.scan((), |_, elem| {
match elem {
Ok(elem) => Some(elem),
Err(err) => {
found_error = Some(err);
// Stop processing the stream on error
None
}
}
})
.collect()
.await;
if is_error {
Err(found_error.unwrap())
} else {
Ok(out)
match found_error {
Some(err) => Err(err),
None => Ok(out),
}
})
}

@ -1,7 +1,7 @@
use std::pin::Pin;
use crate::prelude::*;
use crate::stream::{Product, Stream};
use crate::stream::{Stream, Product};
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
where
@ -36,39 +36,26 @@ where
```
"#]
fn product<'a, S>(stream: S) -> Pin<Box<dyn Future<Output = Result<T, E>> + 'a>>
where
S: Stream<Item = Result<U, E>> + 'a,
where S: Stream<Item = Result<U, E>> + 'a
{
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut is_error = false;
let mut found_error = None;
let out = <T as Product<U>>::product(
stream
.take_while(|elem| {
// Stop processing the stream on `Err`
!is_error
&& (elem.is_ok() || {
is_error = true;
// Capture first `Err`
true
})
})
.filter_map(|elem| match elem {
Ok(value) => Some(value),
let out = <T as Product<U>>::product(stream
.scan((), |_, elem| {
match elem {
Ok(elem) => Some(elem),
Err(err) => {
found_error = Some(err);
// Stop processing the stream on error
None
}
}),
)
.await;
if is_error {
Err(found_error.unwrap())
} else {
Ok(out)
}
})).await;
match found_error {
Some(err) => Err(err),
None => Ok(out)
}
})
}

@ -36,39 +36,26 @@ where
```
"#]
fn sum<'a, S>(stream: S) -> Pin<Box<dyn Future<Output = Result<T, E>> + 'a>>
where
S: Stream<Item = Result<U, E>> + 'a,
where S: Stream<Item = Result<U, E>> + 'a
{
Box::pin(async move {
// Using `take_while` here because it is able to stop the stream early
// Using `scan` here because it is able to stop the stream early
// if a failure occurs
let mut is_error = false;
let mut found_error = None;
let out = <T as Sum<U>>::sum(
stream
.take_while(|elem| {
// Stop processing the stream on `Err`
!is_error
&& (elem.is_ok() || {
is_error = true;
// Capture first `Err`
true
})
})
.filter_map(|elem| match elem {
Ok(value) => Some(value),
let out = <T as Sum<U>>::sum(stream
.scan((), |_, elem| {
match elem {
Ok(elem) => Some(elem),
Err(err) => {
found_error = Some(err);
// Stop processing the stream on error
None
}
}),
)
.await;
if is_error {
Err(found_error.unwrap())
} else {
Ok(out)
}
})).await;
match found_error {
Some(err) => Err(err),
None => Ok(out)
}
})
}

@ -1,34 +0,0 @@
//! The runtime.
use std::env;
use std::thread;
use once_cell::sync::Lazy;
use crate::future;
/// Dummy runtime struct.
pub struct Runtime {}
/// The global runtime.
pub static RUNTIME: Lazy<Runtime> = Lazy::new(|| {
// Create an executor thread pool.
let thread_count = env::var("ASYNC_STD_THREAD_COUNT")
.map(|env| {
env.parse()
.expect("ASYNC_STD_THREAD_COUNT must be a number")
})
.unwrap_or_else(|_| num_cpus::get())
.max(1);
let thread_name = env::var("ASYNC_STD_THREAD_NAME").unwrap_or("async-std/runtime".to_string());
for _ in 0..thread_count {
thread::Builder::new()
.name(thread_name.clone())
.spawn(|| crate::task::block_on(future::pending::<()>()))
.expect("cannot start a runtime thread");
}
Runtime {}
});

@ -0,0 +1,24 @@
use crate::stream::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
/// A stream able to yield elements from both ends.
///
/// Something that implements `DoubleEndedStream` has one extra capability
/// over something that implements [`Stream`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// [`Stream`]: trait.Stream.html
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait DoubleEndedStream: Stream {
/// Removes and returns an element from the end of the stream.
///
/// Returns `None` when there are no more elements.
///
/// The [trait-level] docs contain more details.
///
/// [trait-level]: trait.DoubleEndedStream.html
fn poll_next_back(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
}

@ -1,246 +0,0 @@
use crate::stream::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
mod next_back;
mod nth_back;
mod rfind;
mod rfold;
mod try_rfold;
use next_back::NextBackFuture;
use nth_back::NthBackFuture;
use rfind::RFindFuture;
use rfold::RFoldFuture;
use try_rfold::TryRFoldFuture;
/// A stream able to yield elements from both ends.
///
/// Something that implements `DoubleEndedStream` has one extra capability
/// over something that implements [`Stream`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// [`Stream`]: trait.Stream.html
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait DoubleEndedStream: Stream {
#[doc = r#"
Attempts to receive the next item from the back of the stream.
There are several possible return values:
* `Poll::Pending` means this stream's next_back value is not ready yet.
* `Poll::Ready(None)` means this stream has been exhausted.
* `Poll::Ready(Some(item))` means `item` was received out of the stream.
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use std::pin::Pin;
use async_std::prelude::*;
use async_std::stream;
use async_std::task::{Context, Poll};
fn increment(
s: impl DoubleEndedStream<Item = i32> + Unpin,
) -> impl DoubleEndedStream<Item = i32> + Unpin {
struct Increment<S>(S);
impl<S: DoubleEndedStream<Item = i32> + Unpin> Stream for Increment<S> {
type Item = S::Item;
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
match Pin::new(&mut self.0).poll_next(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
Poll::Ready(Some(item)) => Poll::Ready(Some(item + 1)),
}
}
}
impl<S: DoubleEndedStream<Item = i32> + Unpin> DoubleEndedStream for Increment<S> {
fn poll_next_back(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
match Pin::new(&mut self.0).poll_next_back(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
Poll::Ready(Some(item)) => Poll::Ready(Some(item + 1)),
}
}
}
Increment(s)
}
let mut s = increment(stream::once(7));
assert_eq!(s.next_back().await, Some(8));
assert_eq!(s.next_back().await, None);
#
# }) }
```
"#]
fn poll_next_back(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
#[doc = r#"
Advances the stream and returns the next value.
Returns [`None`] when iteration is finished. Individual stream implementations may
choose to resume iteration, and so calling `next()` again may or may not eventually
start returning more values.
[`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
# Examples
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::stream;
let mut s = stream::from_iter(vec![7u8]);
assert_eq!(s.next_back().await, Some(7));
assert_eq!(s.next_back().await, None);
#
# }) }
```
"#]
fn next_back(&mut self) -> NextBackFuture<'_, Self>
where
Self: Unpin,
{
NextBackFuture { stream: self }
}
#[doc = r#"
Returns the nth element from the back of the stream.
# Examples
Basic usage:
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::stream;
let mut s = stream::from_iter(vec![1u8, 2, 3, 4, 5]);
let second = s.nth_back(1).await;
assert_eq!(second, Some(4));
#
# }) }
```
"#]
fn nth_back(&mut self, n: usize) -> NthBackFuture<'_, Self>
where
Self: Unpin + Sized,
{
NthBackFuture::new(self, n)
}
#[doc = r#"
Returns the the frist element from the right that matches the predicate.
# Examples
Basic usage:
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::stream;
let mut s = stream::from_iter(vec![1u8, 2, 3, 4, 5]);
let second = s.rfind(|v| v % 2 == 0).await;
assert_eq!(second, Some(4));
#
# }) }
```
"#]
fn rfind<P>(&mut self, p: P) -> RFindFuture<'_, Self, P>
where
Self: Unpin + Sized,
P: FnMut(&Self::Item) -> bool,
{
RFindFuture::new(self, p)
}
#[doc = r#"
# Examples
Basic usage:
```
# fn main() { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::stream;
let s = stream::from_iter(vec![1u8, 2, 3, 4, 5]);
let second = s.rfold(0, |acc, v| v + acc).await;
assert_eq!(second, 15);
#
# }) }
```
"#]
fn rfold<B, F>(self, accum: B, f: F) -> RFoldFuture<Self, F, B>
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
RFoldFuture::new(self, accum, f)
}
#[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 async_std::stream;
let s = stream::from_iter(vec![1u8, 2, 3, 4, 5]);
let sum = s.try_rfold(0, |acc, v| {
if (acc+v) % 2 == 1 {
Ok(v+3)
} else {
Err("fail")
}
}).await;
assert_eq!(sum, Err("fail"));
#
# }) }
```
"#]
fn try_rfold<B, F, E>(self, accum: B, f: F) -> TryRFoldFuture<Self, F, B>
where
Self: Sized,
F: FnMut(B, Self::Item) -> Result<B, E>,
{
TryRFoldFuture::new(self, accum, f)
}
}

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

Loading…
Cancel
Save