mirror of
https://github.com/async-rs/async-std.git
synced 2025-01-30 17:25:32 +00:00
Merge branch 'master' into stream_count
This commit is contained in:
commit
60f822bee5
221 changed files with 7140 additions and 2864 deletions
71
.github/workflows/ci.yml
vendored
71
.github/workflows/ci.yml
vendored
|
@ -7,16 +7,17 @@ on:
|
|||
- staging
|
||||
- trying
|
||||
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Build and test
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
rust: [nightly]
|
||||
rust: [nightly, beta, stable]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
@ -31,13 +32,31 @@ jobs:
|
|||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples
|
||||
args: --all --bins --tests
|
||||
|
||||
- name: check unstable
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --features unstable --all --benches --bins --examples --tests
|
||||
args: --features unstable --all --bins --examples --tests
|
||||
- name: check bench
|
||||
uses: actions-rs/cargo@v1
|
||||
if: matrix.rust == 'nightly'
|
||||
with:
|
||||
command: check
|
||||
args: --benches
|
||||
|
||||
- name: check std only
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --no-default-features --features std
|
||||
|
||||
- name: check attributes
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --features attributes
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
|
@ -48,20 +67,15 @@ jobs:
|
|||
check_fmt_and_docs:
|
||||
name: Checking fmt and docs
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
- id: component
|
||||
uses: actions-rs/components-nightly@v1
|
||||
with:
|
||||
component: rustfmt
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ steps.component.outputs.toolchain }}
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: setup
|
||||
run: |
|
||||
|
@ -78,23 +92,14 @@ jobs:
|
|||
- name: Docs
|
||||
run: cargo doc --features docs
|
||||
|
||||
clippy_check:
|
||||
name: Clippy check
|
||||
runs-on: ubuntu-latest
|
||||
# TODO: There is a lot of warnings
|
||||
# env:
|
||||
# RUSTFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- id: component
|
||||
uses: actions-rs/components-nightly@v1
|
||||
with:
|
||||
component: clippy
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ steps.component.outputs.toolchain }}
|
||||
override: true
|
||||
- run: rustup component add clippy
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# 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
|
||||
|
|
153
CHANGELOG.md
153
CHANGELOG.md
|
@ -7,6 +7,154 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
# [1.0.0] - 2019-11-11
|
||||
|
||||
[API Documentation](https://docs.rs/async-std/1.0.0/async-std)
|
||||
|
||||
This release marks the `1.0.0` release of async-std; a major milestone for our
|
||||
development. This release itself mostly includes quality of life improvements
|
||||
for all of modules, including more consistent API bounds for a lot of our
|
||||
submodules.
|
||||
|
||||
The biggest change is that we're now using the full semver range,
|
||||
`major.minor.patch`, and any breaking changes to our "stable" APIs will require
|
||||
an update of the `major` number.
|
||||
|
||||
We're excited we've hit this milestone together with you all. Thank you!
|
||||
|
||||
## Added
|
||||
|
||||
- Added `Future::join` as "unstable", replacing `future::join!`.
|
||||
- Added `Future::try_join` as "unstable", replacing `future::try_join!`.
|
||||
- Enabled `stable` and `beta` channel testing on CI.
|
||||
- Implemented `FromIterator` and `Extend` for `PathBuf`.
|
||||
- Implemented `FromStream` for `PathBuf`.
|
||||
- Loosened the trait bounds of `io::copy` on "unstable".
|
||||
|
||||
## Changed
|
||||
|
||||
- Added a `Sync` bound to `RwLock`, resolving a memory safety issue.
|
||||
- Fixed a bug in `Stream::take_while` where it could continue after it should've
|
||||
ended.
|
||||
- Fixed a bug where our `attributes` Cargo feature wasn't working as intended.
|
||||
- Improved documentation of `Stream::merge`, documenting ordering guarantees.
|
||||
- Update doc imports in examples to prefer async-std's types.
|
||||
- Various quality of life improvements to the `future` submodule.
|
||||
- Various quality of life improvements to the `path` submodule.
|
||||
- Various quality of life improvements to the `stream` submodule.
|
||||
|
||||
## Removed
|
||||
|
||||
- Removed `future::join!` in favor of `Future::join`.
|
||||
- Removed `future::try_join!` in favor of `Future::try_join`.
|
||||
|
||||
# [0.99.12] - 2019-11-07
|
||||
|
||||
[API Documentation](https://docs.rs/async-std/0.99.12/async-std)
|
||||
|
||||
This patch upgrades us to `futures` 0.3, support for `async/await` on Rust
|
||||
Stable, performance improvements, and brand new module-level documentation.
|
||||
|
||||
## Added
|
||||
|
||||
- Added `Future::flatten` as "unstable".
|
||||
- Added `Future::race` as "unstable" (replaces `future::select!`).
|
||||
- Added `Future::try_race` as "unstable" (replaces `future::try_select!`).
|
||||
- Added `Stderr::lock` as "unstable".
|
||||
- Added `Stdin::lock` as "unstable".
|
||||
- Added `Stdout::lock` as "unstable".
|
||||
- Added `Stream::copied` as "unstable".
|
||||
- Added `Stream::eq` as "unstable".
|
||||
- Added `Stream::max_by_key` as "unstable".
|
||||
- Added `Stream::min` as "unstable".
|
||||
- Added `Stream::ne` as "unstable".
|
||||
- Added `Stream::position` as "unstable".
|
||||
- Added `StreamExt` and `FutureExt` as enumerable in the `prelude`.
|
||||
- Added `TcpListener` and `TcpStream` integration tests.
|
||||
- Added `stream::from_iter`.
|
||||
- Added `sync::WakerSet` for internal use.
|
||||
- Added an example to handle both `IP v4` and `IP v6` connections.
|
||||
- Added the `default` Cargo feature.
|
||||
- Added the `attributes` Cargo feature.
|
||||
- Added the `std` Cargo feature.
|
||||
|
||||
## Changed
|
||||
|
||||
- Fixed a bug in the blocking threadpool where it didn't spawn more than one thread.
|
||||
- Fixed a bug with `Stream::merge` where sometimes it ended too soon.
|
||||
- Fixed a bug with our GitHub actions setup.
|
||||
- Fixed an issue where our channels could spuriously deadlock.
|
||||
- Refactored the `task` module.
|
||||
- Removed a deprecated GitHub action.
|
||||
- Replaced `futures-preview` with `futures`.
|
||||
- Replaced `lazy_static` with `once_cell`.
|
||||
- Replaced all uses of `VecDequeue` in the examples with `stream::from_iter`.
|
||||
- Simplified `sync::RwLock` using the internal `sync::WakerSet` type.
|
||||
- Updated the `path` submodule documentation to match std.
|
||||
- Updated the mod-level documentation to match std.
|
||||
|
||||
## Removed
|
||||
|
||||
- Removed `future::select!` (replaced by `Future::race`).
|
||||
- Removed `future::try_select!` (replaced by `Future::try_race`).
|
||||
|
||||
# [0.99.11] - 2019-10-29
|
||||
|
||||
This patch introduces `async_std::sync::channel`, a novel asynchronous port of
|
||||
the ultra-fast Crossbeam channels. This has been one of the most anticipated
|
||||
features for async-std, and we're excited to be providing a first version of
|
||||
this!
|
||||
|
||||
In addition to channels, this patch has the regular list of new methods, types,
|
||||
and doc fixes.
|
||||
|
||||
## Examples
|
||||
|
||||
__Send and receive items from a channel__
|
||||
```rust
|
||||
// Create a bounded channel with a max-size of 1
|
||||
let (s, r) = channel(1);
|
||||
|
||||
// This call returns immediately because there is enough space in the channel.
|
||||
s.send(1).await;
|
||||
|
||||
task::spawn(async move {
|
||||
// This call blocks the current task because the channel is full.
|
||||
// It will be able to complete only after the first message is received.
|
||||
s.send(2).await;
|
||||
});
|
||||
|
||||
// Receive items from the channel
|
||||
task::sleep(Duration::from_secs(1)).await;
|
||||
assert_eq!(r.recv().await, Some(1));
|
||||
assert_eq!(r.recv().await, Some(2));
|
||||
```
|
||||
|
||||
## Added
|
||||
- Added `Future::delay` as "unstable"
|
||||
- Added `Stream::flat_map` as "unstable"
|
||||
- Added `Stream::flatten` as "unstable"
|
||||
- Added `Stream::product` as "unstable"
|
||||
- Added `Stream::sum` as "unstable"
|
||||
- Added `Stream::min_by_key`
|
||||
- Added `Stream::max_by`
|
||||
- Added `Stream::timeout` as "unstable"
|
||||
- Added `sync::channel` as "unstable".
|
||||
- Added doc links from instantiated structs to the methods that create them.
|
||||
- Implemented `Extend` + `FromStream` for `PathBuf`.
|
||||
|
||||
## Changed
|
||||
- Fixed an issue with `block_on` so it works even when nested.
|
||||
- Fixed issues with our Clippy check on CI.
|
||||
- Replaced our uses of `cfg_if` with our own macros, simplifying the codebase.
|
||||
- Updated the homepage link in `Cargo.toml` to point to [async.rs](https://async.rs).
|
||||
- Updated the module-level documentation for `stream` and `sync`.
|
||||
- Various typos and grammar fixes.
|
||||
- Removed redundant file flushes, improving the performance of `File` operations
|
||||
|
||||
## Removed
|
||||
Nothing was removed in this release.
|
||||
|
||||
# [0.99.10] - 2019-10-16
|
||||
|
||||
This patch stabilizes several core concurrency macros, introduces async versions
|
||||
|
@ -281,7 +429,10 @@ task::blocking(async {
|
|||
|
||||
- Initial beta release
|
||||
|
||||
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.10...HEAD
|
||||
[Unreleased]: https://github.com/async-rs/async-std/compare/v1.0.0...HEAD
|
||||
[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
|
||||
[0.99.11]: https://github.com/async-rs/async-std/compare/v0.99.10...v0.99.11
|
||||
[0.99.10]: https://github.com/async-rs/async-std/compare/v0.99.9...v0.99.10
|
||||
[0.99.9]: https://github.com/async-rs/async-std/compare/v0.99.8...v0.99.9
|
||||
[0.99.8]: https://github.com/async-rs/async-std/compare/v0.99.7...v0.99.8
|
||||
|
|
80
Cargo.toml
80
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-std"
|
||||
version = "0.99.10"
|
||||
version = "1.0.0"
|
||||
authors = [
|
||||
"Stjepan Glavina <stjepang@gmail.com>",
|
||||
"Yoshua Wuyts <yoshuawuyts@gmail.com>",
|
||||
|
@ -21,37 +21,67 @@ features = ["docs"]
|
|||
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||
|
||||
[features]
|
||||
docs = ["unstable"]
|
||||
unstable = ["broadcaster"]
|
||||
default = [
|
||||
"std",
|
||||
"async-task",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"futures-timer",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"mio",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
]
|
||||
docs = ["attributes", "unstable"]
|
||||
unstable = ["default", "broadcaster"]
|
||||
attributes = ["async-attributes"]
|
||||
std = [
|
||||
"async-macros",
|
||||
"crossbeam-utils",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-macros = "1.0.0"
|
||||
async-task = "1.0.0"
|
||||
crossbeam-channel = "0.3.9"
|
||||
crossbeam-deque = "0.7.1"
|
||||
crossbeam-utils = "0.6.6"
|
||||
futures-core-preview = "=0.3.0-alpha.19"
|
||||
futures-io-preview = "=0.3.0-alpha.19"
|
||||
futures-timer = "1.0.2"
|
||||
lazy_static = "1.4.0"
|
||||
log = { version = "0.4.8", features = ["kv_unstable"] }
|
||||
memchr = "2.2.1"
|
||||
mio = "0.6.19"
|
||||
mio-uds = "0.6.7"
|
||||
num_cpus = "1.10.1"
|
||||
pin-utils = "0.1.0-alpha.4"
|
||||
slab = "0.4.2"
|
||||
kv-log-macro = "1.0.4"
|
||||
async-attributes = { version = "1.1.0", optional = true }
|
||||
async-macros = { version = "1.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"] }
|
||||
pin-project-lite = "0.1"
|
||||
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 = "1.0.2", optional = true }
|
||||
kv-log-macro = { version = "1.0.4", optional = true }
|
||||
log = { version = "0.4.8", features = ["kv_unstable"], 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 }
|
||||
|
||||
[dev-dependencies]
|
||||
femme = "1.2.0"
|
||||
rand = "0.7.2"
|
||||
# surf = "1.0.2"
|
||||
tempdir = "0.3.7"
|
||||
futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] }
|
||||
futures = "0.3.0"
|
||||
|
||||
# These are used by the book for examples
|
||||
futures-channel-preview = "=0.3.0-alpha.19"
|
||||
futures-util-preview = "=0.3.0-alpha.19"
|
||||
[[test]]
|
||||
name = "stream"
|
||||
required-features = ["unstable"]
|
||||
|
||||
[[example]]
|
||||
name = "tcp-ipv4-and-6-echo"
|
||||
required-features = ["unstable"]
|
||||
|
|
|
@ -61,7 +61,7 @@ syntax.
|
|||
## Features
|
||||
|
||||
- __Modern:__ Built from the ground up for `std::future` and `async/await` with
|
||||
blazing fast compilation times.
|
||||
blazing fast compilation time.
|
||||
- __Fast:__ Our robust allocator and threadpool designs provide ultra-high
|
||||
throughput with predictably low latency.
|
||||
- __Intuitive:__ Complete parity with the stdlib means you only need to learn
|
||||
|
|
42
benches/mutex.rs
Normal file
42
benches/mutex.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_std::sync::Mutex;
|
||||
use async_std::task;
|
||||
use test::Bencher;
|
||||
|
||||
#[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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
11
benches/task.rs
Normal file
11
benches/task.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use async_std::task;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn block_on(b: &mut Bencher) {
|
||||
b.iter(|| task::block_on(async {}));
|
||||
}
|
|
@ -24,11 +24,7 @@ To sum up: Rust gives us the ability to safely abstract over important propertie
|
|||
|
||||
## An easy view of computation
|
||||
|
||||
While computation is a subject to write a whole [book](https://computationbook.com/) about, a very simplified view suffices for us:
|
||||
|
||||
- computation is a sequence of composable operations
|
||||
- they can branch based on a decision
|
||||
- they either run to succession and yield a result, or they can yield an error
|
||||
While computation is a subject to write a whole [book](https://computationbook.com/) about, a very simplified view suffices for us: A sequence of composable operations which can branch based on a decision, run to succession and yield a result or yield an error
|
||||
|
||||
## Deferring computation
|
||||
|
||||
|
@ -136,11 +132,11 @@ When executing 2 or more of these functions at the same time, our runtime system
|
|||
|
||||
## Conclusion
|
||||
|
||||
Working from values, we searched for something that expresses *working towards a value available sometime later*. From there, we talked about the concept of polling.
|
||||
Working from values, we searched for something that expresses *working towards a value available later*. From there, we talked about the concept of polling.
|
||||
|
||||
A `Future` is any data type that does not represent a value, but the ability to *produce a value at some point in the future*. Implementations of this are very varied and detailed depending on use-case, but the interface is simple.
|
||||
|
||||
Next, we will introduce you to `tasks`, which we need to actually *run* Futures.
|
||||
Next, we will introduce you to `tasks`, which we will use to actually *run* Futures.
|
||||
|
||||
[^1]: Two parties reading while it is guaranteed that no one is writing is always safe.
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ Tasks in `async_std` are one of the core abstractions. Much like Rust's `thread`
|
|||
|
||||
## Blocking
|
||||
|
||||
`Task`s are assumed to run _concurrently_, potentially by sharing a thread of execution. This means that operations blocking an _operating system thread_, such as `std::thread::sleep` or io function from Rust's `std` library will _stop execution of all tasks sharing this thread_. Other libraries (such as database drivers) have similar behaviour. Note that _blocking the current thread_ is not in and by itself bad behaviour, just something that does not mix well with the concurrent execution model of `async-std`. Essentially, never do this:
|
||||
`Task`s are assumed to run _concurrently_, potentially by sharing a thread of execution. This means that operations blocking an _operating system thread_, such as `std::thread::sleep` or io function from Rust's `std` library will _stop execution of all tasks sharing this thread_. Other libraries (such as database drivers) have similar behaviour. Note that _blocking the current thread_ is not in and of itself bad behaviour, just something that does not mix well with the concurrent execution model of `async-std`. Essentially, never do this:
|
||||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes a `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include I/O primitives, but also `async/await` compatible versions of primitives like `Mutex`.
|
||||
|
||||
[organization]: https://github.com/async-rs/async-std
|
||||
[organization]: https://github.com/async-rs
|
||||
|
|
|
@ -31,7 +31,7 @@ In general, this crate will be conservative with respect to the minimum supporte
|
|||
|
||||
## Security fixes
|
||||
|
||||
Security fixes will be applied to _all_ minor branches of this library in all _supported_ major revisions. This policy might change in the future, in which case we give at least _3 month_ of ahead notice.
|
||||
Security fixes will be applied to _all_ minor branches of this library in all _supported_ major revisions. This policy might change in the future, in which case we give a notice at least _3 months_ ahead.
|
||||
|
||||
## Credits
|
||||
|
||||
|
|
|
@ -4,16 +4,15 @@ At this point, we only need to start the broker to get a fully-functioning (in t
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
use async_std::{
|
||||
io::{self, BufReader},
|
||||
net::{TcpListener, TcpStream, ToSocketAddrs},
|
||||
prelude::*,
|
||||
task,
|
||||
};
|
||||
use futures_channel::mpsc;
|
||||
use futures_util::SinkExt;
|
||||
use futures::channel::mpsc;
|
||||
use futures::SinkExt;
|
||||
use std::{
|
||||
collections::hash_map::{HashMap, Entry},
|
||||
sync::Arc,
|
||||
|
|
|
@ -22,16 +22,15 @@ Let's add waiting to the server:
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::{
|
||||
# io::{self, BufReader},
|
||||
# net::{TcpListener, TcpStream, ToSocketAddrs},
|
||||
# prelude::*,
|
||||
# task,
|
||||
# };
|
||||
# use futures_channel::mpsc;
|
||||
# use futures_util::SinkExt;
|
||||
# use futures::channel::mpsc;
|
||||
# use futures::SinkExt;
|
||||
# use std::{
|
||||
# collections::hash_map::{HashMap, Entry},
|
||||
# sync::Arc,
|
||||
|
@ -156,16 +155,15 @@ And to the broker:
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::{
|
||||
# io::{self, BufReader},
|
||||
# net::{TcpListener, TcpStream, ToSocketAddrs},
|
||||
# prelude::*,
|
||||
# task,
|
||||
# };
|
||||
# use futures_channel::mpsc;
|
||||
# use futures_util::SinkExt;
|
||||
# use futures::channel::mpsc;
|
||||
# use futures::SinkExt;
|
||||
# use std::{
|
||||
# collections::hash_map::{HashMap, Entry},
|
||||
# sync::Arc,
|
||||
|
|
|
@ -12,15 +12,14 @@ The order of events "Bob sends message to Alice" and "Alice joins" is determined
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::{
|
||||
# net::TcpStream,
|
||||
# prelude::*,
|
||||
# task,
|
||||
# };
|
||||
# use futures_channel::mpsc;
|
||||
# use futures_util::sink::SinkExt;
|
||||
# use futures::channel::mpsc;
|
||||
# use futures::sink::SinkExt;
|
||||
# use std::sync::Arc;
|
||||
#
|
||||
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
|
|
@ -19,11 +19,10 @@ First, let's add a shutdown channel to the `connection_loop`:
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::net::TcpStream;
|
||||
# use futures_channel::mpsc;
|
||||
# use futures_util::SinkExt;
|
||||
# use futures::channel::mpsc;
|
||||
# use futures::SinkExt;
|
||||
# use std::sync::Arc;
|
||||
#
|
||||
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
@ -70,11 +69,10 @@ We use the `select` macro for this purpose:
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::{net::TcpStream, prelude::*};
|
||||
use futures_channel::mpsc;
|
||||
use futures_util::{select, FutureExt};
|
||||
use futures::channel::mpsc;
|
||||
use futures::{select, FutureExt};
|
||||
# use std::sync::Arc;
|
||||
|
||||
# type Receiver<T> = mpsc::UnboundedReceiver<T>;
|
||||
|
@ -122,16 +120,15 @@ The final code looks like this:
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
use async_std::{
|
||||
io::BufReader,
|
||||
net::{TcpListener, TcpStream, ToSocketAddrs},
|
||||
prelude::*,
|
||||
task,
|
||||
};
|
||||
use futures_channel::mpsc;
|
||||
use futures_util::{select, FutureExt, SinkExt};
|
||||
use futures::channel::mpsc;
|
||||
use futures::{select, FutureExt, SinkExt};
|
||||
use std::{
|
||||
collections::hash_map::{Entry, HashMap},
|
||||
future::Future,
|
||||
|
|
|
@ -16,14 +16,14 @@ With async, we can just use the `select!` macro.
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
use async_std::{
|
||||
io::{stdin, BufReader},
|
||||
net::{TcpStream, ToSocketAddrs},
|
||||
prelude::*,
|
||||
task,
|
||||
};
|
||||
use futures_util::{select, FutureExt};
|
||||
use futures::{select, FutureExt};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
|
|
|
@ -13,14 +13,13 @@ if Alice and Charley send two messages to Bob at the same time, Bob will see the
|
|||
|
||||
```rust,edition2018
|
||||
# extern crate async_std;
|
||||
# extern crate futures_channel;
|
||||
# extern crate futures_util;
|
||||
# extern crate futures;
|
||||
# use async_std::{
|
||||
# net::TcpStream,
|
||||
# prelude::*,
|
||||
# };
|
||||
use futures_channel::mpsc; // 1
|
||||
use futures_util::sink::SinkExt;
|
||||
use futures::channel::mpsc; // 1
|
||||
use futures::sink::SinkExt;
|
||||
use std::sync::Arc;
|
||||
|
||||
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
|
|
@ -12,7 +12,7 @@ After that, the client can send messages to other clients using the following sy
|
|||
login1, login2, ... loginN: message
|
||||
```
|
||||
|
||||
Each of the specified clients than receives a `from login: message` message.
|
||||
Each of the specified clients then receives a `from login: message` message.
|
||||
|
||||
A possible session might look like this
|
||||
|
||||
|
@ -50,6 +50,6 @@ Add the following lines to `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
futures-preview = { version = "0.3.0-alpha.19", features = [ "async-await" ] }
|
||||
async-std = "0.99"
|
||||
futures = "0.3.0"
|
||||
async-std = "1.0.0"
|
||||
```
|
||||
|
|
|
@ -8,6 +8,6 @@ fn main() -> Result<()> {
|
|||
match (args.nth(1).as_ref().map(String::as_str), args.next()) {
|
||||
(Some("client"), None) => client::main(),
|
||||
(Some("server"), None) => server::main(),
|
||||
_ => Err("Usage: a-chat [client|server]")?,
|
||||
_ => Err("Usage: a-chat [client|server]".into()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ async fn connection_loop(mut broker: Sender<Event>, stream: TcpStream) -> Result
|
|||
let mut lines = reader.lines();
|
||||
|
||||
let name = match lines.next().await {
|
||||
None => Err("peer disconnected immediately")?,
|
||||
None => return Err("peer disconnected immediately".into()),
|
||||
Some(line) => line?,
|
||||
};
|
||||
let (_shutdown_sender, shutdown_receiver) = mpsc::unbounded::<Void>();
|
||||
|
|
44
examples/tcp-ipv4-and-6-echo.rs
Normal file
44
examples/tcp-ipv4-and-6-echo.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
//! TCP echo server, accepting connections both on both ipv4 and ipv6 sockets.
|
||||
//!
|
||||
//! To send messages, do:
|
||||
//!
|
||||
//! ```sh
|
||||
//! $ nc 127.0.0.1 8080
|
||||
//! $ nc ::1 8080
|
||||
//! ```
|
||||
|
||||
use async_std::io;
|
||||
use async_std::net::{TcpListener, TcpStream};
|
||||
use async_std::prelude::*;
|
||||
use async_std::task;
|
||||
|
||||
async fn process(stream: TcpStream) -> io::Result<()> {
|
||||
println!("Accepted from: {}", stream.peer_addr()?);
|
||||
|
||||
let (reader, writer) = &mut (&stream, &stream);
|
||||
io::copy(reader, writer).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
task::block_on(async {
|
||||
let ipv4_listener = TcpListener::bind("127.0.0.1:8080").await?;
|
||||
println!("Listening on {}", ipv4_listener.local_addr()?);
|
||||
let ipv6_listener = TcpListener::bind("[::1]:8080").await?;
|
||||
println!("Listening on {}", ipv6_listener.local_addr()?);
|
||||
|
||||
let ipv4_incoming = ipv4_listener.incoming();
|
||||
let ipv6_incoming = ipv6_listener.incoming();
|
||||
|
||||
let mut incoming = ipv4_incoming.merge(ipv6_incoming);
|
||||
|
||||
while let Some(stream) = incoming.next().await {
|
||||
let stream = stream?;
|
||||
task::spawn(async {
|
||||
process(stream).await.unwrap();
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -2,10 +2,10 @@ use std::collections::BinaryHeap;
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<T: Ord> Extend<T> for BinaryHeap<T> {
|
||||
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
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>> {
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
use std::collections::BinaryHeap;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<T: Ord> FromStream<T> for BinaryHeap<T> {
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = T>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = BinaryHeap::new();
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::BTreeMap;
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
|
||||
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
|
||||
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>> {
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<K: Ord, V> FromStream<(K, V)> for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = (K, V)>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = BTreeMap::new();
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::BTreeSet;
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<T: Ord> Extend<T> for BTreeSet<T> {
|
||||
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
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>> {
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<T: Ord> FromStream<T> for BTreeSet<T> {
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = T>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = BTreeSet::new();
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ use std::hash::{BuildHasher, Hash};
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<K, V, H> Extend<(K, V)> for HashMap<K, V, H>
|
||||
impl<K, V, H> stream::Extend<(K, V)> for HashMap<K, V, H>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
H: BuildHasher + Default,
|
||||
{
|
||||
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
|
||||
fn extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
|
||||
&'a mut self,
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::collections::HashMap;
|
|||
use std::hash::{BuildHasher, Hash};
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<K, V, H> FromStream<(K, V)> for HashMap<K, V, H>
|
||||
where
|
||||
|
@ -10,19 +11,16 @@ where
|
|||
H: BuildHasher + Default,
|
||||
{
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = (K, V)>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = HashMap::with_hasher(Default::default());
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ use std::hash::{BuildHasher, Hash};
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<T, H> Extend<T> for HashSet<T, H>
|
||||
impl<T, H> stream::Extend<T> for HashSet<T, H>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
H: BuildHasher + Default,
|
||||
{
|
||||
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
fn extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
&'a mut self,
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::collections::HashSet;
|
|||
use std::hash::{BuildHasher, Hash};
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<T, H> FromStream<T> for HashSet<T, H>
|
||||
where
|
||||
|
@ -10,19 +11,16 @@ where
|
|||
H: BuildHasher + Default,
|
||||
{
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = T>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = HashSet::with_hasher(Default::default());
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::LinkedList;
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<T> Extend<T> for LinkedList<T> {
|
||||
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
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>> {
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
use std::collections::LinkedList;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<T> FromStream<T> for LinkedList<T> {
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = T>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = LinkedList::new();
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::VecDeque;
|
|||
use std::pin::Pin;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{Extend, IntoStream};
|
||||
use crate::stream::{self, IntoStream};
|
||||
|
||||
impl<T> Extend<T> for VecDeque<T> {
|
||||
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
|
||||
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>> {
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::stream::{Extend, FromStream, IntoStream};
|
||||
use crate::prelude::*;
|
||||
use crate::stream::{self, FromStream, IntoStream};
|
||||
|
||||
impl<T> FromStream<T> for VecDeque<T> {
|
||||
#[inline]
|
||||
fn from_stream<'a, S: IntoStream<Item = T>>(
|
||||
fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
|
||||
stream: S,
|
||||
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
|
||||
where
|
||||
<S as IntoStream>::IntoStream: 'a,
|
||||
{
|
||||
) -> Pin<Box<dyn Future<Output = Self> + 'a>> {
|
||||
let stream = stream.into_stream();
|
||||
|
||||
Box::pin(async move {
|
||||
pin_utils::pin_mut!(stream);
|
||||
|
||||
let mut out = VecDeque::new();
|
||||
out.stream_extend(stream).await;
|
||||
stream::extend(&mut out, stream).await;
|
||||
out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Returns the canonical form of a path.
|
||||
///
|
||||
|
@ -32,5 +32,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::canonicalize(&path).map(Into::into)).await
|
||||
spawn_blocking(move || std::fs::canonicalize(&path).map(Into::into)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Copies the contents and permissions of a file to a new location.
|
||||
///
|
||||
|
@ -41,5 +41,5 @@ use crate::task::blocking;
|
|||
pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
|
||||
let from = from.as_ref().to_owned();
|
||||
let to = to.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::copy(&from, &to)).await
|
||||
spawn_blocking(move || std::fs::copy(&from, &to)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Creates a new directory.
|
||||
///
|
||||
|
@ -34,5 +34,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::create_dir(path)).await
|
||||
spawn_blocking(move || std::fs::create_dir(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Creates a new directory and all of its parents if they are missing.
|
||||
///
|
||||
|
@ -29,5 +29,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::create_dir_all(path)).await
|
||||
spawn_blocking(move || std::fs::create_dir_all(path)).await
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::future::Future;
|
|||
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// A builder for creating directories with configurable options.
|
||||
///
|
||||
|
@ -107,7 +107,7 @@ impl DirBuilder {
|
|||
}
|
||||
|
||||
let path = path.as_ref().to_owned();
|
||||
async move { blocking::spawn(move || builder.create(path)).await }
|
||||
async move { spawn_blocking(move || builder.create(path)).await }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
|||
use crate::fs::{FileType, Metadata};
|
||||
use crate::io;
|
||||
use crate::path::PathBuf;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// An entry in a directory.
|
||||
///
|
||||
|
@ -87,7 +87,7 @@ impl DirEntry {
|
|||
/// ```
|
||||
pub async fn metadata(&self) -> io::Result<Metadata> {
|
||||
let inner = self.0.clone();
|
||||
blocking::spawn(move || inner.metadata()).await
|
||||
spawn_blocking(move || inner.metadata()).await
|
||||
}
|
||||
|
||||
/// Reads the file type for this entry.
|
||||
|
@ -125,7 +125,7 @@ impl DirEntry {
|
|||
/// ```
|
||||
pub async fn file_type(&self) -> io::Result<FileType> {
|
||||
let inner = self.0.clone();
|
||||
blocking::spawn(move || inner.file_type()).await
|
||||
spawn_blocking(move || inner.file_type()).await
|
||||
}
|
||||
|
||||
/// Returns the bare name of this entry without the leading path.
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::future;
|
|||
use crate::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use crate::path::Path;
|
||||
use crate::prelude::*;
|
||||
use crate::task::{self, blocking, Context, Poll, Waker};
|
||||
use crate::task::{self, spawn_blocking, Context, Poll, Waker};
|
||||
|
||||
/// An open file on the filesystem.
|
||||
///
|
||||
|
@ -66,6 +66,23 @@ pub struct File {
|
|||
}
|
||||
|
||||
impl File {
|
||||
/// Creates an async file handle.
|
||||
pub(crate) fn new(file: std::fs::File, is_flushed: bool) -> File {
|
||||
let file = Arc::new(file);
|
||||
|
||||
File {
|
||||
file: file.clone(),
|
||||
lock: Lock::new(State {
|
||||
file,
|
||||
mode: Mode::Idle,
|
||||
cache: Vec::new(),
|
||||
is_flushed,
|
||||
last_read_err: None,
|
||||
last_write_err: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens a file in read-only mode.
|
||||
///
|
||||
/// See the [`OpenOptions::open`] function for more options.
|
||||
|
@ -95,8 +112,8 @@ impl File {
|
|||
/// ```
|
||||
pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
||||
let path = path.as_ref().to_owned();
|
||||
let file = blocking::spawn(move || std::fs::File::open(&path)).await?;
|
||||
Ok(file.into())
|
||||
let file = spawn_blocking(move || std::fs::File::open(&path)).await?;
|
||||
Ok(File::new(file, true))
|
||||
}
|
||||
|
||||
/// Opens a file in write-only mode.
|
||||
|
@ -130,8 +147,8 @@ impl File {
|
|||
/// ```
|
||||
pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
||||
let path = path.as_ref().to_owned();
|
||||
let file = blocking::spawn(move || std::fs::File::create(&path)).await?;
|
||||
Ok(file.into())
|
||||
let file = spawn_blocking(move || std::fs::File::create(&path)).await?;
|
||||
Ok(File::new(file, true))
|
||||
}
|
||||
|
||||
/// Synchronizes OS-internal buffered contents and metadata to disk.
|
||||
|
@ -163,7 +180,7 @@ impl File {
|
|||
})
|
||||
.await?;
|
||||
|
||||
blocking::spawn(move || state.file.sync_all()).await
|
||||
spawn_blocking(move || state.file.sync_all()).await
|
||||
}
|
||||
|
||||
/// Synchronizes OS-internal buffered contents to disk.
|
||||
|
@ -199,7 +216,7 @@ impl File {
|
|||
})
|
||||
.await?;
|
||||
|
||||
blocking::spawn(move || state.file.sync_data()).await
|
||||
spawn_blocking(move || state.file.sync_data()).await
|
||||
}
|
||||
|
||||
/// Truncates or extends the file.
|
||||
|
@ -232,7 +249,7 @@ impl File {
|
|||
})
|
||||
.await?;
|
||||
|
||||
blocking::spawn(move || state.file.set_len(size)).await
|
||||
spawn_blocking(move || state.file.set_len(size)).await
|
||||
}
|
||||
|
||||
/// Reads the file's metadata.
|
||||
|
@ -251,7 +268,7 @@ impl File {
|
|||
/// ```
|
||||
pub async fn metadata(&self) -> io::Result<Metadata> {
|
||||
let file = self.file.clone();
|
||||
blocking::spawn(move || file.metadata()).await
|
||||
spawn_blocking(move || file.metadata()).await
|
||||
}
|
||||
|
||||
/// Changes the permissions on the file.
|
||||
|
@ -280,7 +297,7 @@ impl File {
|
|||
/// ```
|
||||
pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
|
||||
let file = self.file.clone();
|
||||
blocking::spawn(move || file.set_permissions(perm)).await
|
||||
spawn_blocking(move || file.set_permissions(perm)).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,19 +400,7 @@ impl Seek for &File {
|
|||
|
||||
impl From<std::fs::File> for File {
|
||||
fn from(file: std::fs::File) -> File {
|
||||
let file = Arc::new(file);
|
||||
|
||||
File {
|
||||
file: file.clone(),
|
||||
lock: Lock::new(State {
|
||||
file,
|
||||
mode: Mode::Idle,
|
||||
cache: Vec::new(),
|
||||
is_flushed: false,
|
||||
last_read_err: None,
|
||||
last_write_err: None,
|
||||
}),
|
||||
}
|
||||
File::new(file, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,7 +692,7 @@ impl LockGuard<State> {
|
|||
self.register(cx);
|
||||
|
||||
// Start a read operation asynchronously.
|
||||
blocking::spawn(move || {
|
||||
spawn_blocking(move || {
|
||||
// Read some data from the file into the cache.
|
||||
let res = {
|
||||
let State { file, cache, .. } = &mut *self;
|
||||
|
@ -796,7 +801,7 @@ impl LockGuard<State> {
|
|||
self.register(cx);
|
||||
|
||||
// Start a write operation asynchronously.
|
||||
blocking::spawn(move || {
|
||||
spawn_blocking(move || {
|
||||
match (&*self.file).write_all(&self.cache) {
|
||||
Ok(_) => {
|
||||
// Switch to idle mode.
|
||||
|
@ -829,7 +834,7 @@ impl LockGuard<State> {
|
|||
self.register(cx);
|
||||
|
||||
// Start a flush operation asynchronously.
|
||||
blocking::spawn(move || {
|
||||
spawn_blocking(move || {
|
||||
match (&*self.file).flush() {
|
||||
Ok(()) => {
|
||||
// Mark the file as flushed.
|
||||
|
|
|
@ -40,7 +40,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn is_dir(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns `true` if this file type represents a regular file.
|
||||
|
@ -60,7 +60,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn is_file(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns `true` if this file type represents a symbolic link.
|
||||
|
@ -78,7 +78,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Creates a hard link on the filesystem.
|
||||
///
|
||||
|
@ -32,5 +32,5 @@ use crate::task::blocking;
|
|||
pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||
let from = from.as_ref().to_owned();
|
||||
let to = to.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::hard_link(&from, &to)).await
|
||||
spawn_blocking(move || std::fs::hard_link(&from, &to)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Reads metadata for a path.
|
||||
///
|
||||
|
@ -34,7 +34,7 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::metadata(path)).await
|
||||
spawn_blocking(move || std::fs::metadata(path)).await
|
||||
}
|
||||
|
||||
cfg_not_docs! {
|
||||
|
@ -78,7 +78,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn file_type(&self) -> FileType {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns `true` if this metadata is for a regular directory.
|
||||
|
@ -98,7 +98,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn is_dir(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns `true` if this metadata is for a regular file.
|
||||
|
@ -118,7 +118,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn is_file(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns the file size in bytes.
|
||||
|
@ -136,7 +136,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn len(&self) -> u64 {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns the permissions from this metadata.
|
||||
|
@ -154,7 +154,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn permissions(&self) -> Permissions {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns the last modification time.
|
||||
|
@ -177,7 +177,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns the last access time.
|
||||
|
@ -200,7 +200,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Returns the creation time.
|
||||
|
@ -223,7 +223,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::future::Future;
|
|||
use crate::fs::File;
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// A builder for opening files with configurable options.
|
||||
///
|
||||
|
@ -284,7 +284,10 @@ impl OpenOptions {
|
|||
pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
|
||||
let path = path.as_ref().to_owned();
|
||||
let options = self.0.clone();
|
||||
async move { blocking::spawn(move || options.open(path).map(|f| f.into())).await }
|
||||
async move {
|
||||
let file = spawn_blocking(move || options.open(path)).await?;
|
||||
Ok(File::new(file, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn readonly(&self) -> bool {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
|
||||
/// Configures the read-only flag.
|
||||
|
@ -50,7 +50,7 @@ cfg_docs! {
|
|||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
pub fn set_readonly(&mut self, readonly: bool) {
|
||||
unimplemented!()
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Reads the entire contents of a file as raw bytes.
|
||||
///
|
||||
|
@ -36,5 +36,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::read(path)).await
|
||||
spawn_blocking(move || std::fs::read(path)).await
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::fs::DirEntry;
|
||||
use crate::future::Future;
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::stream::Stream;
|
||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
|
||||
|
||||
/// Returns a stream of entries in a directory.
|
||||
///
|
||||
|
@ -45,7 +45,7 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
|
|||
/// ```
|
||||
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::read_dir(path))
|
||||
spawn_blocking(move || std::fs::read_dir(path))
|
||||
.await
|
||||
.map(ReadDir::new)
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ impl Stream for ReadDir {
|
|||
let mut inner = opt.take().unwrap();
|
||||
|
||||
// Start the operation asynchronously.
|
||||
self.0 = State::Busy(blocking::spawn(move || {
|
||||
self.0 = State::Busy(spawn_blocking(move || {
|
||||
let next = inner.next();
|
||||
(inner, next)
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Reads a symbolic link and returns the path it points to.
|
||||
///
|
||||
|
@ -28,5 +28,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::read_link(path).map(Into::into)).await
|
||||
spawn_blocking(move || std::fs::read_link(path).map(Into::into)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Reads the entire contents of a file as a string.
|
||||
///
|
||||
|
@ -37,5 +37,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::read_to_string(path)).await
|
||||
spawn_blocking(move || std::fs::read_to_string(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Removes an empty directory.
|
||||
///
|
||||
|
@ -29,5 +29,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::remove_dir(path)).await
|
||||
spawn_blocking(move || std::fs::remove_dir(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Removes a directory and all of its contents.
|
||||
///
|
||||
|
@ -29,5 +29,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::remove_dir_all(path)).await
|
||||
spawn_blocking(move || std::fs::remove_dir_all(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Removes a file.
|
||||
///
|
||||
|
@ -29,5 +29,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::remove_file(path)).await
|
||||
spawn_blocking(move || std::fs::remove_file(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Renames a file or directory to a new location.
|
||||
///
|
||||
|
@ -34,5 +34,5 @@ use crate::task::blocking;
|
|||
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
|
||||
let from = from.as_ref().to_owned();
|
||||
let to = to.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::rename(&from, &to)).await
|
||||
spawn_blocking(move || std::fs::rename(&from, &to)).await
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::fs::Permissions;
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Changes the permissions of a file or directory.
|
||||
///
|
||||
|
@ -32,5 +32,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::set_permissions(path, perm)).await
|
||||
spawn_blocking(move || std::fs::set_permissions(path, perm)).await
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::fs::Metadata;
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Reads metadata for a path without following symbolic links.
|
||||
///
|
||||
|
@ -34,5 +34,5 @@ use crate::task::blocking;
|
|||
/// ```
|
||||
pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
|
||||
let path = path.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::symlink_metadata(path)).await
|
||||
spawn_blocking(move || std::fs::symlink_metadata(path)).await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::task::blocking;
|
||||
use crate::task::spawn_blocking;
|
||||
|
||||
/// Writes a slice of bytes as the new contents of a file.
|
||||
///
|
||||
|
@ -33,5 +33,5 @@ use crate::task::blocking;
|
|||
pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
|
||||
let path = path.as_ref().to_owned();
|
||||
let contents = contents.as_ref().to_owned();
|
||||
blocking::spawn(move || std::fs::write(path, contents)).await
|
||||
spawn_blocking(move || std::fs::write(path, contents)).await
|
||||
}
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
extension_trait! {
|
||||
use std::pin::Pin;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
#[doc = r#"
|
||||
A future represents an asynchronous computation.
|
||||
|
||||
A future is a value that may not have finished computing yet. This kind of
|
||||
"asynchronous value" makes it possible for a thread to continue doing useful
|
||||
work while it waits for the value to become available.
|
||||
|
||||
# The `poll` method
|
||||
|
||||
The core method of future, `poll`, *attempts* to resolve the future into a
|
||||
final value. This method does not block if the value is not ready. Instead,
|
||||
the current task is scheduled to be woken up when it's possible to make
|
||||
further progress by `poll`ing again. The `context` passed to the `poll`
|
||||
method can provide a [`Waker`], which is a handle for waking up the current
|
||||
task.
|
||||
|
||||
When using a future, you generally won't call `poll` directly, but instead
|
||||
`.await` the value.
|
||||
|
||||
[`Waker`]: ../task/struct.Waker.html
|
||||
"#]
|
||||
pub trait Future {
|
||||
#[doc = r#"
|
||||
The type of value produced on completion.
|
||||
"#]
|
||||
type Output;
|
||||
|
||||
#[doc = r#"
|
||||
Attempt to resolve the future to a final value, registering
|
||||
the current task for wakeup if the value is not yet available.
|
||||
|
||||
# Return value
|
||||
|
||||
This function returns:
|
||||
|
||||
- [`Poll::Pending`] if the future is not ready yet
|
||||
- [`Poll::Ready(val)`] with the result `val` of this future if it
|
||||
finished successfully.
|
||||
|
||||
Once a future has finished, clients should not `poll` it again.
|
||||
|
||||
When a future is not ready yet, `poll` returns `Poll::Pending` and
|
||||
stores a clone of the [`Waker`] copied from the current [`Context`].
|
||||
This [`Waker`] is then woken once the future can make progress.
|
||||
For example, a future waiting for a socket to become
|
||||
readable would call `.clone()` on the [`Waker`] and store it.
|
||||
When a signal arrives elsewhere indicating that the socket is readable,
|
||||
[`Waker::wake`] is called and the socket future's task is awoken.
|
||||
Once a task has been woken up, it should attempt to `poll` the future
|
||||
again, which may or may not produce a final value.
|
||||
|
||||
Note that on multiple calls to `poll`, only the [`Waker`] from the
|
||||
[`Context`] passed to the most recent call should be scheduled to
|
||||
receive a wakeup.
|
||||
|
||||
# Runtime characteristics
|
||||
|
||||
Futures alone are *inert*; they must be *actively* `poll`ed to make
|
||||
progress, meaning that each time the current task is woken up, it should
|
||||
actively re-`poll` pending futures that it still has an interest in.
|
||||
|
||||
The `poll` function is not called repeatedly in a tight loop -- instead,
|
||||
it should only be called when the future indicates that it is ready to
|
||||
make progress (by calling `wake()`). If you're familiar with the
|
||||
`poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
|
||||
typically do *not* suffer the same problems of "all wakeups must poll
|
||||
all events"; they are more like `epoll(4)`.
|
||||
|
||||
An implementation of `poll` should strive to return quickly, and should
|
||||
not block. Returning quickly prevents unnecessarily clogging up
|
||||
threads or event loops. If it is known ahead of time that a call to
|
||||
`poll` may end up taking awhile, the work should be offloaded to a
|
||||
thread pool (or something similar) to ensure that `poll` can return
|
||||
quickly.
|
||||
|
||||
# Panics
|
||||
|
||||
Once a future has completed (returned `Ready` from `poll`), calling its
|
||||
`poll` method again may panic, block forever, or cause other kinds of
|
||||
problems; the `Future` trait places no requirements on the effects of
|
||||
such a call. However, as the `poll` method is not marked `unsafe`,
|
||||
Rust's usual rules apply: calls must never cause undefined behavior
|
||||
(memory corruption, incorrect use of `unsafe` functions, or the like),
|
||||
regardless of the future's state.
|
||||
|
||||
[`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
|
||||
[`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
|
||||
[`Context`]: ../task/struct.Context.html
|
||||
[`Waker`]: ../task/struct.Waker.html
|
||||
[`Waker::wake`]: ../task/struct.Waker.html#method.wake
|
||||
"#]
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
|
||||
}
|
||||
|
||||
pub trait FutureExt: std::future::Future {
|
||||
}
|
||||
|
||||
impl<F: Future + Unpin + ?Sized> Future for Box<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future + Unpin + ?Sized> Future for &mut F {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> Future for Pin<P>
|
||||
where
|
||||
P: DerefMut + Unpin,
|
||||
<P as Deref>::Target: Future,
|
||||
{
|
||||
type Output = <<P as Deref>::Target as Future>::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future> Future for std::panic::AssertUnwindSafe<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
}
|
43
src/future/future/delay.rs
Normal file
43
src/future/future/delay.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
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};
|
||||
|
||||
pin_project! {
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct DelayFuture<F> {
|
||||
#[pin]
|
||||
future: F,
|
||||
#[pin]
|
||||
delay: Delay,
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> DelayFuture<F> {
|
||||
pub fn new(future: F, dur: Duration) -> DelayFuture<F> {
|
||||
let delay = Delay::new(dur);
|
||||
|
||||
DelayFuture { future, delay }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future> Future for DelayFuture<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
match this.delay.poll(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(_) => match this.future.poll(cx) {
|
||||
Poll::Ready(v) => Poll::Ready(v),
|
||||
Poll::Pending => Poll::Pending,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
52
src/future/future/flatten.rs
Normal file
52
src/future/future/flatten.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::future::IntoFuture;
|
||||
use crate::task::{ready, Context, Poll};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct FlattenFuture<Fut1, Fut2> {
|
||||
state: State<Fut1, Fut2>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum State<Fut1, Fut2> {
|
||||
First(Fut1),
|
||||
Second(Fut2),
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl<Fut1, Fut2> FlattenFuture<Fut1, Fut2> {
|
||||
pub(crate) fn new(future: Fut1) -> FlattenFuture<Fut1, Fut2> {
|
||||
FlattenFuture {
|
||||
state: State::First(future),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Fut1> Future for FlattenFuture<Fut1, <Fut1::Output as IntoFuture>::Future>
|
||||
where
|
||||
Fut1: Future,
|
||||
Fut1::Output: IntoFuture,
|
||||
{
|
||||
type Output = <Fut1::Output as IntoFuture>::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self { state } = unsafe { self.get_unchecked_mut() };
|
||||
loop {
|
||||
match state {
|
||||
State::First(fut1) => {
|
||||
let fut2 = ready!(unsafe { Pin::new_unchecked(fut1) }.poll(cx)).into_future();
|
||||
*state = State::Second(fut2);
|
||||
}
|
||||
State::Second(fut2) => {
|
||||
let v = ready!(unsafe { Pin::new_unchecked(fut2) }.poll(cx));
|
||||
*state = State::Empty;
|
||||
return Poll::Ready(v);
|
||||
}
|
||||
State::Empty => panic!("polled a completed future"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/future/future/join.rs
Normal file
62
src/future/future/join.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use std::pin::Pin;
|
||||
|
||||
use async_macros::MaybeDone;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
use std::future::Future;
|
||||
|
||||
pin_project! {
|
||||
#[allow(missing_docs)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Join<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>
|
||||
{
|
||||
#[pin] left: MaybeDone<L>,
|
||||
#[pin] right: MaybeDone<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> Join<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
pub(crate) fn new(left: L, right: R) -> Self {
|
||||
Self {
|
||||
left: MaybeDone::new(left),
|
||||
right: MaybeDone::new(right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> Future for Join<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
type Output = (L::Output, R::Output);
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
let mut left = this.left;
|
||||
let mut right = this.right;
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
395
src/future/future/mod.rs
Normal file
395
src/future/future/mod.rs
Normal file
|
@ -0,0 +1,395 @@
|
|||
cfg_unstable! {
|
||||
mod delay;
|
||||
mod flatten;
|
||||
mod race;
|
||||
mod try_race;
|
||||
mod join;
|
||||
mod try_join;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use delay::DelayFuture;
|
||||
use flatten::FlattenFuture;
|
||||
use crate::future::IntoFuture;
|
||||
use race::Race;
|
||||
use try_race::TryRace;
|
||||
use join::Join;
|
||||
use try_join::TryJoin;
|
||||
}
|
||||
|
||||
extension_trait! {
|
||||
use std::pin::Pin;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
#[doc = r#"
|
||||
A future represents an asynchronous computation.
|
||||
|
||||
A future is a value that may not have finished computing yet. This kind of
|
||||
"asynchronous value" makes it possible for a thread to continue doing useful
|
||||
work while it waits for the value to become available.
|
||||
|
||||
The [provided methods] do not really exist in the trait itself, but they become
|
||||
available when [`FutureExt`] from the [prelude] is imported:
|
||||
|
||||
```
|
||||
# #[allow(unused_imports)]
|
||||
use async_std::prelude::*;
|
||||
```
|
||||
|
||||
# The `poll` method
|
||||
|
||||
The core method of future, `poll`, *attempts* to resolve the future into a
|
||||
final value. This method does not block if the value is not ready. Instead,
|
||||
the current task is scheduled to be woken up when it's possible to make
|
||||
further progress by `poll`ing again. The `context` passed to the `poll`
|
||||
method can provide a [`Waker`], which is a handle for waking up the current
|
||||
task.
|
||||
|
||||
When using a future, you generally won't call `poll` directly, but instead
|
||||
`.await` the value.
|
||||
|
||||
[`Waker`]: ../task/struct.Waker.html
|
||||
[provided methods]: #provided-methods
|
||||
[`FutureExt`]: ../prelude/trait.FutureExt.html
|
||||
[prelude]: ../prelude/index.html
|
||||
"#]
|
||||
pub trait Future {
|
||||
#[doc = r#"
|
||||
The type of value produced on completion.
|
||||
"#]
|
||||
type Output;
|
||||
|
||||
#[doc = r#"
|
||||
Attempt to resolve the future to a final value, registering
|
||||
the current task for wakeup if the value is not yet available.
|
||||
|
||||
# Return value
|
||||
|
||||
This function returns:
|
||||
|
||||
- [`Poll::Pending`] if the future is not ready yet
|
||||
- [`Poll::Ready(val)`] with the result `val` of this future if it
|
||||
finished successfully.
|
||||
|
||||
Once a future has finished, clients should not `poll` it again.
|
||||
|
||||
When a future is not ready yet, `poll` returns `Poll::Pending` and
|
||||
stores a clone of the [`Waker`] copied from the current [`Context`].
|
||||
This [`Waker`] is then woken once the future can make progress.
|
||||
For example, a future waiting for a socket to become
|
||||
readable would call `.clone()` on the [`Waker`] and store it.
|
||||
When a signal arrives elsewhere indicating that the socket is readable,
|
||||
[`Waker::wake`] is called and the socket future's task is awoken.
|
||||
Once a task has been woken up, it should attempt to `poll` the future
|
||||
again, which may or may not produce a final value.
|
||||
|
||||
Note that on multiple calls to `poll`, only the [`Waker`] from the
|
||||
[`Context`] passed to the most recent call should be scheduled to
|
||||
receive a wakeup.
|
||||
|
||||
# Runtime characteristics
|
||||
|
||||
Futures alone are *inert*; they must be *actively* `poll`ed to make
|
||||
progress, meaning that each time the current task is woken up, it should
|
||||
actively re-`poll` pending futures that it still has an interest in.
|
||||
|
||||
The `poll` function is not called repeatedly in a tight loop -- instead,
|
||||
it should only be called when the future indicates that it is ready to
|
||||
make progress (by calling `wake()`). If you're familiar with the
|
||||
`poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
|
||||
typically do *not* suffer the same problems of "all wakeups must poll
|
||||
all events"; they are more like `epoll(4)`.
|
||||
|
||||
An implementation of `poll` should strive to return quickly, and should
|
||||
not block. Returning quickly prevents unnecessarily clogging up
|
||||
threads or event loops. If it is known ahead of time that a call to
|
||||
`poll` may end up taking awhile, the work should be offloaded to a
|
||||
thread pool (or something similar) to ensure that `poll` can return
|
||||
quickly.
|
||||
|
||||
# Panics
|
||||
|
||||
Once a future has completed (returned `Ready` from `poll`), calling its
|
||||
`poll` method again may panic, block forever, or cause other kinds of
|
||||
problems; the `Future` trait places no requirements on the effects of
|
||||
such a call. However, as the `poll` method is not marked `unsafe`,
|
||||
Rust's usual rules apply: calls must never cause undefined behavior
|
||||
(memory corruption, incorrect use of `unsafe` functions, or the like),
|
||||
regardless of the future's state.
|
||||
|
||||
[`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
|
||||
[`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
|
||||
[`Context`]: ../task/struct.Context.html
|
||||
[`Waker`]: ../task/struct.Waker.html
|
||||
[`Waker::wake`]: ../task/struct.Waker.html#method.wake
|
||||
"#]
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Extension methods for [`Future`].
|
||||
|
||||
[`Future`]: ../future/trait.Future.html
|
||||
"#]
|
||||
pub trait FutureExt: std::future::Future {
|
||||
/// Returns a Future that delays execution for a specified time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # async_std::task::block_on(async {
|
||||
/// use async_std::prelude::*;
|
||||
/// use async_std::future;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let a = future::ready(1).delay(Duration::from_millis(2000));
|
||||
/// dbg!(a.await);
|
||||
/// # })
|
||||
/// ```
|
||||
#[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
|
||||
Self: Sized,
|
||||
{
|
||||
DelayFuture::new(self, dur)
|
||||
}
|
||||
|
||||
/// Flatten out the execution of this future when the result itself
|
||||
/// can be converted into another future.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # async_std::task::block_on(async {
|
||||
/// use async_std::prelude::*;
|
||||
///
|
||||
/// let nested_future = async { async { 1 } };
|
||||
/// let future = nested_future.flatten();
|
||||
/// assert_eq!(future.await, 1);
|
||||
/// # })
|
||||
/// ```
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||
fn flatten(
|
||||
self,
|
||||
) -> impl Future<Output = <Self::Output as IntoFuture>::Output>
|
||||
[FlattenFuture<Self, <Self::Output as IntoFuture>::Future>]
|
||||
where
|
||||
Self: Sized,
|
||||
<Self as Future>::Output: IntoFuture,
|
||||
{
|
||||
FlattenFuture::new(self)
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Waits for one of two similarly-typed futures to complete.
|
||||
|
||||
Awaits multiple futures simultaneously, returning the output of the
|
||||
first future that completes.
|
||||
|
||||
This function will return a new future which awaits for either one of both
|
||||
futures to complete. If multiple futures are completed at the same time,
|
||||
resolution will occur in the order that they have been passed.
|
||||
|
||||
Note that this function consumes all futures passed, and once a future is
|
||||
completed, all other futures are dropped.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
# async_std::task::block_on(async {
|
||||
use async_std::prelude::*;
|
||||
use async_std::future;
|
||||
|
||||
let a = future::pending();
|
||||
let b = future::ready(1u8);
|
||||
let c = future::ready(2u8);
|
||||
|
||||
let f = a.race(b).race(c);
|
||||
assert_eq!(f.await, 1u8);
|
||||
# });
|
||||
```
|
||||
"#]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||
fn race<F>(
|
||||
self,
|
||||
other: F,
|
||||
) -> impl Future<Output = <Self as std::future::Future>::Output> [Race<Self, F>]
|
||||
where
|
||||
Self: std::future::Future + Sized,
|
||||
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
|
||||
{
|
||||
Race::new(self, other)
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Waits for one of two similarly-typed fallible futures to complete.
|
||||
|
||||
Awaits multiple futures simultaneously, returning all results once complete.
|
||||
|
||||
`try_race` is similar to [`race`], but keeps going if a future
|
||||
resolved to an error until all futures have been resolved. In which case
|
||||
an error is returned.
|
||||
|
||||
The ordering of which value is yielded when two futures resolve
|
||||
simultaneously is intentionally left unspecified.
|
||||
|
||||
[`race`]: #method.race
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
#
|
||||
use async_std::prelude::*;
|
||||
use async_std::future;
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
||||
let a = future::pending::<Result<_, Error>>();
|
||||
let b = future::ready(Err(Error::from(ErrorKind::Other)));
|
||||
let c = future::ready(Ok(1u8));
|
||||
|
||||
let f = a.try_race(b).try_race(c);
|
||||
assert_eq!(f.await?, 1u8);
|
||||
#
|
||||
# Ok(()) }) }
|
||||
```
|
||||
"#]
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||
fn try_race<F, T, E>(
|
||||
self,
|
||||
other: F
|
||||
) -> impl Future<Output = <Self as std::future::Future>::Output> [TryRace<Self, F>]
|
||||
where
|
||||
Self: std::future::Future<Output = Result<T, E>> + Sized,
|
||||
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
|
||||
{
|
||||
TryRace::new(self, other)
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Waits for two similarly-typed futures to complete.
|
||||
|
||||
Awaits multiple futures simultaneously, returning the output of the
|
||||
futures once both complete.
|
||||
|
||||
This function returns a new future which polls both futures
|
||||
concurrently.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
# async_std::task::block_on(async {
|
||||
use async_std::prelude::*;
|
||||
use async_std::future;
|
||||
|
||||
let a = future::ready(1u8);
|
||||
let b = future::ready(2u8);
|
||||
|
||||
let f = a.join(b);
|
||||
assert_eq!(f.await, (1u8, 2u8));
|
||||
# });
|
||||
```
|
||||
"#]
|
||||
#[cfg(any(feature = "unstable", feature = "docs"))]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
|
||||
fn join<F>(
|
||||
self,
|
||||
other: F
|
||||
) -> 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<Output = <Self as std::future::Future>::Output>,
|
||||
{
|
||||
Join::new(self, other)
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Waits for two similarly-typed fallible futures to complete.
|
||||
|
||||
Awaits multiple futures simultaneously, returning all results once
|
||||
complete.
|
||||
|
||||
`try_join` is similar to [`join`], but returns an error immediately
|
||||
if a future resolves to an error.
|
||||
|
||||
[`join`]: #method.join
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
#
|
||||
use async_std::prelude::*;
|
||||
use async_std::future;
|
||||
|
||||
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::<u8, String>(2u8));
|
||||
|
||||
let f = a.try_join(b);
|
||||
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, T, E>(
|
||||
self,
|
||||
other: F
|
||||
) -> impl Future<Output = Result<(T, T), E>> [TryJoin<Self, F>]
|
||||
where
|
||||
Self: std::future::Future<Output = Result<T, E>> + Sized,
|
||||
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
|
||||
{
|
||||
TryJoin::new(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future + Unpin + ?Sized> Future for Box<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future + Unpin + ?Sized> Future for &mut F {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> Future for Pin<P>
|
||||
where
|
||||
P: DerefMut + Unpin,
|
||||
<P as Deref>::Target: Future,
|
||||
{
|
||||
type Output = <<P as Deref>::Target as Future>::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Future> Future for std::panic::AssertUnwindSafe<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unreachable!("this impl only appears in the rendered docs")
|
||||
}
|
||||
}
|
||||
}
|
57
src/future/future/race.rs
Normal file
57
src/future/future/race.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use async_macros::MaybeDone;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
pin_project! {
|
||||
#[allow(missing_docs)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Race<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>
|
||||
{
|
||||
#[pin] left: MaybeDone<L>,
|
||||
#[pin] right: MaybeDone<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> Race<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
pub(crate) fn new(left: L, right: R) -> Self {
|
||||
Self {
|
||||
left: MaybeDone::new(left),
|
||||
right: MaybeDone::new(right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> Future for Race<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
type Output = L::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
let mut left = this.left;
|
||||
if Future::poll(Pin::new(&mut left), cx).is_ready() {
|
||||
return Poll::Ready(left.take().unwrap());
|
||||
}
|
||||
|
||||
let mut right = this.right;
|
||||
if Future::poll(Pin::new(&mut right), cx).is_ready() {
|
||||
return Poll::Ready(right.take().unwrap());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
72
src/future/future/try_join.rs
Normal file
72
src/future/future/try_join.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::pin::Pin;
|
||||
|
||||
use async_macros::MaybeDone;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
use std::future::Future;
|
||||
|
||||
pin_project! {
|
||||
#[allow(missing_docs)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct TryJoin<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>
|
||||
{
|
||||
#[pin] left: MaybeDone<L>,
|
||||
#[pin] right: MaybeDone<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> TryJoin<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
pub(crate) fn new(left: L, right: R) -> Self {
|
||||
Self {
|
||||
left: MaybeDone::new(left),
|
||||
right: MaybeDone::new(right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R, T, E> Future for TryJoin<L, R>
|
||||
where
|
||||
L: Future<Output = Result<T, E>>,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
type Output = Result<(T, T), E>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
let mut left = this.left;
|
||||
let mut right = this.right;
|
||||
|
||||
if Future::poll(Pin::new(&mut left), cx).is_ready() {
|
||||
if left.as_ref().output().unwrap().is_err() {
|
||||
return Poll::Ready(Err(left.take().unwrap().err().unwrap()));
|
||||
} else if right.as_ref().output().is_some() {
|
||||
return Poll::Ready(Ok((
|
||||
left.take().unwrap().ok().unwrap(),
|
||||
right.take().unwrap().ok().unwrap(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if Future::poll(Pin::new(&mut right), cx).is_ready() {
|
||||
if right.as_ref().output().unwrap().is_err() {
|
||||
return Poll::Ready(Err(right.take().unwrap().err().unwrap()));
|
||||
} else if left.as_ref().output().is_some() {
|
||||
return Poll::Ready(Ok((
|
||||
left.take().unwrap().ok().unwrap(),
|
||||
right.take().unwrap().ok().unwrap(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
66
src/future/future/try_race.rs
Normal file
66
src/future/future/try_race.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use std::pin::Pin;
|
||||
|
||||
use async_macros::MaybeDone;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::task::{Context, Poll};
|
||||
use std::future::Future;
|
||||
|
||||
pin_project! {
|
||||
#[allow(missing_docs)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct TryRace<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>
|
||||
{
|
||||
#[pin] left: MaybeDone<L>,
|
||||
#[pin] right: MaybeDone<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> TryRace<L, R>
|
||||
where
|
||||
L: Future,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
pub(crate) fn new(left: L, right: R) -> Self {
|
||||
Self {
|
||||
left: MaybeDone::new(left),
|
||||
right: MaybeDone::new(right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R, T, E> Future for TryRace<L, R>
|
||||
where
|
||||
L: Future<Output = Result<T, E>>,
|
||||
R: Future<Output = L::Output>,
|
||||
{
|
||||
type Output = L::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
let mut left_errored = false;
|
||||
|
||||
// Check if the left future is ready & successful. Continue if not.
|
||||
let mut left = this.left;
|
||||
if Future::poll(Pin::new(&mut left), cx).is_ready() {
|
||||
if left.as_ref().output().unwrap().is_ok() {
|
||||
return Poll::Ready(left.take().unwrap());
|
||||
} else {
|
||||
left_errored = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the right future is ready & successful. Return err if left
|
||||
// future also resolved to err. Continue if not.
|
||||
let mut right = this.right;
|
||||
let is_ready = Future::poll(Pin::new(&mut right), cx).is_ready();
|
||||
if is_ready && (right.as_ref().output().unwrap().is_ok() || left_errored) {
|
||||
return Poll::Ready(right.take().unwrap());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::future::Future;
|
||||
use std::future::Future;
|
||||
|
||||
/// Convert a type into a `Future`.
|
||||
///
|
||||
|
@ -45,7 +45,6 @@ pub trait IntoFuture {
|
|||
|
||||
impl<T: Future> IntoFuture for T {
|
||||
type Output = T::Output;
|
||||
|
||||
type Future = T;
|
||||
|
||||
fn into_future(self) -> Self::Future {
|
||||
|
|
|
@ -4,62 +4,64 @@
|
|||
//!
|
||||
//! Often it's desireable to await multiple futures as if it was a single
|
||||
//! future. The `join` family of operations converts multiple futures into a
|
||||
//! single future that returns all of their outputs. The `select` family of
|
||||
//! single future that returns all of their outputs. The `race` family of
|
||||
//! operations converts multiple future into a single future that returns the
|
||||
//! first output.
|
||||
//!
|
||||
//! For operating on futures the following macros can be used:
|
||||
//! For operating on futures the following functions can be used:
|
||||
//!
|
||||
//! | Name | Return signature | When does it return? |
|
||||
//! | --- | --- | --- |
|
||||
//! | `future::join` | `(T1, T2)` | Wait for all to complete
|
||||
//! | `future::select` | `T` | Return on first value
|
||||
//! | Name | Return signature | When does it return? |
|
||||
//! | --- | --- | --- |
|
||||
//! | [`Future::join`] | `(T1, T2)` | Wait for all to complete
|
||||
//! | [`Future::race`] | `T` | Return on first value
|
||||
//!
|
||||
//! ## Fallible Futures Concurrency
|
||||
//!
|
||||
//! For operating on futures that return `Result` additional `try_` variants of
|
||||
//! the macros mentioned before can be used. These macros are aware of `Result`,
|
||||
//! the functions mentioned before can be used. These functions are aware of `Result`,
|
||||
//! and will behave slightly differently from their base variants.
|
||||
//!
|
||||
//! In the case of `try_join`, if any of the futures returns `Err` all
|
||||
//! futures are dropped and an error is returned. This is referred to as
|
||||
//! "short-circuiting".
|
||||
//!
|
||||
//! In the case of `try_select`, instead of returning the first future that
|
||||
//! In the case of `try_race`, instead of returning the first future that
|
||||
//! completes it returns the first future that _successfully_ completes. This
|
||||
//! means `try_select` will keep going until any one of the futures returns
|
||||
//! means `try_race` will keep going until any one of the futures returns
|
||||
//! `Ok`, or _all_ futures have returned `Err`.
|
||||
//!
|
||||
//! However sometimes it can be useful to use the base variants of the macros
|
||||
//! However sometimes it can be useful to use the base variants of the functions
|
||||
//! even on futures that return `Result`. Here is an overview of operations that
|
||||
//! work on `Result`, and their respective semantics:
|
||||
//!
|
||||
//! | Name | Return signature | When does it return? |
|
||||
//! | --- | --- | --- |
|
||||
//! | `future::join` | `(Result<T, E>, Result<T, E>)` | Wait for all to complete
|
||||
//! | `future::try_join` | `Result<(T1, T2), E>` | Return on first `Err`, wait for all to complete
|
||||
//! | `future::select` | `Result<T, E>` | Return on first value
|
||||
//! | `future::try_select` | `Result<T, E>` | Return on first `Ok`, reject on last Err
|
||||
|
||||
#[doc(inline)]
|
||||
pub use async_macros::{join, try_join};
|
||||
//! | Name | Return signature | When does it return? |
|
||||
//! | --- | --- | --- |
|
||||
//! | [`Future::join`] | `(Result<T, E>, Result<T, E>)` | Wait for all to complete
|
||||
//! | [`Future::try_join`] | `Result<(T1, T2), E>` | Return on first `Err`, wait for all to complete
|
||||
//! | [`Future::race`] | `Result<T, E>` | Return on first value
|
||||
//! | [`Future::try_race`] | `Result<T, E>` | Return on first `Ok`, reject on last Err
|
||||
//!
|
||||
//! [`Future::join`]: trait.Future.html#method.join
|
||||
//! [`Future::try_join`]: trait.Future.html#method.try_join
|
||||
//! [`Future::race`]: trait.Future.html#method.race
|
||||
//! [`Future::try_race`]: trait.Future.html#method.try_race
|
||||
|
||||
pub use future::Future;
|
||||
pub use pending::pending;
|
||||
pub use poll_fn::poll_fn;
|
||||
pub use ready::ready;
|
||||
pub use timeout::{timeout, TimeoutError};
|
||||
|
||||
pub(crate) mod future;
|
||||
mod pending;
|
||||
mod poll_fn;
|
||||
mod ready;
|
||||
mod timeout;
|
||||
|
||||
cfg_default! {
|
||||
pub use timeout::{timeout, TimeoutError};
|
||||
mod timeout;
|
||||
}
|
||||
|
||||
cfg_unstable! {
|
||||
#[doc(inline)]
|
||||
pub use async_macros::{select, try_select};
|
||||
|
||||
pub use into_future::IntoFuture;
|
||||
mod into_future;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
/// Never resolves to a value.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
/// Creates a new future wrapping around a function returning [`Poll`].
|
||||
|
|
|
@ -2,11 +2,11 @@ use std::error::Error;
|
|||
use std::fmt;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
use std::future::Future;
|
||||
|
||||
use futures_timer::Delay;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
/// Awaits a future or times out after a duration of time.
|
||||
|
|
|
@ -25,7 +25,7 @@ extension_trait! {
|
|||
[`std::io::BufRead`].
|
||||
|
||||
The [provided methods] do not really exist in the trait itself, but they become
|
||||
available when the prelude is imported:
|
||||
available when [`BufReadExt`] from the [prelude] is imported:
|
||||
|
||||
```
|
||||
# #[allow(unused_imports)]
|
||||
|
@ -36,6 +36,8 @@ extension_trait! {
|
|||
[`futures::io::AsyncBufRead`]:
|
||||
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
|
||||
"#]
|
||||
pub trait BufRead {
|
||||
#[doc = r#"
|
||||
|
@ -62,6 +64,11 @@ extension_trait! {
|
|||
fn consume(self: Pin<&mut Self>, amt: usize);
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Extension methods for [`BufRead`].
|
||||
|
||||
[`BufRead`]: ../trait.BufRead.html
|
||||
"#]
|
||||
pub trait BufReadExt: futures_io::AsyncBufRead {
|
||||
#[doc = r#"
|
||||
Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::str;
|
||||
use std::future::Future;
|
||||
|
||||
use super::read_until_internal;
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, BufRead};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
@ -37,8 +37,12 @@ impl<T: BufRead + Unpin + ?Sized> Future for ReadLineFuture<'_, T> {
|
|||
))
|
||||
}))
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
debug_assert_eq!(*read, 0);
|
||||
#[allow(clippy::debug_assert_with_mut_call)]
|
||||
{
|
||||
debug_assert!(buf.is_empty());
|
||||
debug_assert_eq!(*read, 0);
|
||||
}
|
||||
|
||||
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
|
||||
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
|
||||
Poll::Ready(ret)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use super::read_until_internal;
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, BufRead};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use std::fmt;
|
||||
use std::pin::Pin;
|
||||
|
||||
use futures_core::ready;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::io::write::WriteExt;
|
||||
use crate::io::{self, Seek, SeekFrom, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
use crate::task::{Context, Poll, ready};
|
||||
|
||||
const DEFAULT_CAPACITY: usize = 8 * 1024;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, BufRead, BufReader, Read, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
@ -43,6 +43,7 @@ use crate::task::{Context, Poll};
|
|||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
#[cfg(any(feature = "docs", not(feature = "unstable")))]
|
||||
pub async fn copy<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64>
|
||||
where
|
||||
R: Read + Unpin + ?Sized,
|
||||
|
@ -91,3 +92,90 @@ where
|
|||
};
|
||||
future.await
|
||||
}
|
||||
|
||||
/// Copies the entire contents of a reader into a writer.
|
||||
///
|
||||
/// This function will continuously read data from `reader` and then
|
||||
/// write it into `writer` in a streaming fashion until `reader`
|
||||
/// returns EOF.
|
||||
///
|
||||
/// On success, the total number of bytes that were copied from
|
||||
/// `reader` to `writer` is returned.
|
||||
///
|
||||
/// If you’re wanting to copy the contents of one file to another and you’re
|
||||
/// working with filesystem paths, see the [`fs::copy`] function.
|
||||
///
|
||||
/// This function is an async version of [`std::io::copy`].
|
||||
///
|
||||
/// [`std::io::copy`]: https://doc.rust-lang.org/std/io/fn.copy.html
|
||||
/// [`fs::copy`]: ../fs/fn.copy.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error immediately if any call to `read` or
|
||||
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
|
||||
/// handled by this function and the underlying operation is retried.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::io;
|
||||
///
|
||||
/// let mut reader: &[u8] = b"hello";
|
||||
/// let mut writer = io::stdout();
|
||||
///
|
||||
/// io::copy(&mut reader, &mut writer).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
#[cfg(all(feature = "unstable", not(feature = "docs")))]
|
||||
pub async fn copy<R, W>(reader: R, writer: W) -> io::Result<u64>
|
||||
where
|
||||
R: Read + Unpin,
|
||||
W: Write + Unpin,
|
||||
{
|
||||
pin_project! {
|
||||
struct CopyFuture<R, W> {
|
||||
#[pin]
|
||||
reader: R,
|
||||
#[pin]
|
||||
writer: W,
|
||||
amt: u64,
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Future for CopyFuture<R, W>
|
||||
where
|
||||
R: BufRead,
|
||||
W: Write + Unpin,
|
||||
{
|
||||
type Output = io::Result<u64>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
loop {
|
||||
let buffer = futures_core::ready!(this.reader.as_mut().poll_fill_buf(cx))?;
|
||||
if buffer.is_empty() {
|
||||
futures_core::ready!(this.writer.as_mut().poll_flush(cx))?;
|
||||
return Poll::Ready(Ok(*this.amt));
|
||||
}
|
||||
|
||||
let i = futures_core::ready!(this.writer.as_mut().poll_write(cx, buffer))?;
|
||||
if i == 0 {
|
||||
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
||||
}
|
||||
*this.amt += i as u64;
|
||||
this.reader.as_mut().consume(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let future = CopyFuture {
|
||||
reader: BufReader::new(reader),
|
||||
writer,
|
||||
amt: 0,
|
||||
};
|
||||
future.await
|
||||
}
|
||||
|
|
|
@ -28,9 +28,10 @@ pub fn empty() -> Empty {
|
|||
|
||||
/// A reader that contains no data.
|
||||
///
|
||||
/// This reader is constructed by the [`sink`] function.
|
||||
/// This reader is created by the [`empty`] function. See its
|
||||
/// documentation for more.
|
||||
///
|
||||
/// [`sink`]: fn.sink.html
|
||||
/// [`empty`]: fn.empty.html
|
||||
pub struct Empty {
|
||||
_private: (),
|
||||
}
|
||||
|
|
104
src/io/mod.rs
104
src/io/mod.rs
|
@ -19,8 +19,8 @@
|
|||
//! [`File`]s:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::prelude::*;
|
||||
//! use async_std::fs::File;
|
||||
//! use async_std::prelude::*;
|
||||
//!
|
||||
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
//! #
|
||||
|
@ -47,9 +47,9 @@
|
|||
//! coming from:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::io::prelude::*;
|
||||
//! use async_std::io::SeekFrom;
|
||||
//! use async_std::fs::File;
|
||||
//! use async_std::io::SeekFrom;
|
||||
//! use async_std::prelude::*;
|
||||
//!
|
||||
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
//! #
|
||||
|
@ -82,9 +82,9 @@
|
|||
//! methods to any reader:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::io::prelude::*;
|
||||
//! use async_std::io::BufReader;
|
||||
//! use async_std::fs::File;
|
||||
//! use async_std::io::BufReader;
|
||||
//! use async_std::prelude::*;
|
||||
//!
|
||||
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
//! #
|
||||
|
@ -104,9 +104,9 @@
|
|||
//! to [`write`][`Write::write`]:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::io::prelude::*;
|
||||
//! use async_std::io::BufWriter;
|
||||
//! use async_std::fs::File;
|
||||
//! use async_std::io::BufWriter;
|
||||
//! use async_std::io::prelude::*;
|
||||
//!
|
||||
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
//! #
|
||||
|
@ -179,9 +179,9 @@
|
|||
//! lines:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::prelude::*;
|
||||
//! use async_std::io::BufReader;
|
||||
//! use async_std::fs::File;
|
||||
//! use async_std::io::BufReader;
|
||||
//! use async_std::prelude::*;
|
||||
//!
|
||||
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
//! #
|
||||
|
@ -269,45 +269,57 @@
|
|||
//! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
||||
//! [`.unwrap()`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap
|
||||
|
||||
#[doc(inline)]
|
||||
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
|
||||
cfg_std! {
|
||||
#[doc(inline)]
|
||||
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
|
||||
|
||||
pub use buf_read::{BufRead, Lines};
|
||||
pub use buf_reader::BufReader;
|
||||
pub use buf_writer::BufWriter;
|
||||
pub use copy::copy;
|
||||
pub use cursor::Cursor;
|
||||
pub use empty::{empty, Empty};
|
||||
pub use read::Read;
|
||||
pub use repeat::{repeat, Repeat};
|
||||
pub use seek::Seek;
|
||||
pub use sink::{sink, Sink};
|
||||
pub use stderr::{stderr, Stderr};
|
||||
pub use stdin::{stdin, Stdin};
|
||||
pub use stdout::{stdout, Stdout};
|
||||
pub use timeout::timeout;
|
||||
pub use write::Write;
|
||||
pub use buf_read::{BufRead, Lines};
|
||||
pub use buf_reader::BufReader;
|
||||
pub use buf_writer::BufWriter;
|
||||
pub use copy::copy;
|
||||
pub use cursor::Cursor;
|
||||
pub use empty::{empty, Empty};
|
||||
pub use read::Read;
|
||||
pub use repeat::{repeat, Repeat};
|
||||
pub use seek::Seek;
|
||||
pub use sink::{sink, Sink};
|
||||
pub use write::Write;
|
||||
|
||||
// For use in the print macros.
|
||||
#[doc(hidden)]
|
||||
pub use stdio::{_eprint, _print};
|
||||
pub mod prelude;
|
||||
|
||||
pub mod prelude;
|
||||
pub(crate) mod buf_read;
|
||||
pub(crate) mod read;
|
||||
pub(crate) mod seek;
|
||||
pub(crate) mod write;
|
||||
|
||||
pub(crate) mod buf_read;
|
||||
pub(crate) mod read;
|
||||
pub(crate) mod seek;
|
||||
pub(crate) mod write;
|
||||
mod buf_reader;
|
||||
mod buf_writer;
|
||||
mod copy;
|
||||
mod cursor;
|
||||
mod empty;
|
||||
mod repeat;
|
||||
mod sink;
|
||||
}
|
||||
|
||||
mod buf_reader;
|
||||
mod buf_writer;
|
||||
mod copy;
|
||||
mod cursor;
|
||||
mod empty;
|
||||
mod repeat;
|
||||
mod sink;
|
||||
mod stderr;
|
||||
mod stdin;
|
||||
mod stdio;
|
||||
mod stdout;
|
||||
mod timeout;
|
||||
cfg_default! {
|
||||
// For use in the print macros.
|
||||
#[doc(hidden)]
|
||||
pub use stdio::{_eprint, _print};
|
||||
|
||||
pub use stderr::{stderr, Stderr};
|
||||
pub use stdin::{stdin, Stdin};
|
||||
pub use stdout::{stdout, Stdout};
|
||||
pub use timeout::timeout;
|
||||
|
||||
mod timeout;
|
||||
mod stderr;
|
||||
mod stdin;
|
||||
mod stdio;
|
||||
mod stdout;
|
||||
}
|
||||
|
||||
cfg_unstable! {
|
||||
pub use stderr::StderrLock;
|
||||
pub use stdin::StdinLock;
|
||||
pub use stdout::StdoutLock;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! The async I/O Prelude
|
||||
//! The async I/O prelude.
|
||||
//!
|
||||
//! The purpose of this module is to alleviate imports of many common I/O traits
|
||||
//! by adding a glob import to the top of I/O heavy modules:
|
||||
|
@ -17,11 +17,11 @@ pub use crate::io::Seek;
|
|||
#[doc(no_inline)]
|
||||
pub use crate::io::Write;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use crate::io::buf_read::BufReadExt as _;
|
||||
#[doc(hidden)]
|
||||
pub use crate::io::read::ReadExt as _;
|
||||
#[doc(hidden)]
|
||||
pub use crate::io::seek::SeekExt as _;
|
||||
#[doc(hidden)]
|
||||
pub use crate::io::write::WriteExt as _;
|
||||
#[doc(inline)]
|
||||
pub use crate::io::buf_read::BufReadExt;
|
||||
#[doc(inline)]
|
||||
pub use crate::io::read::ReadExt;
|
||||
#[doc(inline)]
|
||||
pub use crate::io::seek::SeekExt;
|
||||
#[doc(inline)]
|
||||
pub use crate::io::write::WriteExt;
|
||||
|
|
|
@ -31,7 +31,7 @@ extension_trait! {
|
|||
[`std::io::Read`].
|
||||
|
||||
Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the
|
||||
trait itself, but they become available when the prelude is imported:
|
||||
trait itself, but they become available when [`ReadExt`] from the [prelude] is imported:
|
||||
|
||||
```
|
||||
# #[allow(unused_imports)]
|
||||
|
@ -43,6 +43,8 @@ extension_trait! {
|
|||
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
|
||||
[prelude]: ../prelude/index.html
|
||||
"#]
|
||||
pub trait Read {
|
||||
#[doc = r#"
|
||||
|
@ -66,6 +68,11 @@ extension_trait! {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Extension methods for [`Read`].
|
||||
|
||||
[`Read`]: ../trait.Read.html
|
||||
"#]
|
||||
pub trait ReadExt: futures_io::AsyncRead {
|
||||
#[doc = r#"
|
||||
Reads some bytes from the byte stream.
|
||||
|
@ -267,7 +274,7 @@ extension_trait! {
|
|||
This function returns a new instance of `Read` which will read at most
|
||||
`limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
|
||||
read errors will not count towards the number of bytes read and future
|
||||
calls to [`read()`] may succeed.
|
||||
calls to [`read`] may succeed.
|
||||
|
||||
# Examples
|
||||
|
||||
|
@ -275,7 +282,7 @@ extension_trait! {
|
|||
|
||||
[`File`]: ../fs/struct.File.html
|
||||
[`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
[`read()`]: tymethod.read
|
||||
[`read`]: tymethod.read
|
||||
|
||||
```no_run
|
||||
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Read};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Read};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Read};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::str;
|
||||
use std::future::Future;
|
||||
|
||||
use super::read_to_end_internal;
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Read};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
@ -37,7 +37,11 @@ impl<T: Read + Unpin + ?Sized> Future for ReadToStringFuture<'_, T> {
|
|||
))
|
||||
}))
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
#[allow(clippy::debug_assert_with_mut_call)]
|
||||
{
|
||||
debug_assert!(buf.is_empty());
|
||||
}
|
||||
|
||||
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
|
||||
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
|
||||
Poll::Ready(ret)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, IoSliceMut, Read};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ pub fn repeat(byte: u8) -> Repeat {
|
|||
|
||||
/// A reader which yields one byte over and over and over and over and over and...
|
||||
///
|
||||
/// This reader is constructed by the [`repeat`] function.
|
||||
/// This reader is created by the [`repeat`] function. See its
|
||||
/// documentation for more.
|
||||
///
|
||||
/// [`repeat`]: fn.repeat.html
|
||||
pub struct Repeat {
|
||||
|
|
|
@ -18,7 +18,7 @@ extension_trait! {
|
|||
[`std::io::Seek`].
|
||||
|
||||
The [provided methods] do not really exist in the trait itself, but they become
|
||||
available when the prelude is imported:
|
||||
available when [`SeekExt`] the [prelude] is imported:
|
||||
|
||||
```
|
||||
# #[allow(unused_imports)]
|
||||
|
@ -29,6 +29,8 @@ extension_trait! {
|
|||
[`futures::io::AsyncSeek`]:
|
||||
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
|
||||
"#]
|
||||
pub trait Seek {
|
||||
#[doc = r#"
|
||||
|
@ -41,6 +43,11 @@ extension_trait! {
|
|||
) -> Poll<io::Result<u64>>;
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Extension methods for [`Seek`].
|
||||
|
||||
[`Seek`]: ../trait.Seek.html
|
||||
"#]
|
||||
pub trait SeekExt: futures_io::AsyncSeek {
|
||||
#[doc = r#"
|
||||
Seeks to a new position in a byte stream.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Seek, SeekFrom};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ pub fn sink() -> Sink {
|
|||
|
||||
/// A writer that consumes and drops all data.
|
||||
///
|
||||
/// This writer is constructed by the [`sink`] function.
|
||||
/// This writer is constructed by the [`sink`] function. See its documentation
|
||||
/// for more.
|
||||
///
|
||||
/// [`sink`]: fn.sink.html
|
||||
pub struct Sink {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use std::pin::Pin;
|
||||
use std::sync::Mutex;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||
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.
|
||||
///
|
||||
|
@ -11,6 +16,12 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
|
|||
///
|
||||
/// [`std::io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
|
@ -34,15 +45,35 @@ pub fn stderr() -> Stderr {
|
|||
|
||||
/// A handle to the standard error of the current process.
|
||||
///
|
||||
/// Created by the [`stderr`] function.
|
||||
/// This writer is created by the [`stderr`] function. See its documentation for
|
||||
/// more.
|
||||
///
|
||||
/// This type is an async version of [`std::io::Stderr`].
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// [`stderr`]: fn.stderr.html
|
||||
/// [`std::io::Stderr`]: https://doc.rust-lang.org/std/io/struct.Stderr.html
|
||||
#[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.
|
||||
|
@ -77,6 +108,35 @@ 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(
|
||||
mut self: Pin<&mut Self>,
|
||||
|
@ -114,7 +174,7 @@ impl Write for Stderr {
|
|||
inner.buf[..buf.len()].copy_from_slice(buf);
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
let res = std::io::Write::write(&mut inner.stderr, &inner.buf);
|
||||
inner.last_op = Some(Operation::Write(res));
|
||||
State::Idle(Some(inner))
|
||||
|
@ -142,7 +202,7 @@ impl Write for Stderr {
|
|||
let mut inner = opt.take().unwrap();
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
let res = std::io::Write::flush(&mut inner.stderr);
|
||||
inner.last_op = Some(Operation::Flush(res));
|
||||
State::Idle(Some(inner))
|
||||
|
@ -179,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,9 +1,15 @@
|
|||
use std::pin::Pin;
|
||||
use std::sync::Mutex;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::{self, Future};
|
||||
use crate::future;
|
||||
use crate::io::{self, Read};
|
||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||
use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
|
||||
|
||||
cfg_unstable! {
|
||||
use once_cell::sync::Lazy;
|
||||
use std::io::Read as _;
|
||||
}
|
||||
|
||||
/// Constructs a new handle to the standard input of the current process.
|
||||
///
|
||||
|
@ -11,6 +17,12 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
|
|||
///
|
||||
/// [`std::io::stdin`]: https://doc.rust-lang.org/std/io/fn.stdin.html
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
|
@ -35,15 +47,34 @@ pub fn stdin() -> Stdin {
|
|||
|
||||
/// A handle to the standard input of the current process.
|
||||
///
|
||||
/// Created by the [`stdin`] function.
|
||||
/// This reader is created by the [`stdin`] function. See its documentation for
|
||||
/// more.
|
||||
///
|
||||
/// This type is an async version of [`std::io::Stdin`].
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// [`stdin`]: fn.stdin.html
|
||||
/// [`std::io::Stdin`]: https://doc.rust-lang.org/std/io/struct.Stdin.html
|
||||
#[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.
|
||||
|
@ -117,7 +148,7 @@ impl Stdin {
|
|||
let mut inner = opt.take().unwrap();
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
inner.line.clear();
|
||||
let res = inner.stdin.read_line(&mut inner.line);
|
||||
inner.last_op = Some(Operation::ReadLine(res));
|
||||
|
@ -132,6 +163,35 @@ impl Stdin {
|
|||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
@ -170,7 +230,7 @@ impl Read for Stdin {
|
|||
}
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
let res = std::io::Read::read(&mut inner.stdin, &mut inner.buf);
|
||||
inner.last_op = Some(Operation::Read(res));
|
||||
State::Idle(Some(inner))
|
||||
|
@ -203,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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use std::pin::Pin;
|
||||
use std::sync::Mutex;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{blocking, Context, JoinHandle, Poll};
|
||||
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.
|
||||
///
|
||||
|
@ -11,6 +16,12 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
|
|||
///
|
||||
/// [`std::io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
|
@ -34,15 +45,35 @@ pub fn stdout() -> Stdout {
|
|||
|
||||
/// A handle to the standard output of the current process.
|
||||
///
|
||||
/// Created by the [`stdout`] function.
|
||||
/// This writer is created by the [`stdout`] function. See its documentation
|
||||
/// for more.
|
||||
///
|
||||
/// This type is an async version of [`std::io::Stdout`].
|
||||
/// ### Note: Windows Portability Consideration
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// [`stdout`]: fn.stdout.html
|
||||
/// [`std::io::Stdout`]: https://doc.rust-lang.org/std/io/struct.Stdout.html
|
||||
#[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.
|
||||
|
@ -77,6 +108,35 @@ 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(
|
||||
mut self: Pin<&mut Self>,
|
||||
|
@ -114,7 +174,7 @@ impl Write for Stdout {
|
|||
inner.buf[..buf.len()].copy_from_slice(buf);
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
let res = std::io::Write::write(&mut inner.stdout, &inner.buf);
|
||||
inner.last_op = Some(Operation::Write(res));
|
||||
State::Idle(Some(inner))
|
||||
|
@ -142,7 +202,7 @@ impl Write for Stdout {
|
|||
let mut inner = opt.take().unwrap();
|
||||
|
||||
// Start the operation asynchronously.
|
||||
*state = State::Busy(blocking::spawn(move || {
|
||||
*state = State::Busy(spawn_blocking(move || {
|
||||
let res = std::io::Write::flush(&mut inner.stdout);
|
||||
inner.last_op = Some(Operation::Flush(res));
|
||||
State::Idle(Some(inner))
|
||||
|
@ -179,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,11 +1,11 @@
|
|||
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::future::Future;
|
||||
use crate::io;
|
||||
|
||||
/// Awaits an I/O future or times out after a duration of time.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ extension_trait! {
|
|||
|
||||
Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and
|
||||
[`poll_close`] do not really exist in the trait itself, but they become available when
|
||||
the prelude is imported:
|
||||
[`WriteExt`] from the [prelude] is imported:
|
||||
|
||||
```
|
||||
# #[allow(unused_imports)]
|
||||
|
@ -40,6 +40,8 @@ extension_trait! {
|
|||
[`poll_write_vectored`]: #method.poll_write_vectored
|
||||
[`poll_flush`]: #tymethod.poll_flush
|
||||
[`poll_close`]: #tymethod.poll_close
|
||||
[`WriteExt`]: ../io/prelude/trait.WriteExt.html
|
||||
[prelude]: ../prelude/index.html
|
||||
"#]
|
||||
pub trait Write {
|
||||
#[doc = r#"
|
||||
|
@ -74,6 +76,11 @@ extension_trait! {
|
|||
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Extension methods for [`Write`].
|
||||
|
||||
[`Write`]: ../trait.Write.html
|
||||
"#]
|
||||
pub trait WriteExt: futures_io::AsyncWrite {
|
||||
#[doc = r#"
|
||||
Writes some bytes into the byte stream.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io::{self, IoSlice, Write};
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
|
|
196
src/lib.rs
196
src/lib.rs
|
@ -1,16 +1,133 @@
|
|||
//! Async version of the Rust standard library.
|
||||
//! # Async version of the Rust standard library
|
||||
//!
|
||||
//! Modules in this crate are organized in the same way as in the standard library, except blocking
|
||||
//! `async-std` is a foundation of portable Rust software, a set of minimal and battle-tested
|
||||
//! shared abstractions for the [broader Rust ecosystem][crates.io]. It offers std types, like
|
||||
//! [`Future`] and [`Stream`], library-defined [operations on language primitives](#primitives),
|
||||
//! [standard macros](#macros), [I/O] and [multithreading], among [many other things][other].
|
||||
//!
|
||||
//! `async-std` is available from [crates.io]. Once included, `async-std` can be accessed
|
||||
//! in [`use`] statements through the path `async_std`, as in [`use async_std::future`].
|
||||
//!
|
||||
//! [I/O]: io/index.html
|
||||
//! [multithreading]: task/index.html
|
||||
//! [other]: #what-is-in-the-standard-library-documentation
|
||||
//! [`use`]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html
|
||||
//! [`use async_std::future`]: future/index.html
|
||||
//! [crates.io]: https://crates.io
|
||||
//! [`Future`]: future/trait.Future.html
|
||||
//! [`Stream`]: stream/trait.Stream.html
|
||||
//!
|
||||
//! # How to read this documentation
|
||||
//!
|
||||
//! If you already know the name of what you are looking for, the fastest way to
|
||||
//! find it is to use the <a href="#" onclick="focusSearchBar();">search
|
||||
//! bar</a> at the top of the page.
|
||||
//!
|
||||
//! Otherwise, you may want to jump to one of these useful sections:
|
||||
//!
|
||||
//! * [`async_std::*` modules](#modules)
|
||||
//! * [Async macros](#macros)
|
||||
//! * [The Async Prelude](prelude/index.html)
|
||||
//! * [Cargo.toml feature flags](#features)
|
||||
//! * [Examples](#examples)
|
||||
//!
|
||||
//! If this is your first time, the documentation for `async-std` is
|
||||
//! written to be casually perused. Clicking on interesting things should
|
||||
//! generally lead you to interesting places. Still, there are important bits
|
||||
//! you don't want to miss, so read on for a tour of the `async-std` and
|
||||
//! its documentation!
|
||||
//!
|
||||
//! Once you are familiar with the contents of `async-std` you may
|
||||
//! begin to find the verbosity of the prose distracting. At this stage in your
|
||||
//! development you may want to press the `[-]` button near the top of the
|
||||
//! page to collapse it into a more skimmable view.
|
||||
//!
|
||||
//! While you are looking at that `[-]` button also notice the `[src]`
|
||||
//! button. Rust's API documentation comes with the source code and you are
|
||||
//! 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 `async-std`, except blocking
|
||||
//! functions have been replaced with async functions and threads have been replaced with
|
||||
//! lightweight tasks.
|
||||
//!
|
||||
//! More information, reading materials, and other resources:
|
||||
//! You can find more information, reading materials, and other resources here:
|
||||
//!
|
||||
//! * [🌐 The async-std website](https://async.rs/)
|
||||
//! * [📖 The async-std book](https://book.async.rs)
|
||||
//! * [🐙 GitHub repository](https://github.com/async-rs/async-std)
|
||||
//! * [📒 List of code examples](https://github.com/async-rs/async-std/tree/master/examples)
|
||||
//! * [💬 Discord chat](https://discord.gg/JvZeVNe)
|
||||
//! * [The async-std website](https://async.rs/)
|
||||
//! * [The async-std book](https://book.async.rs)
|
||||
//! * [GitHub repository](https://github.com/async-rs/async-std)
|
||||
//! * [List of code examples](https://github.com/async-rs/async-std/tree/master/examples)
|
||||
//! * [Discord chat](https://discord.gg/JvZeVNe)
|
||||
//!
|
||||
//! # What is in the `async-std` documentation?
|
||||
//!
|
||||
//! First, `async-std` is divided into a number of focused
|
||||
//! modules, [all listed further down this page](#modules). These modules are
|
||||
//! the bedrock upon which async Rust is forged, and they have mighty names
|
||||
//! like [`async_std::os`] and [`async_std::task`]. Modules' documentation
|
||||
//! typically includes an overview of the module along with examples, and are
|
||||
//! a smart place to start familiarizing yourself with the library.
|
||||
//!
|
||||
//! Second, `async-std` defines [The Async Prelude], a small collection
|
||||
//! of items - mostly traits - that should be imported into every module of
|
||||
//! every async crate. The traits in the prelude are pervasive, making the
|
||||
//! prelude documentation a good entry point to learning about the library.
|
||||
//!
|
||||
//! [The Async Prelude]: prelude/index.html
|
||||
//! [`async_std::os`]: os/index.html
|
||||
//! [`async_std::task`]: task/index.html
|
||||
//!
|
||||
//! And finally, `async-std` exports a number of async macros, and
|
||||
//! [lists them on this page](#macros).
|
||||
//!
|
||||
//! # Contributing changes to the documentation
|
||||
//!
|
||||
//! Check out `async-std`'s contribution guidelines [here](https://async.rs/contribute).
|
||||
//! The source for this documentation can be found on [GitHub](https://github.com/async-rs).
|
||||
//! To contribute changes, make sure you read the guidelines first, then submit
|
||||
//! pull requests for your suggested changes.
|
||||
//!
|
||||
//! Contributions are appreciated! If you see a part of the docs that can be
|
||||
//! improved, submit a PR, or chat with us first on
|
||||
//! [Discord](https://discord.gg/JvZeVNe).
|
||||
//!
|
||||
//! # A tour of `async-std`
|
||||
//!
|
||||
//! The rest of this crate documentation is dedicated to pointing out notable
|
||||
//! features of `async-std`.
|
||||
//!
|
||||
//! ## Platform abstractions and I/O
|
||||
//!
|
||||
//! Besides basic data types, `async-std` is largely concerned with
|
||||
//! abstracting over differences in common platforms, most notably Windows and
|
||||
//! Unix derivatives.
|
||||
//!
|
||||
//! Common types of I/O, including [files], [TCP], [UDP], are defined in the
|
||||
//! [`io`], [`fs`], and [`net`] modules.
|
||||
//!
|
||||
//! The [`task`] module contains `async-std`'s task abstractions. [`sync`]
|
||||
//! contains further primitive shared memory types, including [`channel`],
|
||||
//! which contains the channel types for message passing.
|
||||
//!
|
||||
//! [files]: fs/struct.File.html
|
||||
//! [TCP]: net/struct.TcpStream.html
|
||||
//! [UDP]: net/struct.UdpSocket.html
|
||||
//! [`io`]: fs/struct.File.html
|
||||
//! [`sync`]: sync/index.html
|
||||
//! [`channel`]: sync/fn.channel.html
|
||||
//!
|
||||
//! ## Timeouts, intervals, and delays
|
||||
//!
|
||||
//! `async-std` provides several methods to manipulate time:
|
||||
//!
|
||||
//! * [`task::sleep`] to wait for a duration to pass without blocking.
|
||||
//! * [`stream::interval`] for emitting an event at a set interval.
|
||||
//! * [`future::timeout`] to time-out futures if they don't resolve within a
|
||||
//! set interval.
|
||||
//!
|
||||
//! [`task::sleep`]: task/fn.sleep.html
|
||||
//! [`stream::interval`]: stream/fn.interval.html
|
||||
//! [`future::timeout`]: future/fn.timeout.html
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
|
@ -37,30 +154,67 @@
|
|||
//!
|
||||
//! ```toml
|
||||
//! [dependencies.async-std]
|
||||
//! version = "0.99"
|
||||
//! version = "1.0.0"
|
||||
//! features = ["unstable"]
|
||||
//! ```
|
||||
//!
|
||||
//! Items marked with
|
||||
//! <span
|
||||
//! class="module-item stab portability"
|
||||
//! style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"
|
||||
//! ><code>attributes</code></span>
|
||||
//! are available only when the `attributes` Cargo feature is enabled:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies.async-std]
|
||||
//! version = "1.0.0"
|
||||
//! features = ["attributes"]
|
||||
//! ```
|
||||
//!
|
||||
//! 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.0.0"
|
||||
//! default-features = false
|
||||
//! features = ["std"]
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(feature = "docs", feature(doc_cfg))]
|
||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||
#![allow(clippy::mutex_atomic, clippy::module_inception)]
|
||||
#![doc(test(attr(deny(rust_2018_idioms, warnings))))]
|
||||
#![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
|
||||
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
|
||||
#![recursion_limit = "1024"]
|
||||
#![recursion_limit = "2048"]
|
||||
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
|
||||
pub mod fs;
|
||||
pub mod future;
|
||||
pub mod io;
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod prelude;
|
||||
pub mod stream;
|
||||
pub mod sync;
|
||||
pub mod task;
|
||||
#[cfg(feature = "attributes")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(attributes)))]
|
||||
#[doc(inline)]
|
||||
pub use async_attributes::{main, test};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod macros;
|
||||
|
||||
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! {
|
||||
pub mod fs;
|
||||
pub mod path;
|
||||
pub mod net;
|
||||
}
|
||||
|
||||
cfg_unstable! {
|
||||
pub mod pin;
|
||||
|
@ -76,5 +230,3 @@ cfg_unstable! {
|
|||
#[doc(inline)]
|
||||
pub use std::{write, writeln};
|
||||
}
|
||||
|
||||
mod macros;
|
||||
|
|
|
@ -165,3 +165,55 @@ macro_rules! eprintln {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Declares task-local values.
|
||||
///
|
||||
/// The macro wraps any number of static declarations and makes them task-local. Attributes and
|
||||
/// visibility modifiers are allowed.
|
||||
///
|
||||
/// Each declared value is of the accessor type [`LocalKey`].
|
||||
///
|
||||
/// [`LocalKey`]: task/struct.LocalKey.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// use async_std::task;
|
||||
/// use async_std::prelude::*;
|
||||
///
|
||||
/// task_local! {
|
||||
/// static VAL: Cell<u32> = Cell::new(5);
|
||||
/// }
|
||||
///
|
||||
/// task::block_on(async {
|
||||
/// let v = VAL.with(|c| c.get());
|
||||
/// assert_eq!(v, 5);
|
||||
/// });
|
||||
/// ```
|
||||
#[cfg(feature = "default")]
|
||||
#[macro_export]
|
||||
macro_rules! task_local {
|
||||
() => ();
|
||||
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
|
||||
$(#[$attr])* $vis static $name: $crate::task::LocalKey<$t> = {
|
||||
#[inline]
|
||||
fn __init() -> $t {
|
||||
$init
|
||||
}
|
||||
|
||||
$crate::task::LocalKey {
|
||||
__init,
|
||||
__key: ::std::sync::atomic::AtomicU32::new(0),
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
|
||||
$crate::task_local!($(#[$attr])* $vis static $name: $t = $init);
|
||||
$crate::task_local!($($rest)*);
|
||||
);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue