mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-09 00:00:08 +02:00
Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
198363f4f1 | ||
|
|
5b7c7d565a | ||
|
|
117fc2ef3e | ||
|
|
c4f66ed121 | ||
|
|
7d5b12c509 | ||
|
|
cc0911aa64 | ||
|
|
6f8a4d7a0b | ||
|
|
fdde5583f8 | ||
|
|
36cf95ab62 | ||
|
|
27b2d681e6 | ||
|
|
c1cf6b7504 | ||
|
|
5402c948ee | ||
|
|
2af9b755c5 | ||
|
|
7ac44a2d28 | ||
|
|
3dc5f6c0ab | ||
|
|
0a7117fd9a | ||
|
|
5d35c907f6 | ||
|
|
ad8fb41103 | ||
|
|
ecc32d1dca | ||
|
|
204603b7de | ||
|
|
30b4a7486a | ||
|
|
0595902ba4 | ||
|
|
672be92a03 | ||
|
|
766a89bf94 | ||
|
|
8b9bb41809 | ||
|
|
d37486dd06 | ||
|
|
ed667c669a | ||
|
|
da09213c9f | ||
|
|
40d959263b | ||
|
|
0b8bdf9d32 | ||
|
|
51a7082d13 | ||
|
|
22c27b9282 | ||
|
|
2fe2f0401b | ||
|
|
e42317b072 | ||
|
|
3549092a0c | ||
|
|
3b840fb305 | ||
|
|
4beb1862ac | ||
|
|
7f17822ed9 | ||
|
|
3b6bee822d | ||
|
|
56272b2ec7 | ||
|
|
53707f5d9d | ||
|
|
36918e05e5 | ||
|
|
cbd4f4472e | ||
|
|
2d9bea8d63 | ||
|
|
0048d43713 | ||
|
|
770044caa7 | ||
|
|
c4929264bc | ||
|
|
4d7b73f5b3 | ||
|
|
2330edc875 | ||
|
|
fe2664a4e1 | ||
|
|
1eefbc250a |
+2
-2
@@ -21,9 +21,9 @@ task:
|
||||
rustc --version
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo test --all
|
||||
- cargo test --all --all-features
|
||||
- cargo doc --all --no-deps
|
||||
i686_test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- |
|
||||
cargo test --all --target i686-unknown-freebsd
|
||||
cargo test --all --all-features --target i686-unknown-freebsd
|
||||
|
||||
@@ -9,12 +9,7 @@ assignees: ''
|
||||
|
||||
**Version**
|
||||
List the versions of all `tokio` crates you are using. The easiest way to get
|
||||
this information is using `cargo-tree`.
|
||||
|
||||
`cargo install cargo-tree`
|
||||
(see install here: https://github.com/sfackler/cargo-tree)
|
||||
|
||||
Then:
|
||||
this information is using `cargo tree` subcommand:
|
||||
|
||||
`cargo tree | grep tokio`
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
branches: ["master", "tokio-*.x"]
|
||||
pull_request:
|
||||
branches: ["master"]
|
||||
branches: ["master", "tokio-*.x"]
|
||||
|
||||
name: CI
|
||||
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
|
||||
# Run clippy
|
||||
- name: "clippy --all"
|
||||
run: cargo clippy --all --tests
|
||||
run: cargo clippy --all --tests --all-features
|
||||
|
||||
docs:
|
||||
name: docs
|
||||
|
||||
+47
-9
@@ -427,11 +427,14 @@ _Adapted from the [Node.js contributing guide][node]_.
|
||||
|
||||
## Keeping track of issues and PRs
|
||||
|
||||
The Tokio GitHub repository has a lot of issues and PRs, which is not easy to
|
||||
keep track of. This section explains the meaning of various labels, as well as
|
||||
our [GitHub project][project]. The section is primarily targeted at maintainers.
|
||||
The Tokio GitHub repository has a lot of issues and PRs to keep track of. This
|
||||
section explains the meaning of various labels, as well as our [GitHub
|
||||
project][project]. The section is primarily targeted at maintainers. Most
|
||||
contributors aren't able to set these labels.
|
||||
|
||||
**Area.** The area label describes the crates relevant to this issue or PR.
|
||||
### Area
|
||||
|
||||
The area label describes the crates relevant to this issue or PR.
|
||||
|
||||
- **A-tokio** This issue concerns the main Tokio crate.
|
||||
- **A-tokio-util** This issue concerns the `tokio-util` crate.
|
||||
@@ -442,7 +445,7 @@ our [GitHub project][project]. The section is primarily targeted at maintainers.
|
||||
be used for the procedural macros, and not `join!` or `select!`.
|
||||
- **A-ci** This issue concerns our GitHub Actions setup.
|
||||
|
||||
**Category.** The category label describes the category.
|
||||
### Category
|
||||
|
||||
- **C-bug** This is a bug-report. Bug-fix PRs use `C-enhancement` instead.
|
||||
- **C-enhancement** This is a PR that adds a new features.
|
||||
@@ -460,8 +463,7 @@ our [GitHub project][project]. The section is primarily targeted at maintainers.
|
||||
- **C-request** A non-feature request, e.g. "please add deprecation notices to
|
||||
`-alpha.*` versions of crates"
|
||||
|
||||
**Call for participation.** I don't know why it's called `E-`. Many issues are
|
||||
missing a difficulty rating, and you should feel free to add one.
|
||||
### Calls for participation
|
||||
|
||||
- **E-help-wanted** Stuff where we want help. Often seen together with `C-bug`
|
||||
or `C-feature-accepted`.
|
||||
@@ -473,7 +475,13 @@ missing a difficulty rating, and you should feel free to add one.
|
||||
- **E-needs-mvce** This bug is missing a minimal complete and verifiable
|
||||
example.
|
||||
|
||||
**Module.** A more fine groaned categorization than area.
|
||||
The "E-" prefix is the same as used in the Rust compiler repository. Some
|
||||
issues are missing a difficulty rating, but feel free to ask on our Discord
|
||||
server if you want to know how difficult an issue likely is.
|
||||
|
||||
### Module
|
||||
|
||||
The module label provides a more fine grained categorization than **Area**.
|
||||
|
||||
- **M-blocking** Things relevant to `spawn_blocking`, `block_in_place`.
|
||||
- **M-codec** The `tokio_util::codec` module.
|
||||
@@ -491,7 +499,9 @@ missing a difficulty rating, and you should feel free to add one.
|
||||
- **M-time** The `tokio::time` module.
|
||||
- **M-tracing** Tracing support in Tokio.
|
||||
|
||||
**Topic.** Some extra information.
|
||||
### Topic
|
||||
|
||||
Some extra information.
|
||||
|
||||
- **T-docs** This is about documentation.
|
||||
- **T-performance** This is about performance.
|
||||
@@ -501,6 +511,34 @@ Any label not listed here is not in active use.
|
||||
|
||||
[project]: https://github.com/orgs/tokio-rs/projects/1
|
||||
|
||||
## LTS guarantees
|
||||
|
||||
Tokio ≥1.0.0 comes with LTS guarantees:
|
||||
|
||||
* A minimum of 5 years of maintenance.
|
||||
* A minimum of 3 years before a hypothetical 2.0 release.
|
||||
|
||||
The goal of these guarantees is to provide stability to the ecosystem.
|
||||
|
||||
## Mininum Supported Rust Version (MSRV)
|
||||
|
||||
* All Tokio ≥1.0.0 releases will support at least a 6-month old Rust
|
||||
compiler release.
|
||||
* The MSRV will only be increased on 1.x releases.
|
||||
|
||||
## Versioning Policy
|
||||
|
||||
With Tokio ≥1.0.0:
|
||||
|
||||
* Patch (1.\_.x) releases _should only_ contain bug fixes or documentation
|
||||
changes. Besides this, these releases should not substantially change
|
||||
runtime behavior.
|
||||
* Minor (1.x) releases may contain new functionality, MSRV increases (see
|
||||
above), minor dependency updates, deprecations, and larger internal
|
||||
implementation changes.
|
||||
|
||||
This is as defined by [Semantic Versioning 2.0](https://semver.org/).
|
||||
|
||||
## Releasing
|
||||
|
||||
Since the Tokio project consists of a number of crates, many of which depend on
|
||||
|
||||
+3
-3
@@ -7,9 +7,9 @@ edition = "2018"
|
||||
# If you copy one of the examples into a new project, you should be using
|
||||
# [dependencies] instead.
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio", features = ["full", "tracing"] }
|
||||
tokio-util = { version = "0.6.0", path = "../tokio-util", features = ["full"] }
|
||||
tokio-stream = { version = "0.1", path = "../tokio-stream" }
|
||||
tokio = { version = "1.0.0", features = ["full", "tracing"] }
|
||||
tokio-util = { version = "0.6.1", features = ["full"] }
|
||||
tokio-stream = { version = "0.1" }
|
||||
|
||||
async-stream = "0.3"
|
||||
tracing = "0.1"
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ mod tcp {
|
||||
|
||||
mod udp {
|
||||
use bytes::Bytes;
|
||||
use futures::{future, Sink, SinkExt, Stream, StreamExt};
|
||||
use futures::{Sink, SinkExt, Stream, StreamExt};
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
@@ -114,7 +114,7 @@ mod udp {
|
||||
let socket = UdpSocket::bind(&bind_addr).await?;
|
||||
socket.connect(addr).await?;
|
||||
|
||||
future::try_join(send(stdin, &socket), recv(stdout, &socket)).await?;
|
||||
tokio::try_join!(send(stdin, &socket), recv(stdout, &socket))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
// which will allow all of our clients to be processed concurrently.
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buf = [0; 1024];
|
||||
let mut buf = vec![0; 1024];
|
||||
|
||||
// In a loop, read data from the socket and write the data back.
|
||||
loop {
|
||||
|
||||
+1
-2
@@ -26,7 +26,6 @@ use tokio::io;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
|
||||
use futures::future::try_join;
|
||||
use futures::FutureExt;
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
@@ -74,7 +73,7 @@ async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<
|
||||
wi.shutdown().await
|
||||
};
|
||||
|
||||
try_join(client_to_server, server_to_client).await?;
|
||||
tokio::try_join!(client_to_server, server_to_client)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let b = pong(&mut b);
|
||||
|
||||
// Run both futures simultaneously of `a` and `b` sending messages back and forth.
|
||||
match futures::future::try_join(a, b).await {
|
||||
match tokio::try_join!(a, b) {
|
||||
Err(e) => println!("an error occurred; error = {:?}", e),
|
||||
_ => println!("done!"),
|
||||
}
|
||||
|
||||
@@ -11,16 +11,7 @@ use std::io;
|
||||
use std::process::{ExitStatus, Stdio};
|
||||
|
||||
fn cat() -> Command {
|
||||
let mut me = env::current_exe().unwrap();
|
||||
me.pop();
|
||||
|
||||
if me.ends_with("deps") {
|
||||
me.pop();
|
||||
}
|
||||
|
||||
me.push("test-cat");
|
||||
|
||||
let mut cmd = Command::new(me);
|
||||
let mut cmd = Command::new(env!("CARGO_BIN_EXE_test-cat"));
|
||||
cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
|
||||
cmd
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ fn parse_knobs(
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async { #body })
|
||||
.block_on(async #body)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
# 0.1.2 (January 12, 2021)
|
||||
|
||||
Fixed
|
||||
|
||||
- docs: fix some wrappers missing in documentation (#3378)
|
||||
|
||||
# 0.1.1 (January 4, 2021)
|
||||
|
||||
Added
|
||||
|
||||
- add `Stream` wrappers ([#3343])
|
||||
|
||||
Fixed
|
||||
|
||||
- move `async-stream` to `dev-dependencies` ([#3366])
|
||||
|
||||
[#3366]: https://github.com/tokio-rs/tokio/pull/3366
|
||||
[#3343]: https://github.com/tokio-rs/tokio/pull/3343
|
||||
|
||||
# 0.1.0 (December 23, 2020)
|
||||
|
||||
- Initial release
|
||||
- Initial release
|
||||
|
||||
+13
-6
@@ -7,13 +7,13 @@ name = "tokio-stream"
|
||||
# - Cargo.toml
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "tokio-stream-0.1.x" git tag.
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
edition = "2018"
|
||||
authors = ["Tokio Contributors <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
documentation = "https://docs.rs/tokio-stream/0.1.0/tokio_stream"
|
||||
documentation = "https://docs.rs/tokio-stream/0.1.2/tokio_stream"
|
||||
description = """
|
||||
Utilities to work with `Stream` and `tokio`.
|
||||
"""
|
||||
@@ -22,16 +22,23 @@ categories = ["asynchronous"]
|
||||
[features]
|
||||
default = ["time"]
|
||||
time = ["tokio/time"]
|
||||
net = ["tokio/net"]
|
||||
io-util = ["tokio/io-util"]
|
||||
fs = ["tokio/fs"]
|
||||
|
||||
[dependencies]
|
||||
futures-core = { version = "0.3.0" }
|
||||
pin-project-lite = "0.2.0"
|
||||
tokio = { version = "1.0", path = "../tokio", features = ["sync"] }
|
||||
async-stream = "0.3"
|
||||
tokio = { version = "1.0", features = ["sync"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.0", path = "../tokio", features = ["full"] }
|
||||
tokio = { version = "1.0", features = ["full", "test-util"] }
|
||||
tokio-test = { path = "../tokio-test" }
|
||||
async-stream = "0.3"
|
||||
futures = { version = "0.3", default-features = false }
|
||||
|
||||
proptest = "0.10.0"
|
||||
proptest = "0.10.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
+4
-916
@@ -1,4 +1,4 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-stream/0.1.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-stream/0.1.2")]
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::large_enum_variant,
|
||||
@@ -81,46 +81,17 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod all;
|
||||
use all::AllFuture;
|
||||
pub mod wrappers;
|
||||
|
||||
mod any;
|
||||
use any::AnyFuture;
|
||||
|
||||
mod chain;
|
||||
use chain::Chain;
|
||||
|
||||
mod collect;
|
||||
use collect::Collect;
|
||||
pub use collect::FromStream;
|
||||
mod stream_ext;
|
||||
pub use stream_ext::{collect::FromStream, StreamExt};
|
||||
|
||||
mod empty;
|
||||
pub use empty::{empty, Empty};
|
||||
|
||||
mod filter;
|
||||
use filter::Filter;
|
||||
|
||||
mod filter_map;
|
||||
use filter_map::FilterMap;
|
||||
|
||||
mod fold;
|
||||
use fold::FoldFuture;
|
||||
|
||||
mod fuse;
|
||||
use fuse::Fuse;
|
||||
|
||||
mod iter;
|
||||
pub use iter::{iter, Iter};
|
||||
|
||||
mod map;
|
||||
use map::Map;
|
||||
|
||||
mod merge;
|
||||
use merge::Merge;
|
||||
|
||||
mod next;
|
||||
use next::Next;
|
||||
|
||||
mod once;
|
||||
pub use once::{once, Once};
|
||||
|
||||
@@ -130,888 +101,5 @@ pub use pending::{pending, Pending};
|
||||
mod stream_map;
|
||||
pub use stream_map::StreamMap;
|
||||
|
||||
mod skip;
|
||||
use skip::Skip;
|
||||
|
||||
mod skip_while;
|
||||
use skip_while::SkipWhile;
|
||||
|
||||
mod try_next;
|
||||
use try_next::TryNext;
|
||||
|
||||
mod take;
|
||||
use take::Take;
|
||||
|
||||
mod take_while;
|
||||
use take_while::TakeWhile;
|
||||
|
||||
cfg_time! {
|
||||
mod timeout;
|
||||
use timeout::Timeout;
|
||||
use tokio::time::Duration;
|
||||
mod throttle;
|
||||
use crate::throttle::{throttle, Throttle};
|
||||
}
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use futures_core::Stream;
|
||||
|
||||
/// An extension trait for the [`Stream`] trait that provides a variety of
|
||||
/// convenient combinator functions.
|
||||
///
|
||||
/// Be aware that the `Stream` trait in Tokio is a re-export of the trait found
|
||||
/// in the [futures] crate, however both Tokio and futures provide separate
|
||||
/// `StreamExt` utility traits, and some utilities are only available on one of
|
||||
/// these traits. Click [here][futures-StreamExt] to see the other `StreamExt`
|
||||
/// trait in the futures crate.
|
||||
///
|
||||
/// If you need utilities from both `StreamExt` traits, you should prefer to
|
||||
/// import one of them, and use the other through the fully qualified call
|
||||
/// syntax. For example:
|
||||
/// ```
|
||||
/// // import one of the traits:
|
||||
/// use futures::stream::StreamExt;
|
||||
/// # #[tokio::main(flavor = "current_thread")]
|
||||
/// # async fn main() {
|
||||
///
|
||||
/// let a = tokio_stream::iter(vec![1, 3, 5]);
|
||||
/// let b = tokio_stream::iter(vec![2, 4, 6]);
|
||||
///
|
||||
/// // use the fully qualified call syntax for the other trait:
|
||||
/// let merged = tokio_stream::StreamExt::merge(a, b);
|
||||
///
|
||||
/// // use normal call notation for futures::stream::StreamExt::collect
|
||||
/// let output: Vec<_> = merged.collect().await;
|
||||
/// assert_eq!(output, vec![1, 2, 3, 4, 5, 6]);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Stream`]: crate::Stream
|
||||
/// [futures]: https://docs.rs/futures
|
||||
/// [futures-StreamExt]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html
|
||||
pub trait StreamExt: Stream {
|
||||
/// Consumes and returns the next value in the stream or `None` if the
|
||||
/// stream is finished.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn next(&mut self) -> Option<Self::Item>;
|
||||
/// ```
|
||||
///
|
||||
/// Note that because `next` doesn't take ownership over the stream,
|
||||
/// the [`Stream`] type must be [`Unpin`]. If you want to use `next` with a
|
||||
/// [`!Unpin`](Unpin) stream, you'll first have to pin the stream. This can
|
||||
/// be done by boxing the stream using [`Box::pin`] or
|
||||
/// pinning it to the stack using the `pin_mut!` macro from the `pin_utils`
|
||||
/// crate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=3);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(1));
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, Some(3));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// # }
|
||||
/// ```
|
||||
fn next(&mut self) -> Next<'_, Self>
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
Next::new(self)
|
||||
}
|
||||
|
||||
/// Consumes and returns the next item in the stream. If an error is
|
||||
/// encountered before the next item, the error is returned instead.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn try_next(&mut self) -> Result<Option<T>, E>;
|
||||
/// ```
|
||||
///
|
||||
/// This is similar to the [`next`](StreamExt::next) combinator,
|
||||
/// but returns a [`Result<Option<T>, E>`](Result) rather than
|
||||
/// an [`Option<Result<T, E>>`](Option), making for easy use
|
||||
/// with the [`?`](std::ops::Try) operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(vec![Ok(1), Ok(2), Err("nope")]);
|
||||
///
|
||||
/// assert_eq!(stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(stream.try_next().await, Err("nope"));
|
||||
/// # }
|
||||
/// ```
|
||||
fn try_next<T, E>(&mut self) -> TryNext<'_, Self>
|
||||
where
|
||||
Self: Stream<Item = Result<T, E>> + Unpin,
|
||||
{
|
||||
TryNext::new(self)
|
||||
}
|
||||
|
||||
/// Maps this stream's items to a different type, returning a new stream of
|
||||
/// the resulting type.
|
||||
///
|
||||
/// The provided closure is executed over all elements of this stream as
|
||||
/// they are made available. It is executed inline with calls to
|
||||
/// [`poll_next`](Stream::poll_next).
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to the existing `map` methods in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=3);
|
||||
/// let mut stream = stream.map(|x| x + 3);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, Some(5));
|
||||
/// assert_eq!(stream.next().await, Some(6));
|
||||
/// # }
|
||||
/// ```
|
||||
fn map<T, F>(self, f: F) -> Map<Self, F>
|
||||
where
|
||||
F: FnMut(Self::Item) -> T,
|
||||
Self: Sized,
|
||||
{
|
||||
Map::new(self, f)
|
||||
}
|
||||
|
||||
/// Combine two streams into one by interleaving the output of both as it
|
||||
/// is produced.
|
||||
///
|
||||
/// Values are produced from the merged stream in the order they arrive from
|
||||
/// the two source streams. If both source streams provide values
|
||||
/// simultaneously, the merge stream alternates between them. This provides
|
||||
/// some level of fairness. You should not chain calls to `merge`, as this
|
||||
/// will break the fairness of the merging.
|
||||
///
|
||||
/// The merged stream completes once **both** source streams complete. When
|
||||
/// one source stream completes before the other, the merge stream
|
||||
/// exclusively polls the remaining stream.
|
||||
///
|
||||
/// For merging multiple streams, consider using [`StreamMap`] instead.
|
||||
///
|
||||
/// [`StreamMap`]: crate::StreamMap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{StreamExt, Stream};
|
||||
/// use tokio::sync::mpsc;
|
||||
/// use tokio::time;
|
||||
///
|
||||
/// use std::time::Duration;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// # /*
|
||||
/// #[tokio::main]
|
||||
/// # */
|
||||
/// # #[tokio::main(flavor = "current_thread")]
|
||||
/// async fn main() {
|
||||
/// # time::pause();
|
||||
/// let (tx1, mut rx1) = mpsc::channel::<usize>(10);
|
||||
/// let (tx2, mut rx2) = mpsc::channel::<usize>(10);
|
||||
///
|
||||
/// // Convert the channels to a `Stream`.
|
||||
/// let rx1 = Box::pin(async_stream::stream! {
|
||||
/// while let Some(item) = rx1.recv().await {
|
||||
/// yield item;
|
||||
/// }
|
||||
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
|
||||
///
|
||||
/// let rx2 = Box::pin(async_stream::stream! {
|
||||
/// while let Some(item) = rx2.recv().await {
|
||||
/// yield item;
|
||||
/// }
|
||||
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
|
||||
///
|
||||
/// let mut rx = rx1.merge(rx2);
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// // Send some values immediately
|
||||
/// tx1.send(1).await.unwrap();
|
||||
/// tx1.send(2).await.unwrap();
|
||||
///
|
||||
/// // Let the other task send values
|
||||
/// time::sleep(Duration::from_millis(20)).await;
|
||||
///
|
||||
/// tx1.send(4).await.unwrap();
|
||||
/// });
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// // Wait for the first task to send values
|
||||
/// time::sleep(Duration::from_millis(5)).await;
|
||||
///
|
||||
/// tx2.send(3).await.unwrap();
|
||||
///
|
||||
/// time::sleep(Duration::from_millis(25)).await;
|
||||
///
|
||||
/// // Send the final value
|
||||
/// tx2.send(5).await.unwrap();
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(1, rx.next().await.unwrap());
|
||||
/// assert_eq!(2, rx.next().await.unwrap());
|
||||
/// assert_eq!(3, rx.next().await.unwrap());
|
||||
/// assert_eq!(4, rx.next().await.unwrap());
|
||||
/// assert_eq!(5, rx.next().await.unwrap());
|
||||
///
|
||||
/// // The merged stream is consumed
|
||||
/// assert!(rx.next().await.is_none());
|
||||
/// }
|
||||
/// ```
|
||||
fn merge<U>(self, other: U) -> Merge<Self, U>
|
||||
where
|
||||
U: Stream<Item = Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Merge::new(self, other)
|
||||
}
|
||||
|
||||
/// Filters the values produced by this stream according to the provided
|
||||
/// predicate.
|
||||
///
|
||||
/// As values of this stream are made available, the provided predicate `f`
|
||||
/// will be run against them. If the predicate
|
||||
/// resolves to `true`, then the stream will yield the value, but if the
|
||||
/// predicate resolves to `false`, then the value
|
||||
/// will be discarded and the next value will be produced.
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to [`Iterator::filter`] method in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter(|x| x % 2 == 0);
|
||||
///
|
||||
/// assert_eq!(Some(2), evens.next().await);
|
||||
/// assert_eq!(Some(4), evens.next().await);
|
||||
/// assert_eq!(Some(6), evens.next().await);
|
||||
/// assert_eq!(Some(8), evens.next().await);
|
||||
/// assert_eq!(None, evens.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn filter<F>(self, f: F) -> Filter<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
Filter::new(self, f)
|
||||
}
|
||||
|
||||
/// Filters the values produced by this stream while simultaneously mapping
|
||||
/// them to a different type according to the provided closure.
|
||||
///
|
||||
/// As values of this stream are made available, the provided function will
|
||||
/// be run on them. If the predicate `f` resolves to
|
||||
/// [`Some(item)`](Some) then the stream will yield the value `item`, but if
|
||||
/// it resolves to [`None`], then the value will be skipped.
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to [`Iterator::filter_map`] method in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter_map(|x| {
|
||||
/// if x % 2 == 0 { Some(x + 1) } else { None }
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(Some(3), evens.next().await);
|
||||
/// assert_eq!(Some(5), evens.next().await);
|
||||
/// assert_eq!(Some(7), evens.next().await);
|
||||
/// assert_eq!(Some(9), evens.next().await);
|
||||
/// assert_eq!(None, evens.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
|
||||
where
|
||||
F: FnMut(Self::Item) -> Option<T>,
|
||||
Self: Sized,
|
||||
{
|
||||
FilterMap::new(self, f)
|
||||
}
|
||||
|
||||
/// Creates a stream which ends after the first `None`.
|
||||
///
|
||||
/// After a stream returns `None`, behavior is undefined. Future calls to
|
||||
/// `poll_next` may or may not return `Some(T)` again or they may panic.
|
||||
/// `fuse()` adapts a stream, ensuring that after `None` is given, it will
|
||||
/// return `None` forever.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{Stream, StreamExt};
|
||||
///
|
||||
/// use std::pin::Pin;
|
||||
/// use std::task::{Context, Poll};
|
||||
///
|
||||
/// // a stream which alternates between Some and None
|
||||
/// struct Alternate {
|
||||
/// state: i32,
|
||||
/// }
|
||||
///
|
||||
/// impl Stream for Alternate {
|
||||
/// type Item = i32;
|
||||
///
|
||||
/// fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<i32>> {
|
||||
/// let val = self.state;
|
||||
/// self.state = self.state + 1;
|
||||
///
|
||||
/// // if it's even, Some(i32), else None
|
||||
/// if val % 2 == 0 {
|
||||
/// Poll::Ready(Some(val))
|
||||
/// } else {
|
||||
/// Poll::Ready(None)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let mut stream = Alternate { state: 0 };
|
||||
///
|
||||
/// // the stream goes back and forth
|
||||
/// assert_eq!(stream.next().await, Some(0));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
///
|
||||
/// // however, once it is fused
|
||||
/// let mut stream = stream.fuse();
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
///
|
||||
/// // it will always return `None` after the first time.
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// }
|
||||
/// ```
|
||||
fn fuse(self) -> Fuse<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Fuse::new(self)
|
||||
}
|
||||
|
||||
/// Creates a new stream of at most `n` items of the underlying stream.
|
||||
///
|
||||
/// Once `n` items have been yielded from this stream then it will always
|
||||
/// return that the stream is done.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take(3);
|
||||
///
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(Some(2), stream.next().await);
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn take(self, n: usize) -> Take<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Take::new(self, n)
|
||||
}
|
||||
|
||||
/// Take elements from this stream while the provided predicate
|
||||
/// resolves to `true`.
|
||||
///
|
||||
/// This function, like `Iterator::take_while`, will take elements from the
|
||||
/// stream until the predicate `f` resolves to `false`. Once one element
|
||||
/// returns false it will always return that the stream is done.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take_while(|x| *x <= 3);
|
||||
///
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(Some(2), stream.next().await);
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn take_while<F>(self, f: F) -> TakeWhile<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
TakeWhile::new(self, f)
|
||||
}
|
||||
|
||||
/// Creates a new stream that will skip the `n` first items of the
|
||||
/// underlying stream.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).skip(7);
|
||||
///
|
||||
/// assert_eq!(Some(8), stream.next().await);
|
||||
/// assert_eq!(Some(9), stream.next().await);
|
||||
/// assert_eq!(Some(10), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn skip(self, n: usize) -> Skip<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Skip::new(self, n)
|
||||
}
|
||||
|
||||
/// Skip elements from the underlying stream while the provided predicate
|
||||
/// resolves to `true`.
|
||||
///
|
||||
/// This function, like [`Iterator::skip_while`], will ignore elemets from the
|
||||
/// stream until the predicate `f` resolves to `false`. Once one element
|
||||
/// returns false, the rest of the elements will be yielded.
|
||||
///
|
||||
/// [`Iterator::skip_while`]: std::iter::Iterator::skip_while()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// let mut stream = stream::iter(vec![1,2,3,4,1]).skip_while(|x| *x < 3);
|
||||
///
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(Some(4), stream.next().await);
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn skip_while<F>(self, f: F) -> SkipWhile<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
SkipWhile::new(self, f)
|
||||
}
|
||||
|
||||
/// Tests if every element of the stream matches a predicate.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn all<F>(&mut self, f: F) -> bool;
|
||||
/// ```
|
||||
///
|
||||
/// `all()` takes a closure that returns `true` or `false`. It applies
|
||||
/// this closure to each element of the stream, and if they all return
|
||||
/// `true`, then so does `all`. If any of them return `false`, it
|
||||
/// returns `false`. An empty stream returns `true`.
|
||||
///
|
||||
/// `all()` is short-circuiting; in other words, it will stop processing
|
||||
/// as soon as it finds a `false`, given that no matter what else happens,
|
||||
/// the result will also be `false`.
|
||||
///
|
||||
/// An empty stream returns `true`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// assert!(stream::iter(&a).all(|&x| x > 0).await);
|
||||
///
|
||||
/// assert!(!stream::iter(&a).all(|&x| x > 2).await);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Stopping at the first `false`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// let mut iter = stream::iter(&a);
|
||||
///
|
||||
/// assert!(!iter.all(|&x| x != 2).await);
|
||||
///
|
||||
/// // we can still use `iter`, as there are more elements.
|
||||
/// assert_eq!(iter.next().await, Some(&3));
|
||||
/// # }
|
||||
/// ```
|
||||
fn all<F>(&mut self, f: F) -> AllFuture<'_, Self, F>
|
||||
where
|
||||
Self: Unpin,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
AllFuture::new(self, f)
|
||||
}
|
||||
|
||||
/// Tests if any element of the stream matches a predicate.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn any<F>(&mut self, f: F) -> bool;
|
||||
/// ```
|
||||
///
|
||||
/// `any()` takes a closure that returns `true` or `false`. It applies
|
||||
/// this closure to each element of the stream, and if any of them return
|
||||
/// `true`, then so does `any()`. If they all return `false`, it
|
||||
/// returns `false`.
|
||||
///
|
||||
/// `any()` is short-circuiting; in other words, it will stop processing
|
||||
/// as soon as it finds a `true`, given that no matter what else happens,
|
||||
/// the result will also be `true`.
|
||||
///
|
||||
/// An empty stream returns `false`.
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// assert!(stream::iter(&a).any(|&x| x > 0).await);
|
||||
///
|
||||
/// assert!(!stream::iter(&a).any(|&x| x > 5).await);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Stopping at the first `true`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// let mut iter = stream::iter(&a);
|
||||
///
|
||||
/// assert!(iter.any(|&x| x != 2).await);
|
||||
///
|
||||
/// // we can still use `iter`, as there are more elements.
|
||||
/// assert_eq!(iter.next().await, Some(&2));
|
||||
/// # }
|
||||
/// ```
|
||||
fn any<F>(&mut self, f: F) -> AnyFuture<'_, Self, F>
|
||||
where
|
||||
Self: Unpin,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
AnyFuture::new(self, f)
|
||||
}
|
||||
|
||||
/// Combine two streams into one by first returning all values from the
|
||||
/// first stream then all values from the second stream.
|
||||
///
|
||||
/// As long as `self` still has values to emit, no values from `other` are
|
||||
/// emitted, even if some are ready.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let one = stream::iter(vec![1, 2, 3]);
|
||||
/// let two = stream::iter(vec![4, 5, 6]);
|
||||
///
|
||||
/// let mut stream = one.chain(two);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(1));
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, Some(3));
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, Some(5));
|
||||
/// assert_eq!(stream.next().await, Some(6));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// }
|
||||
/// ```
|
||||
fn chain<U>(self, other: U) -> Chain<Self, U>
|
||||
where
|
||||
U: Stream<Item = Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Chain::new(self, other)
|
||||
}
|
||||
|
||||
/// A combinator that applies a function to every element in a stream
|
||||
/// producing a single, final value.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn fold<B, F>(self, init: B, f: F) -> B;
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, *};
|
||||
///
|
||||
/// let s = stream::iter(vec![1u8, 2, 3]);
|
||||
/// let sum = s.fold(0, |acc, x| acc + x).await;
|
||||
///
|
||||
/// assert_eq!(sum, 6);
|
||||
/// # }
|
||||
/// ```
|
||||
fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
FoldFuture::new(self, init, f)
|
||||
}
|
||||
|
||||
/// Drain stream pushing all emitted values into a collection.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn collect<T>(self) -> T;
|
||||
/// ```
|
||||
///
|
||||
/// `collect` streams all values, awaiting as needed. Values are pushed into
|
||||
/// a collection. A number of different target collection types are
|
||||
/// supported, including [`Vec`](std::vec::Vec),
|
||||
/// [`String`](std::string::String), and [`Bytes`].
|
||||
///
|
||||
/// [`Bytes`]: https://docs.rs/bytes/0.6.0/bytes/struct.Bytes.html
|
||||
///
|
||||
/// # `Result`
|
||||
///
|
||||
/// `collect()` can also be used with streams of type `Result<T, E>` where
|
||||
/// `T: FromStream<_>`. In this case, `collect()` will stream as long as
|
||||
/// values yielded from the stream are `Ok(_)`. If `Err(_)` is encountered,
|
||||
/// streaming is terminated and `collect()` returns the `Err`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// `FromStream` is currently a sealed trait. Stabilization is pending
|
||||
/// enhancements to the Rust language.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let doubled: Vec<i32> =
|
||||
/// stream::iter(vec![1, 2, 3])
|
||||
/// .map(|x| x * 2)
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(vec![2, 4, 6], doubled);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Collecting a stream of `Result` values
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// // A stream containing only `Ok` values will be collected
|
||||
/// let values: Result<Vec<i32>, &str> =
|
||||
/// stream::iter(vec![Ok(1), Ok(2), Ok(3)])
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(Ok(vec![1, 2, 3]), values);
|
||||
///
|
||||
/// // A stream containing `Err` values will return the first error.
|
||||
/// let results = vec![Ok(1), Err("no"), Ok(2), Ok(3), Err("nein")];
|
||||
///
|
||||
/// let values: Result<Vec<i32>, &str> =
|
||||
/// stream::iter(results)
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(Err("no"), values);
|
||||
/// }
|
||||
/// ```
|
||||
fn collect<T>(self) -> Collect<Self, T>
|
||||
where
|
||||
T: FromStream<Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Collect::new(self)
|
||||
}
|
||||
|
||||
/// Applies a per-item timeout to the passed stream.
|
||||
///
|
||||
/// `timeout()` takes a `Duration` that represents the maximum amount of
|
||||
/// time each element of the stream has to complete before timing out.
|
||||
///
|
||||
/// If the wrapped stream yields a value before the deadline is reached, the
|
||||
/// value is returned. Otherwise, an error is returned. The caller may decide
|
||||
/// to continue consuming the stream and will eventually get the next source
|
||||
/// stream value once it becomes available.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it.
|
||||
///
|
||||
/// Polling the returned stream will continue to poll the inner stream even
|
||||
/// if one or more items time out.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Suppose we have a stream `int_stream` that yields 3 numbers (1, 2, 3):
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// use std::time::Duration;
|
||||
/// # let int_stream = stream::iter(1..=3);
|
||||
///
|
||||
/// let int_stream = int_stream.timeout(Duration::from_secs(1));
|
||||
/// tokio::pin!(int_stream);
|
||||
///
|
||||
/// // When no items time out, we get the 3 elements in succession:
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(3)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
///
|
||||
/// // If the second item times out, we get an error and continue polling the stream:
|
||||
/// # let mut int_stream = stream::iter(vec![Ok(1), Err(()), Ok(2), Ok(3)]);
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert!(int_stream.try_next().await.is_err());
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(3)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
///
|
||||
/// // If we want to stop consuming the source stream the first time an
|
||||
/// // element times out, we can use the `take_while` operator:
|
||||
/// # let int_stream = stream::iter(vec![Ok(1), Err(()), Ok(2), Ok(3)]);
|
||||
/// let mut int_stream = int_stream.take_while(Result::is_ok);
|
||||
///
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(all(feature = "time"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
fn timeout(self, duration: Duration) -> Timeout<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Timeout::new(self, duration)
|
||||
}
|
||||
|
||||
/// Slows down a stream by enforcing a delay between items.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Create a throttled stream.
|
||||
/// ```rust,no_run
|
||||
/// use std::time::Duration;
|
||||
/// use tokio_stream::StreamExt;
|
||||
///
|
||||
/// # async fn dox() {
|
||||
/// let item_stream = futures::stream::repeat("one").throttle(Duration::from_secs(2));
|
||||
/// tokio::pin!(item_stream);
|
||||
///
|
||||
/// loop {
|
||||
/// // The string will be produced at most every 2 seconds
|
||||
/// println!("{:?}", item_stream.next().await);
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(all(feature = "time"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
fn throttle(self, duration: Duration) -> Throttle<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
throttle(duration, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<St: ?Sized> StreamExt for St where St: Stream {}
|
||||
|
||||
/// Merge the size hints from two streams.
|
||||
fn merge_size_hints(
|
||||
(left_low, left_high): (usize, Option<usize>),
|
||||
(right_low, right_hign): (usize, Option<usize>),
|
||||
) -> (usize, Option<usize>) {
|
||||
let low = left_low.saturating_add(right_low);
|
||||
let high = match (left_high, right_hign) {
|
||||
(Some(h1), Some(h2)) => h1.checked_add(h2),
|
||||
_ => None,
|
||||
};
|
||||
(low, high)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
macro_rules! cfg_fs {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = "fs")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_io_util {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = "io-util")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_net {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = "net")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_time {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
|
||||
@@ -0,0 +1,917 @@
|
||||
use futures_core::Stream;
|
||||
|
||||
mod all;
|
||||
use all::AllFuture;
|
||||
|
||||
mod any;
|
||||
use any::AnyFuture;
|
||||
|
||||
mod chain;
|
||||
use chain::Chain;
|
||||
|
||||
pub(crate) mod collect;
|
||||
use collect::{Collect, FromStream};
|
||||
|
||||
mod filter;
|
||||
use filter::Filter;
|
||||
|
||||
mod filter_map;
|
||||
use filter_map::FilterMap;
|
||||
|
||||
mod fold;
|
||||
use fold::FoldFuture;
|
||||
|
||||
mod fuse;
|
||||
use fuse::Fuse;
|
||||
|
||||
mod map;
|
||||
use map::Map;
|
||||
|
||||
mod merge;
|
||||
use merge::Merge;
|
||||
|
||||
mod next;
|
||||
use next::Next;
|
||||
|
||||
mod skip;
|
||||
use skip::Skip;
|
||||
|
||||
mod skip_while;
|
||||
use skip_while::SkipWhile;
|
||||
|
||||
mod try_next;
|
||||
use try_next::TryNext;
|
||||
|
||||
mod take;
|
||||
use take::Take;
|
||||
|
||||
mod take_while;
|
||||
use take_while::TakeWhile;
|
||||
|
||||
cfg_time! {
|
||||
mod timeout;
|
||||
use timeout::Timeout;
|
||||
use tokio::time::Duration;
|
||||
mod throttle;
|
||||
use throttle::{throttle, Throttle};
|
||||
}
|
||||
|
||||
/// An extension trait for the [`Stream`] trait that provides a variety of
|
||||
/// convenient combinator functions.
|
||||
///
|
||||
/// Be aware that the `Stream` trait in Tokio is a re-export of the trait found
|
||||
/// in the [futures] crate, however both Tokio and futures provide separate
|
||||
/// `StreamExt` utility traits, and some utilities are only available on one of
|
||||
/// these traits. Click [here][futures-StreamExt] to see the other `StreamExt`
|
||||
/// trait in the futures crate.
|
||||
///
|
||||
/// If you need utilities from both `StreamExt` traits, you should prefer to
|
||||
/// import one of them, and use the other through the fully qualified call
|
||||
/// syntax. For example:
|
||||
/// ```
|
||||
/// // import one of the traits:
|
||||
/// use futures::stream::StreamExt;
|
||||
/// # #[tokio::main(flavor = "current_thread")]
|
||||
/// # async fn main() {
|
||||
///
|
||||
/// let a = tokio_stream::iter(vec![1, 3, 5]);
|
||||
/// let b = tokio_stream::iter(vec![2, 4, 6]);
|
||||
///
|
||||
/// // use the fully qualified call syntax for the other trait:
|
||||
/// let merged = tokio_stream::StreamExt::merge(a, b);
|
||||
///
|
||||
/// // use normal call notation for futures::stream::StreamExt::collect
|
||||
/// let output: Vec<_> = merged.collect().await;
|
||||
/// assert_eq!(output, vec![1, 2, 3, 4, 5, 6]);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Stream`]: crate::Stream
|
||||
/// [futures]: https://docs.rs/futures
|
||||
/// [futures-StreamExt]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html
|
||||
pub trait StreamExt: Stream {
|
||||
/// Consumes and returns the next value in the stream or `None` if the
|
||||
/// stream is finished.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn next(&mut self) -> Option<Self::Item>;
|
||||
/// ```
|
||||
///
|
||||
/// Note that because `next` doesn't take ownership over the stream,
|
||||
/// the [`Stream`] type must be [`Unpin`]. If you want to use `next` with a
|
||||
/// [`!Unpin`](Unpin) stream, you'll first have to pin the stream. This can
|
||||
/// be done by boxing the stream using [`Box::pin`] or
|
||||
/// pinning it to the stack using the `pin_mut!` macro from the `pin_utils`
|
||||
/// crate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=3);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(1));
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, Some(3));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// # }
|
||||
/// ```
|
||||
fn next(&mut self) -> Next<'_, Self>
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
Next::new(self)
|
||||
}
|
||||
|
||||
/// Consumes and returns the next item in the stream. If an error is
|
||||
/// encountered before the next item, the error is returned instead.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn try_next(&mut self) -> Result<Option<T>, E>;
|
||||
/// ```
|
||||
///
|
||||
/// This is similar to the [`next`](StreamExt::next) combinator,
|
||||
/// but returns a [`Result<Option<T>, E>`](Result) rather than
|
||||
/// an [`Option<Result<T, E>>`](Option), making for easy use
|
||||
/// with the [`?`](std::ops::Try) operator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(vec![Ok(1), Ok(2), Err("nope")]);
|
||||
///
|
||||
/// assert_eq!(stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(stream.try_next().await, Err("nope"));
|
||||
/// # }
|
||||
/// ```
|
||||
fn try_next<T, E>(&mut self) -> TryNext<'_, Self>
|
||||
where
|
||||
Self: Stream<Item = Result<T, E>> + Unpin,
|
||||
{
|
||||
TryNext::new(self)
|
||||
}
|
||||
|
||||
/// Maps this stream's items to a different type, returning a new stream of
|
||||
/// the resulting type.
|
||||
///
|
||||
/// The provided closure is executed over all elements of this stream as
|
||||
/// they are made available. It is executed inline with calls to
|
||||
/// [`poll_next`](Stream::poll_next).
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to the existing `map` methods in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=3);
|
||||
/// let mut stream = stream.map(|x| x + 3);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, Some(5));
|
||||
/// assert_eq!(stream.next().await, Some(6));
|
||||
/// # }
|
||||
/// ```
|
||||
fn map<T, F>(self, f: F) -> Map<Self, F>
|
||||
where
|
||||
F: FnMut(Self::Item) -> T,
|
||||
Self: Sized,
|
||||
{
|
||||
Map::new(self, f)
|
||||
}
|
||||
|
||||
/// Combine two streams into one by interleaving the output of both as it
|
||||
/// is produced.
|
||||
///
|
||||
/// Values are produced from the merged stream in the order they arrive from
|
||||
/// the two source streams. If both source streams provide values
|
||||
/// simultaneously, the merge stream alternates between them. This provides
|
||||
/// some level of fairness. You should not chain calls to `merge`, as this
|
||||
/// will break the fairness of the merging.
|
||||
///
|
||||
/// The merged stream completes once **both** source streams complete. When
|
||||
/// one source stream completes before the other, the merge stream
|
||||
/// exclusively polls the remaining stream.
|
||||
///
|
||||
/// For merging multiple streams, consider using [`StreamMap`] instead.
|
||||
///
|
||||
/// [`StreamMap`]: crate::StreamMap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{StreamExt, Stream};
|
||||
/// use tokio::sync::mpsc;
|
||||
/// use tokio::time;
|
||||
///
|
||||
/// use std::time::Duration;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// # /*
|
||||
/// #[tokio::main]
|
||||
/// # */
|
||||
/// # #[tokio::main(flavor = "current_thread")]
|
||||
/// async fn main() {
|
||||
/// # time::pause();
|
||||
/// let (tx1, mut rx1) = mpsc::channel::<usize>(10);
|
||||
/// let (tx2, mut rx2) = mpsc::channel::<usize>(10);
|
||||
///
|
||||
/// // Convert the channels to a `Stream`.
|
||||
/// let rx1 = Box::pin(async_stream::stream! {
|
||||
/// while let Some(item) = rx1.recv().await {
|
||||
/// yield item;
|
||||
/// }
|
||||
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
|
||||
///
|
||||
/// let rx2 = Box::pin(async_stream::stream! {
|
||||
/// while let Some(item) = rx2.recv().await {
|
||||
/// yield item;
|
||||
/// }
|
||||
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
|
||||
///
|
||||
/// let mut rx = rx1.merge(rx2);
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// // Send some values immediately
|
||||
/// tx1.send(1).await.unwrap();
|
||||
/// tx1.send(2).await.unwrap();
|
||||
///
|
||||
/// // Let the other task send values
|
||||
/// time::sleep(Duration::from_millis(20)).await;
|
||||
///
|
||||
/// tx1.send(4).await.unwrap();
|
||||
/// });
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// // Wait for the first task to send values
|
||||
/// time::sleep(Duration::from_millis(5)).await;
|
||||
///
|
||||
/// tx2.send(3).await.unwrap();
|
||||
///
|
||||
/// time::sleep(Duration::from_millis(25)).await;
|
||||
///
|
||||
/// // Send the final value
|
||||
/// tx2.send(5).await.unwrap();
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(1, rx.next().await.unwrap());
|
||||
/// assert_eq!(2, rx.next().await.unwrap());
|
||||
/// assert_eq!(3, rx.next().await.unwrap());
|
||||
/// assert_eq!(4, rx.next().await.unwrap());
|
||||
/// assert_eq!(5, rx.next().await.unwrap());
|
||||
///
|
||||
/// // The merged stream is consumed
|
||||
/// assert!(rx.next().await.is_none());
|
||||
/// }
|
||||
/// ```
|
||||
fn merge<U>(self, other: U) -> Merge<Self, U>
|
||||
where
|
||||
U: Stream<Item = Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Merge::new(self, other)
|
||||
}
|
||||
|
||||
/// Filters the values produced by this stream according to the provided
|
||||
/// predicate.
|
||||
///
|
||||
/// As values of this stream are made available, the provided predicate `f`
|
||||
/// will be run against them. If the predicate
|
||||
/// resolves to `true`, then the stream will yield the value, but if the
|
||||
/// predicate resolves to `false`, then the value
|
||||
/// will be discarded and the next value will be produced.
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to [`Iterator::filter`] method in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter(|x| x % 2 == 0);
|
||||
///
|
||||
/// assert_eq!(Some(2), evens.next().await);
|
||||
/// assert_eq!(Some(4), evens.next().await);
|
||||
/// assert_eq!(Some(6), evens.next().await);
|
||||
/// assert_eq!(Some(8), evens.next().await);
|
||||
/// assert_eq!(None, evens.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn filter<F>(self, f: F) -> Filter<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
Filter::new(self, f)
|
||||
}
|
||||
|
||||
/// Filters the values produced by this stream while simultaneously mapping
|
||||
/// them to a different type according to the provided closure.
|
||||
///
|
||||
/// As values of this stream are made available, the provided function will
|
||||
/// be run on them. If the predicate `f` resolves to
|
||||
/// [`Some(item)`](Some) then the stream will yield the value `item`, but if
|
||||
/// it resolves to [`None`], then the value will be skipped.
|
||||
///
|
||||
/// Note that this function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it, similar to [`Iterator::filter_map`] method in the
|
||||
/// standard library.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter_map(|x| {
|
||||
/// if x % 2 == 0 { Some(x + 1) } else { None }
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(Some(3), evens.next().await);
|
||||
/// assert_eq!(Some(5), evens.next().await);
|
||||
/// assert_eq!(Some(7), evens.next().await);
|
||||
/// assert_eq!(Some(9), evens.next().await);
|
||||
/// assert_eq!(None, evens.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
|
||||
where
|
||||
F: FnMut(Self::Item) -> Option<T>,
|
||||
Self: Sized,
|
||||
{
|
||||
FilterMap::new(self, f)
|
||||
}
|
||||
|
||||
/// Creates a stream which ends after the first `None`.
|
||||
///
|
||||
/// After a stream returns `None`, behavior is undefined. Future calls to
|
||||
/// `poll_next` may or may not return `Some(T)` again or they may panic.
|
||||
/// `fuse()` adapts a stream, ensuring that after `None` is given, it will
|
||||
/// return `None` forever.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{Stream, StreamExt};
|
||||
///
|
||||
/// use std::pin::Pin;
|
||||
/// use std::task::{Context, Poll};
|
||||
///
|
||||
/// // a stream which alternates between Some and None
|
||||
/// struct Alternate {
|
||||
/// state: i32,
|
||||
/// }
|
||||
///
|
||||
/// impl Stream for Alternate {
|
||||
/// type Item = i32;
|
||||
///
|
||||
/// fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<i32>> {
|
||||
/// let val = self.state;
|
||||
/// self.state = self.state + 1;
|
||||
///
|
||||
/// // if it's even, Some(i32), else None
|
||||
/// if val % 2 == 0 {
|
||||
/// Poll::Ready(Some(val))
|
||||
/// } else {
|
||||
/// Poll::Ready(None)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let mut stream = Alternate { state: 0 };
|
||||
///
|
||||
/// // the stream goes back and forth
|
||||
/// assert_eq!(stream.next().await, Some(0));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
///
|
||||
/// // however, once it is fused
|
||||
/// let mut stream = stream.fuse();
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
///
|
||||
/// // it will always return `None` after the first time.
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// }
|
||||
/// ```
|
||||
fn fuse(self) -> Fuse<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Fuse::new(self)
|
||||
}
|
||||
|
||||
/// Creates a new stream of at most `n` items of the underlying stream.
|
||||
///
|
||||
/// Once `n` items have been yielded from this stream then it will always
|
||||
/// return that the stream is done.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take(3);
|
||||
///
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(Some(2), stream.next().await);
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn take(self, n: usize) -> Take<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Take::new(self, n)
|
||||
}
|
||||
|
||||
/// Take elements from this stream while the provided predicate
|
||||
/// resolves to `true`.
|
||||
///
|
||||
/// This function, like `Iterator::take_while`, will take elements from the
|
||||
/// stream until the predicate `f` resolves to `false`. Once one element
|
||||
/// returns false it will always return that the stream is done.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take_while(|x| *x <= 3);
|
||||
///
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(Some(2), stream.next().await);
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn take_while<F>(self, f: F) -> TakeWhile<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
TakeWhile::new(self, f)
|
||||
}
|
||||
|
||||
/// Creates a new stream that will skip the `n` first items of the
|
||||
/// underlying stream.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).skip(7);
|
||||
///
|
||||
/// assert_eq!(Some(8), stream.next().await);
|
||||
/// assert_eq!(Some(9), stream.next().await);
|
||||
/// assert_eq!(Some(10), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn skip(self, n: usize) -> Skip<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Skip::new(self, n)
|
||||
}
|
||||
|
||||
/// Skip elements from the underlying stream while the provided predicate
|
||||
/// resolves to `true`.
|
||||
///
|
||||
/// This function, like [`Iterator::skip_while`], will ignore elemets from the
|
||||
/// stream until the predicate `f` resolves to `false`. Once one element
|
||||
/// returns false, the rest of the elements will be yielded.
|
||||
///
|
||||
/// [`Iterator::skip_while`]: std::iter::Iterator::skip_while()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// let mut stream = stream::iter(vec![1,2,3,4,1]).skip_while(|x| *x < 3);
|
||||
///
|
||||
/// assert_eq!(Some(3), stream.next().await);
|
||||
/// assert_eq!(Some(4), stream.next().await);
|
||||
/// assert_eq!(Some(1), stream.next().await);
|
||||
/// assert_eq!(None, stream.next().await);
|
||||
/// # }
|
||||
/// ```
|
||||
fn skip_while<F>(self, f: F) -> SkipWhile<Self, F>
|
||||
where
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
Self: Sized,
|
||||
{
|
||||
SkipWhile::new(self, f)
|
||||
}
|
||||
|
||||
/// Tests if every element of the stream matches a predicate.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn all<F>(&mut self, f: F) -> bool;
|
||||
/// ```
|
||||
///
|
||||
/// `all()` takes a closure that returns `true` or `false`. It applies
|
||||
/// this closure to each element of the stream, and if they all return
|
||||
/// `true`, then so does `all`. If any of them return `false`, it
|
||||
/// returns `false`. An empty stream returns `true`.
|
||||
///
|
||||
/// `all()` is short-circuiting; in other words, it will stop processing
|
||||
/// as soon as it finds a `false`, given that no matter what else happens,
|
||||
/// the result will also be `false`.
|
||||
///
|
||||
/// An empty stream returns `true`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// assert!(stream::iter(&a).all(|&x| x > 0).await);
|
||||
///
|
||||
/// assert!(!stream::iter(&a).all(|&x| x > 2).await);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Stopping at the first `false`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// let mut iter = stream::iter(&a);
|
||||
///
|
||||
/// assert!(!iter.all(|&x| x != 2).await);
|
||||
///
|
||||
/// // we can still use `iter`, as there are more elements.
|
||||
/// assert_eq!(iter.next().await, Some(&3));
|
||||
/// # }
|
||||
/// ```
|
||||
fn all<F>(&mut self, f: F) -> AllFuture<'_, Self, F>
|
||||
where
|
||||
Self: Unpin,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
AllFuture::new(self, f)
|
||||
}
|
||||
|
||||
/// Tests if any element of the stream matches a predicate.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn any<F>(&mut self, f: F) -> bool;
|
||||
/// ```
|
||||
///
|
||||
/// `any()` takes a closure that returns `true` or `false`. It applies
|
||||
/// this closure to each element of the stream, and if any of them return
|
||||
/// `true`, then so does `any()`. If they all return `false`, it
|
||||
/// returns `false`.
|
||||
///
|
||||
/// `any()` is short-circuiting; in other words, it will stop processing
|
||||
/// as soon as it finds a `true`, given that no matter what else happens,
|
||||
/// the result will also be `true`.
|
||||
///
|
||||
/// An empty stream returns `false`.
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// assert!(stream::iter(&a).any(|&x| x > 0).await);
|
||||
///
|
||||
/// assert!(!stream::iter(&a).any(|&x| x > 5).await);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Stopping at the first `true`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// let mut iter = stream::iter(&a);
|
||||
///
|
||||
/// assert!(iter.any(|&x| x != 2).await);
|
||||
///
|
||||
/// // we can still use `iter`, as there are more elements.
|
||||
/// assert_eq!(iter.next().await, Some(&2));
|
||||
/// # }
|
||||
/// ```
|
||||
fn any<F>(&mut self, f: F) -> AnyFuture<'_, Self, F>
|
||||
where
|
||||
Self: Unpin,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
AnyFuture::new(self, f)
|
||||
}
|
||||
|
||||
/// Combine two streams into one by first returning all values from the
|
||||
/// first stream then all values from the second stream.
|
||||
///
|
||||
/// As long as `self` still has values to emit, no values from `other` are
|
||||
/// emitted, even if some are ready.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let one = stream::iter(vec![1, 2, 3]);
|
||||
/// let two = stream::iter(vec![4, 5, 6]);
|
||||
///
|
||||
/// let mut stream = one.chain(two);
|
||||
///
|
||||
/// assert_eq!(stream.next().await, Some(1));
|
||||
/// assert_eq!(stream.next().await, Some(2));
|
||||
/// assert_eq!(stream.next().await, Some(3));
|
||||
/// assert_eq!(stream.next().await, Some(4));
|
||||
/// assert_eq!(stream.next().await, Some(5));
|
||||
/// assert_eq!(stream.next().await, Some(6));
|
||||
/// assert_eq!(stream.next().await, None);
|
||||
/// }
|
||||
/// ```
|
||||
fn chain<U>(self, other: U) -> Chain<Self, U>
|
||||
where
|
||||
U: Stream<Item = Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Chain::new(self, other)
|
||||
}
|
||||
|
||||
/// A combinator that applies a function to every element in a stream
|
||||
/// producing a single, final value.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn fold<B, F>(self, init: B, f: F) -> B;
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, *};
|
||||
///
|
||||
/// let s = stream::iter(vec![1u8, 2, 3]);
|
||||
/// let sum = s.fold(0, |acc, x| acc + x).await;
|
||||
///
|
||||
/// assert_eq!(sum, 6);
|
||||
/// # }
|
||||
/// ```
|
||||
fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
FoldFuture::new(self, init, f)
|
||||
}
|
||||
|
||||
/// Drain stream pushing all emitted values into a collection.
|
||||
///
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// async fn collect<T>(self) -> T;
|
||||
/// ```
|
||||
///
|
||||
/// `collect` streams all values, awaiting as needed. Values are pushed into
|
||||
/// a collection. A number of different target collection types are
|
||||
/// supported, including [`Vec`](std::vec::Vec),
|
||||
/// [`String`](std::string::String), and [`Bytes`].
|
||||
///
|
||||
/// [`Bytes`]: https://docs.rs/bytes/0.6.0/bytes/struct.Bytes.html
|
||||
///
|
||||
/// # `Result`
|
||||
///
|
||||
/// `collect()` can also be used with streams of type `Result<T, E>` where
|
||||
/// `T: FromStream<_>`. In this case, `collect()` will stream as long as
|
||||
/// values yielded from the stream are `Ok(_)`. If `Err(_)` is encountered,
|
||||
/// streaming is terminated and `collect()` returns the `Err`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// `FromStream` is currently a sealed trait. Stabilization is pending
|
||||
/// enhancements to the Rust language.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let doubled: Vec<i32> =
|
||||
/// stream::iter(vec![1, 2, 3])
|
||||
/// .map(|x| x * 2)
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(vec![2, 4, 6], doubled);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Collecting a stream of `Result` values
|
||||
///
|
||||
/// ```
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// // A stream containing only `Ok` values will be collected
|
||||
/// let values: Result<Vec<i32>, &str> =
|
||||
/// stream::iter(vec![Ok(1), Ok(2), Ok(3)])
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(Ok(vec![1, 2, 3]), values);
|
||||
///
|
||||
/// // A stream containing `Err` values will return the first error.
|
||||
/// let results = vec![Ok(1), Err("no"), Ok(2), Ok(3), Err("nein")];
|
||||
///
|
||||
/// let values: Result<Vec<i32>, &str> =
|
||||
/// stream::iter(results)
|
||||
/// .collect()
|
||||
/// .await;
|
||||
///
|
||||
/// assert_eq!(Err("no"), values);
|
||||
/// }
|
||||
/// ```
|
||||
fn collect<T>(self) -> Collect<Self, T>
|
||||
where
|
||||
T: FromStream<Self::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
Collect::new(self)
|
||||
}
|
||||
|
||||
/// Applies a per-item timeout to the passed stream.
|
||||
///
|
||||
/// `timeout()` takes a `Duration` that represents the maximum amount of
|
||||
/// time each element of the stream has to complete before timing out.
|
||||
///
|
||||
/// If the wrapped stream yields a value before the deadline is reached, the
|
||||
/// value is returned. Otherwise, an error is returned. The caller may decide
|
||||
/// to continue consuming the stream and will eventually get the next source
|
||||
/// stream value once it becomes available.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This function consumes the stream passed into it and returns a
|
||||
/// wrapped version of it.
|
||||
///
|
||||
/// Polling the returned stream will continue to poll the inner stream even
|
||||
/// if one or more items time out.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Suppose we have a stream `int_stream` that yields 3 numbers (1, 2, 3):
|
||||
///
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// use std::time::Duration;
|
||||
/// # let int_stream = stream::iter(1..=3);
|
||||
///
|
||||
/// let int_stream = int_stream.timeout(Duration::from_secs(1));
|
||||
/// tokio::pin!(int_stream);
|
||||
///
|
||||
/// // When no items time out, we get the 3 elements in succession:
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(3)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
///
|
||||
/// // If the second item times out, we get an error and continue polling the stream:
|
||||
/// # let mut int_stream = stream::iter(vec![Ok(1), Err(()), Ok(2), Ok(3)]);
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert!(int_stream.try_next().await.is_err());
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(2)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(3)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
///
|
||||
/// // If we want to stop consuming the source stream the first time an
|
||||
/// // element times out, we can use the `take_while` operator:
|
||||
/// # let int_stream = stream::iter(vec![Ok(1), Err(()), Ok(2), Ok(3)]);
|
||||
/// let mut int_stream = int_stream.take_while(Result::is_ok);
|
||||
///
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
|
||||
/// assert_eq!(int_stream.try_next().await, Ok(None));
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(all(feature = "time"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
fn timeout(self, duration: Duration) -> Timeout<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Timeout::new(self, duration)
|
||||
}
|
||||
|
||||
/// Slows down a stream by enforcing a delay between items.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Create a throttled stream.
|
||||
/// ```rust,no_run
|
||||
/// use std::time::Duration;
|
||||
/// use tokio_stream::StreamExt;
|
||||
///
|
||||
/// # async fn dox() {
|
||||
/// let item_stream = futures::stream::repeat("one").throttle(Duration::from_secs(2));
|
||||
/// tokio::pin!(item_stream);
|
||||
///
|
||||
/// loop {
|
||||
/// // The string will be produced at most every 2 seconds
|
||||
/// println!("{:?}", item_stream.next().await);
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(all(feature = "time"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
fn throttle(self, duration: Duration) -> Throttle<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
throttle(duration, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<St: ?Sized> StreamExt for St where St: Stream {}
|
||||
|
||||
/// Merge the size hints from two streams.
|
||||
fn merge_size_hints(
|
||||
(left_low, left_high): (usize, Option<usize>),
|
||||
(right_low, right_hign): (usize, Option<usize>),
|
||||
) -> (usize, Option<usize>) {
|
||||
let low = left_low.saturating_add(right_low);
|
||||
let high = match (left_high, right_hign) {
|
||||
(Some(h1), Some(h2)) => h1.checked_add(h2),
|
||||
_ => None,
|
||||
};
|
||||
(low, high)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{Fuse, Stream};
|
||||
use crate::stream_ext::Fuse;
|
||||
use crate::Stream;
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{Fuse, Stream};
|
||||
use crate::stream_ext::Fuse;
|
||||
use crate::Stream;
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{Fuse, Stream};
|
||||
use crate::stream_ext::Fuse;
|
||||
use crate::Stream;
|
||||
use tokio::time::{Instant, Sleep};
|
||||
|
||||
use core::future::Future;
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{Next, Stream};
|
||||
use crate::stream_ext::Next;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -0,0 +1,35 @@
|
||||
//! Wrappers for Tokio types that implement `Stream`.
|
||||
|
||||
mod mpsc_bounded;
|
||||
pub use mpsc_bounded::ReceiverStream;
|
||||
|
||||
mod mpsc_unbounded;
|
||||
pub use mpsc_unbounded::UnboundedReceiverStream;
|
||||
|
||||
cfg_time! {
|
||||
mod interval;
|
||||
pub use interval::IntervalStream;
|
||||
}
|
||||
|
||||
cfg_net! {
|
||||
mod tcp_listener;
|
||||
pub use tcp_listener::TcpListenerStream;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix_listener;
|
||||
#[cfg(unix)]
|
||||
pub use unix_listener::UnixListenerStream;
|
||||
}
|
||||
|
||||
cfg_io_util! {
|
||||
mod split;
|
||||
pub use split::SplitStream;
|
||||
|
||||
mod lines;
|
||||
pub use lines::LinesStream;
|
||||
}
|
||||
|
||||
cfg_fs! {
|
||||
mod read_dir;
|
||||
pub use read_dir::ReadDirStream;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use crate::Stream;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::time::{Instant, Interval};
|
||||
|
||||
/// A wrapper around [`Interval`] that implements [`Stream`].
|
||||
///
|
||||
/// [`Interval`]: struct@tokio::time::Interval
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
pub struct IntervalStream {
|
||||
inner: Interval,
|
||||
}
|
||||
|
||||
impl IntervalStream {
|
||||
/// Create a new `IntervalStream`.
|
||||
pub fn new(interval: Interval) -> Self {
|
||||
Self { inner: interval }
|
||||
}
|
||||
|
||||
/// Get back the inner `Interval`.
|
||||
pub fn into_inner(self) -> Interval {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for IntervalStream {
|
||||
type Item = Instant;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
|
||||
self.inner.poll_tick(cx).map(Some)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(std::usize::MAX, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Interval> for IntervalStream {
|
||||
fn as_ref(&self) -> &Interval {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Interval> for IntervalStream {
|
||||
fn as_mut(&mut self) -> &mut Interval {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
use crate::Stream;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::{AsyncBufRead, Lines};
|
||||
|
||||
pin_project! {
|
||||
/// A wrapper around [`tokio::io::Lines`] that implements [`Stream`].
|
||||
///
|
||||
/// [`tokio::io::Lines`]: struct@tokio::io::Lines
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
||||
pub struct LinesStream<R> {
|
||||
#[pin]
|
||||
inner: Lines<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> LinesStream<R> {
|
||||
/// Create a new `LinesStream`.
|
||||
pub fn new(lines: Lines<R>) -> Self {
|
||||
Self { inner: lines }
|
||||
}
|
||||
|
||||
/// Get back the inner `Lines`.
|
||||
pub fn into_inner(self) -> Lines<R> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Obtain a pinned reference to the inner `Lines<R>`.
|
||||
#[allow(clippy::wrong_self_convention)] // https://github.com/rust-lang/rust-clippy/issues/4546
|
||||
pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Lines<R>> {
|
||||
self.project().inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncBufRead> Stream for LinesStream<R> {
|
||||
type Item = io::Result<String>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.project()
|
||||
.inner
|
||||
.poll_next_line(cx)
|
||||
.map(Result::transpose)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AsRef<Lines<R>> for LinesStream<R> {
|
||||
fn as_ref(&self) -> &Lines<R> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AsMut<Lines<R>> for LinesStream<R> {
|
||||
fn as_mut(&mut self) -> &mut Lines<R> {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use crate::Stream;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
|
||||
/// A wrapper around [`tokio::sync::mpsc::Receiver`] that implements [`Stream`].
|
||||
///
|
||||
/// [`tokio::sync::mpsc::Receiver`]: struct@tokio::sync::mpsc::Receiver
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
pub struct ReceiverStream<T> {
|
||||
inner: Receiver<T>,
|
||||
}
|
||||
|
||||
impl<T> ReceiverStream<T> {
|
||||
/// Create a new `ReceiverStream`.
|
||||
pub fn new(recv: Receiver<T>) -> Self {
|
||||
Self { inner: recv }
|
||||
}
|
||||
|
||||
/// Get back the inner `Receiver`.
|
||||
pub fn into_inner(self) -> Receiver<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Closes the receiving half of a channel without dropping it.
|
||||
///
|
||||
/// This prevents any further messages from being sent on the channel while
|
||||
/// still enabling the receiver to drain messages that are buffered. Any
|
||||
/// outstanding [`Permit`] values will still be able to send messages.
|
||||
///
|
||||
/// To guarantee no messages are dropped, after calling `close()`, you must
|
||||
/// receive all items from the stream until `None` is returned.
|
||||
///
|
||||
/// [`Permit`]: struct@tokio::sync::mpsc::Permit
|
||||
pub fn close(&mut self) {
|
||||
self.inner.close()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for ReceiverStream<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.inner.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<Receiver<T>> for ReceiverStream<T> {
|
||||
fn as_ref(&self) -> &Receiver<T> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<Receiver<T>> for ReceiverStream<T> {
|
||||
fn as_mut(&mut self) -> &mut Receiver<T> {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use crate::Stream;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
/// A wrapper around [`tokio::sync::mpsc::UnboundedReceiver`] that implements [`Stream`].
|
||||
///
|
||||
/// [`tokio::sync::mpsc::UnboundedReceiver`]: struct@tokio::sync::mpsc::UnboundedReceiver
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
pub struct UnboundedReceiverStream<T> {
|
||||
inner: UnboundedReceiver<T>,
|
||||
}
|
||||
|
||||
impl<T> UnboundedReceiverStream<T> {
|
||||
/// Create a new `UnboundedReceiverStream`.
|
||||
pub fn new(recv: UnboundedReceiver<T>) -> Self {
|
||||
Self { inner: recv }
|
||||
}
|
||||
|
||||
/// Get back the inner `UnboundedReceiver`.
|
||||
pub fn into_inner(self) -> UnboundedReceiver<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Closes the receiving half of a channel without dropping it.
|
||||
///
|
||||
/// This prevents any further messages from being sent on the channel while
|
||||
/// still enabling the receiver to drain messages that are buffered.
|
||||
pub fn close(&mut self) {
|
||||
self.inner.close()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for UnboundedReceiverStream<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.inner.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
|
||||
fn as_ref(&self) -> &UnboundedReceiver<T> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
|
||||
fn as_mut(&mut self) -> &mut UnboundedReceiver<T> {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use crate::Stream;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::fs::{DirEntry, ReadDir};
|
||||
|
||||
/// A wrapper around [`tokio::fs::ReadDir`] that implements [`Stream`].
|
||||
///
|
||||
/// [`tokio::fs::ReadDir`]: struct@tokio::fs::ReadDir
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
|
||||
pub struct ReadDirStream {
|
||||
inner: ReadDir,
|
||||
}
|
||||
|
||||
impl ReadDirStream {
|
||||
/// Create a new `ReadDirStream`.
|
||||
pub fn new(read_dir: ReadDir) -> Self {
|
||||
Self { inner: read_dir }
|
||||
}
|
||||
|
||||
/// Get back the inner `ReadDir`.
|
||||
pub fn into_inner(self) -> ReadDir {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for ReadDirStream {
|
||||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.inner.poll_next_entry(cx).map(Result::transpose)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ReadDir> for ReadDirStream {
|
||||
fn as_ref(&self) -> &ReadDir {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<ReadDir> for ReadDirStream {
|
||||
fn as_mut(&mut self) -> &mut ReadDir {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
use crate::Stream;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::{AsyncBufRead, Split};
|
||||
|
||||
pin_project! {
|
||||
/// A wrapper around [`tokio::io::Split`] that implements [`Stream`].
|
||||
///
|
||||
/// [`tokio::io::Split`]: struct@tokio::io::Split
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
||||
pub struct SplitStream<R> {
|
||||
#[pin]
|
||||
inner: Split<R>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> SplitStream<R> {
|
||||
/// Create a new `SplitStream`.
|
||||
pub fn new(split: Split<R>) -> Self {
|
||||
Self { inner: split }
|
||||
}
|
||||
|
||||
/// Get back the inner `Split`.
|
||||
pub fn into_inner(self) -> Split<R> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Obtain a pinned reference to the inner `Split<R>`.
|
||||
#[allow(clippy::wrong_self_convention)] // https://github.com/rust-lang/rust-clippy/issues/4546
|
||||
pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Split<R>> {
|
||||
self.project().inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncBufRead> Stream for SplitStream<R> {
|
||||
type Item = io::Result<Vec<u8>>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.project()
|
||||
.inner
|
||||
.poll_next_segment(cx)
|
||||
.map(Result::transpose)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AsRef<Split<R>> for SplitStream<R> {
|
||||
fn as_ref(&self) -> &Split<R> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AsMut<Split<R>> for SplitStream<R> {
|
||||
fn as_mut(&mut self) -> &mut Split<R> {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
use crate::Stream;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
|
||||
/// A wrapper around [`TcpListener`] that implements [`Stream`].
|
||||
///
|
||||
/// [`TcpListener`]: struct@tokio::net::TcpListener
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
|
||||
pub struct TcpListenerStream {
|
||||
inner: TcpListener,
|
||||
}
|
||||
|
||||
impl TcpListenerStream {
|
||||
/// Create a new `TcpListenerStream`.
|
||||
pub fn new(listener: TcpListener) -> Self {
|
||||
Self { inner: listener }
|
||||
}
|
||||
|
||||
/// Get back the inner `TcpListener`.
|
||||
pub fn into_inner(self) -> TcpListener {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for TcpListenerStream {
|
||||
type Item = io::Result<TcpStream>;
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<io::Result<TcpStream>>> {
|
||||
match self.inner.poll_accept(cx) {
|
||||
Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(stream))),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<TcpListener> for TcpListenerStream {
|
||||
fn as_ref(&self) -> &TcpListener {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<TcpListener> for TcpListenerStream {
|
||||
fn as_mut(&mut self) -> &mut TcpListener {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
use crate::Stream;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
|
||||
/// A wrapper around [`UnixListener`] that implements [`Stream`].
|
||||
///
|
||||
/// [`UnixListener`]: struct@tokio::net::UnixListener
|
||||
/// [`Stream`]: trait@crate::Stream
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(unix, feature = "net"))))]
|
||||
pub struct UnixListenerStream {
|
||||
inner: UnixListener,
|
||||
}
|
||||
|
||||
impl UnixListenerStream {
|
||||
/// Create a new `UnixListenerStream`.
|
||||
pub fn new(listener: UnixListener) -> Self {
|
||||
Self { inner: listener }
|
||||
}
|
||||
|
||||
/// Get back the inner `UnixListener`.
|
||||
pub fn into_inner(self) -> UnixListener {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for UnixListenerStream {
|
||||
type Item = io::Result<UnixStream>;
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<io::Result<UnixStream>>> {
|
||||
match self.inner.poll_accept(cx) {
|
||||
Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(stream))),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<UnixListener> for UnixListenerStream {
|
||||
fn as_ref(&self) -> &UnixListener {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<UnixListener> for UnixListenerStream {
|
||||
fn as_mut(&mut self) -> &mut UnixListener {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,22 @@
|
||||
# 0.6.2 (January 21, 2020)
|
||||
|
||||
### Added
|
||||
|
||||
- sync: add pollable `Semaphore` ([#3444])
|
||||
|
||||
### Fixed
|
||||
|
||||
- time: fix panics on updating `DelayQueue` entries ([#3270])
|
||||
|
||||
# 0.6.1 (January 12, 2020)
|
||||
|
||||
### Added
|
||||
|
||||
- codec: `get_ref()`, `get_mut()`, `get_pin_mut()` and `into_inner()` for
|
||||
`Framed`, `FramedRead`, `FramedWrite` and `StreamReader` ([#3364]).
|
||||
- codec: `write_buffer()` and `write_buffer_mut()` for `Framed` and
|
||||
`FramedWrite` ([#3387]).
|
||||
|
||||
# 0.6.0 (December 23, 2020)
|
||||
|
||||
### Changed
|
||||
@@ -53,6 +72,10 @@
|
||||
|
||||
- Initial release
|
||||
|
||||
[#3444]: https://github.com/tokio-rs/tokio/pull/3444
|
||||
[#3387]: https://github.com/tokio-rs/tokio/pull/3387
|
||||
[#3364]: https://github.com/tokio-rs/tokio/pull/3364
|
||||
[#3270]: https://github.com/tokio-rs/tokio/pull/3270
|
||||
[#2326]: https://github.com/tokio-rs/tokio/pull/2326
|
||||
[#2215]: https://github.com/tokio-rs/tokio/pull/2215
|
||||
[#2198]: https://github.com/tokio-rs/tokio/pull/2198
|
||||
|
||||
@@ -7,13 +7,13 @@ name = "tokio-util"
|
||||
# - Cargo.toml
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "tokio-util-0.6.x" git tag.
|
||||
version = "0.6.0"
|
||||
version = "0.6.2"
|
||||
edition = "2018"
|
||||
authors = ["Tokio Contributors <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
documentation = "https://docs.rs/tokio-util/0.6.0/tokio_util"
|
||||
documentation = "https://docs.rs/tokio-util/0.6.2/tokio_util"
|
||||
description = """
|
||||
Additional utilities for working with Tokio.
|
||||
"""
|
||||
@@ -36,8 +36,8 @@ rt = ["tokio/rt"]
|
||||
__docs_rs = ["futures-util"]
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio" }
|
||||
tokio-stream = { version = "0.1", path = "../tokio-stream" }
|
||||
tokio = { version = "1.0.0" }
|
||||
tokio-stream = { version = "0.1" }
|
||||
|
||||
bytes = "1.0.0"
|
||||
futures-core = "0.3.0"
|
||||
@@ -47,16 +47,15 @@ futures-util = { version = "0.3.0", optional = true }
|
||||
log = "0.4"
|
||||
pin-project-lite = "0.2.0"
|
||||
slab = { version = "0.4.1", optional = true } # Backs `DelayQueue`
|
||||
async-stream = "0.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
|
||||
tokio-test = { version = "0.4.0", path = "../tokio-test" }
|
||||
tokio = { version = "1.0.0", features = ["full"] }
|
||||
tokio-test = { version = "0.4.0" }
|
||||
|
||||
futures = "0.3.0"
|
||||
futures-test = "0.3.5"
|
||||
|
||||
async-stream = "0.3.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
@@ -170,6 +170,16 @@ impl<T, U> Framed<T, U> {
|
||||
&mut self.inner.inner
|
||||
}
|
||||
|
||||
/// Returns a pinned mutable reference to the underlying I/O stream wrapped by
|
||||
/// `Framed`.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||
self.project().inner.project().inner
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying codec wrapped by
|
||||
/// `Framed`.
|
||||
///
|
||||
@@ -198,6 +208,16 @@ impl<T, U> Framed<T, U> {
|
||||
&mut self.inner.state.read.buffer
|
||||
}
|
||||
|
||||
/// Returns a reference to the write buffer.
|
||||
pub fn write_buffer(&self) -> &BytesMut {
|
||||
&self.inner.state.write.buffer
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the write buffer.
|
||||
pub fn write_buffer_mut(&mut self) -> &mut BytesMut {
|
||||
&mut self.inner.state.write.buffer
|
||||
}
|
||||
|
||||
/// Consumes the `Framed`, returning its underlying I/O stream.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
|
||||
@@ -78,6 +78,16 @@ impl<T, D> FramedRead<T, D> {
|
||||
&mut self.inner.inner
|
||||
}
|
||||
|
||||
/// Returns a pinned mutable reference to the underlying I/O stream wrapped by
|
||||
/// `FramedRead`.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||
self.project().inner.project().inner
|
||||
}
|
||||
|
||||
/// Consumes the `FramedRead`, returning its underlying I/O stream.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::codec::framed_impl::{FramedImpl, WriteFrame};
|
||||
use tokio::io::AsyncWrite;
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use bytes::BytesMut;
|
||||
use futures_sink::Sink;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::fmt;
|
||||
@@ -58,6 +59,16 @@ impl<T, E> FramedWrite<T, E> {
|
||||
&mut self.inner.inner
|
||||
}
|
||||
|
||||
/// Returns a pinned mutable reference to the underlying I/O stream wrapped by
|
||||
/// `FramedWrite`.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||
self.project().inner.project().inner
|
||||
}
|
||||
|
||||
/// Consumes the `FramedWrite`, returning its underlying I/O stream.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
@@ -76,6 +87,16 @@ impl<T, E> FramedWrite<T, E> {
|
||||
pub fn encoder_mut(&mut self) -> &mut E {
|
||||
&mut self.inner.codec
|
||||
}
|
||||
|
||||
/// Returns a reference to the write buffer.
|
||||
pub fn write_buffer(&self) -> &BytesMut {
|
||||
&self.inner.state.buffer
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the write buffer.
|
||||
pub fn write_buffer_mut(&mut self) -> &mut BytesMut {
|
||||
&mut self.inner.state.buffer
|
||||
}
|
||||
}
|
||||
|
||||
// This impl just defers to the underlying FramedImpl
|
||||
|
||||
@@ -93,6 +93,36 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> StreamReader<S, B> {
|
||||
/// Gets a reference to the underlying stream.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying stream.
|
||||
pub fn get_ref(&self) -> &S {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying stream.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying stream.
|
||||
pub fn get_mut(&mut self) -> &mut S {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Gets a pinned mutable reference to the underlying stream.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying stream.
|
||||
pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
|
||||
self.project().inner
|
||||
}
|
||||
|
||||
/// Consumes this `BufWriter`, returning the underlying stream.
|
||||
///
|
||||
/// Note that any leftover data in the internal buffer is lost.
|
||||
pub fn into_inner(self) -> S {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> AsyncRead for StreamReader<S, B>
|
||||
where
|
||||
S: Stream<Item = Result<B, E>>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-util/0.6.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-util/0.6.2")]
|
||||
#![allow(clippy::needless_doctest_main)]
|
||||
#![warn(
|
||||
missing_debug_implementations,
|
||||
|
||||
@@ -4,3 +4,6 @@ mod cancellation_token;
|
||||
pub use cancellation_token::{CancellationToken, WaitForCancellationFuture};
|
||||
|
||||
mod intrusive_double_linked_list;
|
||||
|
||||
mod poll_semaphore;
|
||||
pub use poll_semaphore::PollSemaphore;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
use futures_core::Stream;
|
||||
use std::fmt;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::sync::{OwnedSemaphorePermit, Semaphore};
|
||||
|
||||
/// A wrapper around [`Semaphore`] that provides a `poll_acquire` method.
|
||||
///
|
||||
/// [`Semaphore`]: tokio::sync::Semaphore
|
||||
pub struct PollSemaphore {
|
||||
semaphore: Arc<Semaphore>,
|
||||
inner: Pin<Box<dyn Stream<Item = OwnedSemaphorePermit> + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl PollSemaphore {
|
||||
/// Create a new `PollSemaphore`.
|
||||
pub fn new(semaphore: Arc<Semaphore>) -> Self {
|
||||
Self {
|
||||
semaphore: semaphore.clone(),
|
||||
inner: Box::pin(async_stream::stream! {
|
||||
loop {
|
||||
match semaphore.clone().acquire_owned().await {
|
||||
Ok(permit) => yield permit,
|
||||
Err(_closed) => break,
|
||||
}
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes the semaphore.
|
||||
pub fn close(&self) {
|
||||
self.semaphore.close()
|
||||
}
|
||||
|
||||
/// Obtain a clone of the inner semaphore.
|
||||
pub fn clone_inner(&self) -> Arc<Semaphore> {
|
||||
self.semaphore.clone()
|
||||
}
|
||||
|
||||
/// Get back the inner semaphore.
|
||||
pub fn into_inner(self) -> Arc<Semaphore> {
|
||||
self.semaphore
|
||||
}
|
||||
|
||||
/// Poll to acquire a permit from the semaphore.
|
||||
///
|
||||
/// This can return the following values:
|
||||
///
|
||||
/// - `Poll::Pending` if a permit is not currently available.
|
||||
/// - `Poll::Ready(Some(permit))` if a permit was acquired.
|
||||
/// - `Poll::Ready(None)` if the semaphore has been closed.
|
||||
///
|
||||
/// When this method returns `Poll::Pending`, the current task is scheduled
|
||||
/// to receive a wakeup when a permit becomes available, or when the
|
||||
/// semaphore is closed. Note that on multiple calls to `poll_acquire`, only
|
||||
/// the `Waker` from the `Context` passed to the most recent call is
|
||||
/// scheduled to receive a wakeup.
|
||||
pub fn poll_acquire(&mut self, cx: &mut Context<'_>) -> Poll<Option<OwnedSemaphorePermit>> {
|
||||
self.inner.as_mut().poll_next(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for PollSemaphore {
|
||||
type Item = OwnedSemaphorePermit;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<OwnedSemaphorePermit>> {
|
||||
Pin::into_inner(self).poll_acquire(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PollSemaphore {
|
||||
fn clone(&self) -> PollSemaphore {
|
||||
PollSemaphore::new(self.clone_inner())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PollSemaphore {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PollSemaphore")
|
||||
.field("semaphore", &self.semaphore)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -36,14 +36,14 @@ use std::task::{self, Poll, Waker};
|
||||
/// # `Stream` implementation
|
||||
///
|
||||
/// Items are retrieved from the queue via [`DelayQueue::poll_expired`]. If no delays have
|
||||
/// expired, no items are returned. In this case, `NotReady` is returned and the
|
||||
/// expired, no items are returned. In this case, `Pending` is returned and the
|
||||
/// current task is registered to be notified once the next item's delay has
|
||||
/// expired.
|
||||
///
|
||||
/// If no items are in the queue, i.e. `is_empty()` returns `true`, then `poll`
|
||||
/// returns `Ready(None)`. This indicates that the stream has reached an end.
|
||||
/// However, if a new item is inserted *after*, `poll` will once again start
|
||||
/// returning items or `NotReady.
|
||||
/// returning items or `Pending.
|
||||
///
|
||||
/// Items are returned ordered by their expirations. Items that are configured
|
||||
/// to expire first will be returned first. There are no ordering guarantees
|
||||
@@ -538,7 +538,7 @@ impl<T> DelayQueue<T> {
|
||||
///
|
||||
/// delay_queue.reset_at(&key, Instant::now() + Duration::from_secs(10));
|
||||
///
|
||||
/// // "foo"is now scheduled to be returned in 10 seconds
|
||||
/// // "foo" is now scheduled to be returned in 10 seconds
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn reset_at(&mut self, key: &Key, when: Instant) {
|
||||
@@ -548,6 +548,8 @@ impl<T> DelayQueue<T> {
|
||||
let when = self.normalize_deadline(when);
|
||||
|
||||
self.slab[key.index].when = when;
|
||||
self.slab[key.index].expired = false;
|
||||
|
||||
self.insert_idx(when, key.index);
|
||||
|
||||
let next_deadline = self.next_deadline();
|
||||
@@ -711,7 +713,7 @@ impl<T> DelayQueue<T> {
|
||||
/// Returns `true` if there are no items in the queue.
|
||||
///
|
||||
/// Note that this function returns `false` even if all items have not yet
|
||||
/// expired and a call to `poll` will return `NotReady`.
|
||||
/// expired and a call to `poll` will return `Pending`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
||||
@@ -46,7 +46,7 @@ impl<T: Stack> Level<T> {
|
||||
() => {
|
||||
T::default()
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Level {
|
||||
level,
|
||||
@@ -233,14 +233,13 @@ fn slot_for(duration: u64, level: usize) -> usize {
|
||||
((duration >> (level * 6)) % LEVEL_MULT as u64) as usize
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(all(test, not(loom)))]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_slot_for() {
|
||||
for pos in 1..64 {
|
||||
for pos in 0..64 {
|
||||
assert_eq!(pos as usize, slot_for(pos, 0));
|
||||
}
|
||||
|
||||
@@ -252,4 +251,3 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -116,9 +116,17 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove `item` from thee timing wheel.
|
||||
/// Remove `item` from the timing wheel.
|
||||
pub(crate) fn remove(&mut self, item: &T::Borrowed, store: &mut T::Store) {
|
||||
let when = T::when(item, store);
|
||||
|
||||
assert!(
|
||||
self.elapsed <= when,
|
||||
"elapsed={}; when={}",
|
||||
self.elapsed,
|
||||
when
|
||||
);
|
||||
|
||||
let level = self.level_for(when);
|
||||
|
||||
self.levels[level].remove_entry(when, item, store);
|
||||
@@ -240,9 +248,11 @@ where
|
||||
}
|
||||
|
||||
fn level_for(elapsed: u64, when: u64) -> usize {
|
||||
let masked = elapsed ^ when;
|
||||
const SLOT_MASK: u64 = (1 << 6) - 1;
|
||||
|
||||
assert!(masked != 0, "elapsed={}; when={}", elapsed, when);
|
||||
// Mask in the trailing bits ignored by the level calculation in order to cap
|
||||
// the possible leading zeros
|
||||
let masked = elapsed ^ when | SLOT_MASK;
|
||||
|
||||
let leading_zeros = masked.leading_zeros() as usize;
|
||||
let significant = 63 - leading_zeros;
|
||||
@@ -255,7 +265,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_level_for() {
|
||||
for pos in 1..64 {
|
||||
for pos in 0..64 {
|
||||
assert_eq!(
|
||||
0,
|
||||
level_for(0, pos),
|
||||
|
||||
@@ -245,6 +245,35 @@ async fn reset_twice() {
|
||||
assert!(queue.is_woken());
|
||||
}
|
||||
|
||||
/// Regression test: Given an entry inserted with a deadline in the past, so
|
||||
/// that it is placed directly on the expired queue, reset the entry to a
|
||||
/// deadline in the future. Validate that this leaves the entry and queue in an
|
||||
/// internally consistent state by running an additional reset on the entry
|
||||
/// before polling it to completion.
|
||||
#[tokio::test]
|
||||
async fn repeatedly_reset_entry_inserted_as_expired() {
|
||||
time::pause();
|
||||
let mut queue = task::spawn(DelayQueue::new());
|
||||
let now = Instant::now();
|
||||
|
||||
let key = queue.insert_at("foo", now - ms(100));
|
||||
|
||||
queue.reset_at(&key, now + ms(100));
|
||||
queue.reset_at(&key, now + ms(50));
|
||||
|
||||
assert_pending!(poll!(queue));
|
||||
|
||||
time::sleep_until(now + ms(60)).await;
|
||||
|
||||
assert!(queue.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(queue)).into_inner();
|
||||
assert_eq!(entry, "foo");
|
||||
|
||||
let entry = assert_ready!(poll!(queue));
|
||||
assert!(entry.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remove_expired_item() {
|
||||
time::pause();
|
||||
@@ -261,6 +290,38 @@ async fn remove_expired_item() {
|
||||
assert_eq!(entry.into_inner(), "foo");
|
||||
}
|
||||
|
||||
/// Regression test: it should be possible to remove entries which fall in the
|
||||
/// 0th slot of the internal timer wheel — that is, entries whose expiration
|
||||
/// (a) falls at the beginning of one of the wheel's hierarchical levels and (b)
|
||||
/// is equal to the wheel's current elapsed time.
|
||||
#[tokio::test]
|
||||
async fn remove_at_timer_wheel_threshold() {
|
||||
time::pause();
|
||||
|
||||
let mut queue = task::spawn(DelayQueue::new());
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
let key1 = queue.insert_at("foo", now + ms(64));
|
||||
let key2 = queue.insert_at("bar", now + ms(64));
|
||||
|
||||
sleep(ms(80)).await;
|
||||
|
||||
let entry = assert_ready_ok!(poll!(queue)).into_inner();
|
||||
|
||||
match entry {
|
||||
"foo" => {
|
||||
let entry = queue.remove(&key2).into_inner();
|
||||
assert_eq!(entry, "bar");
|
||||
}
|
||||
"bar" => {
|
||||
let entry = queue.remove(&key1).into_inner();
|
||||
assert_eq!(entry, "foo");
|
||||
}
|
||||
other => panic!("other: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn expires_before_last_insert() {
|
||||
time::pause();
|
||||
|
||||
+698
-367
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -8,12 +8,12 @@ name = "tokio"
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v1.0.x" git tag.
|
||||
version = "1.0.0"
|
||||
version = "1.0.2"
|
||||
edition = "2018"
|
||||
authors = ["Tokio Contributors <[email protected]>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
documentation = "https://docs.rs/tokio/1.0.0/tokio/"
|
||||
documentation = "https://docs.rs/tokio/1.0.2/tokio/"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
description = """
|
||||
|
||||
@@ -29,7 +29,6 @@ the Rust programming language. It is:
|
||||
[Website](https://tokio.rs) |
|
||||
[Guides](https://tokio.rs/tokio/tutorial) |
|
||||
[API Docs](https://docs.rs/tokio/latest/tokio) |
|
||||
[Roadmap](https://github.com/tokio-rs/tokio/blob/master/ROADMAP.md) |
|
||||
[Chat](https://discord.gg/tokio)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -20,12 +20,15 @@ pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
|
||||
Ok(ReadDir(State::Idle(Some(std))))
|
||||
}
|
||||
|
||||
/// Stream of the entries in a directory.
|
||||
/// Read the the entries in a directory.
|
||||
///
|
||||
/// This stream is returned from the [`read_dir`] function of this module and
|
||||
/// will yield instances of [`DirEntry`]. Through a [`DirEntry`]
|
||||
/// information like the entry's path and possibly other metadata can be
|
||||
/// learned.
|
||||
/// This struct is returned from the [`read_dir`] function of this module and
|
||||
/// will yield instances of [`DirEntry`]. Through a [`DirEntry`] information
|
||||
/// like the entry's path and possibly other metadata can be learned.
|
||||
///
|
||||
/// A `ReadDir` can be turned into a `Stream` with [`ReadDirStream`].
|
||||
///
|
||||
/// [`ReadDirStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.ReadDirStream.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
||||
@@ -23,9 +23,11 @@ use std::{task::Context, task::Poll};
|
||||
/// to retake control from the tokio IO reactor.
|
||||
///
|
||||
/// The inner object is required to implement [`AsRawFd`]. This file descriptor
|
||||
/// must not change while [`AsyncFd`] owns the inner object. Changing the file
|
||||
/// descriptor results in unspecified behavior in the IO driver, which may
|
||||
/// include breaking notifications for other sockets/etc.
|
||||
/// must not change while [`AsyncFd`] owns the inner object, i.e. the
|
||||
/// [`AsRawFd::as_raw_fd`] method on the inner type must always return the same
|
||||
/// file descriptor when called multiple times. Failure to uphold this results
|
||||
/// in unspecified behavior in the IO driver, which may include breaking
|
||||
/// notifications for other sockets/etc.
|
||||
///
|
||||
/// Polling for readiness is done by calling the async functions [`readable`]
|
||||
/// and [`writable`]. These functions complete when the associated readiness
|
||||
|
||||
@@ -175,7 +175,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Repeates operations that are interrupted
|
||||
/// Repeats operations that are interrupted
|
||||
macro_rules! uninterruptibly {
|
||||
($e:expr) => {{
|
||||
loop {
|
||||
|
||||
@@ -259,8 +259,7 @@ cfg_rt! {
|
||||
/// This function panics if there is no current reactor set and `rt` feature
|
||||
/// flag is not enabled.
|
||||
pub(super) fn current() -> Self {
|
||||
crate::runtime::context::io_handle()
|
||||
.expect("there is no reactor running, must be called from the context of Tokio runtime")
|
||||
crate::runtime::context::io_handle().expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +273,7 @@ cfg_not_rt! {
|
||||
/// This function panics if there is no current reactor set, or if the `rt`
|
||||
/// feature flag is not enabled.
|
||||
pub(super) fn current() -> Self {
|
||||
panic!("there is no reactor running, must be called from the context of Tokio runtime with `rt` enabled.")
|
||||
panic!(crate::util::error::CONTEXT_MISSING_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,25 @@ impl<'a> ReadBuf<'a> {
|
||||
unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the entire buffer, without ensuring that it has been fully
|
||||
/// initialized.
|
||||
///
|
||||
/// The elements between 0 and `self.filled().len()` are filled, and those between 0 and
|
||||
/// `self.initialized().len()` are initialized (and so can be transmuted to a `&mut [u8]`).
|
||||
///
|
||||
/// The caller of this method must ensure that these invariants are upheld. For example, if the
|
||||
/// caller initializes some of the uninitialized section of the buffer, it must call
|
||||
/// [`assume_init`](Self::assume_init) with the number of bytes initialized.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must not de-initialize portions of the buffer that have already been initialized.
|
||||
/// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
|
||||
#[inline]
|
||||
pub unsafe fn inner_mut(&mut self) -> &mut [MaybeUninit<u8>] {
|
||||
self.buf
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
|
||||
/// initialized.
|
||||
///
|
||||
|
||||
@@ -131,7 +131,11 @@ impl<T: AsyncWrite> AsyncWrite for WriteHalf<T> {
|
||||
|
||||
impl<T> Inner<T> {
|
||||
fn poll_lock(&self, cx: &mut Context<'_>) -> Poll<Guard<'_, T>> {
|
||||
if !self.locked.compare_and_swap(false, true, Acquire) {
|
||||
if self
|
||||
.locked
|
||||
.compare_exchange(false, true, Acquire, Acquire)
|
||||
.is_ok()
|
||||
{
|
||||
Poll::Ready(Guard { inner: self })
|
||||
} else {
|
||||
// Spin... but investigate a better strategy
|
||||
|
||||
@@ -8,7 +8,15 @@ use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pin_project! {
|
||||
/// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
|
||||
/// Read lines from an [`AsyncBufRead`].
|
||||
///
|
||||
/// A `Lines` can be turned into a `Stream` with [`LinesStream`].
|
||||
///
|
||||
/// This type is usually created using the [`lines`] method.
|
||||
///
|
||||
/// [`AsyncBufRead`]: crate::io::AsyncBufRead
|
||||
/// [`LinesStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.LinesStream.html
|
||||
/// [`lines`]: crate::io::AsyncBufReadExt::lines
|
||||
#[derive(Debug)]
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
||||
|
||||
@@ -48,6 +48,7 @@ cfg_io_util! {
|
||||
mod read_line;
|
||||
|
||||
mod read_to_end;
|
||||
mod vec_with_initialized;
|
||||
cfg_process! {
|
||||
pub(crate) use read_to_end::read_to_end;
|
||||
}
|
||||
@@ -82,6 +83,7 @@ cfg_io_util! {
|
||||
|
||||
cfg_not_io_util! {
|
||||
cfg_process! {
|
||||
mod vec_with_initialized;
|
||||
mod read_to_end;
|
||||
// Used by process
|
||||
pub(crate) use read_to_end::read_to_end;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::io::{AsyncRead, ReadBuf};
|
||||
use crate::io::util::vec_with_initialized::{into_read_buf_parts, VecU8, VecWithInitialized};
|
||||
use crate::io::AsyncRead;
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::marker::PhantomPinned;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
@@ -13,7 +14,7 @@ pin_project! {
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct ReadToEnd<'a, R: ?Sized> {
|
||||
reader: &'a mut R,
|
||||
buf: &'a mut Vec<u8>,
|
||||
buf: VecWithInitialized<&'a mut Vec<u8>>,
|
||||
// The number of bytes appended to buf. This can be less than buf.len() if
|
||||
// the buffer was not empty when the operation was started.
|
||||
read: usize,
|
||||
@@ -29,20 +30,19 @@ where
|
||||
{
|
||||
ReadToEnd {
|
||||
reader,
|
||||
buf: buffer,
|
||||
buf: VecWithInitialized::new(buffer),
|
||||
read: 0,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn read_to_end_internal<R: AsyncRead + ?Sized>(
|
||||
buf: &mut Vec<u8>,
|
||||
pub(super) fn read_to_end_internal<V: VecU8, R: AsyncRead + ?Sized>(
|
||||
buf: &mut VecWithInitialized<V>,
|
||||
mut reader: Pin<&mut R>,
|
||||
num_read: &mut usize,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
// safety: The caller promised to prepare the buffer.
|
||||
let ret = ready!(poll_read_to_end(buf, reader.as_mut(), cx));
|
||||
match ret {
|
||||
Err(err) => return Poll::Ready(Err(err)),
|
||||
@@ -57,8 +57,8 @@ pub(super) fn read_to_end_internal<R: AsyncRead + ?Sized>(
|
||||
/// Tries to read from the provided AsyncRead.
|
||||
///
|
||||
/// The length of the buffer is increased by the number of bytes read.
|
||||
fn poll_read_to_end<R: AsyncRead + ?Sized>(
|
||||
buf: &mut Vec<u8>,
|
||||
fn poll_read_to_end<V: VecU8, R: AsyncRead + ?Sized>(
|
||||
buf: &mut VecWithInitialized<V>,
|
||||
read: Pin<&mut R>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
@@ -68,38 +68,34 @@ fn poll_read_to_end<R: AsyncRead + ?Sized>(
|
||||
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
|
||||
// time is 4,500 times (!) slower than this if the reader has a very small
|
||||
// amount of data to return.
|
||||
reserve(buf, 32);
|
||||
buf.reserve(32);
|
||||
|
||||
let mut unused_capacity = ReadBuf::uninit(get_unused_capacity(buf));
|
||||
// Get a ReadBuf into the vector.
|
||||
let mut read_buf = buf.get_read_buf();
|
||||
|
||||
ready!(read.poll_read(cx, &mut unused_capacity))?;
|
||||
let filled_before = read_buf.filled().len();
|
||||
let poll_result = read.poll_read(cx, &mut read_buf);
|
||||
let filled_after = read_buf.filled().len();
|
||||
let n = filled_after - filled_before;
|
||||
|
||||
let n = unused_capacity.filled().len();
|
||||
let new_len = buf.len() + n;
|
||||
// Update the length of the vector using the result of poll_read.
|
||||
let read_buf_parts = into_read_buf_parts(read_buf);
|
||||
buf.apply_read_buf(read_buf_parts);
|
||||
|
||||
// This should no longer even be possible in safe Rust. An implementor
|
||||
// would need to have unsafely *replaced* the buffer inside `ReadBuf`,
|
||||
// which... yolo?
|
||||
assert!(new_len <= buf.capacity());
|
||||
unsafe {
|
||||
buf.set_len(new_len);
|
||||
match poll_result {
|
||||
Poll::Pending => {
|
||||
// In this case, nothing should have been read. However we still
|
||||
// update the vector in case the poll_read call initialized parts of
|
||||
// the vector's unused capacity.
|
||||
debug_assert_eq!(filled_before, filled_after);
|
||||
Poll::Pending
|
||||
}
|
||||
Poll::Ready(Err(err)) => {
|
||||
debug_assert_eq!(filled_before, filled_after);
|
||||
Poll::Ready(Err(err))
|
||||
}
|
||||
Poll::Ready(Ok(())) => Poll::Ready(Ok(n)),
|
||||
}
|
||||
Poll::Ready(Ok(n))
|
||||
}
|
||||
|
||||
/// Allocates more memory and ensures that the unused capacity is prepared for use
|
||||
/// with the `AsyncRead`.
|
||||
fn reserve(buf: &mut Vec<u8>, bytes: usize) {
|
||||
if buf.capacity() - buf.len() >= bytes {
|
||||
return;
|
||||
}
|
||||
buf.reserve(bytes);
|
||||
}
|
||||
|
||||
/// Returns the unused capacity of the provided vector.
|
||||
fn get_unused_capacity(buf: &mut Vec<u8>) -> &mut [MaybeUninit<u8>] {
|
||||
let uninit = bytes::BufMut::chunk_mut(buf);
|
||||
unsafe { &mut *(uninit as *mut _ as *mut [MaybeUninit<u8>]) }
|
||||
}
|
||||
|
||||
impl<A> Future for ReadToEnd<'_, A>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::io::util::read_line::finish_string_read;
|
||||
use crate::io::util::read_to_end::read_to_end_internal;
|
||||
use crate::io::util::vec_with_initialized::VecWithInitialized;
|
||||
use crate::io::AsyncRead;
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
@@ -19,7 +20,7 @@ pin_project! {
|
||||
// while reading to postpone utf-8 handling until after reading.
|
||||
output: &'a mut String,
|
||||
// The actual allocation of the string is moved into this vector instead.
|
||||
buf: Vec<u8>,
|
||||
buf: VecWithInitialized<Vec<u8>>,
|
||||
// The number of bytes appended to buf. This can be less than buf.len() if
|
||||
// the buffer was not empty when the operation was started.
|
||||
read: usize,
|
||||
@@ -39,27 +40,22 @@ where
|
||||
let buf = mem::replace(string, String::new()).into_bytes();
|
||||
ReadToString {
|
||||
reader,
|
||||
buf,
|
||||
buf: VecWithInitialized::new(buf),
|
||||
output: string,
|
||||
read: 0,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Before first calling this method, the unused capacity must have been
|
||||
/// prepared for use with the provided AsyncRead. This can be done using the
|
||||
/// `prepare_buffer` function in `read_to_end.rs`.
|
||||
unsafe fn read_to_string_internal<R: AsyncRead + ?Sized>(
|
||||
fn read_to_string_internal<R: AsyncRead + ?Sized>(
|
||||
reader: Pin<&mut R>,
|
||||
output: &mut String,
|
||||
buf: &mut Vec<u8>,
|
||||
buf: &mut VecWithInitialized<Vec<u8>>,
|
||||
read: &mut usize,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let io_res = ready!(read_to_end_internal(buf, reader, read, cx));
|
||||
let utf8_res = String::from_utf8(mem::replace(buf, Vec::new()));
|
||||
let utf8_res = String::from_utf8(buf.take());
|
||||
|
||||
// At this point both buf and output are empty. The allocation is in utf8_res.
|
||||
|
||||
@@ -77,7 +73,6 @@ where
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let me = self.project();
|
||||
|
||||
// safety: The constructor of ReadToString called `prepare_buffer`.
|
||||
unsafe { read_to_string_internal(Pin::new(*me.reader), me.output, me.buf, me.read, cx) }
|
||||
read_to_string_internal(Pin::new(*me.reader), me.output, me.buf, me.read, cx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pin_project! {
|
||||
/// Stream for the [`split`](crate::io::AsyncBufReadExt::split) method.
|
||||
/// Splitter for the [`split`](crate::io::AsyncBufReadExt::split) method.
|
||||
///
|
||||
/// A `Split` can be turned into a `Stream` with [`SplitStream`].
|
||||
///
|
||||
/// [`SplitStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.SplitStream.html
|
||||
#[derive(Debug)]
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
use crate::io::ReadBuf;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
|
||||
impl Sealed for Vec<u8> {}
|
||||
impl Sealed for &mut Vec<u8> {}
|
||||
}
|
||||
|
||||
/// A sealed trait that constrains the generic type parameter in `VecWithInitialized<V>`. That struct's safety relies
|
||||
/// on certain invariants upheld by `Vec<u8>`.
|
||||
pub(crate) trait VecU8: AsMut<Vec<u8>> + private::Sealed {}
|
||||
|
||||
impl VecU8 for Vec<u8> {}
|
||||
impl VecU8 for &mut Vec<u8> {}
|
||||
/// This struct wraps a `Vec<u8>` or `&mut Vec<u8>`, combining it with a
|
||||
/// `num_initialized`, which keeps track of the number of initialized bytes
|
||||
/// in the unused capacity.
|
||||
///
|
||||
/// The purpose of this struct is to remember how many bytes were initialized
|
||||
/// through a `ReadBuf` from call to call.
|
||||
///
|
||||
/// This struct has the safety invariant that the first `num_initialized` of the
|
||||
/// vector's allocation must be initialized at any time.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct VecWithInitialized<V> {
|
||||
vec: V,
|
||||
// The number of initialized bytes in the vector.
|
||||
// Always between `vec.len()` and `vec.capacity()`.
|
||||
num_initialized: usize,
|
||||
}
|
||||
|
||||
impl VecWithInitialized<Vec<u8>> {
|
||||
#[cfg(feature = "io-util")]
|
||||
pub(crate) fn take(&mut self) -> Vec<u8> {
|
||||
self.num_initialized = 0;
|
||||
std::mem::take(&mut self.vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> VecWithInitialized<V>
|
||||
where
|
||||
V: VecU8,
|
||||
{
|
||||
pub(crate) fn new(mut vec: V) -> Self {
|
||||
// SAFETY: The safety invariants of vector guarantee that the bytes up
|
||||
// to its length are initialized.
|
||||
Self {
|
||||
num_initialized: vec.as_mut().len(),
|
||||
vec,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reserve(&mut self, num_bytes: usize) {
|
||||
let vec = self.vec.as_mut();
|
||||
if vec.capacity() - vec.len() >= num_bytes {
|
||||
return;
|
||||
}
|
||||
// SAFETY: Setting num_initialized to `vec.len()` is correct as
|
||||
// `reserve` does not change the length of the vector.
|
||||
self.num_initialized = vec.len();
|
||||
vec.reserve(num_bytes);
|
||||
}
|
||||
|
||||
#[cfg(feature = "io-util")]
|
||||
pub(crate) fn is_empty(&mut self) -> bool {
|
||||
self.vec.as_mut().is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn get_read_buf<'a>(&'a mut self) -> ReadBuf<'a> {
|
||||
let num_initialized = self.num_initialized;
|
||||
|
||||
// SAFETY: Creating the slice is safe because of the safety invariants
|
||||
// on Vec<u8>. The safety invariants of `ReadBuf` will further guarantee
|
||||
// that no bytes in the slice are de-initialized.
|
||||
let vec = self.vec.as_mut();
|
||||
let len = vec.len();
|
||||
let cap = vec.capacity();
|
||||
let ptr = vec.as_mut_ptr().cast::<MaybeUninit<u8>>();
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut::<'a, MaybeUninit<u8>>(ptr, cap) };
|
||||
|
||||
// SAFETY: This is safe because the safety invariants of
|
||||
// VecWithInitialized say that the first num_initialized bytes must be
|
||||
// initialized.
|
||||
let mut read_buf = ReadBuf::uninit(slice);
|
||||
unsafe {
|
||||
read_buf.assume_init(num_initialized);
|
||||
}
|
||||
read_buf.set_filled(len);
|
||||
|
||||
read_buf
|
||||
}
|
||||
|
||||
pub(crate) fn apply_read_buf(&mut self, parts: ReadBufParts) {
|
||||
let vec = self.vec.as_mut();
|
||||
assert_eq!(vec.as_ptr(), parts.ptr);
|
||||
|
||||
// SAFETY:
|
||||
// The ReadBufParts really does point inside `self.vec` due to the above
|
||||
// check, and the safety invariants of `ReadBuf` guarantee that the
|
||||
// first `parts.initialized` bytes of `self.vec` really have been
|
||||
// initialized. Additionally, `ReadBuf` guarantees that `parts.len` is
|
||||
// at most `parts.initialized`, so the first `parts.len` bytes are also
|
||||
// initialized.
|
||||
//
|
||||
// Note that this relies on the fact that `V` is either `Vec<u8>` or
|
||||
// `&mut Vec<u8>`, so the vector returned by `self.vec.as_mut()` cannot
|
||||
// change from call to call.
|
||||
unsafe {
|
||||
self.num_initialized = parts.initialized;
|
||||
vec.set_len(parts.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ReadBufParts {
|
||||
// Pointer is only used to check that the ReadBuf actually came from the
|
||||
// right VecWithInitialized.
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
initialized: usize,
|
||||
}
|
||||
|
||||
// This is needed to release the borrow on `VecWithInitialized<V>`.
|
||||
pub(crate) fn into_read_buf_parts(rb: ReadBuf<'_>) -> ReadBufParts {
|
||||
ReadBufParts {
|
||||
ptr: rb.filled().as_ptr(),
|
||||
len: rb.filled().len(),
|
||||
initialized: rb.initialized().len(),
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio/1.0.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio/1.0.2")]
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::large_enum_variant,
|
||||
@@ -301,7 +301,7 @@
|
||||
//! Beware though that this will pull in many extra dependencies that you may not
|
||||
//! need.
|
||||
//!
|
||||
//! - `full`: Enables all Tokio public API features listed below.
|
||||
//! - `full`: Enables all Tokio public API features listed below except `test-util`.
|
||||
//! - `rt`: Enables `tokio::spawn`, the basic (current thread) scheduler,
|
||||
//! and non-scheduler utilities.
|
||||
//! - `rt-multi-thread`: Enables the heavier, multi-threaded, work-stealing scheduler.
|
||||
@@ -314,7 +314,6 @@
|
||||
//! - `process`: Enables `tokio::process` types.
|
||||
//! - `macros`: Enables `#[tokio::main]` and `#[tokio::test]` macros.
|
||||
//! - `sync`: Enables all `tokio::sync` types.
|
||||
//! - `stream`: Enables optional `Stream` implementations for types within Tokio.
|
||||
//! - `signal`: Enables all `tokio::signal` types.
|
||||
//! - `fs`: Enables `tokio::fs` types.
|
||||
//! - `test-util`: Enables testing based infrastructure for the Tokio runtime.
|
||||
|
||||
@@ -24,8 +24,8 @@ mod imp {
|
||||
}
|
||||
|
||||
impl AtomicU64 {
|
||||
pub(crate) fn new(val: u64) -> AtomicU64 {
|
||||
AtomicU64 {
|
||||
pub(crate) fn new(val: u64) -> Self {
|
||||
Self {
|
||||
inner: Mutex::new(val),
|
||||
}
|
||||
}
|
||||
@@ -45,16 +45,31 @@ mod imp {
|
||||
prev
|
||||
}
|
||||
|
||||
pub(crate) fn compare_and_swap(&self, old: u64, new: u64, _: Ordering) -> u64 {
|
||||
pub(crate) fn compare_exchange(
|
||||
&self,
|
||||
current: u64,
|
||||
new: u64,
|
||||
_success: Ordering,
|
||||
_failure: Ordering,
|
||||
) -> Result<u64, u64> {
|
||||
let mut lock = self.inner.lock().unwrap();
|
||||
let prev = *lock;
|
||||
|
||||
if prev != old {
|
||||
return prev;
|
||||
if *lock == current {
|
||||
*lock = new;
|
||||
Ok(current)
|
||||
} else {
|
||||
Err(*lock)
|
||||
}
|
||||
}
|
||||
|
||||
*lock = new;
|
||||
prev
|
||||
pub(crate) fn compare_exchange_weak(
|
||||
&self,
|
||||
current: u64,
|
||||
new: u64,
|
||||
success: Ordering,
|
||||
failure: Ordering,
|
||||
) -> Result<u64, u64> {
|
||||
self.compare_exchange(current, new, success, failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ macro_rules! select {
|
||||
|
||||
(@ { $($t:tt)* } ) => {
|
||||
// No `else` branch
|
||||
$crate::select!(@{ $($t)*; unreachable!() })
|
||||
$crate::select!(@{ $($t)*; panic!("all branches are disabled and there is no else branch") })
|
||||
};
|
||||
(@ { $($t:tt)* } else => $else:expr $(,)?) => {
|
||||
$crate::select!(@{ $($t)*; $else })
|
||||
|
||||
@@ -14,6 +14,10 @@ cfg_net! {
|
||||
/// You can accept a new connection by using the [`accept`](`TcpListener::accept`)
|
||||
/// method.
|
||||
///
|
||||
/// A `TcpListener` can be turned into a `Stream` with [`TcpListenerStream`].
|
||||
///
|
||||
/// [`TcpListenerStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.TcpListenerStream.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Note that accepting a connection can lead to various errors and not all
|
||||
|
||||
@@ -17,6 +17,10 @@ use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
cfg_io_util! {
|
||||
use bytes::BufMut;
|
||||
}
|
||||
|
||||
cfg_net! {
|
||||
/// A TCP stream between a local and a remote socket.
|
||||
///
|
||||
@@ -559,6 +563,85 @@ impl TcpStream {
|
||||
.try_io(Interest::READABLE, || (&*self.io).read(buf))
|
||||
}
|
||||
|
||||
cfg_io_util! {
|
||||
/// Try to read data from the stream into the provided buffer, advancing the
|
||||
/// buffer's internal cursor, returning how many bytes were read.
|
||||
///
|
||||
/// Receives any pending data from the socket but does not wait for new data
|
||||
/// to arrive. On success, returns the number of bytes read. Because
|
||||
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
|
||||
/// the async task and can exist entirely on the stack.
|
||||
///
|
||||
/// Usually, [`readable()`] or [`ready()`] is used with this function.
|
||||
///
|
||||
/// [`readable()`]: TcpStream::readable()
|
||||
/// [`ready()`]: TcpStream::ready()
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
|
||||
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
|
||||
/// and will no longer yield data. If the stream is not ready to read data
|
||||
/// `Err(io::ErrorKind::WouldBlock)` is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::TcpStream;
|
||||
/// use std::error::Error;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// // Connect to a peer
|
||||
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// stream.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(4096);
|
||||
///
|
||||
/// // Try to read data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match stream.try_read_buf(&mut buf) {
|
||||
/// Ok(0) => break,
|
||||
/// Ok(n) => {
|
||||
/// println!("read {} bytes", n);
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
|
||||
self.io.registration().try_io(Interest::READABLE, || {
|
||||
use std::io::Read;
|
||||
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `TcpStream::read` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let n = (&*self.io).read(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok(n)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for the socket to become writable.
|
||||
///
|
||||
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
|
||||
|
||||
+147
-7
@@ -7,6 +7,10 @@ use std::io;
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
cfg_io_util! {
|
||||
use bytes::BufMut;
|
||||
}
|
||||
|
||||
cfg_net! {
|
||||
/// A UDP socket
|
||||
///
|
||||
@@ -18,8 +22,13 @@ cfg_net! {
|
||||
/// * one to one: [`connect`](`UdpSocket::connect`) and associate with a single address, using [`send`](`UdpSocket::send`)
|
||||
/// and [`recv`](`UdpSocket::recv`) to communicate only with that remote address
|
||||
///
|
||||
/// `UdpSocket` can also be used concurrently to `send_to` and `recv_from` in different tasks,
|
||||
/// all that's required is that you `Arc<UdpSocket>` and clone a reference for each task.
|
||||
/// This type does not provide a `split` method, because this functionality
|
||||
/// can be achieved by wrapping the socket in an [`Arc`]. Note that you do
|
||||
/// not need a `Mutex` to share the `UdpSocket` — an `Arc<UdpSocket>` is
|
||||
/// enough. This is because all of the methods take `&self` instead of `&mut
|
||||
/// self`.
|
||||
///
|
||||
/// [`Arc`]: std::sync::Arc
|
||||
///
|
||||
/// # Streams
|
||||
///
|
||||
@@ -74,11 +83,12 @@ cfg_net! {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Example: Sending/Receiving concurrently
|
||||
/// # Example: Splitting with `Arc`
|
||||
///
|
||||
/// Because `send_to` and `recv_from` take `&self`. It's perfectly alright to `Arc<UdpSocket>`
|
||||
/// and share the references to multiple tasks, in order to send/receive concurrently. Here is
|
||||
/// a similar "echo" example but that supports concurrent sending/receiving:
|
||||
/// Because `send_to` and `recv_from` take `&self`. It's perfectly alright
|
||||
/// to use an `Arc<UdpSocket>` and share the references to multiple tasks.
|
||||
/// Here is a similar "echo" example that supports concurrent
|
||||
/// sending/receiving:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::{net::UdpSocket, sync::mpsc};
|
||||
@@ -683,6 +693,137 @@ impl UdpSocket {
|
||||
.try_io(Interest::READABLE, || self.io.recv(buf))
|
||||
}
|
||||
|
||||
cfg_io_util! {
|
||||
/// Try to receive data from the stream into the provided buffer, advancing the
|
||||
/// buffer's internal cursor, returning how many bytes were read.
|
||||
///
|
||||
/// The function must be called with valid byte array buf of sufficient size
|
||||
/// to hold the message bytes. If a message is too long to fit in the
|
||||
/// supplied buffer, excess bytes may be discarded.
|
||||
///
|
||||
/// When there is no pending data, `Err(io::ErrorKind::WouldBlock)` is
|
||||
/// returned. This function is usually paired with `readable()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UdpSocket;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> io::Result<()> {
|
||||
/// // Connect to a peer
|
||||
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
|
||||
/// socket.connect("127.0.0.1:8081").await?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// socket.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(1024);
|
||||
///
|
||||
/// // Try to recv data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match socket.try_recv_buf(&mut buf) {
|
||||
/// Ok(n) => {
|
||||
/// println!("GOT {:?}", &buf[..n]);
|
||||
/// break;
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_recv_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
|
||||
self.io.registration().try_io(Interest::READABLE, || {
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `UdpSocket::recv` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let n = (&*self.io).recv(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok(n)
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to receive a single datagram message on the socket. On success,
|
||||
/// returns the number of bytes read and the origin.
|
||||
///
|
||||
/// The function must be called with valid byte array buf of sufficient size
|
||||
/// to hold the message bytes. If a message is too long to fit in the
|
||||
/// supplied buffer, excess bytes may be discarded.
|
||||
///
|
||||
/// When there is no pending data, `Err(io::ErrorKind::WouldBlock)` is
|
||||
/// returned. This function is usually paired with `readable()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UdpSocket;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> io::Result<()> {
|
||||
/// // Connect to a peer
|
||||
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// socket.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(1024);
|
||||
///
|
||||
/// // Try to recv data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match socket.try_recv_buf_from(&mut buf) {
|
||||
/// Ok((n, _addr)) => {
|
||||
/// println!("GOT {:?}", &buf[..n]);
|
||||
/// break;
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_recv_buf_from<B: BufMut>(&self, buf: &mut B) -> io::Result<(usize, SocketAddr)> {
|
||||
self.io.registration().try_io(Interest::READABLE, || {
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `UdpSocket::recv_from` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let (n, addr) = (&*self.io).recv_from(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok((n, addr))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the given address. On success, returns the
|
||||
/// number of bytes written.
|
||||
///
|
||||
@@ -904,7 +1045,6 @@ impl UdpSocket {
|
||||
/// async fn main() -> io::Result<()> {
|
||||
/// // Connect to a peer
|
||||
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
|
||||
/// socket.connect("127.0.0.1:8081").await?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
|
||||
@@ -10,17 +10,29 @@ use std::os::unix::net;
|
||||
use std::path::Path;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
cfg_io_util! {
|
||||
use bytes::BufMut;
|
||||
}
|
||||
|
||||
cfg_net_unix! {
|
||||
/// An I/O object representing a Unix datagram socket.
|
||||
///
|
||||
/// A socket can be either named (associated with a filesystem path) or
|
||||
/// unnamed.
|
||||
///
|
||||
/// This type does not provide a `split` method, because this functionality
|
||||
/// can be achieved by wrapping the socket in an [`Arc`]. Note that you do
|
||||
/// not need a `Mutex` to share the `UnixDatagram` — an `Arc<UnixDatagram>`
|
||||
/// is enough. This is because all of the methods take `&self` instead of
|
||||
/// `&mut self`.
|
||||
///
|
||||
/// **Note:** named sockets are persisted even after the object is dropped
|
||||
/// and the program has exited, and cannot be reconnected. It is advised
|
||||
/// that you either check for and unlink the existing socket if it exists,
|
||||
/// or use a temporary file that is guaranteed to not already exist.
|
||||
///
|
||||
/// [`Arc`]: std::sync::Arc
|
||||
///
|
||||
/// # Examples
|
||||
/// Using named sockets, associated with a filesystem path:
|
||||
/// ```
|
||||
@@ -652,6 +664,130 @@ impl UnixDatagram {
|
||||
.try_io(Interest::READABLE, || self.io.recv(buf))
|
||||
}
|
||||
|
||||
cfg_io_util! {
|
||||
/// Try to receive data from the socket without waiting.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UnixDatagram;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> io::Result<()> {
|
||||
/// // Connect to a peer
|
||||
/// let dir = tempfile::tempdir().unwrap();
|
||||
/// let client_path = dir.path().join("client.sock");
|
||||
/// let server_path = dir.path().join("server.sock");
|
||||
/// let socket = UnixDatagram::bind(&client_path)?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// socket.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(1024);
|
||||
///
|
||||
/// // Try to recv data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match socket.try_recv_buf_from(&mut buf) {
|
||||
/// Ok((n, _addr)) => {
|
||||
/// println!("GOT {:?}", &buf[..n]);
|
||||
/// break;
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_recv_buf_from<B: BufMut>(&self, buf: &mut B) -> io::Result<(usize, SocketAddr)> {
|
||||
let (n, addr) = self.io.registration().try_io(Interest::READABLE, || {
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `UnixDatagram::recv_from` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let (n, addr) = (&*self.io).recv_from(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok((n, addr))
|
||||
})?;
|
||||
|
||||
Ok((n, SocketAddr(addr)))
|
||||
}
|
||||
|
||||
/// Try to read data from the stream into the provided buffer, advancing the
|
||||
/// buffer's internal cursor, returning how many bytes were read.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UnixDatagram;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> io::Result<()> {
|
||||
/// // Connect to a peer
|
||||
/// let dir = tempfile::tempdir().unwrap();
|
||||
/// let client_path = dir.path().join("client.sock");
|
||||
/// let server_path = dir.path().join("server.sock");
|
||||
/// let socket = UnixDatagram::bind(&client_path)?;
|
||||
/// socket.connect(&server_path)?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// socket.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(1024);
|
||||
///
|
||||
/// // Try to recv data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match socket.try_recv_buf(&mut buf) {
|
||||
/// Ok(n) => {
|
||||
/// println!("GOT {:?}", &buf[..n]);
|
||||
/// break;
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_recv_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
|
||||
self.io.registration().try_io(Interest::READABLE, || {
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `UnixDatagram::recv` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let n = (&*self.io).recv(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok(n)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the specified address.
|
||||
///
|
||||
/// # Examples
|
||||
|
||||
@@ -14,6 +14,10 @@ cfg_net_unix! {
|
||||
///
|
||||
/// You can accept a new connection by using the [`accept`](`UnixListener::accept`) method.
|
||||
///
|
||||
/// A `UnixListener` can be turned into a `Stream` with [`UnixListenerStream`].
|
||||
///
|
||||
/// [`UnixListenerStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.UnixListenerStream.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Note that accepting a connection can lead to various errors and not all
|
||||
|
||||
@@ -15,6 +15,10 @@ use std::path::Path;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
cfg_io_util! {
|
||||
use bytes::BufMut;
|
||||
}
|
||||
|
||||
cfg_net_unix! {
|
||||
/// A structure representing a connected Unix socket.
|
||||
///
|
||||
@@ -267,6 +271,87 @@ impl UnixStream {
|
||||
.try_io(Interest::READABLE, || (&*self.io).read(buf))
|
||||
}
|
||||
|
||||
cfg_io_util! {
|
||||
/// Try to read data from the stream into the provided buffer, advancing the
|
||||
/// buffer's internal cursor, returning how many bytes were read.
|
||||
///
|
||||
/// Receives any pending data from the socket but does not wait for new data
|
||||
/// to arrive. On success, returns the number of bytes read. Because
|
||||
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
|
||||
/// the async task and can exist entirely on the stack.
|
||||
///
|
||||
/// Usually, [`readable()`] or [`ready()`] is used with this function.
|
||||
///
|
||||
/// [`readable()`]: UnixStream::readable()
|
||||
/// [`ready()`]: UnixStream::ready()
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
|
||||
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
|
||||
/// and will no longer yield data. If the stream is not ready to read data
|
||||
/// `Err(io::ErrorKind::WouldBlock)` is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UnixStream;
|
||||
/// use std::error::Error;
|
||||
/// use std::io;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// // Connect to a peer
|
||||
/// let dir = tempfile::tempdir().unwrap();
|
||||
/// let bind_path = dir.path().join("bind_path");
|
||||
/// let stream = UnixStream::connect(bind_path).await?;
|
||||
///
|
||||
/// loop {
|
||||
/// // Wait for the socket to be readable
|
||||
/// stream.readable().await?;
|
||||
///
|
||||
/// let mut buf = Vec::with_capacity(4096);
|
||||
///
|
||||
/// // Try to read data, this may still fail with `WouldBlock`
|
||||
/// // if the readiness event is a false positive.
|
||||
/// match stream.try_read_buf(&mut buf) {
|
||||
/// Ok(0) => break,
|
||||
/// Ok(n) => {
|
||||
/// println!("read {} bytes", n);
|
||||
/// }
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// continue;
|
||||
/// }
|
||||
/// Err(e) => {
|
||||
/// return Err(e.into());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
|
||||
self.io.registration().try_io(Interest::READABLE, || {
|
||||
use std::io::Read;
|
||||
|
||||
let dst = buf.chunk_mut();
|
||||
let dst =
|
||||
unsafe { &mut *(dst as *mut _ as *mut [std::mem::MaybeUninit<u8>] as *mut [u8]) };
|
||||
|
||||
// Safety: We trust `UnixStream::read` to have filled up `n` bytes in the
|
||||
// buffer.
|
||||
let n = (&*self.io).read(dst)?;
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(n);
|
||||
}
|
||||
|
||||
Ok(n)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for the socket to become writable.
|
||||
///
|
||||
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
|
||||
|
||||
@@ -839,15 +839,38 @@ pub struct Child {
|
||||
child: FusedChild,
|
||||
|
||||
/// The handle for writing to the child's standard input (stdin), if it has
|
||||
/// been captured.
|
||||
/// been captured. To avoid partially moving the `child` and thus blocking
|
||||
/// yourself from calling functions on `child` while using `stdin`, you might
|
||||
/// find it helpful to do:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
|
||||
/// let stdin = child.stdin.take().unwrap();
|
||||
/// ```
|
||||
pub stdin: Option<ChildStdin>,
|
||||
|
||||
/// The handle for reading from the child's standard output (stdout), if it
|
||||
/// has been captured.
|
||||
/// has been captured. You might find it helpful to do
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
|
||||
/// let stdout = child.stdout.take().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// to avoid partially moving the `child` and thus blocking yourself from calling
|
||||
/// functions on `child` while using `stdout`.
|
||||
pub stdout: Option<ChildStdout>,
|
||||
|
||||
/// The handle for reading from the child's standard error (stderr), if it
|
||||
/// has been captured.
|
||||
/// has been captured. You might find it helpful to do
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
|
||||
/// let stderr = child.stderr.take().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// to avoid partially moving the `child` and thus blocking yourself from calling
|
||||
/// functions on `child` while using `stderr`.
|
||||
pub stderr: Option<ChildStderr>,
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::runtime::builder::ThreadNameFn;
|
||||
use crate::runtime::context;
|
||||
use crate::runtime::task::{self, JoinHandle};
|
||||
use crate::runtime::{Builder, Callback, Handle};
|
||||
use crate::util::error::CONTEXT_MISSING_ERROR;
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt;
|
||||
@@ -81,7 +82,7 @@ where
|
||||
F: FnOnce() -> R + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let rt = context::current().expect("not currently running on the Tokio runtime.");
|
||||
let rt = context::current().expect(CONTEXT_MISSING_ERROR);
|
||||
rt.spawn_blocking(func)
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ where
|
||||
F: FnOnce() -> R + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let rt = context::current().expect("not currently running on the Tokio runtime.");
|
||||
let rt = context::current().expect(CONTEXT_MISSING_ERROR);
|
||||
|
||||
let (task, _handle) = task::joinable(BlockingTask::new(func));
|
||||
rt.blocking_spawner.spawn(task, &rt)
|
||||
|
||||
@@ -13,9 +13,9 @@ pub(crate) fn current() -> Option<Handle> {
|
||||
|
||||
cfg_io_driver! {
|
||||
pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle {
|
||||
CONTEXT.with(|ctx| match *ctx.borrow() {
|
||||
Some(ref ctx) => ctx.io_handle.clone(),
|
||||
None => Default::default(),
|
||||
CONTEXT.with(|ctx| {
|
||||
let ctx = ctx.borrow();
|
||||
ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).io_handle.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -23,18 +23,18 @@ cfg_io_driver! {
|
||||
cfg_signal_internal! {
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle {
|
||||
CONTEXT.with(|ctx| match *ctx.borrow() {
|
||||
Some(ref ctx) => ctx.signal_handle.clone(),
|
||||
None => Default::default(),
|
||||
CONTEXT.with(|ctx| {
|
||||
let ctx = ctx.borrow();
|
||||
ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).signal_handle.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cfg_time! {
|
||||
pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle {
|
||||
CONTEXT.with(|ctx| match *ctx.borrow() {
|
||||
Some(ref ctx) => ctx.time_handle.clone(),
|
||||
None => Default::default(),
|
||||
CONTEXT.with(|ctx| {
|
||||
let ctx = ctx.borrow();
|
||||
ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).time_handle.clone()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::runtime::blocking::task::BlockingTask;
|
||||
use crate::runtime::task::{self, JoinHandle};
|
||||
use crate::runtime::{blocking, context, driver, Spawner};
|
||||
use crate::util::error::CONTEXT_MISSING_ERROR;
|
||||
|
||||
use std::future::Future;
|
||||
use std::{error, fmt};
|
||||
@@ -97,7 +98,7 @@ impl Handle {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn current() -> Self {
|
||||
context::current().expect("not currently running on the Tokio runtime.")
|
||||
context::current().expect(CONTEXT_MISSING_ERROR)
|
||||
}
|
||||
|
||||
/// Returns a Handle view over the currently running Runtime
|
||||
@@ -213,7 +214,7 @@ impl fmt::Debug for TryCurrentError {
|
||||
|
||||
impl fmt::Display for TryCurrentError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("no tokio Runtime has been initialized")
|
||||
f.write_str(CONTEXT_MISSING_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//!
|
||||
//! Tokio's [`Runtime`] bundles all of these services as a single type, allowing
|
||||
//! them to be started, shut down, and configured together. However, often it is
|
||||
//! not required to configure a [`Runtime`] manually, and user may just use the
|
||||
//! not required to configure a [`Runtime`] manually, and a user may just use the
|
||||
//! [`tokio::main`] attribute macro, which creates a [`Runtime`] under the hood.
|
||||
//!
|
||||
//! # Usage
|
||||
@@ -114,7 +114,7 @@
|
||||
//!
|
||||
//! The multi-thread scheduler executes futures on a _thread pool_, using a
|
||||
//! work-stealing strategy. By default, it will start a worker thread for each
|
||||
//! CPU core available on the system. This tends to be the ideal configurations
|
||||
//! CPU core available on the system. This tends to be the ideal configuration
|
||||
//! for most applications. The multi-thread scheduler requires the `rt-multi-thread`
|
||||
//! feature flag, and is selected by default:
|
||||
//! ```
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::runtime::task;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
|
||||
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
|
||||
|
||||
/// Producer handle. May only be used from a single thread.
|
||||
pub(super) struct Local<T: 'static> {
|
||||
@@ -194,13 +194,17 @@ impl<T> Local<T> {
|
||||
// work. This is because all tasks are pushed into the queue from the
|
||||
// current thread (or memory has been acquired if the local queue handle
|
||||
// moved).
|
||||
let actual = self.inner.head.compare_and_swap(
|
||||
prev,
|
||||
pack(head.wrapping_add(n), head.wrapping_add(n)),
|
||||
Release,
|
||||
);
|
||||
|
||||
if actual != prev {
|
||||
if self
|
||||
.inner
|
||||
.head
|
||||
.compare_exchange(
|
||||
prev,
|
||||
pack(head.wrapping_add(n), head.wrapping_add(n)),
|
||||
Release,
|
||||
Relaxed,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
// We failed to claim the tasks, losing the race. Return out of
|
||||
// this function and try the full `push` routine again. The queue
|
||||
// may not be full anymore.
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
use crate::loom::cell::UnsafeCell;
|
||||
use crate::runtime::task::raw::{self, Vtable};
|
||||
use crate::runtime::task::state::State;
|
||||
use crate::runtime::task::waker::waker_ref;
|
||||
use crate::runtime::task::{Notified, Schedule, Task};
|
||||
use crate::util::linked_list;
|
||||
|
||||
@@ -37,15 +36,23 @@ pub(super) struct Cell<T: Future, S> {
|
||||
pub(super) trailer: Trailer,
|
||||
}
|
||||
|
||||
pub(super) struct Scheduler<S> {
|
||||
scheduler: UnsafeCell<Option<S>>,
|
||||
}
|
||||
|
||||
pub(super) struct CoreStage<T: Future> {
|
||||
stage: UnsafeCell<Stage<T>>,
|
||||
}
|
||||
|
||||
/// The core of the task.
|
||||
///
|
||||
/// Holds the future or output, depending on the stage of execution.
|
||||
pub(super) struct Core<T: Future, S> {
|
||||
/// Scheduler used to drive this future
|
||||
pub(super) scheduler: UnsafeCell<Option<S>>,
|
||||
pub(super) scheduler: Scheduler<S>,
|
||||
|
||||
/// Either the future or the output
|
||||
pub(super) stage: UnsafeCell<Stage<T>>,
|
||||
pub(super) stage: CoreStage<T>,
|
||||
}
|
||||
|
||||
/// Crate public as this is also needed by the pool.
|
||||
@@ -95,8 +102,12 @@ impl<T: Future, S: Schedule> Cell<T, S> {
|
||||
vtable: raw::vtable::<T, S>(),
|
||||
},
|
||||
core: Core {
|
||||
scheduler: UnsafeCell::new(None),
|
||||
stage: UnsafeCell::new(Stage::Running(future)),
|
||||
scheduler: Scheduler {
|
||||
scheduler: UnsafeCell::new(None),
|
||||
},
|
||||
stage: CoreStage {
|
||||
stage: UnsafeCell::new(Stage::Running(future)),
|
||||
},
|
||||
},
|
||||
trailer: Trailer {
|
||||
waker: UnsafeCell::new(None),
|
||||
@@ -105,7 +116,11 @@ impl<T: Future, S: Schedule> Cell<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Future, S: Schedule> Core<T, S> {
|
||||
impl<S: Schedule> Scheduler<S> {
|
||||
pub(super) fn with_mut<R>(&self, f: impl FnOnce(*mut Option<S>) -> R) -> R {
|
||||
self.scheduler.with_mut(f)
|
||||
}
|
||||
|
||||
/// Bind a scheduler to the task.
|
||||
///
|
||||
/// This only happens on the first poll and must be preceeded by a call to
|
||||
@@ -140,6 +155,58 @@ impl<T: Future, S: Schedule> Core<T, S> {
|
||||
self.scheduler.with(|ptr| unsafe { (*ptr).is_some() })
|
||||
}
|
||||
|
||||
/// Schedule the future for execution
|
||||
pub(super) fn schedule(&self, task: Notified<S>) {
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.schedule(task),
|
||||
None => panic!("no scheduler set"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Schedule the future for execution in the near future, yielding the
|
||||
/// thread to other tasks.
|
||||
pub(super) fn yield_now(&self, task: Notified<S>) {
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.yield_now(task),
|
||||
None => panic!("no scheduler set"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Release the task
|
||||
///
|
||||
/// If the `Scheduler` implementation is able to, it returns the `Task`
|
||||
/// handle immediately. The caller of this function will batch a ref-dec
|
||||
/// with a state change.
|
||||
pub(super) fn release(&self, task: Task<S>) -> Option<Task<S>> {
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
let task = ManuallyDrop::new(task);
|
||||
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.release(&*task),
|
||||
// Task was never polled
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Future> CoreStage<T> {
|
||||
pub(super) fn with_mut<R>(&self, f: impl FnOnce(*mut Stage<T>) -> R) -> R {
|
||||
self.stage.with_mut(f)
|
||||
}
|
||||
|
||||
/// Poll the future
|
||||
///
|
||||
/// # Safety
|
||||
@@ -153,7 +220,7 @@ impl<T: Future, S: Schedule> Core<T, S> {
|
||||
///
|
||||
/// `self` must also be pinned. This is handled by storing the task on the
|
||||
/// heap.
|
||||
pub(super) fn poll(&self, header: &Header) -> Poll<T::Output> {
|
||||
pub(super) fn poll(&self, mut cx: Context<'_>) -> Poll<T::Output> {
|
||||
let res = {
|
||||
self.stage.with_mut(|ptr| {
|
||||
// Safety: The caller ensures mutual exclusion to the field.
|
||||
@@ -165,11 +232,6 @@ impl<T: Future, S: Schedule> Core<T, S> {
|
||||
// Safety: The caller ensures the future is pinned.
|
||||
let future = unsafe { Pin::new_unchecked(future) };
|
||||
|
||||
// The waker passed into the `poll` function does not require a ref
|
||||
// count increment.
|
||||
let waker_ref = waker_ref::<T, S>(header);
|
||||
let mut cx = Context::from_waker(&*waker_ref);
|
||||
|
||||
future.poll(&mut cx)
|
||||
})
|
||||
};
|
||||
@@ -221,52 +283,6 @@ impl<T: Future, S: Schedule> Core<T, S> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Schedule the future for execution
|
||||
pub(super) fn schedule(&self, task: Notified<S>) {
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.schedule(task),
|
||||
None => panic!("no scheduler set"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Schedule the future for execution in the near future, yielding the
|
||||
/// thread to other tasks.
|
||||
pub(super) fn yield_now(&self, task: Notified<S>) {
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.yield_now(task),
|
||||
None => panic!("no scheduler set"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Release the task
|
||||
///
|
||||
/// If the `Scheduler` implementation is able to, it returns the `Task`
|
||||
/// handle immediately. The caller of this function will batch a ref-dec
|
||||
/// with a state change.
|
||||
pub(super) fn release(&self, task: Task<S>) -> Option<Task<S>> {
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
let task = ManuallyDrop::new(task);
|
||||
|
||||
self.scheduler.with(|ptr| {
|
||||
// Safety: Can only be called after initial `poll`, which is the
|
||||
// only time the field is mutated.
|
||||
match unsafe { &*ptr } {
|
||||
Some(scheduler) => scheduler.release(&*task),
|
||||
// Task was never polled
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cfg_rt_multi_thread! {
|
||||
@@ -280,6 +296,26 @@ cfg_rt_multi_thread! {
|
||||
}
|
||||
}
|
||||
|
||||
impl Trailer {
|
||||
pub(crate) unsafe fn set_waker(&self, waker: Option<Waker>) {
|
||||
self.waker.with_mut(|ptr| {
|
||||
*ptr = waker;
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn will_wake(&self, waker: &Waker) -> bool {
|
||||
self.waker
|
||||
.with(|ptr| (*ptr).as_ref().unwrap().will_wake(waker))
|
||||
}
|
||||
|
||||
pub(crate) fn wake_join(&self) {
|
||||
self.waker.with(|ptr| match unsafe { &*ptr } {
|
||||
Some(waker) => waker.wake_by_ref(),
|
||||
None => panic!("waker missing"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(loom))]
|
||||
fn header_lte_cache_line() {
|
||||
|
||||
+291
-216
@@ -1,12 +1,13 @@
|
||||
use crate::runtime::task::core::{Cell, Core, Header, Trailer};
|
||||
use crate::runtime::task::core::{Cell, Core, CoreStage, Header, Scheduler, Trailer};
|
||||
use crate::runtime::task::state::Snapshot;
|
||||
use crate::runtime::task::waker::waker_ref;
|
||||
use crate::runtime::task::{JoinError, Notified, Schedule, Task};
|
||||
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
use std::panic;
|
||||
use std::ptr::NonNull;
|
||||
use std::task::{Poll, Waker};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
/// Typed raw task handle
|
||||
pub(super) struct Harness<T: Future, S: 'static> {
|
||||
@@ -35,6 +36,13 @@ where
|
||||
fn core(&self) -> &Core<T, S> {
|
||||
unsafe { &self.cell.as_ref().core }
|
||||
}
|
||||
|
||||
fn scheduler_view(&self) -> SchedulerView<'_, S> {
|
||||
SchedulerView {
|
||||
header: self.header(),
|
||||
scheduler: &self.core().scheduler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Harness<T, S>
|
||||
@@ -48,102 +56,46 @@ where
|
||||
///
|
||||
/// Panics raised while polling the future are handled.
|
||||
pub(super) fn poll(self) {
|
||||
// If this is the first time the task is polled, the task will be bound
|
||||
// to the scheduler, in which case the task ref count must be
|
||||
// incremented.
|
||||
let is_not_bound = !self.core().is_bound();
|
||||
|
||||
// Transition the task to the running state.
|
||||
//
|
||||
// A failure to transition here indicates the task has been cancelled
|
||||
// while in the run queue pending execution.
|
||||
let snapshot = match self.header().state.transition_to_running(is_not_bound) {
|
||||
Ok(snapshot) => snapshot,
|
||||
Err(_) => {
|
||||
// The task was shutdown while in the run queue. At this point,
|
||||
// we just hold a ref counted reference. Drop it here.
|
||||
match self.poll_inner() {
|
||||
PollFuture::Notified => {
|
||||
// Signal yield
|
||||
self.core().scheduler.yield_now(Notified(self.to_task()));
|
||||
// The ref-count was incremented as part of
|
||||
// `transition_to_idle`.
|
||||
self.drop_reference();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if is_not_bound {
|
||||
// Ensure the task is bound to a scheduler instance. Since this is
|
||||
// the first time polling the task, a scheduler instance is pulled
|
||||
// from the local context and assigned to the task.
|
||||
//
|
||||
// The scheduler maintains ownership of the task and responds to
|
||||
// `wake` calls.
|
||||
//
|
||||
// The task reference count has been incremented.
|
||||
//
|
||||
// Safety: Since we have unique access to the task so that we can
|
||||
// safely call `bind_scheduler`.
|
||||
self.core().bind_scheduler(self.to_task());
|
||||
PollFuture::DropReference => {
|
||||
self.drop_reference();
|
||||
}
|
||||
PollFuture::Complete(out, is_join_interested) => {
|
||||
self.complete(out, is_join_interested);
|
||||
}
|
||||
PollFuture::None => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_inner(&self) -> PollFuture<T::Output> {
|
||||
let snapshot = match self.scheduler_view().transition_to_running() {
|
||||
TransitionToRunning::Ok(snapshot) => snapshot,
|
||||
TransitionToRunning::DropReference => return PollFuture::DropReference,
|
||||
};
|
||||
|
||||
// The transition to `Running` done above ensures that a lock on the
|
||||
// future has been obtained. This also ensures the `*mut T` pointer
|
||||
// contains the future (as opposed to the output) and is initialized.
|
||||
|
||||
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
struct Guard<'a, T: Future, S: Schedule> {
|
||||
core: &'a Core<T, S>,
|
||||
}
|
||||
|
||||
impl<T: Future, S: Schedule> Drop for Guard<'_, T, S> {
|
||||
fn drop(&mut self) {
|
||||
self.core.drop_future_or_output();
|
||||
}
|
||||
}
|
||||
|
||||
let guard = Guard { core: self.core() };
|
||||
|
||||
// If the task is cancelled, avoid polling it, instead signalling it
|
||||
// is complete.
|
||||
if snapshot.is_cancelled() {
|
||||
Poll::Ready(Err(JoinError::cancelled()))
|
||||
} else {
|
||||
let res = guard.core.poll(self.header());
|
||||
|
||||
// prevent the guard from dropping the future
|
||||
mem::forget(guard);
|
||||
|
||||
res.map(Ok)
|
||||
}
|
||||
}));
|
||||
|
||||
match res {
|
||||
Ok(Poll::Ready(out)) => {
|
||||
self.complete(out, snapshot.is_join_interested());
|
||||
}
|
||||
Ok(Poll::Pending) => {
|
||||
match self.header().state.transition_to_idle() {
|
||||
Ok(snapshot) => {
|
||||
if snapshot.is_notified() {
|
||||
// Signal yield
|
||||
self.core().yield_now(Notified(self.to_task()));
|
||||
// The ref-count was incremented as part of
|
||||
// `transition_to_idle`.
|
||||
self.drop_reference();
|
||||
}
|
||||
}
|
||||
Err(_) => self.cancel_task(),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
self.complete(Err(JoinError::panic(err)), snapshot.is_join_interested());
|
||||
}
|
||||
}
|
||||
let waker_ref = waker_ref::<T, S>(self.header());
|
||||
let cx = Context::from_waker(&*waker_ref);
|
||||
poll_future(self.header(), &self.core().stage, snapshot, cx)
|
||||
}
|
||||
|
||||
pub(super) fn dealloc(self) {
|
||||
// Release the join waker, if there is one.
|
||||
self.trailer().waker.with_mut(|_| ());
|
||||
self.trailer().waker.with_mut(drop);
|
||||
|
||||
// Check causality
|
||||
self.core().stage.with_mut(|_| {});
|
||||
self.core().scheduler.with_mut(|_| {});
|
||||
self.core().stage.with_mut(drop);
|
||||
self.core().scheduler.with_mut(drop);
|
||||
|
||||
unsafe {
|
||||
drop(Box::from_raw(self.cell.as_ptr()));
|
||||
@@ -154,83 +106,9 @@ where
|
||||
|
||||
/// Read the task output into `dst`.
|
||||
pub(super) fn try_read_output(self, dst: &mut Poll<super::Result<T::Output>>, waker: &Waker) {
|
||||
// Load a snapshot of the current task state
|
||||
let snapshot = self.header().state.load();
|
||||
|
||||
debug_assert!(snapshot.is_join_interested());
|
||||
|
||||
if !snapshot.is_complete() {
|
||||
// The waker must be stored in the task struct.
|
||||
let res = if snapshot.has_join_waker() {
|
||||
// There already is a waker stored in the struct. If it matches
|
||||
// the provided waker, then there is no further work to do.
|
||||
// Otherwise, the waker must be swapped.
|
||||
let will_wake = unsafe {
|
||||
// Safety: when `JOIN_INTEREST` is set, only `JOIN_HANDLE`
|
||||
// may mutate the `waker` field.
|
||||
self.trailer()
|
||||
.waker
|
||||
.with(|ptr| (*ptr).as_ref().unwrap().will_wake(waker))
|
||||
};
|
||||
|
||||
if will_wake {
|
||||
// The task is not complete **and** the waker is up to date,
|
||||
// there is nothing further that needs to be done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Unset the `JOIN_WAKER` to gain mutable access to the `waker`
|
||||
// field then update the field with the new join worker.
|
||||
//
|
||||
// This requires two atomic operations, unsetting the bit and
|
||||
// then resetting it. If the task transitions to complete
|
||||
// concurrently to either one of those operations, then setting
|
||||
// the join waker fails and we proceed to reading the task
|
||||
// output.
|
||||
self.header()
|
||||
.state
|
||||
.unset_waker()
|
||||
.and_then(|snapshot| self.set_join_waker(waker.clone(), snapshot))
|
||||
} else {
|
||||
self.set_join_waker(waker.clone(), snapshot)
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(_) => return,
|
||||
Err(snapshot) => {
|
||||
assert!(snapshot.is_complete());
|
||||
}
|
||||
}
|
||||
if can_read_output(self.header(), self.trailer(), waker) {
|
||||
*dst = Poll::Ready(self.core().stage.take_output());
|
||||
}
|
||||
|
||||
*dst = Poll::Ready(self.core().take_output());
|
||||
}
|
||||
|
||||
fn set_join_waker(&self, waker: Waker, snapshot: Snapshot) -> Result<Snapshot, Snapshot> {
|
||||
assert!(snapshot.is_join_interested());
|
||||
assert!(!snapshot.has_join_waker());
|
||||
|
||||
// Safety: Only the `JoinHandle` may set the `waker` field. When
|
||||
// `JOIN_INTEREST` is **not** set, nothing else will touch the field.
|
||||
unsafe {
|
||||
self.trailer().waker.with_mut(|ptr| {
|
||||
*ptr = Some(waker);
|
||||
});
|
||||
}
|
||||
|
||||
// Update the `JoinWaker` state accordingly
|
||||
let res = self.header().state.set_join_waker();
|
||||
|
||||
// If the state could not be updated, then clear the join waker
|
||||
if res.is_err() {
|
||||
unsafe {
|
||||
self.trailer().waker.with_mut(|ptr| {
|
||||
*ptr = None;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(super) fn drop_join_handle_slow(self) {
|
||||
@@ -242,7 +120,7 @@ where
|
||||
// the scheduler or `JoinHandle`. i.e. if the output remains in the
|
||||
// task structure until the task is deallocated, it may be dropped
|
||||
// by a Waker on any arbitrary thread.
|
||||
self.core().drop_future_or_output();
|
||||
self.core().stage.drop_future_or_output();
|
||||
}
|
||||
|
||||
// Drop the `JoinHandle` reference, possibly deallocating the task
|
||||
@@ -258,7 +136,7 @@ where
|
||||
|
||||
pub(super) fn wake_by_ref(&self) {
|
||||
if self.header().state.transition_to_notified() {
|
||||
self.core().schedule(Notified(self.to_task()));
|
||||
self.core().scheduler.schedule(Notified(self.to_task()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,44 +160,65 @@ where
|
||||
|
||||
// By transitioning the lifcycle to `Running`, we have permission to
|
||||
// drop the future.
|
||||
self.cancel_task();
|
||||
let err = cancel_task(&self.core().stage);
|
||||
self.complete(Err(err), true)
|
||||
}
|
||||
|
||||
// ====== internal ======
|
||||
|
||||
fn cancel_task(self) {
|
||||
// Drop the future from a panic guard.
|
||||
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
self.core().drop_future_or_output();
|
||||
}));
|
||||
|
||||
if let Err(err) = res {
|
||||
// Dropping the future panicked, complete the join
|
||||
// handle with the panic to avoid dropping the panic
|
||||
// on the ground.
|
||||
self.complete(Err(JoinError::panic(err)), true);
|
||||
} else {
|
||||
self.complete(Err(JoinError::cancelled()), true);
|
||||
}
|
||||
}
|
||||
|
||||
fn complete(mut self, output: super::Result<T::Output>, is_join_interested: bool) {
|
||||
fn complete(self, output: super::Result<T::Output>, is_join_interested: bool) {
|
||||
if is_join_interested {
|
||||
// Store the output. The future has already been dropped
|
||||
//
|
||||
// Safety: Mutual exclusion is obtained by having transitioned the task
|
||||
// state -> Running
|
||||
self.core().store_output(output);
|
||||
let stage = &self.core().stage;
|
||||
stage.store_output(output);
|
||||
|
||||
// Transition to `Complete`, notifying the `JoinHandle` if necessary.
|
||||
self.transition_to_complete();
|
||||
transition_to_complete(self.header(), stage, &self.trailer());
|
||||
}
|
||||
|
||||
// The task has completed execution and will no longer be scheduled.
|
||||
//
|
||||
// Attempts to batch a ref-dec with the state transition below.
|
||||
let ref_dec = if self.core().is_bound() {
|
||||
if let Some(task) = self.core().release(self.to_task()) {
|
||||
|
||||
if self
|
||||
.scheduler_view()
|
||||
.transition_to_terminal(is_join_interested)
|
||||
{
|
||||
self.dealloc()
|
||||
}
|
||||
}
|
||||
|
||||
fn to_task(&self) -> Task<S> {
|
||||
self.scheduler_view().to_task()
|
||||
}
|
||||
}
|
||||
|
||||
enum TransitionToRunning {
|
||||
Ok(Snapshot),
|
||||
DropReference,
|
||||
}
|
||||
|
||||
struct SchedulerView<'a, S> {
|
||||
header: &'a Header,
|
||||
scheduler: &'a Scheduler<S>,
|
||||
}
|
||||
|
||||
impl<'a, S> SchedulerView<'a, S>
|
||||
where
|
||||
S: Schedule,
|
||||
{
|
||||
fn to_task(&self) -> Task<S> {
|
||||
// SAFETY The header is from the same struct containing the scheduler `S` so the cast is safe
|
||||
unsafe { Task::from_raw(self.header.into()) }
|
||||
}
|
||||
|
||||
/// Returns true if the task should be deallocated.
|
||||
fn transition_to_terminal(&self, is_join_interested: bool) -> bool {
|
||||
let ref_dec = if self.scheduler.is_bound() {
|
||||
if let Some(task) = self.scheduler.release(self.to_task()) {
|
||||
mem::forget(task);
|
||||
true
|
||||
} else {
|
||||
@@ -331,41 +230,217 @@ where
|
||||
|
||||
// This might deallocate
|
||||
let snapshot = self
|
||||
.header()
|
||||
.header
|
||||
.state
|
||||
.transition_to_terminal(!is_join_interested, ref_dec);
|
||||
|
||||
if snapshot.ref_count() == 0 {
|
||||
self.dealloc()
|
||||
snapshot.ref_count() == 0
|
||||
}
|
||||
|
||||
fn transition_to_running(&self) -> TransitionToRunning {
|
||||
// If this is the first time the task is polled, the task will be bound
|
||||
// to the scheduler, in which case the task ref count must be
|
||||
// incremented.
|
||||
let is_not_bound = !self.scheduler.is_bound();
|
||||
|
||||
// Transition the task to the running state.
|
||||
//
|
||||
// A failure to transition here indicates the task has been cancelled
|
||||
// while in the run queue pending execution.
|
||||
let snapshot = match self.header.state.transition_to_running(is_not_bound) {
|
||||
Ok(snapshot) => snapshot,
|
||||
Err(_) => {
|
||||
// The task was shutdown while in the run queue. At this point,
|
||||
// we just hold a ref counted reference. Since we do not have access to it here
|
||||
// return `DropReference` so the caller drops it.
|
||||
return TransitionToRunning::DropReference;
|
||||
}
|
||||
};
|
||||
|
||||
if is_not_bound {
|
||||
// Ensure the task is bound to a scheduler instance. Since this is
|
||||
// the first time polling the task, a scheduler instance is pulled
|
||||
// from the local context and assigned to the task.
|
||||
//
|
||||
// The scheduler maintains ownership of the task and responds to
|
||||
// `wake` calls.
|
||||
//
|
||||
// The task reference count has been incremented.
|
||||
//
|
||||
// Safety: Since we have unique access to the task so that we can
|
||||
// safely call `bind_scheduler`.
|
||||
self.scheduler.bind_scheduler(self.to_task());
|
||||
}
|
||||
}
|
||||
|
||||
/// Transitions the task's lifecycle to `Complete`. Notifies the
|
||||
/// `JoinHandle` if it still has interest in the completion.
|
||||
fn transition_to_complete(&mut self) {
|
||||
// Transition the task's lifecycle to `Complete` and get a snapshot of
|
||||
// the task's sate.
|
||||
let snapshot = self.header().state.transition_to_complete();
|
||||
|
||||
if !snapshot.is_join_interested() {
|
||||
// The `JoinHandle` is not interested in the output of this task. It
|
||||
// is our responsibility to drop the output.
|
||||
self.core().drop_future_or_output();
|
||||
} else if snapshot.has_join_waker() {
|
||||
// Notify the join handle. The previous transition obtains the
|
||||
// lock on the waker cell.
|
||||
self.wake_join();
|
||||
}
|
||||
}
|
||||
|
||||
fn wake_join(&self) {
|
||||
self.trailer().waker.with(|ptr| match unsafe { &*ptr } {
|
||||
Some(waker) => waker.wake_by_ref(),
|
||||
None => panic!("waker missing"),
|
||||
});
|
||||
}
|
||||
|
||||
fn to_task(&self) -> Task<S> {
|
||||
unsafe { Task::from_raw(self.header().into()) }
|
||||
TransitionToRunning::Ok(snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transitions the task's lifecycle to `Complete`. Notifies the
|
||||
/// `JoinHandle` if it still has interest in the completion.
|
||||
fn transition_to_complete<T>(header: &Header, stage: &CoreStage<T>, trailer: &Trailer)
|
||||
where
|
||||
T: Future,
|
||||
{
|
||||
// Transition the task's lifecycle to `Complete` and get a snapshot of
|
||||
// the task's sate.
|
||||
let snapshot = header.state.transition_to_complete();
|
||||
|
||||
if !snapshot.is_join_interested() {
|
||||
// The `JoinHandle` is not interested in the output of this task. It
|
||||
// is our responsibility to drop the output.
|
||||
stage.drop_future_or_output();
|
||||
} else if snapshot.has_join_waker() {
|
||||
// Notify the join handle. The previous transition obtains the
|
||||
// lock on the waker cell.
|
||||
trailer.wake_join();
|
||||
}
|
||||
}
|
||||
|
||||
fn can_read_output(header: &Header, trailer: &Trailer, waker: &Waker) -> bool {
|
||||
// Load a snapshot of the current task state
|
||||
let snapshot = header.state.load();
|
||||
|
||||
debug_assert!(snapshot.is_join_interested());
|
||||
|
||||
if !snapshot.is_complete() {
|
||||
// The waker must be stored in the task struct.
|
||||
let res = if snapshot.has_join_waker() {
|
||||
// There already is a waker stored in the struct. If it matches
|
||||
// the provided waker, then there is no further work to do.
|
||||
// Otherwise, the waker must be swapped.
|
||||
let will_wake = unsafe {
|
||||
// Safety: when `JOIN_INTEREST` is set, only `JOIN_HANDLE`
|
||||
// may mutate the `waker` field.
|
||||
trailer.will_wake(waker)
|
||||
};
|
||||
|
||||
if will_wake {
|
||||
// The task is not complete **and** the waker is up to date,
|
||||
// there is nothing further that needs to be done.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unset the `JOIN_WAKER` to gain mutable access to the `waker`
|
||||
// field then update the field with the new join worker.
|
||||
//
|
||||
// This requires two atomic operations, unsetting the bit and
|
||||
// then resetting it. If the task transitions to complete
|
||||
// concurrently to either one of those operations, then setting
|
||||
// the join waker fails and we proceed to reading the task
|
||||
// output.
|
||||
header
|
||||
.state
|
||||
.unset_waker()
|
||||
.and_then(|snapshot| set_join_waker(header, trailer, waker.clone(), snapshot))
|
||||
} else {
|
||||
set_join_waker(header, trailer, waker.clone(), snapshot)
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(_) => return false,
|
||||
Err(snapshot) => {
|
||||
assert!(snapshot.is_complete());
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn set_join_waker(
|
||||
header: &Header,
|
||||
trailer: &Trailer,
|
||||
waker: Waker,
|
||||
snapshot: Snapshot,
|
||||
) -> Result<Snapshot, Snapshot> {
|
||||
assert!(snapshot.is_join_interested());
|
||||
assert!(!snapshot.has_join_waker());
|
||||
|
||||
// Safety: Only the `JoinHandle` may set the `waker` field. When
|
||||
// `JOIN_INTEREST` is **not** set, nothing else will touch the field.
|
||||
unsafe {
|
||||
trailer.set_waker(Some(waker));
|
||||
}
|
||||
|
||||
// Update the `JoinWaker` state accordingly
|
||||
let res = header.state.set_join_waker();
|
||||
|
||||
// If the state could not be updated, then clear the join waker
|
||||
if res.is_err() {
|
||||
unsafe {
|
||||
trailer.set_waker(None);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
enum PollFuture<T> {
|
||||
Complete(Result<T, JoinError>, bool),
|
||||
DropReference,
|
||||
Notified,
|
||||
None,
|
||||
}
|
||||
|
||||
fn cancel_task<T: Future>(stage: &CoreStage<T>) -> JoinError {
|
||||
// Drop the future from a panic guard.
|
||||
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
stage.drop_future_or_output();
|
||||
}));
|
||||
|
||||
if let Err(err) = res {
|
||||
// Dropping the future panicked, complete the join
|
||||
// handle with the panic to avoid dropping the panic
|
||||
// on the ground.
|
||||
JoinError::panic(err)
|
||||
} else {
|
||||
JoinError::cancelled()
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_future<T: Future>(
|
||||
header: &Header,
|
||||
core: &CoreStage<T>,
|
||||
snapshot: Snapshot,
|
||||
cx: Context<'_>,
|
||||
) -> PollFuture<T::Output> {
|
||||
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
struct Guard<'a, T: Future> {
|
||||
core: &'a CoreStage<T>,
|
||||
}
|
||||
|
||||
impl<T: Future> Drop for Guard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
self.core.drop_future_or_output();
|
||||
}
|
||||
}
|
||||
|
||||
let guard = Guard { core };
|
||||
|
||||
// If the task is cancelled, avoid polling it, instead signalling it
|
||||
// is complete.
|
||||
if snapshot.is_cancelled() {
|
||||
Poll::Ready(Err(JoinError::cancelled()))
|
||||
} else {
|
||||
let res = guard.core.poll(cx);
|
||||
|
||||
// prevent the guard from dropping the future
|
||||
mem::forget(guard);
|
||||
|
||||
res.map(Ok)
|
||||
}
|
||||
}));
|
||||
match res {
|
||||
Ok(Poll::Pending) => match header.state.transition_to_idle() {
|
||||
Ok(snapshot) => {
|
||||
if snapshot.is_notified() {
|
||||
PollFuture::Notified
|
||||
} else {
|
||||
PollFuture::None
|
||||
}
|
||||
}
|
||||
Err(_) => PollFuture::Complete(Err(cancel_task(core)), true),
|
||||
},
|
||||
Ok(Poll::Ready(ok)) => PollFuture::Complete(ok, snapshot.is_join_interested()),
|
||||
Err(err) => PollFuture::Complete(Err(JoinError::panic(err)), snapshot.is_join_interested()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl Idle {
|
||||
if sleepers[index] == worker_id {
|
||||
sleepers.swap_remove(index);
|
||||
|
||||
// Update the state accordingly whle the lock is held.
|
||||
// Update the state accordingly while the lock is held.
|
||||
State::unpark_one(&self.state);
|
||||
|
||||
return;
|
||||
|
||||
@@ -337,7 +337,7 @@ impl Context {
|
||||
}
|
||||
|
||||
fn run_task(&self, task: Notified, mut core: Box<Core>) -> RunResult {
|
||||
// Make sure thew orker is not in the **searching** state. This enables
|
||||
// Make sure the worker is not in the **searching** state. This enables
|
||||
// another idle worker to try to steal work.
|
||||
core.transition_from_searching(&self.worker);
|
||||
|
||||
|
||||
+12
-42
@@ -361,38 +361,16 @@ struct RecvGuard<'a, T> {
|
||||
}
|
||||
|
||||
/// Receive a value future
|
||||
struct Recv<R, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
{
|
||||
struct Recv<'a, T> {
|
||||
/// Receiver being waited on
|
||||
receiver: R,
|
||||
receiver: &'a mut Receiver<T>,
|
||||
|
||||
/// Entry in the waiter `LinkedList`
|
||||
waiter: UnsafeCell<Waiter>,
|
||||
|
||||
_p: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
/// `AsMut<T>` is not implemented for `T` (coherence). Explicitly implementing
|
||||
/// `AsMut` for `Receiver` would be included in the public API of the receiver
|
||||
/// type. Instead, `Borrow` is used internally to bridge the gap.
|
||||
struct Borrow<T>(T);
|
||||
|
||||
impl<T> AsMut<Receiver<T>> for Borrow<Receiver<T>> {
|
||||
fn as_mut(&mut self) -> &mut Receiver<T> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsMut<Receiver<T>> for Borrow<&'a mut Receiver<T>> {
|
||||
fn as_mut(&mut self) -> &mut Receiver<T> {
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<R: AsMut<Receiver<T>> + Send, T: Send> Send for Recv<R, T> {}
|
||||
unsafe impl<R: AsMut<Receiver<T>> + Sync, T: Send> Sync for Recv<R, T> {}
|
||||
unsafe impl<'a, T: Send> Send for Recv<'a, T> {}
|
||||
unsafe impl<'a, T: Send> Sync for Recv<'a, T> {}
|
||||
|
||||
/// Max number of receivers. Reserve space to lock.
|
||||
const MAX_RECEIVERS: usize = usize::MAX >> 2;
|
||||
@@ -892,7 +870,7 @@ impl<T: Clone> Receiver<T> {
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn recv(&mut self) -> Result<T, RecvError> {
|
||||
let fut = Recv::<_, T>::new(Borrow(self));
|
||||
let fut = Recv::new(self);
|
||||
fut.await
|
||||
}
|
||||
|
||||
@@ -951,7 +929,7 @@ impl<T> Drop for Receiver<T> {
|
||||
|
||||
drop(tail);
|
||||
|
||||
while self.next != until {
|
||||
while self.next < until {
|
||||
match self.recv_ref(None) {
|
||||
Ok(_) => {}
|
||||
// The channel is closed
|
||||
@@ -965,11 +943,8 @@ impl<T> Drop for Receiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T> Recv<R, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
{
|
||||
fn new(receiver: R) -> Recv<R, T> {
|
||||
impl<'a, T> Recv<'a, T> {
|
||||
fn new(receiver: &'a mut Receiver<T>) -> Recv<'a, T> {
|
||||
Recv {
|
||||
receiver,
|
||||
waiter: UnsafeCell::new(Waiter {
|
||||
@@ -978,7 +953,6 @@ where
|
||||
pointers: linked_list::Pointers::new(),
|
||||
_p: PhantomPinned,
|
||||
}),
|
||||
_p: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,14 +964,13 @@ where
|
||||
is_unpin::<&mut Receiver<T>>();
|
||||
|
||||
let me = self.get_unchecked_mut();
|
||||
(me.receiver.as_mut(), &me.waiter)
|
||||
(me.receiver, &me.waiter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T> Future for Recv<R, T>
|
||||
impl<'a, T> Future for Recv<'a, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
T: Clone,
|
||||
{
|
||||
type Output = Result<T, RecvError>;
|
||||
@@ -1016,14 +989,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T> Drop for Recv<R, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
{
|
||||
impl<'a, T> Drop for Recv<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// Acquire the tail lock. This is required for safety before accessing
|
||||
// the waiter node.
|
||||
let mut tail = self.receiver.as_mut().shared.tail.lock();
|
||||
let mut tail = self.receiver.shared.tail.lock();
|
||||
|
||||
// safety: tail lock is held
|
||||
let queued = self.waiter.with(|ptr| unsafe { (*ptr).queued });
|
||||
|
||||
@@ -258,13 +258,15 @@ impl<T> Block<T> {
|
||||
pub(crate) unsafe fn try_push(
|
||||
&self,
|
||||
block: &mut NonNull<Block<T>>,
|
||||
ordering: Ordering,
|
||||
success: Ordering,
|
||||
failure: Ordering,
|
||||
) -> Result<(), NonNull<Block<T>>> {
|
||||
block.as_mut().start_index = self.start_index.wrapping_add(BLOCK_CAP);
|
||||
|
||||
let next_ptr = self
|
||||
.next
|
||||
.compare_and_swap(ptr::null_mut(), block.as_ptr(), ordering);
|
||||
.compare_exchange(ptr::null_mut(), block.as_ptr(), success, failure)
|
||||
.unwrap_or_else(|x| x);
|
||||
|
||||
match NonNull::new(next_ptr) {
|
||||
Some(next_ptr) => Err(next_ptr),
|
||||
@@ -306,11 +308,11 @@ impl<T> Block<T> {
|
||||
//
|
||||
// `Release` ensures that the newly allocated block is available to
|
||||
// other threads acquiring the next pointer.
|
||||
let next = NonNull::new(self.next.compare_and_swap(
|
||||
ptr::null_mut(),
|
||||
new_block.as_ptr(),
|
||||
AcqRel,
|
||||
));
|
||||
let next = NonNull::new(
|
||||
self.next
|
||||
.compare_exchange(ptr::null_mut(), new_block.as_ptr(), AcqRel, Acquire)
|
||||
.unwrap_or_else(|x| x),
|
||||
);
|
||||
|
||||
let next = match next {
|
||||
Some(next) => next,
|
||||
@@ -333,7 +335,7 @@ impl<T> Block<T> {
|
||||
|
||||
// TODO: Should this iteration be capped?
|
||||
loop {
|
||||
let actual = unsafe { curr.as_ref().try_push(&mut new_block, AcqRel) };
|
||||
let actual = unsafe { curr.as_ref().try_push(&mut new_block, AcqRel, Acquire) };
|
||||
|
||||
curr = match actual {
|
||||
Ok(_) => {
|
||||
|
||||
@@ -33,6 +33,10 @@ pub struct Permit<'a, T> {
|
||||
/// Receive values from the associated `Sender`.
|
||||
///
|
||||
/// Instances are created by the [`channel`](channel) function.
|
||||
///
|
||||
/// This receiver can be turned into a `Stream` using [`ReceiverStream`].
|
||||
///
|
||||
/// [`ReceiverStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.ReceiverStream.html
|
||||
pub struct Receiver<T> {
|
||||
/// The channel receiver
|
||||
chan: chan::Rx<T, Semaphore>,
|
||||
@@ -599,6 +603,58 @@ impl<T> Sender<T> {
|
||||
|
||||
Ok(Permit { chan: &self.chan })
|
||||
}
|
||||
|
||||
/// Try to acquire a slot in the channel without waiting for the slot to become
|
||||
/// available.
|
||||
///
|
||||
/// If the channel is full this function will return [`TrySendError`], otherwise
|
||||
/// if there is a slot available it will return a [`Permit`] that will then allow you
|
||||
/// to [`send`] on the channel with a guaranteed slot. This function is similar to
|
||||
/// [`reserve`] execpt it does not await for the slot to become available.
|
||||
///
|
||||
/// Dropping [`Permit`] without sending a message releases the capacity back
|
||||
/// to the channel.
|
||||
///
|
||||
/// [`Permit`]: Permit
|
||||
/// [`send`]: Permit::send
|
||||
/// [`reserve`]: Sender::reserve
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::sync::mpsc;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let (tx, mut rx) = mpsc::channel(1);
|
||||
///
|
||||
/// // Reserve capacity
|
||||
/// let permit = tx.try_reserve().unwrap();
|
||||
///
|
||||
/// // Trying to send directly on the `tx` will fail due to no
|
||||
/// // available capacity.
|
||||
/// assert!(tx.try_send(123).is_err());
|
||||
///
|
||||
/// // Trying to reserve an additional slot on the `tx` will
|
||||
/// // fail because there is no capacity.
|
||||
/// assert!(tx.try_reserve().is_err());
|
||||
///
|
||||
/// // Sending on the permit succeeds
|
||||
/// permit.send(456);
|
||||
///
|
||||
/// // The value sent on the permit is received
|
||||
/// assert_eq!(rx.recv().await.unwrap(), 456);
|
||||
///
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_reserve(&self) -> Result<Permit<'_, T>, TrySendError<()>> {
|
||||
match self.chan.semaphore().0.try_acquire(1) {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err(TrySendError::Full(())),
|
||||
}
|
||||
|
||||
Ok(Permit { chan: &self.chan })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Sender<T> {
|
||||
|
||||
@@ -140,11 +140,11 @@ impl<T> Tx<T> {
|
||||
//
|
||||
// Acquire is not needed as any "actual" value is not accessed.
|
||||
// At this point, the linked list is walked to acquire blocks.
|
||||
let actual =
|
||||
self.block_tail
|
||||
.compare_and_swap(block_ptr, next_block.as_ptr(), Release);
|
||||
|
||||
if actual == block_ptr {
|
||||
if self
|
||||
.block_tail
|
||||
.compare_exchange(block_ptr, next_block.as_ptr(), Release, Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
// Synchronize with any senders
|
||||
let tail_position = self.tail_position.fetch_add(0, Release);
|
||||
|
||||
@@ -191,7 +191,7 @@ impl<T> Tx<T> {
|
||||
|
||||
// TODO: Unify this logic with Block::grow
|
||||
for _ in 0..3 {
|
||||
match curr.as_ref().try_push(&mut block, AcqRel) {
|
||||
match curr.as_ref().try_push(&mut block, AcqRel, Acquire) {
|
||||
Ok(_) => {
|
||||
reused = true;
|
||||
break;
|
||||
|
||||
@@ -33,6 +33,10 @@ impl<T> fmt::Debug for UnboundedSender<T> {
|
||||
///
|
||||
/// Instances are created by the
|
||||
/// [`unbounded_channel`](unbounded_channel) function.
|
||||
///
|
||||
/// This receiver can be turned into a `Stream` using [`UnboundedReceiverStream`].
|
||||
///
|
||||
/// [`UnboundedReceiverStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.UnboundedReceiverStream.html
|
||||
pub struct UnboundedReceiver<T> {
|
||||
/// The channel receiver
|
||||
chan: chan::Rx<T, Semaphore>,
|
||||
|
||||
+13
-4
@@ -142,7 +142,7 @@ pub struct MutexGuard<'a, T: ?Sized> {
|
||||
/// unlike `MutexGuard`, it will have the `'static` lifetime.
|
||||
///
|
||||
/// As long as you have this guard, you have exclusive access to the underlying
|
||||
/// `T`. The guard internally keeps a reference-couned pointer to the original
|
||||
/// `T`. The guard internally keeps a reference-counted pointer to the original
|
||||
/// `Mutex`, so even if the lock goes away, the guard remains valid.
|
||||
///
|
||||
/// The lock is automatically released whenever the guard is dropped, at which
|
||||
@@ -161,13 +161,22 @@ unsafe impl<T> Sync for Mutex<T> where T: ?Sized + Send {}
|
||||
unsafe impl<T> Sync for MutexGuard<'_, T> where T: ?Sized + Send + Sync {}
|
||||
unsafe impl<T> Sync for OwnedMutexGuard<T> where T: ?Sized + Send + Sync {}
|
||||
|
||||
/// Error returned from the [`Mutex::try_lock`] function.
|
||||
/// Error returned from the [`Mutex::try_lock`], [`RwLock::try_read`] and
|
||||
/// [`RwLock::try_write`] functions.
|
||||
///
|
||||
/// A `try_lock` operation can only fail if the mutex is already locked.
|
||||
/// `Mutex::try_lock` operation will only fail if the mutex is already locked.
|
||||
///
|
||||
/// `RwLock::try_read` operation will only fail if the lock is currently held
|
||||
/// by an exclusive writer.
|
||||
///
|
||||
/// `RwLock::try_write` operation will if lock is held by any reader or by an
|
||||
/// exclusive writer.
|
||||
///
|
||||
/// [`Mutex::try_lock`]: Mutex::try_lock
|
||||
/// [`RwLock::try_read`]: fn@super::RwLock::try_read
|
||||
/// [`RwLock::try_write`]: fn@super::RwLock::try_write
|
||||
#[derive(Debug)]
|
||||
pub struct TryLockError(());
|
||||
pub struct TryLockError(pub(super) ());
|
||||
|
||||
impl fmt::Display for TryLockError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
||||
+86
-110
@@ -1,4 +1,5 @@
|
||||
use crate::sync::batch_semaphore::Semaphore;
|
||||
use crate::sync::batch_semaphore::{Semaphore, TryAcquireError};
|
||||
use crate::sync::mutex::TryLockError;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
@@ -237,114 +238,6 @@ pub struct RwLockWriteGuard<'a, T: ?Sized> {
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
|
||||
/// Make a new `RwLockWriteGuard` for a component of the locked data.
|
||||
///
|
||||
/// This operation cannot fail as the `RwLockWriteGuard` passed in already
|
||||
/// locked the data.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RwLockWriteGuard::map(..)`. A method would interfere with methods of
|
||||
/// the same name on the contents of the locked data.
|
||||
///
|
||||
/// This is an asynchronous version of [`RwLockWriteGuard::map`] from the
|
||||
/// [`parking_lot` crate].
|
||||
///
|
||||
/// [`RwLockWriteGuard::map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockWriteGuard.html#method.map
|
||||
/// [`parking_lot` crate]: https://crates.io/crates/parking_lot
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::sync::{RwLock, RwLockWriteGuard};
|
||||
///
|
||||
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// struct Foo(u32);
|
||||
///
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// let lock = RwLock::new(Foo(1));
|
||||
///
|
||||
/// {
|
||||
/// let mut mapped = RwLockWriteGuard::map(lock.write().await, |f| &mut f.0);
|
||||
/// *mapped = 2;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(Foo(2), *lock.read().await);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<F, U: ?Sized>(mut this: Self, f: F) -> RwLockWriteGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&mut T) -> &mut U,
|
||||
{
|
||||
let data = f(&mut *this) as *mut U;
|
||||
let s = this.s;
|
||||
// NB: Forget to avoid drop impl from being called.
|
||||
mem::forget(this);
|
||||
RwLockWriteGuard {
|
||||
s,
|
||||
data,
|
||||
marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to make a new [`RwLockWriteGuard`] for a component of
|
||||
/// the locked data. The original guard is returned if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// This operation cannot fail as the `RwLockWriteGuard` passed in already
|
||||
/// locked the data.
|
||||
///
|
||||
/// This is an associated function that needs to be
|
||||
/// used as `RwLockWriteGuard::try_map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the locked data.
|
||||
///
|
||||
/// This is an asynchronous version of [`RwLockWriteGuard::try_map`] from
|
||||
/// the [`parking_lot` crate].
|
||||
///
|
||||
/// [`RwLockWriteGuard::try_map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockWriteGuard.html#method.try_map
|
||||
/// [`parking_lot` crate]: https://crates.io/crates/parking_lot
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::sync::{RwLock, RwLockWriteGuard};
|
||||
///
|
||||
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// struct Foo(u32);
|
||||
///
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// let lock = RwLock::new(Foo(1));
|
||||
///
|
||||
/// {
|
||||
/// let guard = lock.write().await;
|
||||
/// let mut guard = RwLockWriteGuard::try_map(guard, |f| Some(&mut f.0)).expect("should not fail");
|
||||
/// *guard = 2;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(Foo(2), *lock.read().await);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_map<F, U: ?Sized>(mut this: Self, f: F) -> Result<RwLockWriteGuard<'a, U>, Self>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
{
|
||||
let data = match f(&mut *this) {
|
||||
Some(data) => data as *mut U,
|
||||
None => return Err(this),
|
||||
};
|
||||
let s = this.s;
|
||||
// NB: Forget to avoid drop impl from being called.
|
||||
mem::forget(this);
|
||||
Ok(RwLockWriteGuard {
|
||||
s,
|
||||
data,
|
||||
marker: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Atomically downgrades a write lock into a read lock without allowing
|
||||
/// any writers to take exclusive access of the lock in the meantime.
|
||||
///
|
||||
@@ -530,7 +423,7 @@ impl<T: ?Sized> RwLock<T> {
|
||||
/// // While main has an active read lock, we acquire one too.
|
||||
/// let r = c_lock.read().await;
|
||||
/// assert_eq!(*r, 1);
|
||||
/// }).await.expect("The spawned task has paniced");
|
||||
/// }).await.expect("The spawned task has panicked");
|
||||
///
|
||||
/// // Drop the guard after the spawned task finishes.
|
||||
/// drop(n);
|
||||
@@ -549,6 +442,52 @@ impl<T: ?Sized> RwLock<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this `RwLock` with shared read access.
|
||||
///
|
||||
/// If the access couldn't be acquired immediately, returns [`TryLockError`].
|
||||
/// Otherwise, an RAII guard is returned which will release read access
|
||||
/// when dropped.
|
||||
///
|
||||
/// [`TryLockError`]: TryLockError
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
/// use tokio::sync::RwLock;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let lock = Arc::new(RwLock::new(1));
|
||||
/// let c_lock = lock.clone();
|
||||
///
|
||||
/// let v = lock.try_read().unwrap();
|
||||
/// assert_eq!(*v, 1);
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// // While main has an active read lock, we acquire one too.
|
||||
/// let n = c_lock.read().await;
|
||||
/// assert_eq!(*n, 1);
|
||||
/// }).await.expect("The spawned task has panicked");
|
||||
///
|
||||
/// // Drop the guard when spawned task finishes.
|
||||
/// drop(v);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError> {
|
||||
match self.s.try_acquire(1) {
|
||||
Ok(permit) => permit,
|
||||
Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
|
||||
Err(TryAcquireError::Closed) => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(RwLockReadGuard {
|
||||
s: &self.s,
|
||||
data: self.c.get(),
|
||||
marker: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Locks this rwlock with exclusive write access, causing the current task
|
||||
/// to yield until the lock has been acquired.
|
||||
///
|
||||
@@ -584,6 +523,43 @@ impl<T: ?Sized> RwLock<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this `RwLock` with exclusive write access.
|
||||
///
|
||||
/// If the access couldn't be acquired immediately, returns [`TryLockError`].
|
||||
/// Otherwise, an RAII guard is returned which will release write access
|
||||
/// when dropped.
|
||||
///
|
||||
/// [`TryLockError`]: TryLockError
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::sync::RwLock;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let rw = RwLock::new(1);
|
||||
///
|
||||
/// let v = rw.read().await;
|
||||
/// assert_eq!(*v, 1);
|
||||
///
|
||||
/// assert!(rw.try_write().is_err());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError> {
|
||||
match self.s.try_acquire(MAX_READS as u32) {
|
||||
Ok(permit) => permit,
|
||||
Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
|
||||
Err(TryAcquireError::Closed) => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(RwLockWriteGuard {
|
||||
s: &self.s,
|
||||
data: self.c.get(),
|
||||
marker: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying data.
|
||||
///
|
||||
/// Since this call borrows the `RwLock` mutably, no actual locking needs to
|
||||
|
||||
@@ -171,7 +171,11 @@ impl AtomicWaker {
|
||||
where
|
||||
W: WakerRef,
|
||||
{
|
||||
match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) {
|
||||
match self
|
||||
.state
|
||||
.compare_exchange(WAITING, REGISTERING, Acquire, Acquire)
|
||||
.unwrap_or_else(|x| x)
|
||||
{
|
||||
WAITING => {
|
||||
unsafe {
|
||||
// Locked acquired, update the waker cell
|
||||
|
||||
@@ -178,3 +178,30 @@ fn drop_rx() {
|
||||
assert_ok!(th2.join());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_multiple_rx_with_overflow() {
|
||||
loom::model(move || {
|
||||
// It is essential to have multiple senders and receivers in this test case.
|
||||
let (tx, mut rx) = broadcast::channel(1);
|
||||
let _rx2 = tx.subscribe();
|
||||
|
||||
let _ = tx.send(());
|
||||
let tx2 = tx.clone();
|
||||
let th1 = thread::spawn(move || {
|
||||
block_on(async {
|
||||
for _ in 0..100 {
|
||||
let _ = tx2.send(());
|
||||
}
|
||||
});
|
||||
});
|
||||
let _ = tx.send(());
|
||||
|
||||
let th2 = thread::spawn(move || {
|
||||
block_on(async { while let Ok(_) = rx.recv().await {} });
|
||||
});
|
||||
|
||||
assert_ok!(th1.join());
|
||||
assert_ok!(th2.join());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -283,6 +283,7 @@ impl LocalSet {
|
||||
let future = crate::util::trace::task(future, "local");
|
||||
let (task, handle) = unsafe { task::joinable_local(future) };
|
||||
self.context.tasks.borrow_mut().queue.push_back(task);
|
||||
self.context.shared.waker.wake();
|
||||
handle
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user