Compare commits

...
Author SHA1 Message Date
Alice Ryhl 198363f4f1 chore: prepare tokio-util 0.6.2 (#3453) 2021-01-21 11:46:50 +01:00
vitalyd 5b7c7d565a io: use a sealed trait to constrain VecWithInitialized (#3450) 2021-01-21 11:32:42 +01:00
Blas Rodriguez Irizar 117fc2ef3e tests: fix ping pong saturation (#3390) 2021-01-21 11:02:40 +01:00
William Bain c4f66ed121 util: fix panics on updating DelayQueue entries (#3270) 2021-01-21 10:56:44 +01:00
Oğuz Bilgener 7d5b12c509 sync: fix panic in broadcast::Receiver drop (#3434) 2021-01-20 23:12:51 +01:00
Alice Ryhl cc0911aa64 net: update datagram docs on splitting (#3448) 2021-01-20 16:28:57 +01:00
Henry Gomersall 6f8a4d7a0b docs: trivial typo fix (#3449) 2021-01-20 16:28:35 +01:00
Arve Knudsen fdde5583f8 runtime: consolidate errors for context missing (#3441) 2021-01-20 14:29:13 +01:00
Rain 36cf95ab62 io: add ReadBuf::inner_mut (#3443) 2021-01-20 13:56:14 +01:00
Alice Ryhl 27b2d681e6 util: add pollable Semaphore (#3444) 2021-01-20 09:53:31 +01:00
Alice Ryhl c1cf6b7504 io: keep track of initialized bytes in read_to_end (#3426) 2021-01-20 09:49:24 +01:00
Henry Gomersall 5402c948ee io: clarify AsyncFd docs about changes of the inner fd (#3430) 2021-01-17 21:39:58 +01:00
Carl Lerche 2af9b755c5 Merge branch 'tokio-1.0.x' 2021-01-16 11:36:21 -08:00
Jacob O'Toole 7ac44a2d28 process: add documentation to process::Child fields (#3437) 2021-01-16 19:42:51 +01:00
Carl Lerche 3dc5f6c0ab chore: release tokio v1.0.2 (#3429) 2021-01-15 15:05:38 -08:00
Alice Ryhl 0a7117fd9a io: fix unsoundness in read_to_end (#3428) 2021-01-15 15:05:38 -08:00
Carl Lerche 5d35c907f6 chore: release tokio v1.0.2 (#3429) 2021-01-14 16:37:40 -08:00
Alice Ryhl ad8fb41103 io: fix unsoundness in read_to_end (#3428) 2021-01-14 15:09:07 -08:00
Nylonicious ecc32d1dca sync: add RwLock try_read and try_write methods (#3400)
Closes #2284
2021-01-14 15:05:07 -08:00
Markus Westerlind 204603b7de rt: reduce duplicated code in task harness (#3314)
Task spawning is a common operation that results in a lot of instantiations
of the task code. Reducing the amount of generated code should lead to
faster compile times overall.

This patch extracts code that does not depend on a type parameter into
functions with fewer or no type parameters at all. Reducing the amount of
duplicated code.
2021-01-14 10:07:56 -08:00
Taiki Endo 30b4a7486a chore: use CARGO_BIN_EXE instead of inspecting env::current_exe() (#3427) 2021-01-14 09:59:37 -08:00
Taiki Endo 0595902ba4 Update issue template (#3425)
`cargo tree` subcommand is available by default since Rust 1.44.
2021-01-14 23:09:05 +09:00
Lucio FrancoandAlice Ryhl 672be92a03 mpsc: Add Sender::try_reserve function (#3418)
* mpsc: Add `Sender::try_reserve` function

* Update tokio/src/sync/mpsc/bounded.rs

Co-authored-by: Alice Ryhl <[email protected]>

* Fix doc links

Co-authored-by: Alice Ryhl <[email protected]>
2021-01-13 14:24:23 -05:00
Alice Ryhl 766a89bf94 chore: prepare tokio-stream 0.1.2 (#3414) 2021-01-12 21:38:51 +01:00
David Kellum 8b9bb41809 docs: add tokio 1.0 policies to contributing guide (#3386) 2021-01-12 21:15:44 +01:00
Taiki Endo d37486dd06 util: remove path deps (#3413)
* util: remove path deps

* ci: run clippy with --all-features

* ci: run tests with --all-features on FreeBSD CI
2021-01-13 00:19:57 +09:00
Daiki Mizukami ed667c669a chore: prepare tokio-util v0.6.1 release (#3402) 2021-01-12 12:46:07 +01:00
Milan da09213c9f doc: typo fixes (#3401) 2021-01-11 21:39:50 -08:00
Taiki Endo 40d959263b macros: fix unused_braces in generated code (#3404) 2021-01-11 19:20:40 +09:00
Shantanu Sharma 0b8bdf9d32 runtime: fix typo (#3385) 2021-01-10 20:59:14 +09:00
cssivision 51a7082d13 docs: test-util feature is not enabled with full (#3397) 2021-01-09 14:01:10 +01:00
Cameron 22c27b9282 task: wake LocalSet on spawn_local (#3369) 2021-01-09 11:46:51 +01:00
David Raifaizen 2fe2f0401b util: expose FramedWrite/Framed::write_buffer/write_buffer_mut 2021-01-08 23:20:07 +01:00
Rust大闸蟹 e42317b072 chore: remove macro_rules semicolon (#3381)
fix build warning
2021-01-06 15:46:37 +09:00
Alice Ryhl 3549092a0c docs: fix tokio-stream features not being displayed (#3378) 2021-01-05 11:43:09 +01:00
Alice Ryhl 3b840fb305 stream: remove path deps (#3376) 2021-01-04 21:04:22 +01:00
Alice Ryhl 4beb1862ac chore: prepare tokio-stream 0.1.1 (#3374) 2021-01-04 19:46:01 +01:00
Alice Ryhl 7f17822ed9 stream: add Stream wrappers in tokio-stream (#3343) 2021-01-04 19:03:18 +01:00
cssivision 3b6bee822d net: add try_read_buf and try_recv_buf (#3351) 2021-01-02 10:37:34 +01:00
Rob Ede 56272b2ec7 stream: move async-stream to dev-deps (#3366) 2021-01-02 13:43:41 +09:00
John-John Tedro 53707f5d9d sync: remove underused internal Borrow wrapper (#3363) 2021-01-01 13:04:38 -08:00
Daiki Mizukami 36918e05e5 util: add more get_{ref,mut,pin_mut} methods (#3364)
This commit adds:

- Framed::get_pin_mut
- FramedRead::get_pin_mut
- FramedWrite::get_pin_mut
- StreamReader::get_ref
- StreamReader::get_mut
- StreamReader::get_pin_mut
- StreamReader::into_inner
2021-01-01 13:05:15 +01:00
Arniu Tseng cbd4f4472e docs: update CHANGELOG.md (#3336) 2020-12-27 16:36:36 +01:00
Danilo MartinsandDanilo 2d9bea8d63 runtime: fix typo (#3354)
Co-authored-by: Danilo <[email protected]>
2020-12-27 16:17:00 +01:00
zhongjnandAlice Ryhl 0048d43713 macros: improve select! error message (#3352)
Co-authored-by: Alice Ryhl <[email protected]>
2020-12-27 23:50:32 +09:00
Taiki Endo 770044caa7 chore: replace deprecated compare_and_swap with compare_exchange (#3331) 2020-12-27 10:44:21 +01:00
AJ Frantz c4929264bc examples: adjust buffering in examples (#3328) 2020-12-27 10:43:02 +01:00
Alice Ryhl 4d7b73f5b3 chore: create stream_ext module (#3342) 2020-12-26 17:05:51 +01:00
Alice Ryhl 2330edc875 chore: prepare tokio 1.0.1 release (#3347) 2020-12-25 22:20:05 +01:00
Alice Ryhl fe2664a4e1 sync: remove RwLockWriteGuard::map and RwLockWriteGuard::try_map (#3345) 2020-12-25 21:36:48 +01:00
Laurențiu Nicola 1eefbc250a docs: remove stream feature from docs (#3335) 2020-12-24 23:17:18 +09:00
121 changed files with 4471 additions and 2014 deletions
+2 -2
View File
@@ -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
+1 -6
View File
@@ -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`
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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(())
}
+1 -1
View File
@@ -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!"),
}
+1 -10
View File
@@ -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
}
+1 -1
View File
@@ -254,7 +254,7 @@ fn parse_knobs(
.enable_all()
.build()
.unwrap()
.block_on(async { #body })
.block_on(async #body)
}
};
+20 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+30
View File
@@ -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)*) => {
$(
+917
View File
@@ -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;
+35
View File
@@ -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;
}
+50
View File
@@ -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
}
}
+60
View File
@@ -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
}
}
+59
View File
@@ -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
}
}
+47
View File
@@ -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
}
}
+60
View File
@@ -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
}
}
+54
View File
@@ -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
}
}
+23
View File
@@ -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 -8
View File
@@ -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"]
+20
View File
@@ -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
+10
View File
@@ -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
+21
View File
@@ -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
+30
View File
@@ -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 -1
View File
@@ -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,
+3
View File
@@ -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;
+85
View File
@@ -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()
}
}
+6 -4
View File
@@ -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
///
+2 -4
View File
@@ -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 {
}
}
}
*/
+14 -4
View File
@@ -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),
+61
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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 = """
-1
View File
@@ -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
+8 -5
View File
@@ -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
///
+5 -3
View File
@@ -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
+1 -1
View File
@@ -175,7 +175,7 @@ where
}
}
/// Repeates operations that are interrupted
/// Repeats operations that are interrupted
macro_rules! uninterruptibly {
($e:expr) => {{
loop {
+2 -3
View File
@@ -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)
}
}
}
+19
View File
@@ -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.
///
+5 -1
View File
@@ -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
+9 -1
View File
@@ -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")))]
+2
View File
@@ -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;
+32 -36
View File
@@ -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>
+7 -12
View File
@@ -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)
}
}
+5 -1
View File
@@ -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")))]
+132
View File
@@ -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
View File
@@ -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.
+23 -8
View File
@@ -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)
}
}
}
+1 -1
View File
@@ -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 })
+4
View File
@@ -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
+83
View File
@@ -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
View File
@@ -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
+136
View File
@@ -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
+4
View File
@@ -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
+85
View File
@@ -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
+26 -3
View File
@@ -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>,
}
+3 -2
View File
@@ -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)
+9 -9
View File
@@ -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()
})
}
+3 -2
View File
@@ -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)
}
}
+2 -2
View File
@@ -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:
//! ```
+12 -8
View File
@@ -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.
+94 -58
View File
@@ -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
View File
@@ -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()),
}
}
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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 });
+10 -8
View File
@@ -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(_) => {
+56
View File
@@ -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> {
+6 -6
View File
@@ -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;
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
+5 -1
View File
@@ -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
+27
View File
@@ -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());
});
}
+1
View File
@@ -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