mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-24 00:00:11 +02:00
Move stream items into tokio-stream (#3277)
This change removes all references to `Stream` from within the `tokio` crate and moves them into a new `tokio-stream` crate. Most types have had their `impl Stream` removed as well in-favor of their inherent methods. Closes #2870
This commit is contained in:
@@ -486,7 +486,6 @@ missing a difficulty rating, and you should feel free to add one.
|
||||
- **M-process** The `tokio::process` module.
|
||||
- **M-runtime** The `tokio::runtime` module.
|
||||
- **M-signal** The `tokio::signal` module.
|
||||
- **M-stream** The `tokio::stream` module.
|
||||
- **M-sync** The `tokio::sync` module.
|
||||
- **M-task** The `tokio::task` module.
|
||||
- **M-time** The `tokio::time` module.
|
||||
|
||||
@@ -4,6 +4,7 @@ members = [
|
||||
"tokio",
|
||||
"tokio-macros",
|
||||
"tokio-test",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
|
||||
# Internal
|
||||
|
||||
@@ -30,22 +30,26 @@ fn create_100_000_medium(b: &mut Bencher) {
|
||||
}
|
||||
|
||||
fn send_medium(b: &mut Bencher) {
|
||||
let rt = rt();
|
||||
|
||||
b.iter(|| {
|
||||
let (tx, mut rx) = mpsc::channel::<Medium>(1000);
|
||||
|
||||
let _ = tx.try_send([0; 64]);
|
||||
let _ = rt.block_on(tx.send([0; 64]));
|
||||
|
||||
rx.try_recv().unwrap();
|
||||
rt.block_on(rx.recv()).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
fn send_large(b: &mut Bencher) {
|
||||
let rt = rt();
|
||||
|
||||
b.iter(|| {
|
||||
let (tx, mut rx) = mpsc::channel::<Large>(1000);
|
||||
|
||||
let _ = tx.try_send([[0; 64]; 64]);
|
||||
let _ = rt.block_on(tx.send([[0; 64]; 64]));
|
||||
|
||||
rx.try_recv().unwrap();
|
||||
rt.block_on(rx.recv()).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -8,9 +8,12 @@ edition = "2018"
|
||||
# [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" }
|
||||
|
||||
async-stream = "0.3"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.2.7", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log"] }
|
||||
tokio-util = { version = "0.6.0", path = "../tokio-util", features = ["full"] }
|
||||
bytes = "0.6"
|
||||
futures = "0.3.0"
|
||||
http = "0.2"
|
||||
|
||||
+9
-6
@@ -27,8 +27,8 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::stream::{Stream, StreamExt};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
|
||||
|
||||
use futures::SinkExt;
|
||||
@@ -101,9 +101,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// Shorthand for the transmit half of the message channel.
|
||||
type Tx = mpsc::UnboundedSender<String>;
|
||||
|
||||
/// Shorthand for the receive half of the message channel.
|
||||
type Rx = mpsc::UnboundedReceiver<String>;
|
||||
|
||||
/// Data that is shared between all peers in the chat server.
|
||||
///
|
||||
/// This is the set of `Tx` handles for all connected clients. Whenever a
|
||||
@@ -127,7 +124,7 @@ struct Peer {
|
||||
///
|
||||
/// This is used to receive messages from peers. When a message is received
|
||||
/// off of this `Rx`, it will be written to the socket.
|
||||
rx: Rx,
|
||||
rx: Pin<Box<dyn Stream<Item = String> + Send>>,
|
||||
}
|
||||
|
||||
impl Shared {
|
||||
@@ -159,11 +156,17 @@ impl Peer {
|
||||
let addr = lines.get_ref().peer_addr()?;
|
||||
|
||||
// Create a channel for this peer
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
// Add an entry for this `Peer` in the shared state map.
|
||||
state.lock().await.peers.insert(addr, tx);
|
||||
|
||||
let rx = Box::pin(async_stream::stream! {
|
||||
while let Some(item) = rx.recv().await {
|
||||
yield item;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Peer { lines, rx })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec::{BytesCodec, Decoder};
|
||||
|
||||
use std::env;
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec::{Framed, LinesCodec};
|
||||
|
||||
use futures::SinkExt;
|
||||
|
||||
@@ -20,7 +20,7 @@ use http::{header::HeaderValue, Request, Response, StatusCode};
|
||||
extern crate serde_derive;
|
||||
use std::{env, error::Error, fmt, io};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
|
||||
#[tokio::main]
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio::{io, time};
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec::BytesCodec;
|
||||
use tokio_util::udp::UdpFramed;
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "tokio-stream"
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "tokio-stream-0.1.x" git tag.
|
||||
version = "0.1.0"
|
||||
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"
|
||||
description = """
|
||||
Utilities to work with `Stream` and `tokio`.
|
||||
"""
|
||||
categories = ["asynchronous"]
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
default = ["time"]
|
||||
time = ["tokio/time"]
|
||||
|
||||
[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"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.0", path = "../tokio", features = ["full"] }
|
||||
tokio-test = { path = "../tokio-test" }
|
||||
futures = { version = "0.3", default-features = false }
|
||||
|
||||
proptest = "0.10.0"
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::{Fuse, Stream};
|
||||
use crate::{Fuse, Stream};
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -26,7 +26,7 @@ pin_project! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from a [`Stream`](crate::stream::Stream).
|
||||
/// Convert from a [`Stream`](crate::Stream).
|
||||
///
|
||||
/// This trait is not intended to be used directly. Instead, call
|
||||
/// [`StreamExt::collect()`](super::StreamExt::collect).
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
@@ -24,7 +24,7 @@ unsafe impl<T> Sync for Empty<T> {}
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
use std::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
@@ -8,6 +8,7 @@ use core::task::{Context, Poll};
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
pub struct Iter<I> {
|
||||
iter: I,
|
||||
yield_amt: usize,
|
||||
}
|
||||
|
||||
impl<I> Unpin for Iter<I> {}
|
||||
@@ -20,7 +21,7 @@ impl<I> Unpin for Iter<I> {}
|
||||
///
|
||||
/// ```
|
||||
/// # async fn dox() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(vec![17, 19]);
|
||||
///
|
||||
@@ -35,6 +36,7 @@ where
|
||||
{
|
||||
Iter {
|
||||
iter: i.into_iter(),
|
||||
yield_amt: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +47,18 @@ where
|
||||
type Item = I::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<I::Item>> {
|
||||
let coop = ready!(crate::coop::poll_proceed(cx));
|
||||
coop.made_progress();
|
||||
Poll::Ready(self.iter.next())
|
||||
// TODO: add coop back
|
||||
if self.yield_amt >= 32 {
|
||||
self.yield_amt = 0;
|
||||
|
||||
cx.waker().wake_by_ref();
|
||||
|
||||
Poll::Pending
|
||||
} else {
|
||||
self.yield_amt += 1;
|
||||
|
||||
Poll::Ready(self.iter.next())
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
@@ -1,3 +1,28 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-stream/0.1.0")]
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::large_enum_variant,
|
||||
clippy::needless_doctest_main
|
||||
)]
|
||||
#![warn(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
unreachable_pub
|
||||
)]
|
||||
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
|
||||
#![doc(test(
|
||||
no_crate_inject,
|
||||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
||||
))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
|
||||
#![doc(test(
|
||||
no_crate_inject,
|
||||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
||||
))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
//! Stream utilities for Tokio.
|
||||
//!
|
||||
//! A `Stream` is an asynchronous sequence of values. It can be thought of as
|
||||
@@ -15,7 +40,7 @@
|
||||
//! `while let` loop as follows:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use tokio::stream::{self, StreamExt};
|
||||
//! use tokio_stream::{self as stream, StreamExt};
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! async fn main() {
|
||||
@@ -46,13 +71,16 @@
|
||||
//! [`tokio-util`] provides the [`StreamReader`] and [`ReaderStream`]
|
||||
//! types when the io feature is enabled.
|
||||
//!
|
||||
//! [tokio-util]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
|
||||
//! [`tokio::io`]: crate::io
|
||||
//! [`AsyncRead`]: crate::io::AsyncRead
|
||||
//! [`AsyncWrite`]: crate::io::AsyncWrite
|
||||
//! [tokio-util]: https://docs.rs/tokio-util/0.4/tokio_util/codec/index.html
|
||||
//! [`tokio::io`]: https://docs.rs/tokio/1.0/tokio/io/index.html
|
||||
//! [`AsyncRead`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncRead.html
|
||||
//! [`AsyncWrite`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncWrite.html
|
||||
//! [`ReaderStream`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.ReaderStream.html
|
||||
//! [`StreamReader`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.StreamReader.html
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod all;
|
||||
use all::AllFuture;
|
||||
|
||||
@@ -120,9 +148,9 @@ use take_while::TakeWhile;
|
||||
cfg_time! {
|
||||
mod timeout;
|
||||
use timeout::Timeout;
|
||||
use crate::time::Duration;
|
||||
use tokio::time::Duration;
|
||||
mod throttle;
|
||||
use crate::stream::throttle::{throttle, Throttle};
|
||||
use crate::throttle::{throttle, Throttle};
|
||||
}
|
||||
|
||||
#[doc(no_inline)]
|
||||
@@ -146,11 +174,11 @@ pub use futures_core::Stream;
|
||||
/// # #[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]);
|
||||
/// 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);
|
||||
/// let merged = tokio_stream::StreamExt::merge(a, b);
|
||||
///
|
||||
/// // use normal call notation for futures::stream::StreamExt::collect
|
||||
/// let output: Vec<_> = merged.collect().await;
|
||||
@@ -158,7 +186,7 @@ pub use futures_core::Stream;
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Stream`]: crate::stream::Stream
|
||||
/// [`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 {
|
||||
@@ -183,7 +211,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=3);
|
||||
///
|
||||
@@ -219,7 +247,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(vec![Ok(1), Ok(2), Err("nope")]);
|
||||
///
|
||||
@@ -251,7 +279,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=3);
|
||||
/// let mut stream = stream.map(|x| x + 3);
|
||||
@@ -284,16 +312,17 @@ pub trait StreamExt: Stream {
|
||||
///
|
||||
/// For merging multiple streams, consider using [`StreamMap`] instead.
|
||||
///
|
||||
/// [`StreamMap`]: crate::stream::StreamMap
|
||||
/// [`StreamMap`]: crate::StreamMap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::StreamExt;
|
||||
/// use tokio_stream::{StreamExt, Stream};
|
||||
/// use tokio::sync::mpsc;
|
||||
/// use tokio::time;
|
||||
///
|
||||
/// use std::time::Duration;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// # /*
|
||||
/// #[tokio::main]
|
||||
@@ -301,8 +330,21 @@ pub trait StreamExt: Stream {
|
||||
/// # #[tokio::main(flavor = "current_thread")]
|
||||
/// async fn main() {
|
||||
/// # time::pause();
|
||||
/// let (tx1, rx1) = mpsc::channel(10);
|
||||
/// let (tx2, rx2) = mpsc::channel(10);
|
||||
/// 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);
|
||||
///
|
||||
@@ -365,7 +407,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter(|x| x % 2 == 0);
|
||||
@@ -401,7 +443,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let stream = stream::iter(1..=8);
|
||||
/// let mut evens = stream.filter_map(|x| {
|
||||
@@ -433,7 +475,7 @@ pub trait StreamExt: Stream {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{Stream, StreamExt};
|
||||
/// use tokio_stream::{Stream, StreamExt};
|
||||
///
|
||||
/// use std::pin::Pin;
|
||||
/// use std::task::{Context, Poll};
|
||||
@@ -498,7 +540,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take(3);
|
||||
///
|
||||
@@ -527,7 +569,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).take_while(|x| *x <= 3);
|
||||
///
|
||||
@@ -553,7 +595,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let mut stream = stream::iter(1..=10).skip(7);
|
||||
///
|
||||
@@ -584,7 +626,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// 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);
|
||||
@@ -627,7 +669,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
@@ -642,7 +684,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
@@ -686,7 +728,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
@@ -701,7 +743,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
@@ -730,7 +772,7 @@ pub trait StreamExt: Stream {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -770,7 +812,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, *};
|
||||
/// use tokio_stream::{self as stream, *};
|
||||
///
|
||||
/// let s = stream::iter(vec![1u8, 2, 3]);
|
||||
/// let sum = s.fold(0, |acc, x| acc + x).await;
|
||||
@@ -797,7 +839,9 @@ pub trait StreamExt: Stream {
|
||||
/// `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::Bytes).
|
||||
/// [`String`](std::string::String), and [`Bytes`].
|
||||
///
|
||||
/// [`Bytes`]: https://docs.rs/bytes/0.6.0/bytes/struct.Bytes.html
|
||||
///
|
||||
/// # `Result`
|
||||
///
|
||||
@@ -816,7 +860,7 @@ pub trait StreamExt: Stream {
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -833,7 +877,7 @@ pub trait StreamExt: Stream {
|
||||
/// Collecting a stream of `Result` values
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -889,7 +933,7 @@ pub trait StreamExt: Stream {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() {
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// use std::time::Duration;
|
||||
/// # let int_stream = stream::iter(1..=3);
|
||||
///
|
||||
@@ -934,7 +978,7 @@ pub trait StreamExt: Stream {
|
||||
/// Create a throttled stream.
|
||||
/// ```rust,no_run
|
||||
/// use std::time::Duration;
|
||||
/// use tokio::stream::StreamExt;
|
||||
/// use tokio_stream::StreamExt;
|
||||
///
|
||||
/// # async fn dox() {
|
||||
/// let mut item_stream = futures::stream::repeat("one").throttle(Duration::from_secs(2));
|
||||
@@ -0,0 +1,18 @@
|
||||
macro_rules! cfg_time {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = "time")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ready {
|
||||
($e:expr $(,)?) => {
|
||||
match $e {
|
||||
std::task::Poll::Ready(t) => t,
|
||||
std::task::Poll::Pending => return std::task::Poll::Pending,
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::{Fuse, Stream};
|
||||
use crate::{Fuse, Stream};
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::{self, Iter, Stream};
|
||||
use crate::{Iter, Stream};
|
||||
|
||||
use core::option;
|
||||
use core::pin::Pin;
|
||||
@@ -20,7 +20,7 @@ impl<I> Unpin for Once<I> {}
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -35,7 +35,7 @@ impl<I> Unpin for Once<I> {}
|
||||
/// ```
|
||||
pub fn once<T>(value: T) -> Once<T> {
|
||||
Once {
|
||||
iter: stream::iter(Some(value).into_iter()),
|
||||
iter: crate::iter(Some(value).into_iter()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
@@ -16,7 +16,7 @@ unsafe impl<T> Sync for Pending<T> {}
|
||||
/// Creates a stream that is never ready
|
||||
///
|
||||
/// The returned stream is never ready. Attempting to call
|
||||
/// [`next()`](crate::stream::StreamExt::next) will never complete. Use
|
||||
/// [`next()`](crate::StreamExt::next) will never complete. Use
|
||||
/// [`stream::empty()`](super::empty()) to obtain a stream that is is
|
||||
/// immediately empty but returns no values.
|
||||
///
|
||||
@@ -25,7 +25,7 @@ unsafe impl<T> Sync for Pending<T> {}
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
@@ -42,9 +42,9 @@ use std::task::{Context, Poll};
|
||||
/// to be merged, it may be advisable to use tasks sending values on a shared
|
||||
/// [`mpsc`] channel.
|
||||
///
|
||||
/// [`StreamExt::merge`]: crate::stream::StreamExt::merge
|
||||
/// [`mpsc`]: crate::sync::mpsc
|
||||
/// [`pin!`]: macro@pin
|
||||
/// [`StreamExt::merge`]: crate::StreamExt::merge
|
||||
/// [`mpsc`]: https://docs.rs/tokio/1.0/tokio/sync/mpsc/index.html
|
||||
/// [`pin!`]: https://docs.rs/tokio/1.0/tokio/macro.pin.html
|
||||
/// [`Box::pin`]: std::boxed::Box::pin
|
||||
///
|
||||
/// # Examples
|
||||
@@ -52,13 +52,27 @@ use std::task::{Context, Poll};
|
||||
/// Merging two streams, then remove them after receiving the first value
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamExt, StreamMap};
|
||||
/// use tokio_stream::{StreamExt, StreamMap, Stream};
|
||||
/// use tokio::sync::mpsc;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let (tx1, rx1) = mpsc::channel(10);
|
||||
/// let (tx2, rx2) = mpsc::channel(10);
|
||||
/// 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>>;
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// tx1.send(1).await.unwrap();
|
||||
@@ -103,7 +117,7 @@ use std::task::{Context, Poll};
|
||||
/// sent to the client over a socket.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::stream::{Stream, StreamExt, StreamMap};
|
||||
/// use tokio_stream::{Stream, StreamExt, StreamMap};
|
||||
///
|
||||
/// enum Command {
|
||||
/// Join(String),
|
||||
@@ -112,13 +126,13 @@ use std::task::{Context, Poll};
|
||||
///
|
||||
/// fn commands() -> impl Stream<Item = Command> {
|
||||
/// // Streams in user commands by parsing `stdin`.
|
||||
/// # tokio::stream::pending()
|
||||
/// # tokio_stream::pending()
|
||||
/// }
|
||||
///
|
||||
/// // Join a channel, returns a stream of messages received on the channel.
|
||||
/// fn join(channel: &str) -> impl Stream<Item = String> + Unpin {
|
||||
/// // left as an exercise to the reader
|
||||
/// # tokio::stream::pending()
|
||||
/// # tokio_stream::pending()
|
||||
/// }
|
||||
///
|
||||
/// #[tokio::main]
|
||||
@@ -170,7 +184,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -193,7 +207,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -217,7 +231,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, Pending};
|
||||
/// use tokio_stream::{StreamMap, Pending};
|
||||
///
|
||||
/// let map: StreamMap<&str, Pending<()>> = StreamMap::new();
|
||||
/// ```
|
||||
@@ -233,7 +247,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, Pending};
|
||||
/// use tokio_stream::{StreamMap, Pending};
|
||||
///
|
||||
/// let map: StreamMap<&str, Pending<()>> = StreamMap::with_capacity(10);
|
||||
/// ```
|
||||
@@ -250,7 +264,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -273,7 +287,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -296,7 +310,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -320,7 +334,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, Pending};
|
||||
/// use tokio_stream::{StreamMap, Pending};
|
||||
///
|
||||
/// let map: StreamMap<i32, Pending<()>> = StreamMap::with_capacity(100);
|
||||
/// assert!(map.capacity() >= 100);
|
||||
@@ -334,7 +348,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut a = StreamMap::new();
|
||||
/// assert_eq!(a.len(), 0);
|
||||
@@ -367,7 +381,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut a = StreamMap::new();
|
||||
/// a.insert(1, pending::<i32>());
|
||||
@@ -388,7 +402,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
///
|
||||
@@ -416,7 +430,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
/// map.insert(1, pending::<i32>());
|
||||
@@ -445,7 +459,7 @@ impl<K, V> StreamMap<K, V> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{StreamMap, pending};
|
||||
/// use tokio_stream::{StreamMap, pending};
|
||||
///
|
||||
/// let mut map = StreamMap::new();
|
||||
/// map.insert(1, pending::<i32>());
|
||||
@@ -476,7 +490,7 @@ where
|
||||
fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll<Option<(usize, V::Item)>> {
|
||||
use Poll::*;
|
||||
|
||||
let start = crate::util::thread_rng_n(self.entries.len() as u32) as usize;
|
||||
let start = self::rand::thread_rng_n(self.entries.len() as u32) as usize;
|
||||
let mut idx = start;
|
||||
|
||||
for _ in 0..self.entries.len() {
|
||||
@@ -553,3 +567,98 @@ where
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
mod rand {
|
||||
use std::cell::Cell;
|
||||
|
||||
mod loom {
|
||||
#[cfg(not(loom))]
|
||||
pub(crate) mod rand {
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
static COUNTER: AtomicU32 = AtomicU32::new(1);
|
||||
|
||||
pub(crate) fn seed() -> u64 {
|
||||
let rand_state = RandomState::new();
|
||||
|
||||
let mut hasher = rand_state.build_hasher();
|
||||
|
||||
// Hash some unique-ish data to generate some new state
|
||||
COUNTER.fetch_add(1, Relaxed).hash(&mut hasher);
|
||||
|
||||
// Get the seed
|
||||
hasher.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(loom)]
|
||||
pub(crate) mod rand {
|
||||
pub(crate) fn seed() -> u64 {
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fast random number generate
|
||||
///
|
||||
/// Implement xorshift64+: 2 32-bit xorshift sequences added together.
|
||||
/// Shift triplet [17,7,16] was calculated as indicated in Marsaglia's
|
||||
/// Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
|
||||
/// This generator passes the SmallCrush suite, part of TestU01 framework:
|
||||
/// http://simul.iro.umontreal.ca/testu01/tu01.html
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FastRand {
|
||||
one: Cell<u32>,
|
||||
two: Cell<u32>,
|
||||
}
|
||||
|
||||
impl FastRand {
|
||||
/// Initialize a new, thread-local, fast random number generator.
|
||||
pub(crate) fn new(seed: u64) -> FastRand {
|
||||
let one = (seed >> 32) as u32;
|
||||
let mut two = seed as u32;
|
||||
|
||||
if two == 0 {
|
||||
// This value cannot be zero
|
||||
two = 1;
|
||||
}
|
||||
|
||||
FastRand {
|
||||
one: Cell::new(one),
|
||||
two: Cell::new(two),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fastrand_n(&self, n: u32) -> u32 {
|
||||
// This is similar to fastrand() % n, but faster.
|
||||
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
let mul = (self.fastrand() as u64).wrapping_mul(n as u64);
|
||||
(mul >> 32) as u32
|
||||
}
|
||||
|
||||
fn fastrand(&self) -> u32 {
|
||||
let mut s1 = self.one.get();
|
||||
let s0 = self.two.get();
|
||||
|
||||
s1 ^= s1 << 17;
|
||||
s1 = s1 ^ s0 ^ s1 >> 7 ^ s0 >> 16;
|
||||
|
||||
self.one.set(s0);
|
||||
self.two.set(s1);
|
||||
|
||||
s0.wrapping_add(s1)
|
||||
}
|
||||
}
|
||||
|
||||
// Used by `StreamMap`
|
||||
pub(crate) fn thread_rng_n(n: u32) -> u32 {
|
||||
thread_local! {
|
||||
static THREAD_RNG: FastRand = FastRand::new(loom::rand::seed());
|
||||
}
|
||||
|
||||
THREAD_RNG.with(|rng| rng.fastrand_n(n))
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::cmp;
|
||||
use core::fmt;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::Stream;
|
||||
use crate::Stream;
|
||||
|
||||
use core::fmt;
|
||||
use core::pin::Pin;
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Slow down a stream by enforcing a delay between items.
|
||||
|
||||
use crate::stream::Stream;
|
||||
use crate::time::{Duration, Instant, Sleep};
|
||||
use crate::Stream;
|
||||
use tokio::time::{Duration, Instant, Sleep};
|
||||
|
||||
use std::future::Future;
|
||||
use std::marker::Unpin;
|
||||
@@ -17,7 +17,7 @@ where
|
||||
let delay = if duration == Duration::from_millis(0) {
|
||||
None
|
||||
} else {
|
||||
Some(Sleep::new_timeout(Instant::now() + duration))
|
||||
Some(tokio::time::sleep_until(Instant::now() + duration))
|
||||
};
|
||||
|
||||
Throttle {
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::stream::{Fuse, Stream};
|
||||
use crate::time::{error::Elapsed, Instant, Sleep};
|
||||
use crate::{Fuse, Stream};
|
||||
use tokio::time::{Instant, Sleep};
|
||||
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use pin_project_lite::pin_project;
|
||||
use std::fmt;
|
||||
use std::time::Duration;
|
||||
|
||||
pin_project! {
|
||||
@@ -20,10 +21,14 @@ pin_project! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error returned by `Timeout`.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Elapsed(());
|
||||
|
||||
impl<S: Stream> Timeout<S> {
|
||||
pub(super) fn new(stream: S, duration: Duration) -> Self {
|
||||
let next = Instant::now() + duration;
|
||||
let deadline = Sleep::new_timeout(next);
|
||||
let deadline = tokio::time::sleep_until(next);
|
||||
|
||||
Timeout {
|
||||
stream: Fuse::new(stream),
|
||||
@@ -63,3 +68,25 @@ impl<S: Stream> Stream for Timeout<S> {
|
||||
self.stream.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl Elapsed =====
|
||||
|
||||
impl Elapsed {
|
||||
pub(crate) fn new() -> Self {
|
||||
Elapsed(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Elapsed {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"deadline has elapsed".fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Elapsed {}
|
||||
|
||||
impl From<Elapsed> for std::io::Error {
|
||||
fn from(_err: Elapsed) -> std::io::Error {
|
||||
std::io::ErrorKind::TimedOut.into()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::stream::{Next, Stream};
|
||||
use crate::{Next, Stream};
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomPinned;
|
||||
@@ -0,0 +1,105 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
#[allow(dead_code)]
|
||||
type BoxStream<T> = std::pin::Pin<Box<dyn tokio_stream::Stream<Item = T>>>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn require_send<T: Send>(_t: &T) {}
|
||||
#[allow(dead_code)]
|
||||
fn require_sync<T: Sync>(_t: &T) {}
|
||||
#[allow(dead_code)]
|
||||
fn require_unpin<T: Unpin>(_t: &T) {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Invalid;
|
||||
|
||||
trait AmbiguousIfSend<A> {
|
||||
fn some_item(&self) {}
|
||||
}
|
||||
impl<T: ?Sized> AmbiguousIfSend<()> for T {}
|
||||
impl<T: ?Sized + Send> AmbiguousIfSend<Invalid> for T {}
|
||||
|
||||
trait AmbiguousIfSync<A> {
|
||||
fn some_item(&self) {}
|
||||
}
|
||||
impl<T: ?Sized> AmbiguousIfSync<()> for T {}
|
||||
impl<T: ?Sized + Sync> AmbiguousIfSync<Invalid> for T {}
|
||||
|
||||
trait AmbiguousIfUnpin<A> {
|
||||
fn some_item(&self) {}
|
||||
}
|
||||
impl<T: ?Sized> AmbiguousIfUnpin<()> for T {}
|
||||
impl<T: ?Sized + Unpin> AmbiguousIfUnpin<Invalid> for T {}
|
||||
|
||||
macro_rules! into_todo {
|
||||
($typ:ty) => {{
|
||||
let x: $typ = todo!();
|
||||
x
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! async_assert_fn {
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Send & Sync) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
require_send(&f);
|
||||
require_sync(&f);
|
||||
};
|
||||
};
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Send & !Sync) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
require_send(&f);
|
||||
AmbiguousIfSync::some_item(&f);
|
||||
};
|
||||
};
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Send & Sync) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
AmbiguousIfSend::some_item(&f);
|
||||
require_sync(&f);
|
||||
};
|
||||
};
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Send & !Sync) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
AmbiguousIfSend::some_item(&f);
|
||||
AmbiguousIfSync::some_item(&f);
|
||||
};
|
||||
};
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Unpin) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
AmbiguousIfUnpin::some_item(&f);
|
||||
};
|
||||
};
|
||||
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Unpin) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unused_variables)]
|
||||
const _: fn() = || {
|
||||
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
|
||||
require_unpin(&f);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
async_assert_fn!(tokio_stream::empty<Rc<u8>>(): Send & Sync);
|
||||
async_assert_fn!(tokio_stream::pending<Rc<u8>>(): Send & Sync);
|
||||
async_assert_fn!(tokio_stream::iter(std::vec::IntoIter<u8>): Send & Sync);
|
||||
|
||||
async_assert_fn!(tokio_stream::StreamExt::next(&mut BoxStream<()>): !Unpin);
|
||||
async_assert_fn!(tokio_stream::StreamExt::try_next(&mut BoxStream<Result<(), ()>>): !Unpin);
|
||||
async_assert_fn!(tokio_stream::StreamExt::all(&mut BoxStream<()>, fn(())->bool): !Unpin);
|
||||
async_assert_fn!(tokio_stream::StreamExt::any(&mut BoxStream<()>, fn(())->bool): !Unpin);
|
||||
async_assert_fn!(tokio_stream::StreamExt::fold(&mut BoxStream<()>, (), fn((), ())->()): !Unpin);
|
||||
async_assert_fn!(tokio_stream::StreamExt::collect<Vec<()>>(&mut BoxStream<()>): !Unpin);
|
||||
@@ -1,7 +1,12 @@
|
||||
use tokio::stream::{self, Stream, StreamExt};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||
use tokio_test::{assert_pending, assert_ready, task};
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc;
|
||||
}
|
||||
|
||||
use support::mpsc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic_usage() {
|
||||
let one = stream::iter(vec![1, 2, 3]);
|
||||
@@ -36,8 +41,8 @@ async fn basic_usage() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn pending_first() {
|
||||
let (tx1, rx1) = mpsc::unbounded_channel();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel();
|
||||
let (tx1, rx1) = mpsc::unbounded_channel_stream();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut stream = task::spawn(rx1.chain(rx2));
|
||||
assert_eq!(stream.size_hint(), (0, None));
|
||||
@@ -74,7 +79,7 @@ async fn pending_first() {
|
||||
fn size_overflow() {
|
||||
struct Monster;
|
||||
|
||||
impl tokio::stream::Stream for Monster {
|
||||
impl tokio_stream::Stream for Monster {
|
||||
type Item = ();
|
||||
fn poll_next(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
@@ -1,7 +1,12 @@
|
||||
use tokio::stream::{self, StreamExt};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::{self as stream, StreamExt};
|
||||
use tokio_test::{assert_pending, assert_ready, assert_ready_err, assert_ready_ok, task};
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc;
|
||||
}
|
||||
|
||||
use support::mpsc;
|
||||
|
||||
#[allow(clippy::let_unit_value)]
|
||||
#[tokio::test]
|
||||
async fn empty_unit() {
|
||||
@@ -37,7 +42,7 @@ async fn empty_result() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn collect_vec_items() {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
let mut fut = task::spawn(rx.collect::<Vec<i32>>());
|
||||
|
||||
assert_pending!(fut.poll());
|
||||
@@ -58,7 +63,8 @@ async fn collect_vec_items() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn collect_string_items() {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut fut = task::spawn(rx.collect::<String>());
|
||||
|
||||
assert_pending!(fut.poll());
|
||||
@@ -79,7 +85,8 @@ async fn collect_string_items() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn collect_str_items() {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut fut = task::spawn(rx.collect::<String>());
|
||||
|
||||
assert_pending!(fut.poll());
|
||||
@@ -100,7 +107,8 @@ async fn collect_str_items() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn collect_results_ok() {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut fut = task::spawn(rx.collect::<Result<String, &str>>());
|
||||
|
||||
assert_pending!(fut.poll());
|
||||
@@ -121,7 +129,8 @@ async fn collect_results_ok() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn collect_results_err() {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut fut = task::spawn(rx.collect::<Result<String, &str>>());
|
||||
|
||||
assert_pending!(fut.poll());
|
||||
@@ -1,4 +1,4 @@
|
||||
use tokio::stream::{self, Stream, StreamExt};
|
||||
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic_usage() {
|
||||
@@ -1,4 +1,4 @@
|
||||
use tokio::stream::{Stream, StreamExt};
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
@@ -1,4 +1,4 @@
|
||||
use tokio::stream;
|
||||
use tokio_stream as stream;
|
||||
use tokio_test::task;
|
||||
|
||||
use std::iter;
|
||||
@@ -1,8 +1,13 @@
|
||||
use tokio::stream::{self, Stream, StreamExt};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||
use tokio_test::task;
|
||||
use tokio_test::{assert_pending, assert_ready};
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc;
|
||||
}
|
||||
|
||||
use support::mpsc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn merge_sync_streams() {
|
||||
let mut s = stream::iter(vec![0, 2, 4, 6]).merge(stream::iter(vec![1, 3, 5]));
|
||||
@@ -18,8 +23,8 @@ async fn merge_sync_streams() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn merge_async_streams() {
|
||||
let (tx1, rx1) = mpsc::unbounded_channel();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel();
|
||||
let (tx1, rx1) = mpsc::unbounded_channel_stream();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let mut rx = task::spawn(rx1.merge(rx2));
|
||||
|
||||
@@ -57,7 +62,7 @@ async fn merge_async_streams() {
|
||||
fn size_overflow() {
|
||||
struct Monster;
|
||||
|
||||
impl tokio::stream::Stream for Monster {
|
||||
impl tokio_stream::Stream for Monster {
|
||||
type Item = ();
|
||||
fn poll_next(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
@@ -1,4 +1,4 @@
|
||||
use tokio::stream::{self, Stream, StreamExt};
|
||||
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic_usage() {
|
||||
@@ -1,4 +1,4 @@
|
||||
use tokio::stream::{self, Stream, StreamExt};
|
||||
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||
use tokio_test::{assert_pending, task};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1,7 +1,12 @@
|
||||
use tokio::stream::{self, pending, Stream, StreamExt, StreamMap};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::{self as stream, pending, Stream, StreamExt, StreamMap};
|
||||
use tokio_test::{assert_ok, assert_pending, assert_ready, task};
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc;
|
||||
}
|
||||
|
||||
use support::mpsc;
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
macro_rules! assert_ready_some {
|
||||
@@ -38,7 +43,8 @@ async fn empty() {
|
||||
#[tokio::test]
|
||||
async fn single_entry() {
|
||||
let mut map = task::spawn(StreamMap::new());
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
let rx = Box::pin(rx);
|
||||
|
||||
assert_ready_none!(map.poll_next());
|
||||
|
||||
@@ -76,8 +82,11 @@ async fn single_entry() {
|
||||
#[tokio::test]
|
||||
async fn multiple_entries() {
|
||||
let mut map = task::spawn(StreamMap::new());
|
||||
let (tx1, rx1) = mpsc::unbounded_channel();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel();
|
||||
let (tx1, rx1) = mpsc::unbounded_channel_stream();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let rx1 = Box::pin(rx1);
|
||||
let rx2 = Box::pin(rx2);
|
||||
|
||||
map.insert("foo", rx1);
|
||||
map.insert("bar", rx2);
|
||||
@@ -132,7 +141,9 @@ async fn multiple_entries() {
|
||||
#[tokio::test]
|
||||
async fn insert_remove() {
|
||||
let mut map = task::spawn(StreamMap::new());
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let rx = Box::pin(rx);
|
||||
|
||||
assert_ready_none!(map.poll_next());
|
||||
|
||||
@@ -160,8 +171,11 @@ async fn insert_remove() {
|
||||
#[tokio::test]
|
||||
async fn replace() {
|
||||
let mut map = task::spawn(StreamMap::new());
|
||||
let (tx1, rx1) = mpsc::unbounded_channel();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel();
|
||||
let (tx1, rx1) = mpsc::unbounded_channel_stream();
|
||||
let (tx2, rx2) = mpsc::unbounded_channel_stream();
|
||||
|
||||
let rx1 = Box::pin(rx1);
|
||||
let rx2 = Box::pin(rx2);
|
||||
|
||||
assert!(map.insert("foo", rx1).is_none());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use tokio::stream::{self, StreamExt};
|
||||
use tokio::time::{self, sleep, Duration};
|
||||
use tokio_stream::{self, StreamExt};
|
||||
use tokio_test::*;
|
||||
|
||||
use futures::StreamExt as _;
|
||||
@@ -0,0 +1,15 @@
|
||||
use async_stream::stream;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||
use tokio_stream::Stream;
|
||||
|
||||
pub fn unbounded_channel_stream<T: Unpin>() -> (UnboundedSender<T>, impl Stream<Item = T>) {
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
let stream = stream! {
|
||||
while let Some(item) = rx.recv().await {
|
||||
yield item;
|
||||
}
|
||||
};
|
||||
|
||||
(tx, stream)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio::time;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_test::*;
|
||||
|
||||
use std::time::Duration;
|
||||
@@ -22,6 +22,8 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio", features = ["rt", "stream", "sync", "time", "test-util"] }
|
||||
tokio-stream = { version = "0.1", path = "../tokio-stream" }
|
||||
async-stream = "0.3"
|
||||
|
||||
bytes = "0.6.0"
|
||||
futures-core = "0.3.0"
|
||||
|
||||
+17
-6
@@ -22,8 +22,9 @@ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::{self, Duration, Instant, Sleep};
|
||||
|
||||
use futures_core::ready;
|
||||
use futures_core::{ready, Stream};
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -63,13 +64,13 @@ enum Action {
|
||||
WriteError(Option<Arc<io::Error>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Inner {
|
||||
actions: VecDeque<Action>,
|
||||
waiting: Option<Instant>,
|
||||
sleep: Option<Sleep>,
|
||||
read_wait: Option<Waker>,
|
||||
rx: mpsc::UnboundedReceiver<Action>,
|
||||
// rx: mpsc::UnboundedReceiver<Action>,
|
||||
rx: Pin<Box<dyn Stream<Item = Action> + Send>>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
@@ -184,7 +185,13 @@ impl Handle {
|
||||
|
||||
impl Inner {
|
||||
fn new(actions: VecDeque<Action>) -> (Inner, Handle) {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
let rx = Box::pin(async_stream::stream! {
|
||||
while let Some(item) = rx.recv().await {
|
||||
yield item;
|
||||
}
|
||||
});
|
||||
|
||||
let inner = Inner {
|
||||
actions,
|
||||
@@ -200,8 +207,6 @@ impl Inner {
|
||||
}
|
||||
|
||||
fn poll_action(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Action>> {
|
||||
use futures_core::stream::Stream;
|
||||
|
||||
Pin::new(&mut self.rx).poll_next(cx)
|
||||
}
|
||||
|
||||
@@ -485,3 +490,9 @@ fn is_task_ctx() -> bool {
|
||||
r
|
||||
}
|
||||
*/
|
||||
|
||||
impl fmt::Debug for Inner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Inner {{...}}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::pin::Pin;
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
use tokio::stream::Stream;
|
||||
use tokio_stream::Stream;
|
||||
|
||||
/// TODO: dox
|
||||
pub fn spawn<T>(task: T) -> Spawn<T> {
|
||||
|
||||
@@ -38,6 +38,7 @@ __docs_rs = ["futures-util"]
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio" }
|
||||
tokio-stream = { version = "0.1", path = "../tokio-stream" }
|
||||
|
||||
bytes = "0.6.0"
|
||||
futures-core = "0.3.0"
|
||||
|
||||
@@ -153,7 +153,7 @@ pub trait Decoder {
|
||||
/// calling `split` on the [`Framed`] returned by this method, which will
|
||||
/// break them into separate objects, allowing them to interact more easily.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`Framed`]: crate::codec::Framed
|
||||
fn framed<T: AsyncRead + AsyncWrite + Sized>(self, io: T) -> Framed<T, Self>
|
||||
|
||||
@@ -2,10 +2,8 @@ use crate::codec::decoder::Decoder;
|
||||
use crate::codec::encoder::Encoder;
|
||||
use crate::codec::framed_impl::{FramedImpl, RWFrames, ReadFrame, WriteFrame};
|
||||
|
||||
use tokio::{
|
||||
io::{AsyncRead, AsyncWrite},
|
||||
stream::Stream,
|
||||
};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use bytes::BytesMut;
|
||||
use futures_sink::Sink;
|
||||
@@ -22,7 +20,7 @@ pin_project! {
|
||||
/// You can create a `Framed` instance by using the [`Decoder::framed`] adapter, or
|
||||
/// by using the `new` function seen below.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`AsyncRead`]: tokio::io::AsyncRead
|
||||
/// [`Decoder::framed`]: crate::codec::Decoder::framed()
|
||||
@@ -54,7 +52,7 @@ where
|
||||
/// calling [`split`] on the `Framed` returned by this method, which will
|
||||
/// break them into separate objects, allowing them to interact more easily.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`Decode`]: crate::codec::Decoder
|
||||
/// [`Encoder`]: crate::codec::Encoder
|
||||
@@ -88,7 +86,7 @@ where
|
||||
/// calling [`split`] on the `Framed` returned by this method, which will
|
||||
/// break them into separate objects, allowing them to interact more easily.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`Decode`]: crate::codec::Decoder
|
||||
/// [`Encoder`]: crate::codec::Encoder
|
||||
@@ -133,7 +131,7 @@ impl<T, U> Framed<T, U> {
|
||||
/// calling [`split`] on the `Framed` returned by this method, which will
|
||||
/// break them into separate objects, allowing them to interact more easily.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`Decoder`]: crate::codec::Decoder
|
||||
/// [`Encoder`]: crate::codec::Encoder
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use crate::codec::decoder::Decoder;
|
||||
use crate::codec::encoder::Encoder;
|
||||
|
||||
use tokio::{
|
||||
io::{AsyncRead, AsyncWrite},
|
||||
stream::Stream,
|
||||
};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use bytes::BytesMut;
|
||||
use futures_core::ready;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::codec::framed_impl::{FramedImpl, ReadFrame};
|
||||
use crate::codec::Decoder;
|
||||
|
||||
use tokio::{io::AsyncRead, stream::Stream};
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use bytes::BytesMut;
|
||||
use futures_sink::Sink;
|
||||
@@ -13,7 +14,7 @@ use std::task::{Context, Poll};
|
||||
pin_project! {
|
||||
/// A [`Stream`] of messages decoded from an [`AsyncRead`].
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`AsyncRead`]: tokio::io::AsyncRead
|
||||
pub struct FramedRead<T, D> {
|
||||
#[pin]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::codec::encoder::Encoder;
|
||||
use crate::codec::framed_impl::{FramedImpl, WriteFrame};
|
||||
|
||||
use tokio::{io::AsyncWrite, stream::Stream};
|
||||
use tokio::io::AsyncWrite;
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use futures_sink::Sink;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! [`AsyncRead`]: tokio::io::AsyncRead
|
||||
//! [`AsyncWrite`]: tokio::io::AsyncWrite
|
||||
//! [`Stream`]: tokio::stream::Stream
|
||||
//! [`Stream`]: tokio_stream::Stream
|
||||
//! [`Sink`]: futures_sink::Sink
|
||||
|
||||
mod bytes_codec;
|
||||
|
||||
@@ -167,10 +167,8 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tokio::{
|
||||
io::{repeat, AsyncReadExt, Repeat},
|
||||
stream::{once, Once, StreamExt},
|
||||
};
|
||||
use tokio::io::{repeat, AsyncReadExt, Repeat};
|
||||
use tokio_stream::{once, Once, StreamExt};
|
||||
|
||||
#[tokio::test]
|
||||
async fn either_is_stream() {
|
||||
|
||||
@@ -13,7 +13,7 @@ use tokio::io::AsyncRead;
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, BytesMut};
|
||||
/// use tokio::stream;
|
||||
/// use tokio_stream as stream;
|
||||
/// use tokio::io::Result;
|
||||
/// use tokio_util::io::{StreamReader, read_buf};
|
||||
/// # #[tokio::main]
|
||||
|
||||
@@ -18,7 +18,7 @@ pin_project! {
|
||||
/// ```
|
||||
/// # #[tokio::main]
|
||||
/// # async fn main() -> std::io::Result<()> {
|
||||
/// use tokio::stream::StreamExt;
|
||||
/// use tokio_stream::StreamExt;
|
||||
/// use tokio_util::io::ReaderStream;
|
||||
///
|
||||
/// // Create a stream of data.
|
||||
@@ -40,7 +40,7 @@ pin_project! {
|
||||
///
|
||||
/// [`AsyncRead`]: tokio::io::AsyncRead
|
||||
/// [`StreamReader`]: crate::io::StreamReader
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
#[derive(Debug)]
|
||||
pub struct ReaderStream<R> {
|
||||
// Reader itself.
|
||||
@@ -58,7 +58,7 @@ impl<R: AsyncRead> ReaderStream<R> {
|
||||
/// `Result<Bytes, std::io::Error>`.
|
||||
///
|
||||
/// [`AsyncRead`]: tokio::io::AsyncRead
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
pub fn new(reader: R) -> Self {
|
||||
ReaderStream {
|
||||
reader: Some(reader),
|
||||
|
||||
@@ -21,7 +21,7 @@ pin_project! {
|
||||
/// # async fn main() -> std::io::Result<()> {
|
||||
///
|
||||
/// // Create a stream from an iterator.
|
||||
/// let stream = tokio::stream::iter(vec![
|
||||
/// let stream = tokio_stream::iter(vec![
|
||||
/// Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
|
||||
/// Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
|
||||
/// Result::Ok(Bytes::from_static(&[8, 9, 10, 11])),
|
||||
@@ -51,7 +51,7 @@ pin_project! {
|
||||
/// ```
|
||||
///
|
||||
/// [`AsyncRead`]: tokio::io::AsyncRead
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`ReaderStream`]: crate::io::ReaderStream
|
||||
#[derive(Debug)]
|
||||
pub struct StreamReader<S, B> {
|
||||
|
||||
@@ -72,7 +72,7 @@ mod util {
|
||||
///
|
||||
/// ```
|
||||
/// use bytes::{Bytes, BytesMut};
|
||||
/// use tokio::stream;
|
||||
/// use tokio_stream as stream;
|
||||
/// use tokio::io::Result;
|
||||
/// use tokio_util::io::{StreamReader, poll_read_buf};
|
||||
/// use futures::future::poll_fn;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::codec::{Decoder, Encoder};
|
||||
|
||||
use tokio::{io::ReadBuf, net::UdpSocket, stream::Stream};
|
||||
use tokio::{io::ReadBuf, net::UdpSocket};
|
||||
use tokio_stream::Stream;
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures_core::ready;
|
||||
@@ -27,7 +28,7 @@ use std::{io, mem::MaybeUninit};
|
||||
/// calling [`split`] on the `UdpFramed` returned by this method, which will break
|
||||
/// them into separate objects, allowing them to interact more easily.
|
||||
///
|
||||
/// [`Stream`]: tokio::stream::Stream
|
||||
/// [`Stream`]: tokio_stream::Stream
|
||||
/// [`Sink`]: futures_sink::Sink
|
||||
/// [`split`]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html#method.split
|
||||
#[must_use = "sinks do nothing unless polled"]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::{prelude::*, stream::StreamExt};
|
||||
use tokio::prelude::*;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_test::assert_ok;
|
||||
use tokio_util::codec::{Decoder, Encoder, Framed, FramedParts};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::{AsyncRead, ReadBuf};
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
/// produces at most `remaining` zeros, that returns error.
|
||||
/// each time it reads at most 31 byte.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::stream::iter;
|
||||
use tokio_stream::iter;
|
||||
use tokio_util::io::StreamReader;
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::{net::UdpSocket, stream::StreamExt};
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec::{Decoder, Encoder, LinesCodec};
|
||||
use tokio_util::udp::UdpFramed;
|
||||
|
||||
|
||||
@@ -123,9 +123,11 @@ optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = { version = "0.4.0", path = "../tokio-test" }
|
||||
tokio-stream = { version = "0.1", path = "../tokio-stream" }
|
||||
futures = { version = "0.3.0", features = ["async-await"] }
|
||||
proptest = "0.10.0"
|
||||
tempfile = "3.1.0"
|
||||
async-stream = "0.3"
|
||||
|
||||
[target.'cfg(loom)'.dev-dependencies]
|
||||
loom = { version = "0.3.5", features = ["futures", "checkpoint"] }
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@
|
||||
//! Consider a future like this one:
|
||||
//!
|
||||
//! ```
|
||||
//! # use tokio::stream::{Stream, StreamExt};
|
||||
//! # use tokio_stream::{Stream, StreamExt};
|
||||
//! async fn drop_all<I: Stream + Unpin>(mut input: I) {
|
||||
//! while let Some(_) = input.next().await {}
|
||||
//! }
|
||||
@@ -25,7 +25,7 @@
|
||||
//! opt-in yield points, this problem is alleviated:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! # use tokio::stream::{Stream, StreamExt};
|
||||
//! # use tokio_stream::{Stream, StreamExt};
|
||||
//! async fn drop_all<I: Stream + Unpin>(mut input: I) {
|
||||
//! while let Some(_) = input.next().await {
|
||||
//! tokio::coop::proceed().await;
|
||||
|
||||
@@ -29,12 +29,11 @@ pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This [`Stream`] will return an [`Err`] if there's some sort of intermittent
|
||||
/// This stream will return an [`Err`] if there's some sort of intermittent
|
||||
/// IO error during iteration.
|
||||
///
|
||||
/// [`read_dir`]: read_dir
|
||||
/// [`DirEntry`]: DirEntry
|
||||
/// [`Stream`]: crate::stream::Stream
|
||||
/// [`Err`]: std::result::Result::Err
|
||||
#[derive(Debug)]
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
@@ -111,19 +110,6 @@ feature! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl crate::stream::Stream for ReadDir {
|
||||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(match ready!(self.poll_next_entry(cx)) {
|
||||
Ok(Some(entry)) => Some(Ok(entry)),
|
||||
Ok(None) => None,
|
||||
Err(err) => Some(Err(err)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Entries returned by the [`ReadDir`] stream.
|
||||
///
|
||||
/// [`ReadDir`]: struct@ReadDir
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@
|
||||
//! [`Read`]: std::io::Read
|
||||
//! [`SeekFrom`]: enum@SeekFrom
|
||||
//! [`Sink`]: https://docs.rs/futures/0.3/futures/sink/trait.Sink.html
|
||||
//! [`Stream`]: crate::stream::Stream
|
||||
//! [`Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
|
||||
//! [`Write`]: std::io::Write
|
||||
cfg_io_blocking! {
|
||||
pub(crate) mod blocking;
|
||||
|
||||
@@ -228,7 +228,6 @@ cfg_io_util! {
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::io::AsyncBufReadExt;
|
||||
/// use tokio::stream::StreamExt;
|
||||
///
|
||||
/// use std::io::Cursor;
|
||||
///
|
||||
@@ -236,12 +235,12 @@ cfg_io_util! {
|
||||
/// async fn main() {
|
||||
/// let cursor = Cursor::new(b"lorem\nipsum\r\ndolor");
|
||||
///
|
||||
/// let mut lines = cursor.lines().map(|res| res.unwrap());
|
||||
/// let mut lines = cursor.lines();
|
||||
///
|
||||
/// assert_eq!(lines.next().await, Some(String::from("lorem")));
|
||||
/// assert_eq!(lines.next().await, Some(String::from("ipsum")));
|
||||
/// assert_eq!(lines.next().await, Some(String::from("dolor")));
|
||||
/// assert_eq!(lines.next().await, None);
|
||||
/// assert_eq!(lines.next_line().await.unwrap(), Some(String::from("lorem")));
|
||||
/// assert_eq!(lines.next_line().await.unwrap(), Some(String::from("ipsum")));
|
||||
/// assert_eq!(lines.next_line().await.unwrap(), Some(String::from("dolor")));
|
||||
/// assert_eq!(lines.next_line().await.unwrap(), None);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
||||
@@ -108,19 +108,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl<R: AsyncBufRead> crate::stream::Stream for Lines<R> {
|
||||
type Item = io::Result<String>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(match ready!(self.poll_next_line(cx)) {
|
||||
Ok(Some(line)) => Some(Ok(line)),
|
||||
Ok(None) => None,
|
||||
Err(err) => Some(Err(err)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -89,19 +89,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl<R: AsyncBufRead> crate::stream::Stream for Split<R> {
|
||||
type Item = io::Result<Vec<u8>>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(match ready!(self.poll_next_segment(cx)) {
|
||||
Ok(Some(segment)) => Some(Ok(segment)),
|
||||
Ok(None) => None,
|
||||
Err(err) => Some(Err(err)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
+7
-4
@@ -389,10 +389,6 @@ cfg_signal_internal! {
|
||||
pub(crate) mod signal;
|
||||
}
|
||||
|
||||
cfg_stream! {
|
||||
pub mod stream;
|
||||
}
|
||||
|
||||
cfg_sync! {
|
||||
pub mod sync;
|
||||
}
|
||||
@@ -411,6 +407,13 @@ cfg_time! {
|
||||
|
||||
mod util;
|
||||
|
||||
/// Due to the `Stream` trait's inclusion in `std` landing later than Tokio's 1.0
|
||||
/// release, most of the Tokio stream utilities have been moved into the [`tokio-stream`]
|
||||
/// crate.
|
||||
///
|
||||
/// [`tokio-stream`]: https://docs.rs/tokio-stream
|
||||
pub mod stream {}
|
||||
|
||||
cfg_macros! {
|
||||
/// Implementation detail of the `select!` macro. This macro is **not**
|
||||
/// intended to be used as part of the public API and is permitted to
|
||||
|
||||
@@ -241,16 +241,6 @@ macro_rules! cfg_not_signal_internal {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_stream {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = "stream")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_sync {
|
||||
($($item:item)*) => {
|
||||
$(
|
||||
@@ -361,7 +351,6 @@ macro_rules! cfg_coop {
|
||||
feature = "rt",
|
||||
feature = "signal",
|
||||
feature = "sync",
|
||||
feature = "stream",
|
||||
feature = "time",
|
||||
))]
|
||||
$item
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::{pin, select};
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// async fn my_async_fn() {
|
||||
/// // async logic here
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
/// Basic stream selecting.
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -188,7 +188,7 @@
|
||||
/// is complete, all calls to `next()` return `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
@@ -220,7 +220,7 @@
|
||||
/// Here, a stream is consumed for at most 1 second.
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::{self, StreamExt};
|
||||
/// use tokio_stream::{self as stream, StreamExt};
|
||||
/// use tokio::time::{self, Duration};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
|
||||
@@ -11,10 +11,8 @@ use std::task::{Context, Poll};
|
||||
cfg_net! {
|
||||
/// A TCP socket server, listening for connections.
|
||||
///
|
||||
/// You can accept a new connection by using the [`accept`](`TcpListener::accept`) method. Alternatively `TcpListener`
|
||||
/// implements the [`Stream`](`crate::stream::Stream`) trait, which allows you to use the listener in places that want a
|
||||
/// stream. The stream will never return `None` and will also not yield the peer's `SocketAddr` structure. Iterating over
|
||||
/// it is equivalent to calling accept in a loop.
|
||||
/// You can accept a new connection by using the [`accept`](`TcpListener::accept`)
|
||||
/// method.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -47,24 +45,6 @@ cfg_net! {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Using `impl Stream`:
|
||||
/// ```no_run
|
||||
/// use tokio::{net::TcpListener, stream::StreamExt};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let mut listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
|
||||
/// while let Some(stream) = listener.next().await {
|
||||
/// match stream {
|
||||
/// Ok(stream) => {
|
||||
/// println!("new client!");
|
||||
/// }
|
||||
/// Err(e) => { /* connection failed */ }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct TcpListener {
|
||||
io: PollEvented<mio::net::TcpListener>,
|
||||
}
|
||||
@@ -323,16 +303,6 @@ impl TcpListener {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl crate::stream::Stream for TcpListener {
|
||||
type Item = io::Result<TcpStream>;
|
||||
|
||||
fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let (socket, _) = ready!(self.poll_accept(cx))?;
|
||||
Poll::Ready(Some(Ok(socket)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<net::TcpListener> for TcpListener {
|
||||
type Error = io::Error;
|
||||
|
||||
|
||||
@@ -23,10 +23,11 @@ cfg_net! {
|
||||
///
|
||||
/// # Streams
|
||||
///
|
||||
/// If you need to listen over UDP and produce a [`Stream`](`crate::stream::Stream`), you can look
|
||||
/// If you need to listen over UDP and produce a [`Stream`], you can look
|
||||
/// at [`UdpFramed`].
|
||||
///
|
||||
/// [`UdpFramed`]: https://docs.rs/tokio-util/latest/tokio_util/udp/struct.UdpFramed.html
|
||||
/// [`Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
|
||||
///
|
||||
/// # Example: one to many (bind)
|
||||
///
|
||||
|
||||
@@ -12,10 +12,7 @@ use std::task::{Context, Poll};
|
||||
cfg_net_unix! {
|
||||
/// A Unix socket which can accept connections from other Unix sockets.
|
||||
///
|
||||
/// You can accept a new connection by using the [`accept`](`UnixListener::accept`) method. Alternatively `UnixListener`
|
||||
/// implements the [`Stream`](`crate::stream::Stream`) trait, which allows you to use the listener in places that want a
|
||||
/// stream. The stream will never return `None` and will also not yield the peer's `SocketAddr` structure. Iterating over
|
||||
/// it is equivalent to calling accept in a loop.
|
||||
/// You can accept a new connection by using the [`accept`](`UnixListener::accept`) method.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -29,14 +26,13 @@ cfg_net_unix! {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tokio::net::UnixListener;
|
||||
/// use tokio::stream::StreamExt;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let mut listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
||||
/// while let Some(stream) = listener.next().await {
|
||||
/// match stream {
|
||||
/// Ok(stream) => {
|
||||
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
||||
/// loop {
|
||||
/// match listener.accept().await {
|
||||
/// Ok((stream, _addr)) => {
|
||||
/// println!("new client!");
|
||||
/// }
|
||||
/// Err(e) => { /* connection failed */ }
|
||||
@@ -127,16 +123,6 @@ impl UnixListener {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl crate::stream::Stream for UnixListener {
|
||||
type Item = io::Result<UnixStream>;
|
||||
|
||||
fn poll_next(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let (socket, _) = ready!(self.poll_accept(cx))?;
|
||||
Poll::Ready(Some(Ok(socket)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<std::os::unix::net::UnixListener> for UnixListener {
|
||||
type Error = io::Error;
|
||||
|
||||
|
||||
@@ -407,16 +407,6 @@ impl Signal {
|
||||
}
|
||||
}
|
||||
|
||||
cfg_stream! {
|
||||
impl crate::stream::Stream for Signal {
|
||||
type Item = ();
|
||||
|
||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||
self.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Work around for abstracting streams internally
|
||||
pub(crate) trait InternalStream: Unpin {
|
||||
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>;
|
||||
|
||||
@@ -231,16 +231,6 @@ impl CtrlC {
|
||||
}
|
||||
}
|
||||
|
||||
cfg_stream! {
|
||||
impl crate::stream::Stream for CtrlC {
|
||||
type Item = ();
|
||||
|
||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||
self.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a stream which receives "ctrl-break" notifications sent to the process
|
||||
/// via `SetConsoleCtrlHandler`.
|
||||
///
|
||||
@@ -313,16 +303,6 @@ impl CtrlBreak {
|
||||
}
|
||||
}
|
||||
|
||||
cfg_stream! {
|
||||
impl crate::stream::Stream for CtrlBreak {
|
||||
type Item = ();
|
||||
|
||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||
self.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new stream which receives "ctrl-break" notifications sent to the
|
||||
/// process.
|
||||
///
|
||||
@@ -351,7 +331,6 @@ pub fn ctrl_break() -> io::Result<CtrlBreak> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::runtime::Runtime;
|
||||
use crate::stream::StreamExt;
|
||||
|
||||
use tokio_test::{assert_ok, assert_pending, assert_ready_ok, task};
|
||||
|
||||
@@ -388,7 +367,7 @@ mod tests {
|
||||
super::handler(CTRL_BREAK_EVENT);
|
||||
}
|
||||
|
||||
ctrl_break.next().await.unwrap();
|
||||
ctrl_break.recv().await.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -940,48 +940,6 @@ impl<T: Clone> Receiver<T> {
|
||||
let guard = self.recv_ref(None)?;
|
||||
guard.clone_value().ok_or(TryRecvError::Closed)
|
||||
}
|
||||
|
||||
/// Convert the receiver into a `Stream`.
|
||||
///
|
||||
/// The conversion allows using `Receiver` with APIs that require stream
|
||||
/// values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::stream::StreamExt;
|
||||
/// use tokio::sync::broadcast;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let (tx, rx) = broadcast::channel(128);
|
||||
///
|
||||
/// tokio::spawn(async move {
|
||||
/// for i in 0..10_i32 {
|
||||
/// tx.send(i).unwrap();
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// // Streams must be pinned to iterate.
|
||||
/// tokio::pin! {
|
||||
/// let stream = rx
|
||||
/// .into_stream()
|
||||
/// .filter(Result::is_ok)
|
||||
/// .map(Result::unwrap)
|
||||
/// .filter(|v| v % 2 == 0)
|
||||
/// .map(|v| v + 1);
|
||||
/// }
|
||||
///
|
||||
/// while let Some(i) = stream.next().await {
|
||||
/// println!("{}", i);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "stream")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
|
||||
pub fn into_stream(self) -> impl Stream<Item = Result<T, RecvError>> {
|
||||
Recv::new(Borrow(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Receiver<T> {
|
||||
@@ -1058,31 +1016,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
cfg_stream! {
|
||||
use futures_core::Stream;
|
||||
|
||||
impl<R, T: Clone> Stream for Recv<R, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
T: Clone,
|
||||
{
|
||||
type Item = Result<T, RecvError>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let (receiver, waiter) = self.project();
|
||||
|
||||
let guard = match receiver.recv_ref(Some((waiter, cx.waker()))) {
|
||||
Ok(value) => value,
|
||||
Err(TryRecvError::Empty) => return Poll::Pending,
|
||||
Err(TryRecvError::Lagged(n)) => return Poll::Ready(Some(Err(RecvError::Lagged(n)))),
|
||||
Err(TryRecvError::Closed) => return Poll::Ready(None),
|
||||
};
|
||||
|
||||
Poll::Ready(guard.clone_value().map(Ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T> Drop for Recv<R, T>
|
||||
where
|
||||
R: AsMut<Receiver<T>>,
|
||||
|
||||
@@ -11,7 +11,7 @@ cfg_time! {
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
#[cfg(any(feature = "signal", feature = "process", feature = "stream"))]
|
||||
#[cfg(any(feature = "signal", feature = "process"))]
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// Send values to the associated `Receiver`.
|
||||
@@ -255,16 +255,6 @@ impl<T> fmt::Debug for Receiver<T> {
|
||||
|
||||
impl<T> Unpin for Receiver<T> {}
|
||||
|
||||
cfg_stream! {
|
||||
impl<T> crate::stream::Stream for Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||
self.chan.recv(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
pub(crate) fn new(chan: chan::Tx<T, Semaphore>) -> Sender<T> {
|
||||
Sender { chan }
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
//! Similar to the `mpsc` channels provided by `std`, the channel constructor
|
||||
//! functions provide separate send and receive handles, [`Sender`] and
|
||||
//! [`Receiver`] for the bounded channel, [`UnboundedSender`] and
|
||||
//! [`UnboundedReceiver`] for the unbounded channel. Both [`Receiver`] and
|
||||
//! [`UnboundedReceiver`] implement [`Stream`] and allow a task to read
|
||||
//! values out of the channel. If there is no message to read, the current task
|
||||
//! will be notified when a new value is sent. [`Sender`] and
|
||||
//! [`UnboundedReceiver`] for the unbounded channel. If there is no message to read,
|
||||
//! the current task will be notified when a new value is sent. [`Sender`] and
|
||||
//! [`UnboundedSender`] allow sending values into the channel. If the bounded
|
||||
//! channel is at capacity, the send is rejected and the task will be notified
|
||||
//! when additional capacity is available. In other words, the channel provides
|
||||
@@ -62,7 +60,6 @@
|
||||
//!
|
||||
//! [`Sender`]: crate::sync::mpsc::Sender
|
||||
//! [`Receiver`]: crate::sync::mpsc::Receiver
|
||||
//! [`Stream`]: crate::stream::Stream
|
||||
//! [bounded-send]: crate::sync::mpsc::Sender::send()
|
||||
//! [bounded-recv]: crate::sync::mpsc::Receiver::recv()
|
||||
//! [blocking-send]: crate::sync::mpsc::Sender::blocking_send()
|
||||
|
||||
@@ -161,15 +161,6 @@ impl<T> UnboundedReceiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl<T> crate::stream::Stream for UnboundedReceiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||
self.poll_recv(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UnboundedSender<T> {
|
||||
pub(crate) fn new(chan: chan::Tx<T, Semaphore>) -> UnboundedSender<T> {
|
||||
UnboundedSender { chan }
|
||||
|
||||
@@ -107,11 +107,6 @@ pub fn interval_at(start: Instant, period: Duration) -> Interval {
|
||||
}
|
||||
|
||||
/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
|
||||
///
|
||||
/// This type only implements the [`Stream`] trait if the "stream" feature is
|
||||
/// enabled.
|
||||
///
|
||||
/// [`Stream`]: trait@crate::stream::Stream
|
||||
#[derive(Debug)]
|
||||
pub struct Interval {
|
||||
/// Future that completes the next time the `Interval` yields a value.
|
||||
@@ -162,12 +157,3 @@ impl Interval {
|
||||
poll_fn(|cx| self.poll_tick(cx)).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
impl crate::stream::Stream for Interval {
|
||||
type Item = Instant;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
|
||||
Poll::Ready(Some(ready!(self.poll_tick(cx))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ cfg_io_driver! {
|
||||
))]
|
||||
pub(crate) mod linked_list;
|
||||
|
||||
#[cfg(any(feature = "rt-multi-thread", feature = "macros", feature = "stream"))]
|
||||
#[cfg(any(feature = "rt-multi-thread", feature = "macros"))]
|
||||
mod rand;
|
||||
|
||||
cfg_rt! {
|
||||
@@ -32,6 +32,6 @@ cfg_rt_multi_thread! {
|
||||
|
||||
pub(crate) mod trace;
|
||||
|
||||
#[cfg(any(feature = "macros", feature = "stream"))]
|
||||
#[cfg(any(feature = "macros"))]
|
||||
#[cfg_attr(not(feature = "macros"), allow(unreachable_pub))]
|
||||
pub use rand::thread_rng_n;
|
||||
|
||||
@@ -52,7 +52,7 @@ impl FastRand {
|
||||
}
|
||||
|
||||
// Used by the select macro and `StreamMap`
|
||||
#[cfg(any(feature = "macros", feature = "stream"))]
|
||||
#[cfg(any(feature = "macros"))]
|
||||
#[doc(hidden)]
|
||||
#[cfg_attr(not(feature = "macros"), allow(unreachable_pub))]
|
||||
pub fn thread_rng_n(n: u32) -> u32 {
|
||||
|
||||
@@ -14,8 +14,7 @@ type BoxFutureSync<T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> +
|
||||
type BoxFutureSend<T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send>>;
|
||||
#[allow(dead_code)]
|
||||
type BoxFuture<T> = std::pin::Pin<Box<dyn std::future::Future<Output = T>>>;
|
||||
#[allow(dead_code)]
|
||||
type BoxStream<T> = std::pin::Pin<Box<dyn tokio::stream::Stream<Item = T>>>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
type BoxAsyncRead = std::pin::Pin<Box<dyn tokio::io::AsyncBufRead>>;
|
||||
#[allow(dead_code)]
|
||||
@@ -222,10 +221,6 @@ async_assert_fn!(tokio::signal::ctrl_c(): Send & Sync);
|
||||
#[cfg(unix)]
|
||||
async_assert_fn!(tokio::signal::unix::Signal::recv(_): Send & Sync);
|
||||
|
||||
async_assert_fn!(tokio::stream::empty<Rc<u8>>(): Send & Sync);
|
||||
async_assert_fn!(tokio::stream::pending<Rc<u8>>(): Send & Sync);
|
||||
async_assert_fn!(tokio::stream::iter(std::vec::IntoIter<u8>): Send & Sync);
|
||||
|
||||
async_assert_fn!(tokio::sync::Barrier::wait(_): Send & Sync);
|
||||
async_assert_fn!(tokio::sync::Mutex<u8>::lock(_): Send & Sync);
|
||||
async_assert_fn!(tokio::sync::Mutex<Cell<u8>>::lock(_): Send & Sync);
|
||||
@@ -285,13 +280,6 @@ async_assert_fn!(tokio::time::timeout_at(Instant, BoxFutureSend<()>): Send & !Sy
|
||||
async_assert_fn!(tokio::time::timeout_at(Instant, BoxFuture<()>): !Send & !Sync);
|
||||
async_assert_fn!(tokio::time::Interval::tick(_): Send & Sync);
|
||||
|
||||
async_assert_fn!(tokio::stream::StreamExt::next(&mut BoxStream<()>): !Unpin);
|
||||
async_assert_fn!(tokio::stream::StreamExt::try_next(&mut BoxStream<Result<(), ()>>): !Unpin);
|
||||
async_assert_fn!(tokio::stream::StreamExt::all(&mut BoxStream<()>, fn(())->bool): !Unpin);
|
||||
async_assert_fn!(tokio::stream::StreamExt::any(&mut BoxStream<()>, fn(())->bool): !Unpin);
|
||||
async_assert_fn!(tokio::stream::StreamExt::fold(&mut BoxStream<()>, (), fn((), ())->()): !Unpin);
|
||||
async_assert_fn!(tokio::stream::StreamExt::collect<Vec<()>>(&mut BoxStream<()>): !Unpin);
|
||||
|
||||
async_assert_fn!(tokio::io::AsyncBufReadExt::read_until(&mut BoxAsyncRead, u8, &mut Vec<u8>): !Unpin);
|
||||
async_assert_fn!(tokio::io::AsyncBufReadExt::read_line(&mut BoxAsyncRead, &mut String): !Unpin);
|
||||
async_assert_fn!(tokio::io::AsyncReadExt::read(&mut BoxAsyncRead, &mut [u8]): !Unpin);
|
||||
|
||||
@@ -85,35 +85,3 @@ async fn read_inherent() {
|
||||
vec!["aa".to_string(), "bb".to_string(), "cc".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn read_stream() {
|
||||
use tokio::stream::StreamExt;
|
||||
|
||||
let base_dir = tempdir().unwrap();
|
||||
|
||||
let p = base_dir.path();
|
||||
std::fs::create_dir(p.join("aa")).unwrap();
|
||||
std::fs::create_dir(p.join("bb")).unwrap();
|
||||
std::fs::create_dir(p.join("cc")).unwrap();
|
||||
|
||||
let files = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let f = files.clone();
|
||||
let p = p.to_path_buf();
|
||||
|
||||
let mut entries = fs::read_dir(p).await.unwrap();
|
||||
|
||||
while let Some(res) = entries.next().await {
|
||||
let e = assert_ok!(res);
|
||||
let s = e.file_name().to_str().unwrap().to_string();
|
||||
f.lock().unwrap().push(s);
|
||||
}
|
||||
|
||||
let mut files = files.lock().unwrap();
|
||||
files.sort(); // because the order is not guaranteed
|
||||
assert_eq!(
|
||||
*files,
|
||||
vec!["aa".to_string(), "bb".to_string(), "cc".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,3 @@ async fn lines_inherent() {
|
||||
assert_eq!(b, "");
|
||||
assert!(assert_ok!(st.next_line().await).is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn lines_stream() {
|
||||
use tokio::stream::StreamExt;
|
||||
|
||||
let rd: &[u8] = b"hello\r\nworld\n\n";
|
||||
let mut st = rd.lines();
|
||||
|
||||
let b = assert_ok!(st.next().await.unwrap());
|
||||
assert_eq!(b, "hello");
|
||||
let b = assert_ok!(st.next().await.unwrap());
|
||||
assert_eq!(b, "world");
|
||||
let b = assert_ok!(st.next().await.unwrap());
|
||||
assert_eq!(b, "");
|
||||
assert!(st.next().await.is_none());
|
||||
}
|
||||
|
||||
+11
-4
@@ -2,12 +2,16 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use tokio::sync::oneshot;
|
||||
use tokio_test::{assert_err, assert_ok};
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc_stream;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spawned_task_does_not_progress_without_block_on() {
|
||||
let (tx, mut rx) = oneshot::channel();
|
||||
@@ -36,7 +40,7 @@ fn no_extra_poll() {
|
||||
Arc,
|
||||
};
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::stream::{Stream, StreamExt};
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
|
||||
pin_project! {
|
||||
struct TrackPolls<S> {
|
||||
@@ -58,8 +62,8 @@ fn no_extra_poll() {
|
||||
}
|
||||
}
|
||||
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let mut rx = TrackPolls {
|
||||
let (tx, rx) = support::mpsc_stream::unbounded_channel_stream::<()>();
|
||||
let rx = TrackPolls {
|
||||
npolls: Arc::new(AtomicUsize::new(0)),
|
||||
s: rx,
|
||||
};
|
||||
@@ -67,6 +71,9 @@ fn no_extra_poll() {
|
||||
|
||||
let rt = rt();
|
||||
|
||||
// TODO: could probably avoid this, but why not.
|
||||
let mut rx = Box::pin(rx);
|
||||
|
||||
rt.spawn(async move { while rx.next().await.is_some() {} });
|
||||
rt.block_on(async {
|
||||
tokio::task::yield_now().await;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use async_stream::stream;
|
||||
use tokio::sync::mpsc::{self, Sender, UnboundedSender};
|
||||
use tokio_stream::Stream;
|
||||
|
||||
pub fn unbounded_channel_stream<T: Unpin>() -> (UnboundedSender<T>, impl Stream<Item = T>) {
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
let stream = stream! {
|
||||
while let Some(item) = rx.recv().await {
|
||||
yield item;
|
||||
}
|
||||
};
|
||||
|
||||
(tx, stream)
|
||||
}
|
||||
|
||||
pub fn channel_stream<T: Unpin>(size: usize) -> (Sender<T>, impl Stream<Item = T>) {
|
||||
let (tx, mut rx) = mpsc::channel(size);
|
||||
|
||||
let stream = stream! {
|
||||
while let Some(item) = rx.recv().await {
|
||||
yield item;
|
||||
}
|
||||
};
|
||||
|
||||
(tx, stream)
|
||||
}
|
||||
@@ -89,46 +89,6 @@ fn send_two_recv() {
|
||||
assert_empty!(rx2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn send_recv_into_stream_ready() {
|
||||
use tokio::stream::StreamExt;
|
||||
|
||||
let (tx, rx) = broadcast::channel::<i32>(8);
|
||||
tokio::pin! {
|
||||
let rx = rx.into_stream();
|
||||
}
|
||||
|
||||
assert_ok!(tx.send(1));
|
||||
assert_ok!(tx.send(2));
|
||||
|
||||
assert_eq!(Some(Ok(1)), rx.next().await);
|
||||
assert_eq!(Some(Ok(2)), rx.next().await);
|
||||
|
||||
drop(tx);
|
||||
|
||||
assert_eq!(None, rx.next().await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn send_recv_into_stream_pending() {
|
||||
use tokio::stream::StreamExt;
|
||||
|
||||
let (tx, rx) = broadcast::channel::<i32>(8);
|
||||
|
||||
tokio::pin! {
|
||||
let rx = rx.into_stream();
|
||||
}
|
||||
|
||||
let mut recv = task::spawn(rx.next());
|
||||
assert_pending!(recv.poll());
|
||||
|
||||
assert_ok!(tx.send(1));
|
||||
|
||||
assert!(recv.is_woken());
|
||||
let val = assert_ready!(recv.poll());
|
||||
assert_eq!(val, Some(Ok(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_recv_bounded() {
|
||||
let (tx, mut rx) = broadcast::channel(16);
|
||||
|
||||
@@ -13,6 +13,10 @@ use tokio_test::{
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc_stream;
|
||||
}
|
||||
|
||||
trait AssertSend: Send {}
|
||||
impl AssertSend for mpsc::Sender<i32> {}
|
||||
impl AssertSend for mpsc::Receiver<i32> {}
|
||||
@@ -80,9 +84,10 @@ async fn reserve_disarm() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn send_recv_stream_with_buffer() {
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
let (tx, mut rx) = mpsc::channel::<i32>(16);
|
||||
let (tx, rx) = support::mpsc_stream::channel_stream::<i32>(16);
|
||||
let mut rx = Box::pin(rx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
assert_ok!(tx.send(1).await);
|
||||
@@ -178,9 +183,11 @@ async fn async_send_recv_unbounded() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn send_recv_stream_unbounded() {
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
let (tx, mut rx) = mpsc::unbounded_channel::<i32>();
|
||||
let (tx, rx) = support::mpsc_stream::unbounded_channel_stream::<i32>();
|
||||
|
||||
let mut rx = Box::pin(rx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
assert_ok!(tx.send(1));
|
||||
|
||||
@@ -7,6 +7,10 @@ use tokio_test::assert_ok;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
mod support {
|
||||
pub(crate) mod mpsc_stream;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic_blocking() {
|
||||
// Run a few times
|
||||
@@ -165,7 +169,8 @@ fn coop_disabled_in_block_in_place() {
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let (tx, rx) = support::mpsc_stream::unbounded_channel_stream();
|
||||
|
||||
for i in 0..200 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
@@ -175,7 +180,7 @@ fn coop_disabled_in_block_in_place() {
|
||||
let jh = tokio::spawn(async move {
|
||||
tokio::task::block_in_place(move || {
|
||||
futures::executor::block_on(async move {
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
assert_eq!(rx.fold(0, |n, _| n + 1).await, 200);
|
||||
})
|
||||
})
|
||||
@@ -195,7 +200,8 @@ fn coop_disabled_in_block_in_place_in_block_on() {
|
||||
thread::spawn(move || {
|
||||
let outer = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let (tx, rx) = support::mpsc_stream::unbounded_channel_stream();
|
||||
|
||||
for i in 0..200 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
@@ -204,7 +210,7 @@ fn coop_disabled_in_block_in_place_in_block_on() {
|
||||
outer.block_on(async move {
|
||||
tokio::task::block_in_place(move || {
|
||||
futures::executor::block_on(async move {
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_stream::StreamExt;
|
||||
assert_eq!(rx.fold(0, |n, _| n + 1).await, 200);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -46,7 +46,7 @@ use std::sync::{
|
||||
Arc,
|
||||
};
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::stream::{Stream, StreamExt};
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
|
||||
struct TrackPolls<'a> {
|
||||
npolls: Arc<AtomicUsize>,
|
||||
@@ -88,7 +88,7 @@ async fn no_extra_poll() {
|
||||
assert_eq!(npolls.load(SeqCst), 1);
|
||||
|
||||
let _ = assert_ok!(TcpStream::connect(&addr).await);
|
||||
accepted_rx.next().await.unwrap();
|
||||
accepted_rx.recv().await.unwrap();
|
||||
|
||||
// should have been polled twice more: once to yield Some(), then once to yield Pending
|
||||
assert_eq!(npolls.load(SeqCst), 1 + 2);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user