mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-07 00:00:09 +02:00
Limit futures dependency to Stream via feature flag (#1774)
In an effort to reach API stability, the `tokio` crate is shedding its
_public_ dependencies on crates that are either a) do not provide a
stable (1.0+) release with longevity guarantees or b) match the `tokio`
release cadence. Of course, implementing `std` traits fits the
requirements.
The on exception, for now, is the `Stream` trait found in `futures_core`.
It is expected that this trait will not change much and be moved into `std.
Since Tokio is not yet going reaching 1.0, I feel that it is acceptable to maintain
a dependency on this trait given how foundational it is.
Since the `Stream` implementation is optional, types that are logically
streams provide `async fn next_*` functions to obtain the next value.
Avoiding the `next()` name prevents fn conflicts with `StreamExt::next()`.
Additionally, some misc cleanup is also done:
- `tokio::io::io` -> `tokio::io::util`.
- `delay` -> `delay_until`.
- `Timeout::new` -> `timeout(...)`.
- `signal::ctrl_c()` returns a future instead of a stream.
- `{tcp,unix}::Incoming` is removed (due to lack of `Stream` trait).
- `time::Throttle` is removed (due to lack of `Stream` trait).
- Fix: `mpsc::UnboundedSender::send(&self)` (no more conflict with `Sink` fns).
This commit is contained in:
+5
-11
@@ -116,18 +116,12 @@ impl Shared {
|
|||||||
|
|
||||||
/// Send a `LineCodec` encoded message to every peer, except
|
/// Send a `LineCodec` encoded message to every peer, except
|
||||||
/// for the sender.
|
/// for the sender.
|
||||||
async fn broadcast(
|
async fn broadcast(&mut self, sender: SocketAddr, message: &str) {
|
||||||
&mut self,
|
|
||||||
sender: SocketAddr,
|
|
||||||
message: &str,
|
|
||||||
) -> Result<(), mpsc::error::UnboundedSendError> {
|
|
||||||
for peer in self.peers.iter_mut() {
|
for peer in self.peers.iter_mut() {
|
||||||
if *peer.0 != sender {
|
if *peer.0 != sender {
|
||||||
peer.1.send(message.into()).await?;
|
let _ = peer.1.send(message.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +212,7 @@ async fn process(
|
|||||||
let mut state = state.lock().await;
|
let mut state = state.lock().await;
|
||||||
let msg = format!("{} has joined the chat", username);
|
let msg = format!("{} has joined the chat", username);
|
||||||
println!("{}", msg);
|
println!("{}", msg);
|
||||||
state.broadcast(addr, &msg).await?;
|
state.broadcast(addr, &msg).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process incoming messages until our stream is exhausted by a disconnect.
|
// Process incoming messages until our stream is exhausted by a disconnect.
|
||||||
@@ -230,7 +224,7 @@ async fn process(
|
|||||||
let mut state = state.lock().await;
|
let mut state = state.lock().await;
|
||||||
let msg = format!("{}: {}", username, msg);
|
let msg = format!("{}: {}", username, msg);
|
||||||
|
|
||||||
state.broadcast(addr, &msg).await?;
|
state.broadcast(addr, &msg).await;
|
||||||
}
|
}
|
||||||
// A message was received from a peer. Send it to the
|
// A message was received from a peer. Send it to the
|
||||||
// current user.
|
// current user.
|
||||||
@@ -254,7 +248,7 @@ async fn process(
|
|||||||
|
|
||||||
let msg = format!("{} has left the chat", username);
|
let msg = format!("{} has left the chat", username);
|
||||||
println!("{}", msg);
|
println!("{}", msg);
|
||||||
state.broadcast(addr, &msg).await?;
|
state.broadcast(addr, &msg).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+6
-4
@@ -20,7 +20,7 @@ use tokio::io;
|
|||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tokio_util::codec::{FramedRead, FramedWrite};
|
use tokio_util::codec::{FramedRead, FramedWrite};
|
||||||
|
|
||||||
use futures::{SinkExt, Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -69,12 +69,14 @@ async fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
// Temporary work around for stdin blocking the stream
|
// Temporary work around for stdin blocking the stream
|
||||||
fn stdin() -> impl Stream<Item = Result<Vec<u8>, io::Error>> + Unpin {
|
fn stdin() -> impl Stream<Item = Result<Vec<u8>, io::Error>> + Unpin {
|
||||||
let mut stdin = FramedRead::new(io::stdin(), codec::Bytes).map(Ok);
|
let mut stdin = FramedRead::new(io::stdin(), codec::Bytes);
|
||||||
|
|
||||||
let (mut tx, rx) = mpsc::unbounded_channel();
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tx.send_all(&mut stdin).await.unwrap();
|
while let Some(res) = stdin.next().await {
|
||||||
|
let _ = tx.send(res);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rx
|
rx
|
||||||
|
|||||||
@@ -55,9 +55,9 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio::prelude::*;
|
|
||||||
use tokio_util::codec::{BytesCodec, Decoder};
|
use tokio_util::codec::{BytesCodec, Decoder};
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|||||||
+3
-3
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use futures::{future::try_join, FutureExt, StreamExt};
|
use futures::{future::try_join, FutureExt};
|
||||||
use std::{env, error::Error};
|
use std::{env, error::Error};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::AsyncReadExt,
|
io::AsyncReadExt,
|
||||||
@@ -37,9 +37,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
println!("Listening on: {}", listen_addr);
|
println!("Listening on: {}", listen_addr);
|
||||||
println!("Proxying to: {}", server_addr);
|
println!("Proxying to: {}", server_addr);
|
||||||
|
|
||||||
let mut incoming = TcpListener::bind(listen_addr).await?.incoming();
|
let mut listener = TcpListener::bind(listen_addr).await?;
|
||||||
|
|
||||||
while let Some(Ok(inbound)) = incoming.next().await {
|
while let Ok((inbound, _)) = listener.accept().await {
|
||||||
let transfer = transfer(inbound, server_addr.clone()).map(|r| {
|
let transfer = transfer(inbound, server_addr.clone()).map(|r| {
|
||||||
if let Err(e) = r {
|
if let Err(e) = r {
|
||||||
println!("Failed to transfer; error={}", e);
|
println!("Failed to transfer; error={}", e);
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
|
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::future::FutureExt as TokioFutureExt;
|
|
||||||
use tokio::io;
|
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::{io, time};
|
||||||
use tokio_util::codec::BytesCodec;
|
use tokio_util::codec::BytesCodec;
|
||||||
use tokio_util::udp::UdpFramed;
|
use tokio_util::udp::UdpFramed;
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ async fn ping(socket: &mut UdpFramed<BytesCodec>, b_addr: SocketAddr) -> Result<
|
|||||||
async fn pong(socket: &mut UdpFramed<BytesCodec>) -> Result<(), io::Error> {
|
async fn pong(socket: &mut UdpFramed<BytesCodec>) -> Result<(), io::Error> {
|
||||||
let timeout = Duration::from_millis(200);
|
let timeout = Duration::from_millis(200);
|
||||||
|
|
||||||
while let Ok(Some(Ok((bytes, addr)))) = socket.next().timeout(timeout).await {
|
while let Ok(Some(Ok((bytes, addr)))) = time::timeout(timeout, socket.next()).await {
|
||||||
println!("[b] recv: {}", String::from_utf8_lossy(&bytes));
|
println!("[b] recv: {}", String::from_utf8_lossy(&bytes));
|
||||||
|
|
||||||
socket.send((Bytes::from(&b"PONG"[..]), addr)).await?;
|
socket.send((Bytes::from(&b"PONG"[..]), addr)).await?;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use tokio::process::{Child, Command};
|
|||||||
use tokio_test::assert_ok;
|
use tokio_test::assert_ok;
|
||||||
|
|
||||||
use futures::future::{self, FutureExt};
|
use futures::future::{self, FutureExt};
|
||||||
use futures::stream::StreamExt;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::process::{ExitStatus, Stdio};
|
use std::process::{ExitStatus, Stdio};
|
||||||
@@ -47,9 +46,9 @@ async fn feed_cat(mut cat: Child, n: usize) -> io::Result<ExitStatus> {
|
|||||||
// (i.e. EOF is reached after `n` lines.
|
// (i.e. EOF is reached after `n` lines.
|
||||||
loop {
|
loop {
|
||||||
let data = reader
|
let data = reader
|
||||||
.next()
|
.next_line()
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|| Ok(String::new()))
|
.unwrap_or_else(|_| Some(String::new()))
|
||||||
.expect("failed to read line");
|
.expect("failed to read line");
|
||||||
|
|
||||||
let num_read = data.len();
|
let num_read = data.len();
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ impl Handle {
|
|||||||
/// The next operation in the mock's script will be to expect a `read` call
|
/// The next operation in the mock's script will be to expect a `read` call
|
||||||
/// and return `buf`.
|
/// and return `buf`.
|
||||||
pub fn read(&mut self, buf: &[u8]) -> &mut Self {
|
pub fn read(&mut self, buf: &[u8]) -> &mut Self {
|
||||||
self.tx.try_send(Action::Read(buf.into())).unwrap();
|
self.tx.send(Action::Read(buf.into())).unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ impl Handle {
|
|||||||
/// The next operation in the mock's script will be to expect a `write`
|
/// The next operation in the mock's script will be to expect a `write`
|
||||||
/// call.
|
/// call.
|
||||||
pub fn write(&mut self, buf: &[u8]) -> &mut Self {
|
pub fn write(&mut self, buf: &[u8]) -> &mut Self {
|
||||||
self.tx.try_send(Action::Write(buf.into())).unwrap();
|
self.tx.send(Action::Write(buf.into())).unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ impl AsyncRead for Mock {
|
|||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
if let Some(rem) = self.inner.remaining_wait() {
|
if let Some(rem) = self.inner.remaining_wait() {
|
||||||
let until = Instant::now() + rem;
|
let until = Instant::now() + rem;
|
||||||
self.inner.sleep = Some(time::delay(until));
|
self.inner.sleep = Some(time::delay_until(until));
|
||||||
} else {
|
} else {
|
||||||
self.inner.read_wait = Some(cx.waker().clone());
|
self.inner.read_wait = Some(cx.waker().clone());
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@@ -340,7 +340,7 @@ impl AsyncWrite for Mock {
|
|||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
if let Some(rem) = self.inner.remaining_wait() {
|
if let Some(rem) = self.inner.remaining_wait() {
|
||||||
let until = Instant::now() + rem;
|
let until = Instant::now() + rem;
|
||||||
self.inner.sleep = Some(time::delay(until));
|
self.inner.sleep = Some(time::delay_until(until));
|
||||||
} else {
|
} else {
|
||||||
panic!("unexpected WouldBlock");
|
panic!("unexpected WouldBlock");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::time::{delay, Duration, Instant};
|
use tokio::time::{delay_until, Duration, Instant};
|
||||||
use tokio_test::block_on;
|
use tokio_test::block_on;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,5 +20,5 @@ fn async_fn() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_delay() {
|
fn test_delay() {
|
||||||
let deadline = Instant::now() + Duration::from_millis(100);
|
let deadline = Instant::now() + Duration::from_millis(100);
|
||||||
assert_eq!((), block_on(delay(deadline)));
|
assert_eq!((), block_on(delay_until(deadline)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ async fn client_to_server() {
|
|||||||
drop(env_logger::try_init());
|
drop(env_logger::try_init());
|
||||||
|
|
||||||
// Create a server listening on a port, then figure out what that port is
|
// Create a server listening on a port, then figure out what that port is
|
||||||
let srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
let mut srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
||||||
let addr = t!(srv.local_addr());
|
let addr = t!(srv.local_addr());
|
||||||
|
|
||||||
let (server_cx, client_cx) = contexts();
|
let (server_cx, client_cx) = contexts();
|
||||||
@@ -559,7 +559,7 @@ async fn server_to_client() {
|
|||||||
drop(env_logger::try_init());
|
drop(env_logger::try_init());
|
||||||
|
|
||||||
// Create a server listening on a port, then figure out what that port is
|
// Create a server listening on a port, then figure out what that port is
|
||||||
let srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
let mut srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
||||||
let addr = t!(srv.local_addr());
|
let addr = t!(srv.local_addr());
|
||||||
|
|
||||||
let (server_cx, client_cx) = contexts();
|
let (server_cx, client_cx) = contexts();
|
||||||
@@ -590,7 +590,7 @@ async fn one_byte_at_a_time() {
|
|||||||
const AMT: usize = 1024;
|
const AMT: usize = 1024;
|
||||||
drop(env_logger::try_init());
|
drop(env_logger::try_init());
|
||||||
|
|
||||||
let srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
let mut srv = t!(TcpListener::bind("127.0.0.1:0").await);
|
||||||
let addr = t!(srv.local_addr());
|
let addr = t!(srv.local_addr());
|
||||||
|
|
||||||
let (server_cx, client_cx) = contexts();
|
let (server_cx, client_cx) = contexts();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pin-project = "0.4"
|
|||||||
tokio = { version = "=0.2.0-alpha.6", path = "../tokio" }
|
tokio = { version = "=0.2.0-alpha.6", path = "../tokio" }
|
||||||
tokio-test = { version = "=0.2.0-alpha.6", path = "../tokio-test" }
|
tokio-test = { version = "=0.2.0-alpha.6", path = "../tokio-test" }
|
||||||
|
|
||||||
futures-util = "0.3.0"
|
futures = "0.3.0"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
//! use tokio::prelude::*;
|
//! use tokio::prelude::*;
|
||||||
//! use tokio_util::codec::{Framed, LengthDelimitedCodec};
|
//! use tokio_util::codec::{Framed, LengthDelimitedCodec};
|
||||||
//!
|
//!
|
||||||
|
//! use futures::SinkExt;
|
||||||
//! use bytes::Bytes;
|
//! use bytes::Bytes;
|
||||||
//!
|
//!
|
||||||
//! async fn write_frame<T>(io: T) -> Result<(), Box<dyn std::error::Error>>
|
//! async fn write_frame<T>(io: T) -> Result<(), Box<dyn std::error::Error>>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use tokio_test::assert_ok;
|
|||||||
use tokio_util::codec::{Decoder, Encoder, Framed, FramedParts};
|
use tokio_util::codec::{Decoder, Encoder, Framed, FramedParts};
|
||||||
|
|
||||||
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
|
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
|
||||||
|
use futures::StreamExt;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::prelude::*;
|
use tokio::io::AsyncRead;
|
||||||
use tokio_test::assert_ready;
|
use tokio_test::assert_ready;
|
||||||
use tokio_test::task;
|
use tokio_test::task;
|
||||||
use tokio_util::codec::{Decoder, FramedRead};
|
use tokio_util::codec::{Decoder, FramedRead};
|
||||||
|
|
||||||
use bytes::{Buf, BytesMut, IntoBuf};
|
use bytes::{Buf, BytesMut, IntoBuf};
|
||||||
|
use futures::Stream;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
use tokio::prelude::*;
|
|
||||||
use tokio_test::task;
|
use tokio_test::task;
|
||||||
use tokio_test::{
|
use tokio_test::{
|
||||||
assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok,
|
assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok,
|
||||||
@@ -9,7 +8,7 @@ use tokio_test::{
|
|||||||
use tokio_util::codec::*;
|
use tokio_util::codec::*;
|
||||||
|
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use futures_util::pin_mut;
|
use futures::{pin_mut, Sink, Stream};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use tokio_util::codec::{Decoder, Encoder};
|
|||||||
use tokio_util::udp::UdpFramed;
|
use tokio_util::udp::UdpFramed;
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures_util::future::try_join;
|
use futures::future::try_join;
|
||||||
use futures_util::future::FutureExt;
|
use futures::future::FutureExt;
|
||||||
use futures_util::sink::SinkExt;
|
use futures::sink::SinkExt;
|
||||||
use futures_util::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
+6
-4
@@ -32,6 +32,7 @@ default = [
|
|||||||
"process",
|
"process",
|
||||||
"rt-full",
|
"rt-full",
|
||||||
"signal",
|
"signal",
|
||||||
|
"stream",
|
||||||
"sync",
|
"sync",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
@@ -40,7 +41,7 @@ blocking = ["rt-core"]
|
|||||||
dns = ["blocking"]
|
dns = ["blocking"]
|
||||||
fs = ["blocking"]
|
fs = ["blocking"]
|
||||||
io-driver = ["mio", "lazy_static", "sync"] # TODO: get rid of sync
|
io-driver = ["mio", "lazy_static", "sync"] # TODO: get rid of sync
|
||||||
io-util = ["pin-project", "memchr"]
|
io-util = ["pin-project", "pin-project-lite", "memchr"]
|
||||||
macros = ["tokio-macros"]
|
macros = ["tokio-macros"]
|
||||||
net = ["dns", "tcp", "udp", "uds"]
|
net = ["dns", "tcp", "udp", "uds"]
|
||||||
process = [
|
process = [
|
||||||
@@ -55,6 +56,7 @@ process = [
|
|||||||
]
|
]
|
||||||
# Includes basic task execution capabilities
|
# Includes basic task execution capabilities
|
||||||
rt-core = []
|
rt-core = []
|
||||||
|
# TODO: rename this -> `rt-threaded`
|
||||||
rt-full = [
|
rt-full = [
|
||||||
"macros",
|
"macros",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
@@ -72,6 +74,7 @@ signal = [
|
|||||||
"winapi/consoleapi",
|
"winapi/consoleapi",
|
||||||
"winapi/minwindef",
|
"winapi/minwindef",
|
||||||
]
|
]
|
||||||
|
stream = ["futures-core"]
|
||||||
sync = ["fnv"]
|
sync = ["fnv"]
|
||||||
test-util = []
|
test-util = []
|
||||||
tcp = ["io-driver"]
|
tcp = ["io-driver"]
|
||||||
@@ -84,18 +87,17 @@ uds = ["io-driver", "mio-uds", "libc"]
|
|||||||
tokio-macros = { version = "=0.2.0-alpha.6", optional = true, path = "../tokio-macros" }
|
tokio-macros = { version = "=0.2.0-alpha.6", optional = true, path = "../tokio-macros" }
|
||||||
|
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
futures-core = "0.3.0"
|
|
||||||
futures-sink = "0.3.0"
|
|
||||||
futures-util = { version = "0.3.0", features = ["sink", "channel"] }
|
|
||||||
iovec = "0.1"
|
iovec = "0.1"
|
||||||
|
|
||||||
# Everything else is optional...
|
# Everything else is optional...
|
||||||
fnv = { version = "1.0.6", optional = true }
|
fnv = { version = "1.0.6", optional = true }
|
||||||
|
futures-core = { version = "0.3.0", optional = true }
|
||||||
lazy_static = { version = "1.0.2", optional = true }
|
lazy_static = { version = "1.0.2", optional = true }
|
||||||
memchr = { version = "2.2", optional = true }
|
memchr = { version = "2.2", optional = true }
|
||||||
mio = { version = "0.6.14", optional = true }
|
mio = { version = "0.6.14", optional = true }
|
||||||
num_cpus = { version = "1.8.0", optional = true }
|
num_cpus = { version = "1.8.0", optional = true }
|
||||||
pin-project = { version = "0.4", optional = true }
|
pin-project = { version = "0.4", optional = true }
|
||||||
|
pin-project-lite = { version = "0.1", optional = true }
|
||||||
# Backs `DelayQueue`
|
# Backs `DelayQueue`
|
||||||
slab = { version = "0.4.1", optional = true }
|
slab = { version = "0.4.1", optional = true }
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::fs::sys;
|
use crate::fs::sys;
|
||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::fs::blocking::Buf;
|
|||||||
use crate::fs::{asyncify, sys};
|
use crate::fs::{asyncify, sys};
|
||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{Metadata, Permissions};
|
use std::fs::{Metadata, Permissions};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -430,7 +429,7 @@ impl File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn complete_inflight(&mut self) {
|
async fn complete_inflight(&mut self) {
|
||||||
use futures_util::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
if let Err(e) = poll_fn(|cx| Pin::new(&mut *self).poll_flush(cx)).await {
|
if let Err(e) = poll_fn(|cx| Pin::new(&mut *self).poll_flush(cx)).await {
|
||||||
self.last_write_err = Some(e.kind());
|
self.last_write_err = Some(e.kind());
|
||||||
|
|||||||
+30
-20
@@ -1,7 +1,5 @@
|
|||||||
use crate::fs::{asyncify, sys};
|
use crate::fs::{asyncify, sys};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{FileType, Metadata};
|
use std::fs::{FileType, Metadata};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -50,10 +48,15 @@ enum State {
|
|||||||
Pending(sys::Blocking<(Option<io::Result<std::fs::DirEntry>>, std::fs::ReadDir)>),
|
Pending(sys::Blocking<(Option<io::Result<std::fs::DirEntry>>, std::fs::ReadDir)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for ReadDir {
|
impl ReadDir {
|
||||||
type Item = io::Result<DirEntry>;
|
/// Returns the next entry in the directory stream.
|
||||||
|
pub async fn next_entry(&mut self) -> io::Result<Option<DirEntry>> {
|
||||||
|
use crate::future::poll_fn;
|
||||||
|
poll_fn(|cx| self.poll_next_entry(cx)).await
|
||||||
|
}
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
#[doc(hidden)]
|
||||||
|
pub fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Option<DirEntry>>> {
|
||||||
loop {
|
loop {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
State::Idle(ref mut std) => {
|
State::Idle(ref mut std) => {
|
||||||
@@ -68,7 +71,11 @@ impl Stream for ReadDir {
|
|||||||
let (ret, std) = ready!(Pin::new(rx).poll(cx))?;
|
let (ret, std) = ready!(Pin::new(rx).poll(cx))?;
|
||||||
self.0 = State::Idle(Some(std));
|
self.0 = State::Idle(Some(std));
|
||||||
|
|
||||||
let ret = ret.map(|res| res.map(|std| DirEntry(Arc::new(std))));
|
let ret = match ret {
|
||||||
|
Some(Ok(std)) => Ok(Some(DirEntry(Arc::new(std)))),
|
||||||
|
Some(Err(e)) => Err(e),
|
||||||
|
None => Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
return Poll::Ready(ret);
|
return Poll::Ready(ret);
|
||||||
}
|
}
|
||||||
@@ -77,6 +84,19 @@ impl Stream for ReadDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
|
impl futures_core::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.
|
/// Entries returned by the [`ReadDir`] stream.
|
||||||
///
|
///
|
||||||
/// [`ReadDir`]: struct.ReadDir.html
|
/// [`ReadDir`]: struct.ReadDir.html
|
||||||
@@ -100,13 +120,11 @@ impl DirEntry {
|
|||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use tokio::fs;
|
/// use tokio::fs;
|
||||||
/// use tokio::prelude::*;
|
|
||||||
///
|
///
|
||||||
/// # async fn dox() -> std::io::Result<()> {
|
/// # async fn dox() -> std::io::Result<()> {
|
||||||
/// let mut entries = fs::read_dir(".").await?;
|
/// let mut entries = fs::read_dir(".").await?;
|
||||||
///
|
///
|
||||||
/// while let Some(res) = entries.next().await {
|
/// while let Some(entry) = entries.next_entry().await? {
|
||||||
/// let entry = res?;
|
|
||||||
/// println!("{:?}", entry.path());
|
/// println!("{:?}", entry.path());
|
||||||
/// }
|
/// }
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -133,13 +151,11 @@ impl DirEntry {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tokio::fs;
|
/// use tokio::fs;
|
||||||
/// use tokio::prelude::*;
|
|
||||||
///
|
///
|
||||||
/// # async fn dox() -> std::io::Result<()> {
|
/// # async fn dox() -> std::io::Result<()> {
|
||||||
/// let mut entries = fs::read_dir(".").await?;
|
/// let mut entries = fs::read_dir(".").await?;
|
||||||
///
|
///
|
||||||
/// while let Some(res) = entries.next().await {
|
/// while let Some(entry) = entries.next_entry().await? {
|
||||||
/// let entry = res?;
|
|
||||||
/// println!("{:?}", entry.file_name());
|
/// println!("{:?}", entry.file_name());
|
||||||
/// }
|
/// }
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -164,14 +180,11 @@ impl DirEntry {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tokio::fs;
|
/// use tokio::fs;
|
||||||
/// use tokio::prelude::*;
|
|
||||||
///
|
///
|
||||||
/// # async fn dox() -> std::io::Result<()> {
|
/// # async fn dox() -> std::io::Result<()> {
|
||||||
/// let mut entries = fs::read_dir(".").await?;
|
/// let mut entries = fs::read_dir(".").await?;
|
||||||
///
|
///
|
||||||
/// while let Some(res) = entries.next().await {
|
/// while let Some(entry) = entries.next_entry().await? {
|
||||||
/// let entry = res?;
|
|
||||||
///
|
|
||||||
/// if let Ok(metadata) = entry.metadata().await {
|
/// if let Ok(metadata) = entry.metadata().await {
|
||||||
/// // Now let's show our entry's permissions!
|
/// // Now let's show our entry's permissions!
|
||||||
/// println!("{:?}: {:?}", entry.path(), metadata.permissions());
|
/// println!("{:?}: {:?}", entry.path(), metadata.permissions());
|
||||||
@@ -202,14 +215,11 @@ impl DirEntry {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tokio::fs;
|
/// use tokio::fs;
|
||||||
/// use tokio::prelude::*;
|
|
||||||
///
|
///
|
||||||
/// # async fn dox() -> std::io::Result<()> {
|
/// # async fn dox() -> std::io::Result<()> {
|
||||||
/// let mut entries = fs::read_dir(".").await?;
|
/// let mut entries = fs::read_dir(".").await?;
|
||||||
///
|
///
|
||||||
/// while let Some(res) = entries.next().await {
|
/// while let Some(entry) = entries.next_entry().await? {
|
||||||
/// let entry = res?;
|
|
||||||
///
|
|
||||||
/// if let Ok(file_type) = entry.file_type().await {
|
/// if let Ok(file_type) = entry.file_type().await {
|
||||||
/// // Now let's show our entry's file type!
|
/// // Now let's show our entry's file type!
|
||||||
/// println!("{:?}: {:?}", entry.path(), file_type);
|
/// println!("{:?}: {:?}", entry.path(), file_type);
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
//! Asynchronous values.
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use crate::time::Timeout;
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use futures_util::future::{err, ok, pending, poll_fn, ready};
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use std::future::Future;
|
|
||||||
|
|
||||||
/// An extension trait for `Future` that provides a variety of convenient
|
|
||||||
/// combinator functions.
|
|
||||||
///
|
|
||||||
/// Currently, there only is a [`timeout`] function, but this will increase
|
|
||||||
/// over time.
|
|
||||||
///
|
|
||||||
/// Users are not expected to implement this trait. All types that implement
|
|
||||||
/// `Future` already implement `FutureExt`.
|
|
||||||
///
|
|
||||||
/// This trait can be imported directly or via the Tokio prelude: `use
|
|
||||||
/// tokio::prelude::*`.
|
|
||||||
///
|
|
||||||
/// [`timeout`]: #method.timeout
|
|
||||||
pub trait FutureExt: Future {
|
|
||||||
/// Creates a new future which allows `self` until `timeout`.
|
|
||||||
///
|
|
||||||
/// This combinator creates a new future which wraps the receiving future
|
|
||||||
/// with a timeout. The returned future is allowed to execute until it
|
|
||||||
/// completes or `timeout` has elapsed, whichever happens first.
|
|
||||||
///
|
|
||||||
/// If the future completes before `timeout` then the future will resolve
|
|
||||||
/// with that item. Otherwise the future will resolve to an error.
|
|
||||||
///
|
|
||||||
/// The future is guaranteed to be polled at least once, even if `timeout`
|
|
||||||
/// is set to zero.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tokio::prelude::*;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// async fn long_future() {
|
|
||||||
/// // do work here
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # async fn dox() {
|
|
||||||
/// let res = long_future()
|
|
||||||
/// .timeout(Duration::from_secs(1))
|
|
||||||
/// .await;
|
|
||||||
///
|
|
||||||
/// if res.is_err() {
|
|
||||||
/// println!("operation timed out");
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
fn timeout(self, timeout: Duration) -> Timeout<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Timeout::new(self, timeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ?Sized> FutureExt for T where T: Future {}
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
//! Definition of the MaybeDone combinator
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
use std::mem;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
/// A future that may have completed.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum MaybeDone<Fut: Future> {
|
||||||
|
/// A not-yet-completed future
|
||||||
|
Future(Fut),
|
||||||
|
/// The output of the completed future
|
||||||
|
Done(Fut::Output),
|
||||||
|
/// The empty variant after the result of a [`MaybeDone`] has been
|
||||||
|
/// taken using the [`take_output`](MaybeDone::take_output) method.
|
||||||
|
Gone,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because we never generate `Pin<&mut Fut::Output>`
|
||||||
|
impl<Fut: Future + Unpin> Unpin for MaybeDone<Fut> {}
|
||||||
|
|
||||||
|
/// Wraps a future into a `MaybeDone`
|
||||||
|
pub(crate) fn maybe_done<Fut: Future>(future: Fut) -> MaybeDone<Fut> {
|
||||||
|
MaybeDone::Future(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Fut: Future> MaybeDone<Fut> {
|
||||||
|
/// Returns an [`Option`] containing a mutable reference to the output of the future.
|
||||||
|
/// The output of this method will be [`Some`] if and only if the inner
|
||||||
|
/// future has been completed and [`take_output`](MaybeDone::take_output)
|
||||||
|
/// has not yet been called.
|
||||||
|
pub(crate) fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> {
|
||||||
|
unsafe {
|
||||||
|
let this = self.get_unchecked_mut();
|
||||||
|
match this {
|
||||||
|
MaybeDone::Done(res) => Some(res),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to take the output of a `MaybeDone` without driving it
|
||||||
|
/// towards completion.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn take_output(self: Pin<&mut Self>) -> Option<Fut::Output> {
|
||||||
|
unsafe {
|
||||||
|
let this = self.get_unchecked_mut();
|
||||||
|
match this {
|
||||||
|
MaybeDone::Done(_) => {}
|
||||||
|
MaybeDone::Future(_) | MaybeDone::Gone => return None,
|
||||||
|
};
|
||||||
|
if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) {
|
||||||
|
Some(output)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Fut: Future> Future for MaybeDone<Fut> {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let res = unsafe {
|
||||||
|
match self.as_mut().get_unchecked_mut() {
|
||||||
|
MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)),
|
||||||
|
MaybeDone::Done(_) => return Poll::Ready(()),
|
||||||
|
MaybeDone::Gone => panic!("MaybeDone polled after value taken"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.set(MaybeDone::Done(res));
|
||||||
|
Poll::Ready(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#![allow(unused_imports, dead_code)]
|
||||||
|
|
||||||
|
//! Asynchronous values.
|
||||||
|
|
||||||
|
mod maybe_done;
|
||||||
|
pub(crate) use maybe_done::{maybe_done, MaybeDone};
|
||||||
|
|
||||||
|
mod poll_fn;
|
||||||
|
pub(crate) use poll_fn::poll_fn;
|
||||||
|
|
||||||
|
mod ready;
|
||||||
|
pub(crate) use ready::{ok, Ready};
|
||||||
|
|
||||||
|
mod try_join;
|
||||||
|
pub(crate) use try_join::try_join3;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
use std::future::Future;
|
||||||
|
use std::marker;
|
||||||
|
use sdt::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
/// Future for the [`pending()`] function.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
|
struct Pending<T> {
|
||||||
|
_data: marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a future which never resolves, representing a computation that never
|
||||||
|
/// finishes.
|
||||||
|
///
|
||||||
|
/// The returned future will forever return [`Poll::Pending`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::future;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main {
|
||||||
|
/// future::pending().await;
|
||||||
|
/// unreachable!();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn pending() -> ! {
|
||||||
|
Pending {
|
||||||
|
_data: marker::PhantomData,
|
||||||
|
}.await
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Future for Pending<T> {
|
||||||
|
type Output = !;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Unpin for Pending<T> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//! Definition of the `PollFn` adapter combinator
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
/// Future for the [`poll_fn`] function.
|
||||||
|
pub(crate) struct PollFn<F> {
|
||||||
|
f: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> Unpin for PollFn<F> {}
|
||||||
|
|
||||||
|
/// Creates a new future wrapping around a function returning [`Poll`].
|
||||||
|
pub(crate) fn poll_fn<T, F>(f: F) -> PollFn<F>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut Context<'_>) -> Poll<T>,
|
||||||
|
{
|
||||||
|
PollFn { f }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> fmt::Debug for PollFn<F> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("PollFn").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F> Future for PollFn<F>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut Context<'_>) -> Poll<T>,
|
||||||
|
{
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
|
||||||
|
(&mut self.f)(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
/// Future for the [`ready`](ready()) function.
|
||||||
|
///
|
||||||
|
/// `pub` in order to use the future as an associated type in a sealed trait.
|
||||||
|
#[derive(Debug)]
|
||||||
|
// Used as an associated type in a "sealed" trait.
|
||||||
|
#[allow(unreachable_pub)]
|
||||||
|
pub struct Ready<T>(Option<T>);
|
||||||
|
|
||||||
|
impl<T> Unpin for Ready<T> {}
|
||||||
|
|
||||||
|
impl<T> Future for Ready<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
|
||||||
|
Poll::Ready(self.0.take().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a future that is immediately ready with a success value.
|
||||||
|
pub(crate) fn ok<T, E>(t: T) -> Ready<Result<T, E>> {
|
||||||
|
Ready(Some(Ok(t)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
use crate::future::{maybe_done, MaybeDone};
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pub(crate) fn try_join3<T1, F1, T2, F2, T3, F3, E>(
|
||||||
|
future1: F1,
|
||||||
|
future2: F2,
|
||||||
|
future3: F3,
|
||||||
|
) -> TryJoin3<F1, F2, F3>
|
||||||
|
where
|
||||||
|
F1: Future<Output = Result<T1, E>>,
|
||||||
|
F2: Future<Output = Result<T2, E>>,
|
||||||
|
F3: Future<Output = Result<T3, E>>,
|
||||||
|
{
|
||||||
|
TryJoin3 {
|
||||||
|
future1: maybe_done(future1),
|
||||||
|
future2: maybe_done(future2),
|
||||||
|
future3: maybe_done(future3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TryJoin3<F1, F2, F3>
|
||||||
|
where
|
||||||
|
F1: Future,
|
||||||
|
F2: Future,
|
||||||
|
F3: Future,
|
||||||
|
{
|
||||||
|
future1: MaybeDone<F1>,
|
||||||
|
future2: MaybeDone<F2>,
|
||||||
|
future3: MaybeDone<F3>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, F1, T2, F2, T3, F3, E> Future for TryJoin3<F1, F2, F3>
|
||||||
|
where
|
||||||
|
F1: Future<Output = Result<T1, E>>,
|
||||||
|
F2: Future<Output = Result<T2, E>>,
|
||||||
|
F3: Future<Output = Result<T3, E>>,
|
||||||
|
{
|
||||||
|
type Output = Result<(T1, T2, T3), E>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut all_done = true;
|
||||||
|
|
||||||
|
// Safety: the fn takes `Pin`, we don't move any data out of `self`.
|
||||||
|
unsafe {
|
||||||
|
let me = self.get_unchecked_mut();
|
||||||
|
|
||||||
|
if Pin::new_unchecked(&mut me.future1).poll(cx).is_pending() {
|
||||||
|
all_done = false;
|
||||||
|
} else if Pin::new_unchecked(&mut me.future1)
|
||||||
|
.output_mut()
|
||||||
|
.unwrap()
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Poll::Ready(Err(Pin::new_unchecked(&mut me.future1)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.err()
|
||||||
|
.unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if Pin::new_unchecked(&mut me.future2).poll(cx).is_pending() {
|
||||||
|
all_done = false;
|
||||||
|
} else if Pin::new_unchecked(&mut me.future2)
|
||||||
|
.output_mut()
|
||||||
|
.unwrap()
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Poll::Ready(Err(Pin::new_unchecked(&mut me.future2)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.err()
|
||||||
|
.unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if Pin::new_unchecked(&mut me.future3).poll(cx).is_pending() {
|
||||||
|
all_done = false;
|
||||||
|
} else if Pin::new_unchecked(&mut me.future3)
|
||||||
|
.output_mut()
|
||||||
|
.unwrap()
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Poll::Ready(Err(Pin::new_unchecked(&mut me.future3)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.err()
|
||||||
|
.unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if all_done {
|
||||||
|
Poll::Ready(Ok((
|
||||||
|
Pin::new_unchecked(&mut me.future1)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.ok()
|
||||||
|
.unwrap(),
|
||||||
|
Pin::new_unchecked(&mut me.future2)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.ok()
|
||||||
|
.unwrap(),
|
||||||
|
Pin::new_unchecked(&mut me.future3)
|
||||||
|
.take_output()
|
||||||
|
.unwrap()
|
||||||
|
.ok()
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use futures_core::ready;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use futures_core::ready;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
use crate::io::io::read_line::read_line_internal;
|
|
||||||
use crate::io::AsyncBufRead;
|
|
||||||
|
|
||||||
use futures_core::{ready, Stream};
|
|
||||||
use pin_project::{pin_project, project};
|
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
/// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
|
|
||||||
#[pin_project]
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[must_use = "streams do nothing unless polled"]
|
|
||||||
pub struct Lines<R> {
|
|
||||||
#[pin]
|
|
||||||
reader: R,
|
|
||||||
buf: String,
|
|
||||||
bytes: Vec<u8>,
|
|
||||||
read: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn lines<R>(reader: R) -> Lines<R>
|
|
||||||
where
|
|
||||||
R: AsyncBufRead,
|
|
||||||
{
|
|
||||||
Lines {
|
|
||||||
reader,
|
|
||||||
buf: String::new(),
|
|
||||||
bytes: Vec::new(),
|
|
||||||
read: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AsyncBufRead> Stream for Lines<R> {
|
|
||||||
type Item = io::Result<String>;
|
|
||||||
|
|
||||||
#[project]
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
#[project]
|
|
||||||
let Lines {
|
|
||||||
reader,
|
|
||||||
buf,
|
|
||||||
bytes,
|
|
||||||
read,
|
|
||||||
} = self.project();
|
|
||||||
|
|
||||||
let n = ready!(read_line_internal(reader, cx, buf, bytes, read))?;
|
|
||||||
if n == 0 && buf.is_empty() {
|
|
||||||
return Poll::Ready(None);
|
|
||||||
}
|
|
||||||
if buf.ends_with('\n') {
|
|
||||||
buf.pop();
|
|
||||||
if buf.ends_with('\r') {
|
|
||||||
buf.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Poll::Ready(Some(Ok(mem::replace(buf, String::new()))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assert_unpin() {
|
|
||||||
crate::is_unpin::<Lines<()>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
use crate::io::io::read_until::read_until_internal;
|
|
||||||
use crate::io::AsyncBufRead;
|
|
||||||
|
|
||||||
use futures_core::{ready, Stream};
|
|
||||||
use pin_project::{pin_project, project};
|
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
/// Stream for the [`split`](crate::io::AsyncBufReadExt::split) method.
|
|
||||||
#[pin_project]
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[must_use = "streams do nothing unless polled"]
|
|
||||||
pub struct Split<R> {
|
|
||||||
#[pin]
|
|
||||||
reader: R,
|
|
||||||
buf: Vec<u8>,
|
|
||||||
delim: u8,
|
|
||||||
read: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn split<R>(reader: R, delim: u8) -> Split<R>
|
|
||||||
where
|
|
||||||
R: AsyncBufRead,
|
|
||||||
{
|
|
||||||
Split {
|
|
||||||
reader,
|
|
||||||
buf: Vec::new(),
|
|
||||||
delim,
|
|
||||||
read: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AsyncBufRead> Stream for Split<R> {
|
|
||||||
type Item = io::Result<Vec<u8>>;
|
|
||||||
|
|
||||||
#[project]
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
#[project]
|
|
||||||
let Split {
|
|
||||||
reader,
|
|
||||||
buf,
|
|
||||||
delim,
|
|
||||||
read,
|
|
||||||
} = self.project();
|
|
||||||
|
|
||||||
let n = ready!(read_until_internal(reader, cx, *delim, buf, read))?;
|
|
||||||
if n == 0 && buf.is_empty() {
|
|
||||||
return Poll::Ready(None);
|
|
||||||
}
|
|
||||||
if buf.last() == Some(&delim) {
|
|
||||||
buf.pop();
|
|
||||||
}
|
|
||||||
Poll::Ready(Some(Ok(mem::replace(buf, Vec::new()))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assert_unpin() {
|
|
||||||
crate::is_unpin::<Split<()>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+8
-9
@@ -45,20 +45,19 @@ pub use self::async_read::AsyncRead;
|
|||||||
mod async_write;
|
mod async_write;
|
||||||
pub use self::async_write::AsyncWrite;
|
pub use self::async_write::AsyncWrite;
|
||||||
|
|
||||||
#[allow(clippy::module_inception)] // TODO: remove
|
|
||||||
#[cfg(feature = "io-util")]
|
|
||||||
mod io;
|
|
||||||
#[cfg(feature = "io-util")]
|
|
||||||
pub use self::io::{
|
|
||||||
copy, empty, repeat, sink, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufStream,
|
|
||||||
BufWriter, Copy, Empty, Repeat, Sink, Take,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "io-util")]
|
#[cfg(feature = "io-util")]
|
||||||
pub mod split;
|
pub mod split;
|
||||||
#[cfg(feature = "io-util")]
|
#[cfg(feature = "io-util")]
|
||||||
pub use self::split::split;
|
pub use self::split::split;
|
||||||
|
|
||||||
|
#[cfg(feature = "io-util")]
|
||||||
|
mod util;
|
||||||
|
#[cfg(feature = "io-util")]
|
||||||
|
pub use self::util::{
|
||||||
|
copy, empty, repeat, sink, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufStream,
|
||||||
|
BufWriter, Copy, Empty, Lines, Repeat, Sink, Split, Take,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: These should not be guarded by `fs`
|
// TODO: These should not be guarded by `fs`
|
||||||
|
|
||||||
#[cfg(feature = "fs")]
|
#[cfg(feature = "fs")]
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use bytes::{Buf, BufMut};
|
use bytes::{Buf, BufMut};
|
||||||
use futures_core::ready;
|
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::io::io::lines::{lines, Lines};
|
use crate::io::util::lines::{lines, Lines};
|
||||||
use crate::io::io::read_line::{read_line, ReadLine};
|
use crate::io::util::read_line::{read_line, ReadLine};
|
||||||
use crate::io::io::read_until::{read_until, ReadUntil};
|
use crate::io::util::read_until::{read_until, ReadUntil};
|
||||||
use crate::io::io::split::{split, Split};
|
use crate::io::util::split::{split, Split};
|
||||||
use crate::io::AsyncBufRead;
|
use crate::io::AsyncBufRead;
|
||||||
|
|
||||||
/// An extension trait which adds utility methods to `AsyncBufRead` types.
|
/// An extension trait which adds utility methods to `AsyncBufRead` types.
|
||||||
@@ -59,7 +59,7 @@ pub trait AsyncBufReadExt: AsyncBufRead {
|
|||||||
/// Returns a stream of the contents of this reader split on the byte
|
/// Returns a stream of the contents of this reader split on the byte
|
||||||
/// `byte`.
|
/// `byte`.
|
||||||
///
|
///
|
||||||
/// This method is the async equivalent to
|
/// This method is the asynchronous equivalent to
|
||||||
/// [`BufRead::split`](std::io::BufRead::split).
|
/// [`BufRead::split`](std::io::BufRead::split).
|
||||||
///
|
///
|
||||||
/// The stream returned from this function will yield instances of
|
/// The stream returned from this function will yield instances of
|
||||||
@@ -73,9 +73,25 @@ pub trait AsyncBufReadExt: AsyncBufRead {
|
|||||||
///
|
///
|
||||||
/// Each item of the stream has the same error semantics as
|
/// Each item of the stream has the same error semantics as
|
||||||
/// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until).
|
/// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tokio::io::AsyncBufRead;
|
||||||
|
/// use tokio::io::AsyncBufReadExt;
|
||||||
|
///
|
||||||
|
/// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
|
||||||
|
/// let mut segments = my_buf_read.split(b'f');
|
||||||
|
///
|
||||||
|
/// while let Some(segment) = segments.next_segment().await? {
|
||||||
|
/// println!("length = {}", segment.len())
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
fn split(self, byte: u8) -> Split<Self>
|
fn split(self, byte: u8) -> Split<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized + Unpin,
|
||||||
{
|
{
|
||||||
split(self, byte)
|
split(self, byte)
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::io::io::chain::{chain, Chain};
|
use crate::io::util::chain::{chain, Chain};
|
||||||
use crate::io::io::copy::{copy, Copy};
|
use crate::io::util::copy::{copy, Copy};
|
||||||
use crate::io::io::read::{read, Read};
|
use crate::io::util::read::{read, Read};
|
||||||
use crate::io::io::read_exact::{read_exact, ReadExact};
|
use crate::io::util::read_exact::{read_exact, ReadExact};
|
||||||
use crate::io::io::read_to_end::{read_to_end, ReadToEnd};
|
use crate::io::util::read_to_end::{read_to_end, ReadToEnd};
|
||||||
use crate::io::io::read_to_string::{read_to_string, ReadToString};
|
use crate::io::util::read_to_string::{read_to_string, ReadToString};
|
||||||
use crate::io::io::take::{take, Take};
|
use crate::io::util::take::{take, Take};
|
||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
/// An extension trait which adds utility methods to `AsyncRead` types.
|
/// An extension trait which adds utility methods to `AsyncRead` types.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::io::io::flush::{flush, Flush};
|
use crate::io::util::flush::{flush, Flush};
|
||||||
use crate::io::io::shutdown::{shutdown, Shutdown};
|
use crate::io::util::shutdown::{shutdown, Shutdown};
|
||||||
use crate::io::io::write::{write, Write};
|
use crate::io::util::write::{write, Write};
|
||||||
use crate::io::io::write_all::{write_all, WriteAll};
|
use crate::io::util::write_all::{write_all, WriteAll};
|
||||||
use crate::io::AsyncWrite;
|
use crate::io::AsyncWrite;
|
||||||
|
|
||||||
/// An extension trait which adds utility methods to `AsyncWrite` types.
|
/// An extension trait which adds utility methods to `AsyncWrite` types.
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::io::io::DEFAULT_BUF_SIZE;
|
use crate::io::util::DEFAULT_BUF_SIZE;
|
||||||
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use pin_project::{pin_project, project};
|
use pin_project::{pin_project, project};
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::io::io::{BufReader, BufWriter};
|
use crate::io::util::{BufReader, BufWriter};
|
||||||
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::io::io::DEFAULT_BUF_SIZE;
|
use crate::io::util::DEFAULT_BUF_SIZE;
|
||||||
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use pin_project::{pin_project, project};
|
use pin_project::{pin_project, project};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::{AsyncBufRead, AsyncRead};
|
use crate::io::{AsyncBufRead, AsyncRead};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use pin_project::{pin_project, project};
|
use pin_project::{pin_project, project};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
use crate::io::util::read_line::read_line_internal;
|
||||||
|
use crate::io::AsyncBufRead;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
use std::io;
|
||||||
|
use std::mem;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
/// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[must_use = "streams do nothing unless polled"]
|
||||||
|
pub struct Lines<R> {
|
||||||
|
#[pin]
|
||||||
|
reader: R,
|
||||||
|
buf: String,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
read: usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lines<R>(reader: R) -> Lines<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead,
|
||||||
|
{
|
||||||
|
Lines {
|
||||||
|
reader,
|
||||||
|
buf: String::new(),
|
||||||
|
bytes: Vec::new(),
|
||||||
|
read: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Lines<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead + Unpin,
|
||||||
|
{
|
||||||
|
/// Returns the next line in the stream.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tokio::io::AsyncBufRead;
|
||||||
|
/// use tokio::io::AsyncBufReadExt;
|
||||||
|
///
|
||||||
|
/// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
|
||||||
|
/// let mut lines = my_buf_read.lines();
|
||||||
|
///
|
||||||
|
/// while let Some(line) = lines.next_line().await? {
|
||||||
|
/// println!("length = {}", line.len())
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub async fn next_line(&mut self) -> io::Result<Option<String>> {
|
||||||
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
|
poll_fn(|cx| Pin::new(&mut *self).poll_next_line(cx)).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Lines<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead,
|
||||||
|
{
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn poll_next_line(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<io::Result<Option<String>>> {
|
||||||
|
let me = self.project();
|
||||||
|
|
||||||
|
let n = ready!(read_line_internal(me.reader, cx, me.buf, me.bytes, me.read))?;
|
||||||
|
|
||||||
|
if n == 0 && me.buf.is_empty() {
|
||||||
|
return Poll::Ready(Ok(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
if me.buf.ends_with('\n') {
|
||||||
|
me.buf.pop();
|
||||||
|
|
||||||
|
if me.buf.ends_with('\r') {
|
||||||
|
me.buf.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Ready(Ok(Some(mem::replace(me.buf, String::new()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
|
impl<R: AsyncBufRead> futures_core::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::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_unpin() {
|
||||||
|
crate::is_unpin::<Lines<()>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +1,71 @@
|
|||||||
mod async_buf_read_ext;
|
mod async_buf_read_ext;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::async_buf_read_ext::AsyncBufReadExt;
|
||||||
|
|
||||||
mod async_read_ext;
|
mod async_read_ext;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::async_read_ext::AsyncReadExt;
|
||||||
|
|
||||||
mod async_write_ext;
|
mod async_write_ext;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::async_write_ext::AsyncWriteExt;
|
||||||
|
|
||||||
mod buf_reader;
|
mod buf_reader;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::buf_reader::BufReader;
|
||||||
|
|
||||||
mod buf_stream;
|
mod buf_stream;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::buf_stream::BufStream;
|
||||||
|
|
||||||
mod buf_writer;
|
mod buf_writer;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::buf_writer::BufWriter;
|
||||||
|
|
||||||
mod chain;
|
mod chain;
|
||||||
|
|
||||||
mod copy;
|
mod copy;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::copy::{copy, Copy};
|
||||||
|
|
||||||
mod empty;
|
mod empty;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::empty::{empty, Empty};
|
||||||
|
|
||||||
mod flush;
|
mod flush;
|
||||||
|
|
||||||
mod lines;
|
mod lines;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::lines::Lines;
|
||||||
|
|
||||||
mod read;
|
mod read;
|
||||||
mod read_exact;
|
mod read_exact;
|
||||||
mod read_line;
|
mod read_line;
|
||||||
mod read_to_end;
|
mod read_to_end;
|
||||||
mod read_to_string;
|
mod read_to_string;
|
||||||
mod read_until;
|
mod read_until;
|
||||||
mod repeat;
|
|
||||||
mod shutdown;
|
|
||||||
mod sink;
|
|
||||||
mod split;
|
|
||||||
mod take;
|
|
||||||
mod write;
|
|
||||||
mod write_all;
|
|
||||||
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
mod repeat;
|
||||||
pub use self::async_buf_read_ext::AsyncBufReadExt;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::async_read_ext::AsyncReadExt;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::async_write_ext::AsyncWriteExt;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::buf_reader::BufReader;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::buf_stream::BufStream;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::buf_writer::BufWriter;
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::copy::{copy, Copy};
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
|
||||||
pub use self::empty::{empty, Empty};
|
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
pub use self::repeat::{repeat, Repeat};
|
pub use self::repeat::{repeat, Repeat};
|
||||||
|
|
||||||
|
mod shutdown;
|
||||||
|
|
||||||
|
mod sink;
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
pub use self::sink::{sink, Sink};
|
pub use self::sink::{sink, Sink};
|
||||||
|
|
||||||
|
mod split;
|
||||||
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
|
pub use self::split::Split;
|
||||||
|
|
||||||
|
mod take;
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
pub use self::take::Take;
|
pub use self::take::Take;
|
||||||
|
|
||||||
|
mod write;
|
||||||
|
mod write_all;
|
||||||
|
|
||||||
// used by `BufReader` and `BufWriter`
|
// used by `BufReader` and `BufWriter`
|
||||||
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1
|
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1
|
||||||
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
|
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::AsyncRead;
|
use crate::io::AsyncRead;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::marker::Unpin;
|
use std::marker::Unpin;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::io::io::read_until::read_until_internal;
|
use crate::io::util::read_until::read_until_internal;
|
||||||
use crate::io::AsyncBufRead;
|
use crate::io::AsyncBufRead;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::AsyncRead;
|
use crate::io::AsyncRead;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::io::io::read_to_end::read_to_end_internal;
|
use crate::io::util::read_to_end::read_to_end_internal;
|
||||||
use crate::io::AsyncRead;
|
use crate::io::AsyncRead;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::AsyncBufRead;
|
use crate::io::AsyncBufRead;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
use crate::io::util::read_until::read_until_internal;
|
||||||
|
use crate::io::AsyncBufRead;
|
||||||
|
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
use std::io;
|
||||||
|
use std::mem;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
/// Stream for the [`split`](crate::io::AsyncBufReadExt::split) method.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[must_use = "streams do nothing unless polled"]
|
||||||
|
pub struct Split<R> {
|
||||||
|
#[pin]
|
||||||
|
reader: R,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
delim: u8,
|
||||||
|
read: usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn split<R>(reader: R, delim: u8) -> Split<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead,
|
||||||
|
{
|
||||||
|
Split {
|
||||||
|
reader,
|
||||||
|
buf: Vec::new(),
|
||||||
|
delim,
|
||||||
|
read: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Split<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead + Unpin,
|
||||||
|
{
|
||||||
|
/// Returns the next segment in the stream.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tokio::io::AsyncBufRead;
|
||||||
|
/// use tokio::io::AsyncBufReadExt;
|
||||||
|
///
|
||||||
|
/// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
|
||||||
|
/// let mut segments = my_buf_read.split(b'f');
|
||||||
|
///
|
||||||
|
/// while let Some(segment) = segments.next_segment().await? {
|
||||||
|
/// println!("length = {}", segment.len())
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub async fn next_segment(&mut self) -> io::Result<Option<Vec<u8>>> {
|
||||||
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
|
poll_fn(|cx| Pin::new(&mut *self).poll_next_segment(cx)).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Split<R>
|
||||||
|
where
|
||||||
|
R: AsyncBufRead,
|
||||||
|
{
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn poll_next_segment(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<io::Result<Option<Vec<u8>>>> {
|
||||||
|
let me = self.project();
|
||||||
|
|
||||||
|
let n = ready!(read_until_internal(
|
||||||
|
me.reader, cx, *me.delim, me.buf, me.read,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
if n == 0 && me.buf.is_empty() {
|
||||||
|
return Poll::Ready(Ok(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
if me.buf.last() == Some(me.delim) {
|
||||||
|
me.buf.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Ready(Ok(Some(mem::replace(me.buf, Vec::new()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
|
impl<R: AsyncBufRead> futures_core::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::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_unpin() {
|
||||||
|
crate::is_unpin::<Split<()>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::{AsyncBufRead, AsyncRead};
|
use crate::io::{AsyncBufRead, AsyncRead};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use pin_project::{pin_project, project};
|
use pin_project::{pin_project, project};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::io::AsyncWrite;
|
use crate::io::AsyncWrite;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
+10
-3
@@ -75,6 +75,15 @@ macro_rules! thread_local {
|
|||||||
($($tts:tt)+) => { loom::thread_local!{ $($tts)+ } }
|
($($tts:tt)+) => { loom::thread_local!{ $($tts)+ } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! ready {
|
||||||
|
($e:expr $(,)?) => {
|
||||||
|
match $e {
|
||||||
|
std::task::Poll::Ready(t) => t,
|
||||||
|
std::task::Poll::Pending => return std::task::Poll::Pending,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// At the top due to macros
|
// At the top due to macros
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -86,7 +95,7 @@ pub mod blocking;
|
|||||||
#[cfg(feature = "fs")]
|
#[cfg(feature = "fs")]
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
|
||||||
pub mod future;
|
mod future;
|
||||||
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
||||||
@@ -107,8 +116,6 @@ pub mod runtime;
|
|||||||
#[cfg(not(loom))]
|
#[cfg(not(loom))]
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
|
|
||||||
pub mod stream;
|
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use futures_util::future;
|
use crate::future;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
@@ -27,7 +28,7 @@ impl sealed::ToSocketAddrsPriv for SocketAddr {
|
|||||||
|
|
||||||
fn to_socket_addrs(&self) -> Self::Future {
|
fn to_socket_addrs(&self) -> Self::Future {
|
||||||
let iter = Some(*self).into_iter();
|
let iter = Some(*self).into_iter();
|
||||||
future::ready(Ok(iter))
|
future::ok(iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ impl sealed::ToSocketAddrsPriv for (IpAddr, u16) {
|
|||||||
|
|
||||||
fn to_socket_addrs(&self) -> Self::Future {
|
fn to_socket_addrs(&self) -> Self::Future {
|
||||||
let iter = Some(SocketAddr::from(*self)).into_iter();
|
let iter = Some(SocketAddr::from(*self)).into_iter();
|
||||||
future::ready(Ok(iter))
|
future::ok(iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,8 +196,6 @@ pub(crate) mod sealed {
|
|||||||
type Output = io::Result<OneOrMore>;
|
type Output = io::Result<OneOrMore>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
use futures_core::ready;
|
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
MaybeReady::Ready(ref mut i) => {
|
MaybeReady::Ready(ref mut i) => {
|
||||||
let iter = OneOrMore::One(i.take().into_iter());
|
let iter = OneOrMore::One(i.take().into_iter());
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use crate::net::tcp::TcpListener;
|
use crate::net::tcp::{TcpListener, TcpStream};
|
||||||
use crate::net::tcp::TcpStream;
|
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
@@ -11,17 +8,27 @@ use std::task::{Context, Poll};
|
|||||||
/// stream of sockets received from a listener.
|
/// stream of sockets received from a listener.
|
||||||
#[must_use = "streams do nothing unless polled"]
|
#[must_use = "streams do nothing unless polled"]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Incoming {
|
pub struct Incoming<'a> {
|
||||||
inner: TcpListener,
|
inner: &'a mut TcpListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Incoming {
|
impl Incoming<'_> {
|
||||||
pub(crate) fn new(listener: TcpListener) -> Incoming {
|
pub(crate) fn new(listener: &mut TcpListener) -> Incoming<'_> {
|
||||||
Incoming { inner: listener }
|
Incoming { inner: listener }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)] // TODO: dox
|
||||||
|
pub fn poll_accept(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<io::Result<TcpStream>> {
|
||||||
|
let (socket, _) = ready!(self.inner.poll_accept(cx))?;
|
||||||
|
Poll::Ready(Ok(socket))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for Incoming {
|
#[cfg(feature = "stream")]
|
||||||
|
impl futures_core::Stream for Incoming<'_> {
|
||||||
type Item = io::Result<TcpStream>;
|
type Item = io::Result<TcpStream>;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
use crate::future::poll_fn;
|
||||||
use crate::net::tcp::{Incoming, TcpStream};
|
use crate::net::tcp::{Incoming, TcpStream};
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
use crate::net::ToSocketAddrs;
|
use crate::net::ToSocketAddrs;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -12,9 +11,6 @@ use std::task::{Context, Poll};
|
|||||||
|
|
||||||
/// An I/O object representing a TCP socket listening for incoming connections.
|
/// An I/O object representing a TCP socket listening for incoming connections.
|
||||||
///
|
///
|
||||||
/// This object can be converted into a stream of incoming connections for
|
|
||||||
/// various forms of processing.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
@@ -126,7 +122,8 @@ impl TcpListener {
|
|||||||
poll_fn(|cx| self.poll_accept(cx)).await
|
poll_fn(|cx| self.poll_accept(cx)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_accept(
|
#[doc(hidden)] // TODO: document
|
||||||
|
pub fn poll_accept(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<io::Result<(TcpStream, SocketAddr)>> {
|
) -> Poll<io::Result<(TcpStream, SocketAddr)>> {
|
||||||
@@ -242,7 +239,7 @@ impl TcpListener {
|
|||||||
/// necessarily fatal ‒ for example having too many open file descriptors or the other side
|
/// necessarily fatal ‒ for example having too many open file descriptors or the other side
|
||||||
/// closing the connection while it waits in an accept queue. These would terminate the stream
|
/// closing the connection while it waits in an accept queue. These would terminate the stream
|
||||||
/// if not handled in any way.
|
/// if not handled in any way.
|
||||||
pub fn incoming(self) -> Incoming {
|
pub fn incoming(&mut self) -> Incoming<'_> {
|
||||||
Incoming::new(self)
|
Incoming::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,13 @@
|
|||||||
//! [`TcpStream`]: struct.TcpStream.html
|
//! [`TcpStream`]: struct.TcpStream.html
|
||||||
//! [`connect`]: struct.TcpStream.html#method.connect
|
//! [`connect`]: struct.TcpStream.html#method.connect
|
||||||
//! [`TcpListener`]: struct.TcpListener.html
|
//! [`TcpListener`]: struct.TcpListener.html
|
||||||
//! [incoming_method]: struct.TcpListener.html#method.incoming
|
|
||||||
//! [`Incoming`]: struct.Incoming.html
|
|
||||||
|
|
||||||
mod incoming;
|
|
||||||
pub use self::incoming::Incoming;
|
|
||||||
|
|
||||||
mod listener;
|
mod listener;
|
||||||
pub use self::listener::TcpListener;
|
pub use self::listener::TcpListener;
|
||||||
|
|
||||||
|
mod incoming;
|
||||||
|
pub use self::incoming::Incoming;
|
||||||
|
|
||||||
pub mod split;
|
pub mod split;
|
||||||
|
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
|
use crate::future::poll_fn;
|
||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
use crate::net::tcp::split::{split, ReadHalf, WriteHalf};
|
use crate::net::tcp::split::{split, ReadHalf, WriteHalf};
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
use crate::net::ToSocketAddrs;
|
use crate::net::ToSocketAddrs;
|
||||||
|
|
||||||
use bytes::{Buf, BufMut};
|
use bytes::{Buf, BufMut};
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use iovec::IoVec;
|
use iovec::IoVec;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
use crate::future::poll_fn;
|
||||||
use crate::net::udp::split::{split, UdpSocketRecvHalf, UdpSocketSendHalf};
|
use crate::net::udp::split::{split, UdpSocketRecvHalf, UdpSocketSendHalf};
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
use crate::net::ToSocketAddrs;
|
use crate::net::ToSocketAddrs;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
//! The halves can be reunited to the original socket with their `reunite`
|
//! The halves can be reunited to the original socket with their `reunite`
|
||||||
//! methods.
|
//! methods.
|
||||||
|
|
||||||
use super::UdpSocket;
|
use crate::future::poll_fn;
|
||||||
|
use crate::net::udp::UdpSocket;
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
use crate::future::poll_fn;
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use super::{UnixListener, UnixStream};
|
use crate::net::unix::{UnixListener, UnixStream};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
@@ -9,21 +7,31 @@ use std::task::{Context, Poll};
|
|||||||
/// Stream of listeners
|
/// Stream of listeners
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "streams do nothing unless polled"]
|
#[must_use = "streams do nothing unless polled"]
|
||||||
pub struct Incoming {
|
pub struct Incoming<'a> {
|
||||||
inner: UnixListener,
|
inner: &'a mut UnixListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Incoming {
|
impl Incoming<'_> {
|
||||||
pub(crate) fn new(listener: UnixListener) -> Incoming {
|
pub(crate) fn new(listener: &mut UnixListener) -> Incoming<'_> {
|
||||||
Incoming { inner: listener }
|
Incoming { inner: listener }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)] // TODO: dox
|
||||||
|
pub fn poll_accept(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<io::Result<UnixStream>> {
|
||||||
|
let (socket, _) = ready!(self.inner.poll_accept(cx))?;
|
||||||
|
Poll::Ready(Ok(socket))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for Incoming {
|
#[cfg(feature = "stream")]
|
||||||
|
impl futures_core::Stream for Incoming<'_> {
|
||||||
type Item = io::Result<UnixStream>;
|
type Item = io::Result<UnixStream>;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
let (socket, _) = ready!(Pin::new(&mut self.inner).poll_accept(cx))?;
|
let (socket, _) = ready!(self.inner.poll_accept(cx))?;
|
||||||
Poll::Ready(Some(Ok(socket)))
|
Poll::Ready(Some(Ok(socket)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use crate::net::unix::UnixStream;
|
use crate::future::poll_fn;
|
||||||
|
use crate::net::unix::{Incoming, UnixStream};
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use mio::Ready;
|
use mio::Ready;
|
||||||
use mio_uds;
|
use mio_uds;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -90,8 +89,8 @@ impl UnixListener {
|
|||||||
///
|
///
|
||||||
/// This method returns an implementation of the `Stream` trait which
|
/// This method returns an implementation of the `Stream` trait which
|
||||||
/// resolves to the sockets the are accepted on this listener.
|
/// resolves to the sockets the are accepted on this listener.
|
||||||
pub fn incoming(self) -> super::Incoming {
|
pub fn incoming(&mut self) -> Incoming<'_> {
|
||||||
super::Incoming::new(self)
|
Incoming::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
|
use crate::future::poll_fn;
|
||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
use crate::net::unix::split::{split, ReadHalf, WriteHalf};
|
use crate::net::unix::split::{split, ReadHalf, WriteHalf};
|
||||||
use crate::net::unix::ucred::{self, UCred};
|
use crate::net::unix::ucred::{self, UCred};
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
|
|
||||||
use bytes::{Buf, BufMut};
|
use bytes::{Buf, BufMut};
|
||||||
use futures_core::ready;
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use iovec::IoVec;
|
use iovec::IoVec;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::io::{AsyncRead, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncWrite};
|
||||||
use crate::net::driver::{platform, Registration};
|
use crate::net::driver::{platform, Registration};
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use mio::event::Evented;
|
use mio::event::Evented;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
@@ -55,7 +54,7 @@ use std::task::{Context, Poll};
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use tokio::net::util::PollEvented;
|
/// use tokio::net::util::PollEvented;
|
||||||
///
|
///
|
||||||
/// use futures_core::ready;
|
/// use futures::ready;
|
||||||
/// use mio::Ready;
|
/// use mio::Ready;
|
||||||
/// use mio::net::{TcpStream, TcpListener};
|
/// use mio::net::{TcpStream, TcpListener};
|
||||||
/// use std::io;
|
/// use std::io;
|
||||||
|
|||||||
@@ -11,21 +11,6 @@
|
|||||||
//!
|
//!
|
||||||
//! The prelude may grow over time as additional items see ubiquitous use.
|
//! The prelude may grow over time as additional items see ubiquitous use.
|
||||||
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::future::FutureExt as _;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use futures_util::future::FutureExt as _;
|
|
||||||
pub use std::future::Future;
|
|
||||||
|
|
||||||
pub use crate::stream::Stream;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::stream::StreamExt as _;
|
|
||||||
pub use futures_sink::Sink;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use futures_util::sink::SinkExt as _;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use futures_util::stream::StreamExt as _;
|
|
||||||
|
|
||||||
pub use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
pub use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
|
||||||
#[cfg(feature = "io-util")]
|
#[cfg(feature = "io-util")]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
|
|||||||
+16
-16
@@ -58,7 +58,6 @@
|
|||||||
//! use tokio::io::{BufReader, AsyncBufReadExt};
|
//! use tokio::io::{BufReader, AsyncBufReadExt};
|
||||||
//! use tokio::process::Command;
|
//! use tokio::process::Command;
|
||||||
//!
|
//!
|
||||||
//! use futures_util::stream::StreamExt;
|
|
||||||
//! use std::process::Stdio;
|
//! use std::process::Stdio;
|
||||||
//!
|
//!
|
||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
@@ -89,8 +88,8 @@
|
|||||||
//! println!("child status was: {}", status);
|
//! println!("child status was: {}", status);
|
||||||
//! });
|
//! });
|
||||||
//!
|
//!
|
||||||
//! while let Some(line) = reader.next().await {
|
//! while let Some(line) = reader.next_line().await? {
|
||||||
//! println!("Line: {}", line?);
|
//! println!("Line: {}", line);
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
@@ -120,8 +119,6 @@ mod kill;
|
|||||||
use crate::io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
use crate::io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
||||||
use crate::process::kill::Kill;
|
use crate::process::kill::Kill;
|
||||||
|
|
||||||
use futures_core::TryFuture;
|
|
||||||
use futures_util::future::try_join3;
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -681,11 +678,14 @@ impl<T: Kill> Drop for ChildDropGuard<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: TryFuture + Kill + Unpin> Future for ChildDropGuard<T> {
|
impl<T, E, F> Future for ChildDropGuard<F>
|
||||||
type Output = Result<T::Ok, T::Error>;
|
where
|
||||||
|
F: Future<Output = Result<T, E>> + Kill + Unpin,
|
||||||
|
{
|
||||||
|
type Output = Result<T, E>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let ret = Pin::new(&mut self.inner).try_poll(cx);
|
let ret = Pin::new(&mut self.inner).poll(cx);
|
||||||
|
|
||||||
if let Poll::Ready(Ok(_)) = ret {
|
if let Poll::Ready(Ok(_)) = ret {
|
||||||
// Avoid the overhead of trying to kill a reaped process
|
// Avoid the overhead of trying to kill a reaped process
|
||||||
@@ -766,6 +766,8 @@ impl Child {
|
|||||||
/// new pipes between parent and child. Use `stdout(Stdio::piped())` or
|
/// new pipes between parent and child. Use `stdout(Stdio::piped())` or
|
||||||
/// `stderr(Stdio::piped())`, respectively, when creating a `Command`.
|
/// `stderr(Stdio::piped())`, respectively, when creating a `Command`.
|
||||||
pub async fn wait_with_output(mut self) -> io::Result<Output> {
|
pub async fn wait_with_output(mut self) -> io::Result<Output> {
|
||||||
|
use crate::future::try_join3;
|
||||||
|
|
||||||
async fn read_to_end<A: AsyncRead + Unpin>(io: Option<A>) -> io::Result<Vec<u8>> {
|
async fn read_to_end<A: AsyncRead + Unpin>(io: Option<A>) -> io::Result<Vec<u8>> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
if let Some(mut io) = io {
|
if let Some(mut io) = io {
|
||||||
@@ -940,16 +942,14 @@ mod sys {
|
|||||||
|
|
||||||
#[cfg(all(test, not(loom)))]
|
#[cfg(all(test, not(loom)))]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::kill::Kill;
|
||||||
|
use super::ChildDropGuard;
|
||||||
|
|
||||||
|
use futures::future::FutureExt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::Context;
|
use std::task::{Context, Poll};
|
||||||
use std::task::Poll;
|
|
||||||
|
|
||||||
use futures_util::future::FutureExt;
|
|
||||||
|
|
||||||
use super::kill::Kill;
|
|
||||||
use super::ChildDropGuard;
|
|
||||||
|
|
||||||
struct Mock {
|
struct Mock {
|
||||||
num_kills: usize,
|
num_kills: usize,
|
||||||
@@ -1021,7 +1021,7 @@ mod test {
|
|||||||
let mut mock_reaped = Mock::with_result(Poll::Ready(Ok(())));
|
let mut mock_reaped = Mock::with_result(Poll::Ready(Ok(())));
|
||||||
let mut mock_err = Mock::with_result(Poll::Ready(Err(())));
|
let mut mock_err = Mock::with_result(Poll::Ready(Err(())));
|
||||||
|
|
||||||
let waker = futures_util::task::noop_waker();
|
let waker = futures::task::noop_waker();
|
||||||
let mut context = Context::from_waker(&waker);
|
let mut context = Context::from_waker(&waker);
|
||||||
{
|
{
|
||||||
let mut guard = ChildDropGuard::new(&mut mock_pending);
|
let mut guard = ChildDropGuard::new(&mut mock_pending);
|
||||||
|
|||||||
@@ -22,14 +22,16 @@
|
|||||||
//! bad in theory...
|
//! bad in theory...
|
||||||
|
|
||||||
mod orphan;
|
mod orphan;
|
||||||
mod reap;
|
use orphan::{OrphanQueue, OrphanQueueImpl, Wait};
|
||||||
|
|
||||||
|
mod reap;
|
||||||
|
use reap::Reaper;
|
||||||
|
|
||||||
use self::orphan::{OrphanQueue, OrphanQueueImpl, Wait};
|
|
||||||
use self::reap::Reaper;
|
|
||||||
use super::SpawnedChild;
|
|
||||||
use crate::net::util::PollEvented;
|
use crate::net::util::PollEvented;
|
||||||
use crate::process::kill::Kill;
|
use crate::process::kill::Kill;
|
||||||
|
use crate::process::SpawnedChild;
|
||||||
use crate::signal::unix::{signal, Signal, SignalKind};
|
use crate::signal::unix::{signal, Signal, SignalKind};
|
||||||
|
|
||||||
use mio::event::Evented;
|
use mio::event::Evented;
|
||||||
use mio::unix::{EventedFd, UnixReady};
|
use mio::unix::{EventedFd, UnixReady};
|
||||||
use mio::{Poll as MioPoll, PollOpt, Ready, Token};
|
use mio::{Poll as MioPoll, PollOpt, Ready, Token};
|
||||||
@@ -38,11 +40,11 @@ use std::future::Future;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::process::{self, ExitStatus};
|
use std::process::ExitStatus;
|
||||||
use std::task::Context;
|
use std::task::Context;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
impl Wait for process::Child {
|
impl Wait for std::process::Child {
|
||||||
fn id(&self) -> u32 {
|
fn id(&self) -> u32 {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
@@ -52,14 +54,14 @@ impl Wait for process::Child {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kill for process::Child {
|
impl Kill for std::process::Child {
|
||||||
fn kill(&mut self) -> io::Result<()> {
|
fn kill(&mut self) -> io::Result<()> {
|
||||||
self.kill()
|
self.kill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref ORPHAN_QUEUE: OrphanQueueImpl<process::Child> = OrphanQueueImpl::new();
|
static ref ORPHAN_QUEUE: OrphanQueueImpl<std::process::Child> = OrphanQueueImpl::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GlobalOrphanQueue;
|
struct GlobalOrphanQueue;
|
||||||
@@ -70,8 +72,8 @@ impl fmt::Debug for GlobalOrphanQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrphanQueue<process::Child> for GlobalOrphanQueue {
|
impl OrphanQueue<std::process::Child> for GlobalOrphanQueue {
|
||||||
fn push_orphan(&self, orphan: process::Child) {
|
fn push_orphan(&self, orphan: std::process::Child) {
|
||||||
ORPHAN_QUEUE.push_orphan(orphan)
|
ORPHAN_QUEUE.push_orphan(orphan)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ impl OrphanQueue<process::Child> for GlobalOrphanQueue {
|
|||||||
|
|
||||||
#[must_use = "futures do nothing unless polled"]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub(crate) struct Child {
|
pub(crate) struct Child {
|
||||||
inner: Reaper<process::Child, GlobalOrphanQueue, Signal>,
|
inner: Reaper<std::process::Child, GlobalOrphanQueue, Signal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Child {
|
impl fmt::Debug for Child {
|
||||||
@@ -93,7 +95,7 @@ impl fmt::Debug for Child {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spawn_child(cmd: &mut process::Command) -> io::Result<SpawnedChild> {
|
pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result<SpawnedChild> {
|
||||||
let mut child = cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
let stdin = stdio(child.stdin.take())?;
|
let stdin = stdio(child.stdin.take())?;
|
||||||
let stdout = stdio(child.stdout.take())?;
|
let stdout = stdio(child.stdout.take())?;
|
||||||
@@ -196,9 +198,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type ChildStdin = PollEvented<Fd<process::ChildStdin>>;
|
pub(crate) type ChildStdin = PollEvented<Fd<std::process::ChildStdin>>;
|
||||||
pub(crate) type ChildStdout = PollEvented<Fd<process::ChildStdout>>;
|
pub(crate) type ChildStdout = PollEvented<Fd<std::process::ChildStdout>>;
|
||||||
pub(crate) type ChildStderr = PollEvented<Fd<process::ChildStderr>>;
|
pub(crate) type ChildStderr = PollEvented<Fd<std::process::ChildStderr>>;
|
||||||
|
|
||||||
fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Fd<T>>>>
|
fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Fd<T>>>>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::orphan::{OrphanQueue, Wait};
|
use crate::process::imp::orphan::{OrphanQueue, Wait};
|
||||||
use crate::process::kill::Kill;
|
use crate::process::kill::Kill;
|
||||||
use futures_core::stream::Stream;
|
use crate::signal::unix::Signal;
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@@ -22,6 +23,17 @@ where
|
|||||||
signal: S,
|
signal: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Work around removal of `futures_core` dependency
|
||||||
|
pub(crate) trait Stream: Unpin {
|
||||||
|
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for Signal {
|
||||||
|
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||||
|
Signal::poll_recv(self, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<W, Q, S> Deref for Reaper<W, Q, S>
|
impl<W, Q, S> Deref for Reaper<W, Q, S>
|
||||||
where
|
where
|
||||||
W: Wait + Unpin,
|
W: Wait + Unpin,
|
||||||
@@ -60,7 +72,7 @@ impl<W, Q, S> Future for Reaper<W, Q, S>
|
|||||||
where
|
where
|
||||||
W: Wait + Unpin,
|
W: Wait + Unpin,
|
||||||
Q: OrphanQueue<W> + Unpin,
|
Q: OrphanQueue<W> + Unpin,
|
||||||
S: Stream + Unpin,
|
S: Stream,
|
||||||
{
|
{
|
||||||
type Output = io::Result<ExitStatus>;
|
type Output = io::Result<ExitStatus>;
|
||||||
|
|
||||||
@@ -85,7 +97,7 @@ where
|
|||||||
// this future's task will be notified/woken up again. Since the
|
// this future's task will be notified/woken up again. Since the
|
||||||
// futures model allows for spurious wake ups this extra wakeup
|
// futures model allows for spurious wake ups this extra wakeup
|
||||||
// should not cause significant issues with parent futures.
|
// should not cause significant issues with parent futures.
|
||||||
let registered_interest = Pin::new(&mut self.signal).poll_next(cx).is_pending();
|
let registered_interest = self.signal.poll_recv(cx).is_pending();
|
||||||
|
|
||||||
self.orphan_queue.reap_orphans();
|
self.orphan_queue.reap_orphans();
|
||||||
if let Some(status) = self.inner_mut().try_wait()? {
|
if let Some(status) = self.inner_mut().try_wait()? {
|
||||||
@@ -134,11 +146,10 @@ where
|
|||||||
#[cfg(all(test, not(loom)))]
|
#[cfg(all(test, not(loom)))]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use futures_util::future::FutureExt;
|
use futures::future::FutureExt;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::os::unix::process::ExitStatusExt;
|
use std::os::unix::process::ExitStatusExt;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::process::ExitStatus;
|
use std::process::ExitStatus;
|
||||||
use std::task::Context;
|
use std::task::Context;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
@@ -201,13 +212,10 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for MockStream {
|
impl Stream for MockStream {
|
||||||
type Item = io::Result<()>;
|
fn poll_recv(&mut self, _cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||||
|
self.total_polls += 1;
|
||||||
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
match self.values.remove(0) {
|
||||||
let inner = Pin::get_mut(self);
|
Some(()) => Poll::Ready(Some(())),
|
||||||
inner.total_polls += 1;
|
|
||||||
match inner.values.remove(0) {
|
|
||||||
Some(()) => Poll::Ready(Some(Ok(()))),
|
|
||||||
None => Poll::Pending,
|
None => Poll::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +255,7 @@ mod test {
|
|||||||
MockStream::new(vec![None, Some(()), None, None, None]),
|
MockStream::new(vec![None, Some(()), None, None, None]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let waker = futures_util::task::noop_waker();
|
let waker = futures::task::noop_waker();
|
||||||
let mut context = Context::from_waker(&waker);
|
let mut context = Context::from_waker(&waker);
|
||||||
|
|
||||||
// Not yet exited, interest registered
|
// Not yet exited, interest registered
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ use crate::process::kill::Kill;
|
|||||||
use crate::process::SpawnedChild;
|
use crate::process::SpawnedChild;
|
||||||
use crate::sync::oneshot;
|
use crate::sync::oneshot;
|
||||||
|
|
||||||
use futures_util::future::Fuse;
|
|
||||||
use futures_util::future::FutureExt;
|
|
||||||
use mio_named_pipes::NamedPipe;
|
use mio_named_pipes::NamedPipe;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -59,7 +57,7 @@ impl fmt::Debug for Child {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Waiting {
|
struct Waiting {
|
||||||
rx: Fuse<oneshot::Receiver<()>>,
|
rx: oneshot::Receiver<()>,
|
||||||
wait_object: HANDLE,
|
wait_object: HANDLE,
|
||||||
tx: *mut Option<oneshot::Sender<()>>,
|
tx: *mut Option<oneshot::Sender<()>>,
|
||||||
}
|
}
|
||||||
@@ -103,7 +101,7 @@ impl Future for Child {
|
|||||||
let inner = Pin::get_mut(self);
|
let inner = Pin::get_mut(self);
|
||||||
loop {
|
loop {
|
||||||
if let Some(ref mut w) = inner.waiting {
|
if let Some(ref mut w) = inner.waiting {
|
||||||
match w.rx.poll_unpin(cx) {
|
match Pin::new(&mut w.rx).poll(cx) {
|
||||||
Poll::Ready(Ok(())) => {}
|
Poll::Ready(Ok(())) => {}
|
||||||
Poll::Ready(Err(_)) => panic!("should not be canceled"),
|
Poll::Ready(Err(_)) => panic!("should not be canceled"),
|
||||||
Poll::Pending => return Poll::Pending,
|
Poll::Pending => return Poll::Pending,
|
||||||
@@ -134,7 +132,7 @@ impl Future for Child {
|
|||||||
return Poll::Ready(Err(err));
|
return Poll::Ready(Err(err));
|
||||||
}
|
}
|
||||||
inner.waiting = Some(Waiting {
|
inner.waiting = Some(Waiting {
|
||||||
rx: rx.fuse(),
|
rx,
|
||||||
wait_object,
|
wait_object,
|
||||||
tx: ptr,
|
tx: ptr,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -334,6 +334,14 @@ impl Runtime {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enter the runtime context
|
||||||
|
pub fn enter<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce() -> R,
|
||||||
|
{
|
||||||
|
self.handle.enter(f)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a handle to the runtime's spawner.
|
/// Return a handle to the runtime's spawner.
|
||||||
///
|
///
|
||||||
/// The returned handle can be used to spawn tasks that run on this runtime.
|
/// The returned handle can be used to spawn tasks that run on this runtime.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::blocking;
|
|||||||
use crate::runtime::thread_pool::ThreadPool;
|
use crate::runtime::thread_pool::ThreadPool;
|
||||||
use crate::runtime::{Park, Unpark};
|
use crate::runtime::{Park, Unpark};
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ fn val(num: u32) -> Task<Noop> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn num(task: Task<Noop>) -> u32 {
|
fn num(task: Task<Noop>) -> u32 {
|
||||||
use futures_util::task::noop_waker_ref;
|
use futures::task::noop_waker_ref;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::Context;
|
use std::task::Context;
|
||||||
|
|||||||
+26
-37
@@ -1,46 +1,35 @@
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use super::unix::{self as os_impl, Signal as Inner};
|
use super::unix::{self as os_impl};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use super::windows::{self as os_impl, Event as Inner};
|
use super::windows::{self as os_impl};
|
||||||
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
/// Represents a stream which receives "ctrl-c" notifications sent to the process.
|
/// Completes when a "ctrl-c" notification is sent to the process.
|
||||||
///
|
///
|
||||||
/// In general signals are handled very differently across Unix and Windows, but
|
/// While signals are handled very differently between Unix and Windows, both
|
||||||
/// this is somewhat cross platform in terms of how it can be handled. A ctrl-c
|
/// platforms support receiving a signal on "ctrl-c". This function provides a
|
||||||
/// event to a console process can be represented as a stream for both Windows
|
/// portable API for receiving this notification.
|
||||||
/// and Unix.
|
|
||||||
///
|
///
|
||||||
/// Note that there are a number of caveats listening for signals, and you may
|
/// Once the returned future is polled, a listener a listener is registered. The
|
||||||
/// wish to read up on the documentation in the `unix` or `windows` module to
|
/// future will complete on the first received `ctrl-c` **after** the initial
|
||||||
/// take a peek.
|
/// call to either `Future::poll` or `.await`.
|
||||||
///
|
///
|
||||||
/// Notably, a notification to this process notifies *all* streams listening to
|
/// # Examples
|
||||||
/// this event. Moreover, the notifications **are coalesced** if they aren't processed
|
///
|
||||||
/// quickly enough. This means that if two notifications are received back-to-back,
|
/// ```rust,no_run
|
||||||
/// then the stream may only receive one item about the two notifications.
|
/// use tokio::signal;
|
||||||
#[must_use = "streams do nothing unless polled"]
|
///
|
||||||
#[derive(Debug)]
|
/// #[tokio::main]
|
||||||
pub struct CtrlC {
|
/// async fn main() {
|
||||||
inner: Inner,
|
/// println!("waiting for ctrl-c");
|
||||||
}
|
///
|
||||||
|
/// signal::ctrl_c().await.expect("failed to listen for event");
|
||||||
/// Creates a new stream which receives "ctrl-c" notifications sent to the
|
///
|
||||||
/// process.
|
/// println!("received ctrl-c event");
|
||||||
///
|
/// }
|
||||||
/// This function binds to the default reactor.
|
/// ```
|
||||||
pub fn ctrl_c() -> io::Result<CtrlC> {
|
pub async fn ctrl_c() -> io::Result<()> {
|
||||||
os_impl::ctrl_c().map(|inner| CtrlC { inner })
|
os_impl::ctrl_c()?.recv().await;
|
||||||
}
|
Ok(())
|
||||||
|
|
||||||
impl Stream for CtrlC {
|
|
||||||
type Item = ();
|
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
Pin::new(&mut self.inner).poll_next(cx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-41
@@ -14,28 +14,15 @@
|
|||||||
//!
|
//!
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! Print out all ctrl-C notifications received
|
//! Print on "ctrl-c" notification.
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use tokio::signal;
|
//! use tokio::signal;
|
||||||
//!
|
//!
|
||||||
//! use futures_util::future;
|
|
||||||
//! use futures_util::stream::StreamExt;
|
|
||||||
//!
|
|
||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
//! signal::ctrl_c().await?;
|
||||||
//! // on this stream may represent multiple ctrl-c signals.
|
//! println!("ctrl-c received!");
|
||||||
//! let ctrl_c = signal::ctrl_c()?;
|
|
||||||
//!
|
|
||||||
//! // Process each ctrl-c as it comes in
|
|
||||||
//! let prog = ctrl_c.for_each(|_| {
|
|
||||||
//! println!("ctrl-c received!");
|
|
||||||
//! future::ready(())
|
|
||||||
//! });
|
|
||||||
//!
|
|
||||||
//! prog.await;
|
|
||||||
//!
|
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
@@ -45,38 +32,25 @@
|
|||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! # #[cfg(unix)] {
|
//! # #[cfg(unix)] {
|
||||||
//!
|
//!
|
||||||
//! use tokio::signal::{self, unix::{signal, SignalKind}};
|
//! use tokio::signal::unix::{signal, SignalKind};
|
||||||
//!
|
|
||||||
//! use futures_util::future;
|
|
||||||
//! use futures_util::stream::StreamExt;
|
|
||||||
//!
|
//!
|
||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
//! // An infinite stream of hangup signals.
|
||||||
//! // on this stream may represent multiple ctrl-c signals.
|
//! let mut stream = signal(SignalKind::hangup())?;
|
||||||
//! let ctrl_c = signal::ctrl_c()?;
|
|
||||||
//!
|
//!
|
||||||
//! // Process each ctrl-c as it comes in
|
//! // Print whenever a HUP signal is received
|
||||||
//! let prog = ctrl_c.for_each(|_| {
|
//! loop {
|
||||||
//! println!("ctrl-c received!");
|
//! stream.recv().await;
|
||||||
//! future::ready(())
|
//! println!("got signal HUP");
|
||||||
//! });
|
//! }
|
||||||
//!
|
|
||||||
//! prog.await;
|
|
||||||
//!
|
|
||||||
//! // Like the previous example, this is an infinite stream of signals
|
|
||||||
//! // being received, and signals may be coalesced while pending.
|
|
||||||
//! let stream = signal(SignalKind::hangup())?;
|
|
||||||
//!
|
|
||||||
//! // Convert out stream into a future and block the program
|
|
||||||
//! let (signal, _stream) = stream.into_future().await;
|
|
||||||
//! println!("got signal {:?}", signal);
|
|
||||||
//! Ok(())
|
|
||||||
//! }
|
//! }
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
mod ctrl_c;
|
mod ctrl_c;
|
||||||
|
pub use ctrl_c::ctrl_c;
|
||||||
|
|
||||||
mod registry;
|
mod registry;
|
||||||
|
|
||||||
mod os {
|
mod os {
|
||||||
@@ -89,5 +63,3 @@ mod os {
|
|||||||
|
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
pub use self::ctrl_c::{ctrl_c, CtrlC};
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ impl<S: Storage> Registry<S> {
|
|||||||
///
|
///
|
||||||
/// Returns true if an event was delivered to at least one listener.
|
/// Returns true if an event was delivered to at least one listener.
|
||||||
fn broadcast(&self) -> bool {
|
fn broadcast(&self) -> bool {
|
||||||
|
use crate::sync::mpsc::error::TrySendError;
|
||||||
|
|
||||||
let mut did_notify = false;
|
let mut did_notify = false;
|
||||||
self.storage.for_each(|event_info| {
|
self.storage.for_each(|event_info| {
|
||||||
// Any signal of this kind arrived since we checked last?
|
// Any signal of this kind arrived since we checked last?
|
||||||
@@ -103,17 +105,13 @@ impl<S: Storage> Registry<S> {
|
|||||||
for i in (0..recipients.len()).rev() {
|
for i in (0..recipients.len()).rev() {
|
||||||
match recipients[i].try_send(()) {
|
match recipients[i].try_send(()) {
|
||||||
Ok(()) => did_notify = true,
|
Ok(()) => did_notify = true,
|
||||||
Err(ref e) if e.is_closed() => {
|
Err(TrySendError::Closed(..)) => {
|
||||||
recipients.swap_remove(i);
|
recipients.swap_remove(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel is full, ignore the error since the
|
// Channel is full, ignore the error since the
|
||||||
// receiver has already been woken up
|
// receiver has already been woken up
|
||||||
Err(e) => {
|
Err(_) => {}
|
||||||
// Sanity check in case this error type ever gets
|
|
||||||
// additional variants we have not considered.
|
|
||||||
debug_assert!(e.is_full());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -180,7 +178,8 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::runtime::{self, Runtime};
|
use crate::runtime::{self, Runtime};
|
||||||
use crate::sync::{mpsc, oneshot};
|
use crate::sync::{mpsc, oneshot};
|
||||||
use futures::{future, StreamExt};
|
|
||||||
|
use futures::future;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() {
|
fn smoke() {
|
||||||
@@ -220,11 +219,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let _ = fire.send(());
|
let _ = fire.send(());
|
||||||
let all = future::join3(
|
let all = future::join3(collect(first_rx), collect(second_rx), collect(third_rx));
|
||||||
first_rx.collect::<Vec<_>>(),
|
|
||||||
second_rx.collect::<Vec<_>>(),
|
|
||||||
third_rx.collect::<Vec<_>>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (first_results, second_results, third_results) = all.await;
|
let (first_results, second_results, third_results) = all.await;
|
||||||
assert_eq!(2, first_results.len());
|
assert_eq!(2, first_results.len());
|
||||||
@@ -279,7 +274,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let _ = fire.send(());
|
let _ = fire.send(());
|
||||||
let results: Vec<()> = third_rx.collect().await;
|
let results = collect(third_rx).await;
|
||||||
|
|
||||||
assert_eq!(1, results.len());
|
assert_eq!(1, results.len());
|
||||||
});
|
});
|
||||||
@@ -311,4 +306,14 @@ mod tests {
|
|||||||
fn rt() -> Runtime {
|
fn rt() -> Runtime {
|
||||||
runtime::Builder::new().current_thread().build().unwrap()
|
runtime::Builder::new().current_thread().build().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn collect(mut rx: crate::sync::mpsc::Receiver<()>) -> Vec<()> {
|
||||||
|
let mut ret = vec![];
|
||||||
|
|
||||||
|
while let Some(v) = rx.recv().await {
|
||||||
|
ret.push(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -10,10 +10,8 @@ use crate::net::util::PollEvented;
|
|||||||
use crate::signal::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
|
use crate::signal::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
|
||||||
use crate::sync::mpsc::{channel, Receiver};
|
use crate::sync::mpsc::{channel, Receiver};
|
||||||
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use mio_uds::UnixStream;
|
use mio_uds::UnixStream;
|
||||||
use std::future::Future;
|
|
||||||
use std::io::{self, Error, ErrorKind, Write};
|
use std::io::{self, Error, ErrorKind, Write};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@@ -262,10 +260,8 @@ struct Driver {
|
|||||||
wakeup: PollEvented<UnixStream>,
|
wakeup: PollEvented<UnixStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for Driver {
|
impl Driver {
|
||||||
type Output = ();
|
fn poll(&mut self, cx: &mut Context<'_>) -> Poll<()> {
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
// Drain the data from the pipe and maintain interest in getting more
|
// Drain the data from the pipe and maintain interest in getting more
|
||||||
self.drain(cx);
|
self.drain(cx);
|
||||||
// Broadcast any signals which were received
|
// Broadcast any signals which were received
|
||||||
@@ -302,7 +298,7 @@ impl Driver {
|
|||||||
/// We do *NOT* use the existence of any read bytes as evidence a sigal was
|
/// We do *NOT* use the existence of any read bytes as evidence a sigal was
|
||||||
/// received since the `pending` flags would have already been set if that
|
/// received since the `pending` flags would have already been set if that
|
||||||
/// was the case. See #38 for more info.
|
/// was the case. See #38 for more info.
|
||||||
fn drain(mut self: Pin<&mut Self>, cx: &mut Context<'_>) {
|
fn drain(&mut self, cx: &mut Context<'_>) {
|
||||||
loop {
|
loop {
|
||||||
match Pin::new(&mut self.wakeup).poll_read(cx, &mut [0; 128]) {
|
match Pin::new(&mut self.wakeup).poll_read(cx, &mut [0; 128]) {
|
||||||
Poll::Ready(Ok(0)) => panic!("EOF on self-pipe"),
|
Poll::Ready(Ok(0)) => panic!("EOF on self-pipe"),
|
||||||
@@ -395,20 +391,24 @@ pub fn signal(kind: SignalKind) -> io::Result<Signal> {
|
|||||||
Ok(Signal { driver, rx })
|
Ok(Signal { driver, rx })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ctrl_c() -> io::Result<Signal> {
|
impl Signal {
|
||||||
signal(SignalKind::interrupt())
|
#[doc(hidden)] // TODO: Dox
|
||||||
}
|
pub async fn recv(&mut self) -> Option<()> {
|
||||||
|
use crate::future::poll_fn;
|
||||||
impl Stream for Signal {
|
poll_fn(|cx| self.poll_recv(cx)).await
|
||||||
type Item = ();
|
}
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
let _ = Pin::new(&mut self.driver).poll(cx);
|
|
||||||
|
|
||||||
|
#[doc(hidden)] // TODO: document
|
||||||
|
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||||
|
let _ = self.driver.poll(cx);
|
||||||
self.rx.poll_recv(cx)
|
self.rx.poll_recv(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ctrl_c() -> io::Result<Signal> {
|
||||||
|
signal(SignalKind::interrupt())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(test, not(loom)))]
|
#[cfg(all(test, not(loom)))]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
+34
-29
@@ -10,10 +10,8 @@
|
|||||||
use crate::signal::registry::{globals, EventId, EventInfo, Init, Storage};
|
use crate::signal::registry::{globals, EventId, EventInfo, Init, Storage};
|
||||||
use crate::sync::mpsc::{channel, Receiver};
|
use crate::sync::mpsc::{channel, Receiver};
|
||||||
|
|
||||||
use futures_core::stream::Stream;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use winapi::shared::minwindef::*;
|
use winapi::shared::minwindef::*;
|
||||||
@@ -82,6 +80,10 @@ pub(crate) struct Event {
|
|||||||
rx: Receiver<()>,
|
rx: Receiver<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ctrl_c() -> io::Result<Event> {
|
||||||
|
Event::new(CTRL_C_EVENT)
|
||||||
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
fn new(signum: DWORD) -> io::Result<Self> {
|
fn new(signum: DWORD) -> io::Result<Self> {
|
||||||
global_init()?;
|
global_init()?;
|
||||||
@@ -91,17 +93,10 @@ impl Event {
|
|||||||
|
|
||||||
Ok(Event { rx })
|
Ok(Event { rx })
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn ctrl_c() -> io::Result<Event> {
|
pub(crate) async fn recv(&mut self) -> Option<()> {
|
||||||
Event::new(CTRL_C_EVENT)
|
use crate::future::poll_fn;
|
||||||
}
|
poll_fn(|cx| self.rx.poll_recv(cx)).await
|
||||||
|
|
||||||
impl Stream for Event {
|
|
||||||
type Item = ();
|
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
self.rx.poll_recv(cx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +104,7 @@ fn global_init() -> io::Result<()> {
|
|||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
let mut init = None;
|
let mut init = None;
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let rc = SetConsoleCtrlHandler(Some(handler), TRUE);
|
let rc = SetConsoleCtrlHandler(Some(handler), TRUE);
|
||||||
let ret = if rc == 0 {
|
let ret = if rc == 0 {
|
||||||
@@ -153,6 +149,22 @@ pub struct CtrlBreak {
|
|||||||
inner: Event,
|
inner: Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CtrlBreak {
|
||||||
|
#[doc(hidden)] // TODO: document
|
||||||
|
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||||
|
self.inner.rx.poll_recv(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
|
impl futures_core::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
|
/// Creates a new stream which receives "ctrl-break" notifications sent to the
|
||||||
/// process.
|
/// process.
|
||||||
///
|
///
|
||||||
@@ -161,29 +173,22 @@ pub fn ctrl_break() -> io::Result<CtrlBreak> {
|
|||||||
Event::new(CTRL_BREAK_EVENT).map(|inner| CtrlBreak { inner })
|
Event::new(CTRL_BREAK_EVENT).map(|inner| CtrlBreak { inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for CtrlBreak {
|
|
||||||
type Item = ();
|
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
Pin::new(&mut self.inner)
|
|
||||||
.poll_next(cx)
|
|
||||||
.map(|item| item.map(|_| ()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(test, not(loom)))]
|
#[cfg(all(test, not(loom)))]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::runtime::Runtime;
|
use crate::runtime::Runtime;
|
||||||
|
use tokio_test::{assert_ok, assert_pending, assert_ready_ok, task};
|
||||||
|
|
||||||
use futures_util::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ctrl_c() {
|
fn ctrl_c() {
|
||||||
let mut rt = rt();
|
let rt = rt();
|
||||||
|
|
||||||
rt.block_on(async {
|
rt.enter(|| {
|
||||||
let ctrl_c = crate::signal::ctrl_c().expect("failed to create CtrlC");
|
let mut ctrl_c = task::spawn(crate::signal::ctrl_c());
|
||||||
|
|
||||||
|
assert_pending!(ctrl_c.poll());
|
||||||
|
|
||||||
// Windows doesn't have a good programmatic way of sending events
|
// Windows doesn't have a good programmatic way of sending events
|
||||||
// like sending signals on Unix, so we'll stub out the actual OS
|
// like sending signals on Unix, so we'll stub out the actual OS
|
||||||
@@ -192,7 +197,7 @@ mod tests {
|
|||||||
super::handler(CTRL_C_EVENT);
|
super::handler(CTRL_C_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = ctrl_c.into_future().await;
|
assert_ready_ok!(ctrl_c.poll());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +206,7 @@ mod tests {
|
|||||||
let mut rt = rt();
|
let mut rt = rt();
|
||||||
|
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let ctrl_break = super::ctrl_break().expect("failed to create CtrlC");
|
let mut ctrl_break = assert_ok!(super::ctrl_break());
|
||||||
|
|
||||||
// Windows doesn't have a good programmatic way of sending events
|
// Windows doesn't have a good programmatic way of sending events
|
||||||
// like sending signals on Unix, so we'll stub out the actual OS
|
// like sending signals on Unix, so we'll stub out the actual OS
|
||||||
@@ -210,7 +215,7 @@ mod tests {
|
|||||||
super::handler(CTRL_BREAK_EVENT);
|
super::handler(CTRL_BREAK_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = ctrl_break.into_future().await;
|
ctrl_break.next().await.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
//! A sequence of asynchronous values.
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use crate::time::{throttle::Throttle, Timeout};
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use futures_core::Stream;
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use futures_util::stream::{empty, iter, once, pending, poll_fn, repeat, unfold};
|
|
||||||
|
|
||||||
/// An extension trait for `Stream` that provides a variety of convenient
|
|
||||||
/// combinator functions.
|
|
||||||
///
|
|
||||||
/// Currently, there are only [`timeout`] and [`throttle`] functions, but
|
|
||||||
/// this will increase over time.
|
|
||||||
///
|
|
||||||
/// Users are not expected to implement this trait. All types that implement
|
|
||||||
/// `Stream` already implement `StreamExt`.
|
|
||||||
///
|
|
||||||
/// This trait can be imported directly or via the Tokio prelude: `use
|
|
||||||
/// tokio::prelude::*`.
|
|
||||||
///
|
|
||||||
/// [`throttle`]: method.throttle
|
|
||||||
/// [`timeout`]: method.timeout
|
|
||||||
pub trait StreamExt: Stream {
|
|
||||||
/// Throttle down the stream by enforcing a fixed delay between items.
|
|
||||||
///
|
|
||||||
/// Errors are also delayed.
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
fn throttle(self, duration: Duration) -> Throttle<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Throttle::new(self, duration)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new stream which allows `self` until `timeout`.
|
|
||||||
///
|
|
||||||
/// This combinator creates a new stream which wraps the receiving stream
|
|
||||||
/// with a timeout. For each item, the returned stream is allowed to execute
|
|
||||||
/// until it completes or `timeout` has elapsed, whichever happens first.
|
|
||||||
///
|
|
||||||
/// If an item completes before `timeout` then the stream will yield
|
|
||||||
/// with that item. Otherwise the stream will yield to an error.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tokio::prelude::*;
|
|
||||||
///
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// # fn slow_stream() -> impl Stream<Item = ()> {
|
|
||||||
/// # tokio::stream::empty()
|
|
||||||
/// # }
|
|
||||||
/// #
|
|
||||||
/// # async fn dox() {
|
|
||||||
/// let mut stream = slow_stream()
|
|
||||||
/// .timeout(Duration::from_secs(1));
|
|
||||||
///
|
|
||||||
/// while let Some(value) = stream.next().await {
|
|
||||||
/// println!("value = {:?}", value);
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
fn timeout(self, timeout: Duration) -> Timeout<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Timeout::new(self, timeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ?Sized> StreamExt for T where T: Stream {}
|
|
||||||
@@ -8,8 +8,9 @@ use std::sync::Mutex;
|
|||||||
/// # #[tokio::main]
|
/// # #[tokio::main]
|
||||||
/// # async fn main() {
|
/// # async fn main() {
|
||||||
/// use tokio::sync::Barrier;
|
/// use tokio::sync::Barrier;
|
||||||
|
///
|
||||||
|
/// use futures::future::join_all;
|
||||||
/// use std::sync::Arc;
|
/// use std::sync::Arc;
|
||||||
/// use futures_util::future::join_all;
|
|
||||||
///
|
///
|
||||||
/// let mut handles = Vec::with_capacity(10);
|
/// let mut handles = Vec::with_capacity(10);
|
||||||
/// let barrier = Arc::new(Barrier::new(10));
|
/// let barrier = Arc::new(Barrier::new(10));
|
||||||
|
|||||||
+19
-125
@@ -1,8 +1,8 @@
|
|||||||
use crate::sync::mpsc::chan;
|
use crate::sync::mpsc::chan;
|
||||||
|
use crate::sync::mpsc::error::{ClosedError, SendError, TrySendError};
|
||||||
use crate::sync::semaphore;
|
use crate::sync::semaphore;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
/// Send values to the associated `Receiver`.
|
/// Send values to the associated `Receiver`.
|
||||||
@@ -44,27 +44,6 @@ impl<T> fmt::Debug for Receiver<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error returned by the `Sender`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SendError(());
|
|
||||||
|
|
||||||
/// Error returned by `Sender::try_send`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct TrySendError<T> {
|
|
||||||
kind: ErrorKind,
|
|
||||||
value: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum ErrorKind {
|
|
||||||
Closed,
|
|
||||||
NoCapacity,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error returned by `Receiver`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecvError(());
|
|
||||||
|
|
||||||
/// Create a bounded mpsc channel for communicating between asynchronous tasks,
|
/// Create a bounded mpsc channel for communicating between asynchronous tasks,
|
||||||
/// returning the sender/receiver halves.
|
/// returning the sender/receiver halves.
|
||||||
///
|
///
|
||||||
@@ -161,12 +140,12 @@ impl<T> Receiver<T> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn recv(&mut self) -> Option<T> {
|
pub async fn recv(&mut self) -> Option<T> {
|
||||||
use futures_util::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
poll_fn(|cx| self.poll_recv(cx)).await
|
poll_fn(|cx| self.poll_recv(cx)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)] // TODO: remove
|
#[doc(hidden)] // TODO: document
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.chan.recv(cx)
|
self.chan.recv(cx)
|
||||||
}
|
}
|
||||||
@@ -180,11 +159,14 @@ impl<T> Receiver<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Unpin for Receiver<T> {}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
impl<T> futures_core::Stream for Receiver<T> {
|
impl<T> futures_core::Stream for Receiver<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.get_mut().poll_recv(cx)
|
self.poll_recv(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,9 +175,9 @@ impl<T> Sender<T> {
|
|||||||
Sender { chan }
|
Sender { chan }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)] // TODO: remove
|
#[doc(hidden)] // TODO: document
|
||||||
pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), SendError>> {
|
pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ClosedError>> {
|
||||||
self.chan.poll_ready(cx).map_err(|_| SendError(()))
|
self.chan.poll_ready(cx).map_err(|_| ClosedError::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to send a message on this `Sender`, returning the message
|
/// Attempts to send a message on this `Sender`, returning the message
|
||||||
@@ -233,105 +215,17 @@ impl<T> Sender<T> {
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn send(&mut self, value: T) -> Result<(), SendError> {
|
pub async fn send(&mut self, value: T) -> Result<(), SendError<T>> {
|
||||||
use futures_util::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
poll_fn(|cx| self.poll_ready(cx)).await?;
|
if poll_fn(|cx| self.poll_ready(cx)).await.is_err() {
|
||||||
|
return Err(SendError(value));
|
||||||
self.try_send(value).map_err(|_| SendError(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> futures_sink::Sink<T> for Sender<T> {
|
|
||||||
type Error = SendError;
|
|
||||||
|
|
||||||
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Sender::poll_ready(self.get_mut(), cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
|
|
||||||
self.as_mut().try_send(msg).map_err(|err| {
|
|
||||||
assert!(err.is_full(), "call `poll_ready` before sending");
|
|
||||||
SendError(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl SendError =====
|
|
||||||
|
|
||||||
impl fmt::Display for SendError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::error::Error for SendError {}
|
|
||||||
|
|
||||||
// ===== impl TrySendError =====
|
|
||||||
|
|
||||||
impl<T> TrySendError<T> {
|
|
||||||
/// Get the inner value.
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Did the send fail because the channel has been closed?
|
|
||||||
pub fn is_closed(&self) -> bool {
|
|
||||||
if let ErrorKind::Closed = self.kind {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Did the send fail because the channel was at capacity?
|
match self.try_send(value) {
|
||||||
pub fn is_full(&self) -> bool {
|
Ok(()) => Ok(()),
|
||||||
if let ErrorKind::NoCapacity = self.kind {
|
Err(TrySendError::Full(_)) => unreachable!(),
|
||||||
true
|
Err(TrySendError::Closed(value)) => Err(SendError(value)),
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Display for TrySendError<T> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let descr = match self.kind {
|
|
||||||
ErrorKind::Closed => "channel closed",
|
|
||||||
ErrorKind::NoCapacity => "no available capacity",
|
|
||||||
};
|
|
||||||
write!(fmt, "{}", descr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> ::std::error::Error for TrySendError<T> {}
|
|
||||||
|
|
||||||
impl<T> From<(T, chan::TrySendError)> for TrySendError<T> {
|
|
||||||
fn from((value, err): (T, chan::TrySendError)) -> TrySendError<T> {
|
|
||||||
TrySendError {
|
|
||||||
value,
|
|
||||||
kind: match err {
|
|
||||||
chan::TrySendError::Closed => ErrorKind::Closed,
|
|
||||||
chan::TrySendError::NoPermits => ErrorKind::NoCapacity,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl RecvError =====
|
|
||||||
|
|
||||||
impl fmt::Display for RecvError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::error::Error for RecvError {}
|
|
||||||
|
|||||||
+74
-24
@@ -1,5 +1,9 @@
|
|||||||
use crate::loom::{cell::CausalCell, future::AtomicWaker, sync::atomic::AtomicUsize, sync::Arc};
|
use crate::loom::cell::CausalCell;
|
||||||
use crate::sync::mpsc::list;
|
use crate::loom::future::AtomicWaker;
|
||||||
|
use crate::loom::sync::atomic::AtomicUsize;
|
||||||
|
use crate::loom::sync::Arc;
|
||||||
|
use crate::sync::mpsc::error::ClosedError;
|
||||||
|
use crate::sync::mpsc::{error, list};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::process;
|
use std::process;
|
||||||
@@ -43,7 +47,25 @@ where
|
|||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum TrySendError {
|
pub(crate) enum TrySendError {
|
||||||
Closed,
|
Closed,
|
||||||
NoPermits,
|
Full,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<(T, TrySendError)> for error::SendError<T> {
|
||||||
|
fn from(src: (T, TrySendError)) -> error::SendError<T> {
|
||||||
|
match src.1 {
|
||||||
|
TrySendError::Closed => error::SendError(src.0),
|
||||||
|
TrySendError::Full => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<(T, TrySendError)> for error::TrySendError<T> {
|
||||||
|
fn from(src: (T, TrySendError)) -> error::TrySendError<T> {
|
||||||
|
match src.1 {
|
||||||
|
TrySendError::Closed => error::TrySendError::Closed(src.0),
|
||||||
|
TrySendError::Full => error::TrySendError::Full(src.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait Semaphore {
|
pub(crate) trait Semaphore {
|
||||||
@@ -59,8 +81,11 @@ pub(crate) trait Semaphore {
|
|||||||
|
|
||||||
fn add_permit(&self);
|
fn add_permit(&self);
|
||||||
|
|
||||||
fn poll_acquire(&self, cx: &mut Context<'_>, permit: &mut Self::Permit)
|
fn poll_acquire(
|
||||||
-> Poll<Result<(), ()>>;
|
&self,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
permit: &mut Self::Permit,
|
||||||
|
) -> Poll<Result<(), ClosedError>>;
|
||||||
|
|
||||||
fn try_acquire(&self, permit: &mut Self::Permit) -> Result<(), TrySendError>;
|
fn try_acquire(&self, permit: &mut Self::Permit) -> Result<(), TrySendError>;
|
||||||
|
|
||||||
@@ -161,26 +186,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
|
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ClosedError>> {
|
||||||
self.inner.semaphore.poll_acquire(cx, &mut self.permit)
|
self.inner.semaphore.poll_acquire(cx, &mut self.permit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message and notify the receiver.
|
/// Send a message and notify the receiver.
|
||||||
pub(crate) fn try_send(&mut self, value: T) -> Result<(), (T, TrySendError)> {
|
pub(crate) fn try_send(&mut self, value: T) -> Result<(), (T, TrySendError)> {
|
||||||
if let Err(e) = self.inner.semaphore.try_acquire(&mut self.permit) {
|
self.inner.try_send(value, &mut self.permit)
|
||||||
return Err((value, e));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the value
|
impl<T> Tx<T, AtomicUsize> {
|
||||||
self.inner.tx.push(value);
|
pub(crate) fn send_unbounded(&self, value: T) -> Result<(), (T, TrySendError)> {
|
||||||
|
self.inner.try_send(value, &mut ())
|
||||||
// Notify the rx task
|
|
||||||
self.inner.rx_waker.wake();
|
|
||||||
|
|
||||||
// Release the permit
|
|
||||||
self.inner.semaphore.forget(&mut self.permit);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,6 +335,28 @@ where
|
|||||||
|
|
||||||
// ===== impl Chan =====
|
// ===== impl Chan =====
|
||||||
|
|
||||||
|
impl<T, S> Chan<T, S>
|
||||||
|
where
|
||||||
|
S: Semaphore,
|
||||||
|
{
|
||||||
|
fn try_send(&self, value: T, permit: &mut S::Permit) -> Result<(), (T, TrySendError)> {
|
||||||
|
if let Err(e) = self.semaphore.try_acquire(permit) {
|
||||||
|
return Err((value, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the value
|
||||||
|
self.tx.push(value);
|
||||||
|
|
||||||
|
// Notify the rx task
|
||||||
|
self.rx_waker.wake();
|
||||||
|
|
||||||
|
// Release the permit
|
||||||
|
self.semaphore.forget(permit);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, S> Drop for Chan<T, S> {
|
impl<T, S> Drop for Chan<T, S> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
use super::block::Read::Value;
|
use super::block::Read::Value;
|
||||||
@@ -339,7 +379,7 @@ impl From<TryAcquireError> for TrySendError {
|
|||||||
if src.is_closed() {
|
if src.is_closed() {
|
||||||
TrySendError::Closed
|
TrySendError::Closed
|
||||||
} else if src.is_no_permits() {
|
} else if src.is_no_permits() {
|
||||||
TrySendError::NoPermits
|
TrySendError::Full
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@@ -369,8 +409,14 @@ impl Semaphore for (crate::sync::semaphore::Semaphore, usize) {
|
|||||||
self.0.available_permits() == self.1
|
self.0.available_permits() == self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_acquire(&self, cx: &mut Context<'_>, permit: &mut Permit) -> Poll<Result<(), ()>> {
|
fn poll_acquire(
|
||||||
permit.poll_acquire(cx, &self.0).map_err(|_| ())
|
&self,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
permit: &mut Permit,
|
||||||
|
) -> Poll<Result<(), ClosedError>> {
|
||||||
|
permit
|
||||||
|
.poll_acquire(cx, &self.0)
|
||||||
|
.map_err(|_| ClosedError::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_acquire(&self, permit: &mut Permit) -> Result<(), TrySendError> {
|
fn try_acquire(&self, permit: &mut Permit) -> Result<(), TrySendError> {
|
||||||
@@ -412,8 +458,12 @@ impl Semaphore for AtomicUsize {
|
|||||||
self.load(Acquire) >> 1 == 0
|
self.load(Acquire) >> 1 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_acquire(&self, _cx: &mut Context<'_>, permit: &mut ()) -> Poll<Result<(), ()>> {
|
fn poll_acquire(
|
||||||
Ready(self.try_acquire(permit).map_err(|_| ()))
|
&self,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
permit: &mut (),
|
||||||
|
) -> Poll<Result<(), ClosedError>> {
|
||||||
|
Ready(self.try_acquire(permit).map_err(|_| ClosedError::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_acquire(&self, _permit: &mut ()) -> Result<(), TrySendError> {
|
fn try_acquire(&self, _permit: &mut ()) -> Result<(), TrySendError> {
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
//! Channel error types
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Error returned by the `Sender`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SendError<T>(pub T);
|
||||||
|
|
||||||
|
impl<T> fmt::Display for SendError<T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "channel closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> ::std::error::Error for SendError<T> {}
|
||||||
|
|
||||||
|
// ===== TrySendError =====
|
||||||
|
|
||||||
|
/// This enumeration is the list of the possible error outcomes for the
|
||||||
|
/// [try_send](super::Sender::try_send) method.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TrySendError<T> {
|
||||||
|
/// The data could not be sent on the channel because the channel is
|
||||||
|
/// currently full and sending would require blocking.
|
||||||
|
Full(T),
|
||||||
|
|
||||||
|
/// The receive half of the channel was explicitly closed or has been
|
||||||
|
/// dropped.
|
||||||
|
Closed(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> Error for TrySendError<T> {}
|
||||||
|
|
||||||
|
impl<T> fmt::Display for TrySendError<T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
fmt,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
TrySendError::Full(..) => "no available capacity",
|
||||||
|
TrySendError::Closed(..) => "channel closed",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<SendError<T>> for TrySendError<T> {
|
||||||
|
fn from(src: SendError<T>) -> TrySendError<T> {
|
||||||
|
TrySendError::Closed(src.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== RecvError =====
|
||||||
|
|
||||||
|
/// Error returned by `Receiver`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RecvError(());
|
||||||
|
|
||||||
|
impl fmt::Display for RecvError {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "channel closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for RecvError {}
|
||||||
|
|
||||||
|
// ===== ClosedError =====
|
||||||
|
|
||||||
|
/// Erorr returned by [`Sender::poll_ready`](super::Sender::poll_ready)].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ClosedError(());
|
||||||
|
|
||||||
|
impl ClosedError {
|
||||||
|
pub(crate) fn new() -> ClosedError {
|
||||||
|
ClosedError(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ClosedError {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "channel closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ClosedError {}
|
||||||
@@ -46,12 +46,7 @@ pub(super) mod list;
|
|||||||
mod unbounded;
|
mod unbounded;
|
||||||
pub use self::unbounded::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
pub use self::unbounded::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
|
|
||||||
pub mod error {
|
pub mod error;
|
||||||
//! Channel error types
|
|
||||||
|
|
||||||
pub use super::bounded::{RecvError, SendError, TrySendError};
|
|
||||||
pub use super::unbounded::{UnboundedRecvError, UnboundedSendError, UnboundedTrySendError};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The number of values a block can contain.
|
/// The number of values a block can contain.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use crate::loom::sync::atomic::AtomicUsize;
|
use crate::loom::sync::atomic::AtomicUsize;
|
||||||
use crate::sync::mpsc::chan;
|
use crate::sync::mpsc::chan;
|
||||||
|
use crate::sync::mpsc::error::SendError;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
/// Send values to the associated `UnboundedReceiver`.
|
/// Send values to the associated `UnboundedReceiver`.
|
||||||
///
|
///
|
||||||
/// Instances are created by the
|
/// Instances are created by the
|
||||||
@@ -47,18 +46,6 @@ impl<T> fmt::Debug for UnboundedReceiver<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error returned by the `UnboundedSender`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UnboundedSendError(());
|
|
||||||
|
|
||||||
/// Returned by `UnboundedSender::try_send` when the channel has been closed.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UnboundedTrySendError<T>(T);
|
|
||||||
|
|
||||||
/// Error returned by `UnboundedReceiver`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UnboundedRecvError(());
|
|
||||||
|
|
||||||
/// Create an unbounded mpsc channel for communicating between asynchronous
|
/// Create an unbounded mpsc channel for communicating between asynchronous
|
||||||
/// tasks.
|
/// tasks.
|
||||||
///
|
///
|
||||||
@@ -86,7 +73,7 @@ impl<T> UnboundedReceiver<T> {
|
|||||||
UnboundedReceiver { chan }
|
UnboundedReceiver { chan }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)] // TODO: remove
|
#[doc(hidden)] // TODO: doc
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.chan.recv(cx)
|
self.chan.recv(cx)
|
||||||
}
|
}
|
||||||
@@ -103,10 +90,10 @@ impl<T> UnboundedReceiver<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::unbounded_channel();
|
/// let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// tx.try_send("hello").unwrap();
|
/// tx.send("hello").unwrap();
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// assert_eq!(Some("hello"), rx.recv().await);
|
/// assert_eq!(Some("hello"), rx.recv().await);
|
||||||
@@ -121,17 +108,17 @@ impl<T> UnboundedReceiver<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::unbounded_channel();
|
/// let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
///
|
///
|
||||||
/// tx.try_send("hello").unwrap();
|
/// tx.send("hello").unwrap();
|
||||||
/// tx.try_send("world").unwrap();
|
/// tx.send("world").unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(Some("hello"), rx.recv().await);
|
/// assert_eq!(Some("hello"), rx.recv().await);
|
||||||
/// assert_eq!(Some("world"), rx.recv().await);
|
/// assert_eq!(Some("world"), rx.recv().await);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn recv(&mut self) -> Option<T> {
|
pub async fn recv(&mut self) -> Option<T> {
|
||||||
use futures_util::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
poll_fn(|cx| self.poll_recv(cx)).await
|
poll_fn(|cx| self.poll_recv(cx)).await
|
||||||
}
|
}
|
||||||
@@ -145,11 +132,12 @@ impl<T> UnboundedReceiver<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
impl<T> futures_core::Stream for UnboundedReceiver<T> {
|
impl<T> futures_core::Stream for UnboundedReceiver<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.chan.recv(cx)
|
self.poll_recv(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,72 +147,8 @@ impl<T> UnboundedSender<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to send a message on this `UnboundedSender` without blocking.
|
/// Attempts to send a message on this `UnboundedSender` without blocking.
|
||||||
pub fn try_send(&mut self, message: T) -> Result<(), UnboundedTrySendError<T>> {
|
pub fn send(&self, message: T) -> Result<(), SendError<T>> {
|
||||||
self.chan.try_send(message)?;
|
self.chan.send_unbounded(message)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> futures_sink::Sink<T> for UnboundedSender<T> {
|
|
||||||
type Error = UnboundedSendError;
|
|
||||||
|
|
||||||
fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
|
|
||||||
self.try_send(msg).map_err(|_| UnboundedSendError(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl UnboundedSendError =====
|
|
||||||
|
|
||||||
impl fmt::Display for UnboundedSendError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::error::Error for UnboundedSendError {}
|
|
||||||
|
|
||||||
// ===== impl TrySendError =====
|
|
||||||
|
|
||||||
impl<T> UnboundedTrySendError<T> {
|
|
||||||
/// Get the inner value.
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Display for UnboundedTrySendError<T> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> ::std::error::Error for UnboundedTrySendError<T> {}
|
|
||||||
|
|
||||||
impl<T> From<(T, chan::TrySendError)> for UnboundedTrySendError<T> {
|
|
||||||
fn from((value, err): (T, chan::TrySendError)) -> UnboundedTrySendError<T> {
|
|
||||||
assert_eq!(chan::TrySendError::Closed, err);
|
|
||||||
UnboundedTrySendError(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl UnboundedRecvError =====
|
|
||||||
|
|
||||||
impl fmt::Display for UnboundedRecvError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::error::Error for UnboundedRecvError {}
|
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
//! [`Mutex`]: struct.Mutex.html
|
//! [`Mutex`]: struct.Mutex.html
|
||||||
//! [`MutexGuard`]: struct.MutexGuard.html
|
//! [`MutexGuard`]: struct.MutexGuard.html
|
||||||
|
|
||||||
|
use crate::future::poll_fn;
|
||||||
use crate::sync::semaphore;
|
use crate::sync::semaphore;
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::loom::cell::CausalCell;
|
|||||||
use crate::loom::sync::atomic::AtomicUsize;
|
use crate::loom::sync::atomic::AtomicUsize;
|
||||||
use crate::loom::sync::Arc;
|
use crate::loom::sync::Arc;
|
||||||
|
|
||||||
use futures_core::ready;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
@@ -225,7 +224,7 @@ impl<T> Sender<T> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn closed(&mut self) {
|
pub async fn closed(&mut self) {
|
||||||
use futures_util::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
|
||||||
poll_fn(|cx| self.poll_closed(cx)).await
|
poll_fn(|cx| self.poll_closed(cx)).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::sync::task::AtomicWaker;
|
use crate::sync::task::AtomicWaker;
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use loom::future::block_on;
|
use loom::future::block_on;
|
||||||
use loom::sync::atomic::AtomicUsize;
|
use loom::sync::atomic::AtomicUsize;
|
||||||
use loom::thread;
|
use loom::thread;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::sync::mpsc;
|
use crate::sync::mpsc;
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use loom::future::block_on;
|
use loom::future::block_on;
|
||||||
use loom::thread;
|
use loom::thread;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::sync::oneshot;
|
use crate::sync::oneshot;
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use loom::future::block_on;
|
use loom::future::block_on;
|
||||||
use loom::thread;
|
use loom::thread;
|
||||||
use std::task::Poll::{Pending, Ready};
|
use std::task::Poll::{Pending, Ready};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::sync::semaphore::*;
|
use crate::sync::semaphore::*;
|
||||||
|
|
||||||
use futures_core::ready;
|
use futures::future::poll_fn;
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use loom::future::block_on;
|
use loom::future::block_on;
|
||||||
use loom::thread;
|
use loom::thread;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|||||||
+32
-84
@@ -51,20 +51,16 @@
|
|||||||
//! [`Sender::closed`]: struct.Sender.html#method.closed
|
//! [`Sender::closed`]: struct.Sender.html#method.closed
|
||||||
//! [`Receiver::get_ref`]: struct.Receiver.html#method.get_ref
|
//! [`Receiver::get_ref`]: struct.Receiver.html#method.get_ref
|
||||||
|
|
||||||
|
use crate::future::poll_fn;
|
||||||
use crate::sync::task::AtomicWaker;
|
use crate::sync::task::AtomicWaker;
|
||||||
|
|
||||||
use core::task::Poll::{Pending, Ready};
|
|
||||||
use core::task::{Context, Poll};
|
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use futures_util::future::poll_fn;
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering::SeqCst;
|
use std::sync::atomic::Ordering::SeqCst;
|
||||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak};
|
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak};
|
||||||
|
use std::task::Poll::{Pending, Ready};
|
||||||
use futures_core::ready;
|
use std::task::{Context, Poll};
|
||||||
use futures_util::pin_mut;
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
/// Receives values from the associated [`Sender`](struct.Sender.html).
|
/// Receives values from the associated [`Sender`](struct.Sender.html).
|
||||||
///
|
///
|
||||||
@@ -235,77 +231,50 @@ impl<T> Receiver<T> {
|
|||||||
Ref { inner }
|
Ref { inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to receive the latest value sent via the channel.
|
// TODO: document
|
||||||
///
|
#[doc(hidden)]
|
||||||
/// If a new, unobserved, value has been sent, a reference to it is
|
pub fn poll_recv_ref<'a>(&'a mut self, cx: &mut Context<'_>) -> Poll<Option<Ref<'a, T>>> {
|
||||||
/// returned. If no new value has been sent, then `Pending` is returned and
|
// Make sure the task is up to date
|
||||||
/// the current task is notified once a new value is sent.
|
self.inner.waker.register_by_ref(cx.waker());
|
||||||
///
|
|
||||||
/// Only the **most recent** value is returned. If the receiver is falling
|
|
||||||
/// behind the sender, intermediate values are dropped.
|
|
||||||
pub async fn recv_ref(&mut self) -> Option<Ref<'_, T>> {
|
|
||||||
let shared = &self.shared;
|
|
||||||
let inner = &self.inner;
|
|
||||||
let version = self.ver;
|
|
||||||
|
|
||||||
match poll_fn(|cx| poll_lock(cx, shared, inner, version)).await {
|
let state = self.shared.version.load(SeqCst);
|
||||||
Some((lock, version)) => {
|
let version = state & !CLOSED;
|
||||||
self.ver = version;
|
|
||||||
Some(lock)
|
if version != self.ver {
|
||||||
}
|
let inner = self.shared.value.read().unwrap();
|
||||||
None => None,
|
self.ver = version;
|
||||||
|
|
||||||
|
return Ready(Some(Ref { inner }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if CLOSED == state & CLOSED {
|
||||||
|
// The `Store` handle has been dropped.
|
||||||
|
return Ready(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_lock<'a, T>(
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
shared: &'a Arc<Shared<T>>,
|
|
||||||
inner: &Arc<WatchInner>,
|
|
||||||
ver: usize,
|
|
||||||
) -> Poll<Option<(Ref<'a, T>, usize)>> {
|
|
||||||
// Make sure the task is up to date
|
|
||||||
inner.waker.register_by_ref(cx.waker());
|
|
||||||
|
|
||||||
let state = shared.version.load(SeqCst);
|
|
||||||
let version = state & !CLOSED;
|
|
||||||
|
|
||||||
if version != ver {
|
|
||||||
let inner = shared.value.read().unwrap();
|
|
||||||
|
|
||||||
return Ready(Some((Ref { inner }, version)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if CLOSED == state & CLOSED {
|
|
||||||
// The `Store` handle has been dropped.
|
|
||||||
return Ready(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pending
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> Receiver<T> {
|
impl<T: Clone> Receiver<T> {
|
||||||
/// Attempts to clone the latest value sent via the channel.
|
/// Attempts to clone the latest value sent via the channel.
|
||||||
///
|
|
||||||
/// This is equivalent to calling `clone()` on the value returned by
|
|
||||||
/// `recv_ref()`.
|
|
||||||
#[allow(clippy::map_clone)] // false positive: https://github.com/rust-lang/rust-clippy/issues/3274
|
|
||||||
pub async fn recv(&mut self) -> Option<T> {
|
pub async fn recv(&mut self) -> Option<T> {
|
||||||
self.recv_ref().await.map(|v_ref| v_ref.clone())
|
poll_fn(|cx| {
|
||||||
|
let v_ref = ready!(self.poll_recv_ref(cx));
|
||||||
|
Poll::Ready(v_ref.map(|v_ref| (*v_ref).clone()))
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stream")]
|
||||||
impl<T: Clone> futures_core::Stream for Receiver<T> {
|
impl<T: Clone> futures_core::Stream for Receiver<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
use std::future::Future;
|
let v_ref = ready!(self.poll_recv_ref(cx));
|
||||||
|
|
||||||
let fut = self.get_mut().recv();
|
Poll::Ready(v_ref.map(|v_ref| (*v_ref).clone()))
|
||||||
pin_mut!(fut);
|
|
||||||
|
|
||||||
let item = ready!(fut.poll(cx));
|
|
||||||
Ready(item.map(|v_ref| v_ref))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,27 +363,6 @@ impl<T> Sender<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> futures_sink::Sink<T> for Sender<T> {
|
|
||||||
type Error = error::SendError<T>;
|
|
||||||
|
|
||||||
fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
|
|
||||||
self.as_ref().get_ref().broadcast(item)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Notify all watchers of a change
|
/// Notify all watchers of a change
|
||||||
fn notify_all<T>(shared: &Shared<T>) {
|
fn notify_all<T>(shared: &Shared<T>) {
|
||||||
let watchers = shared.watchers.lock().unwrap();
|
let watchers = shared.watchers.lock().unwrap();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ fn create_drop_join_handle() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn poll_drop_handle_then_drop() {
|
fn poll_drop_handle_then_drop() {
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ fn shutdown_from_queue_after_poll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gated(n: usize, complete_first_poll: bool, by_val: bool) -> impl Future<Output = &'static str> {
|
fn gated(n: usize, complete_first_poll: bool, by_val: bool) -> impl Future<Output = &'static str> {
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ fn join_one_task<T: Future + 'static>(join_handle: T) -> loom::thread::JoinHandl
|
|||||||
fn join_two_tasks<T: Future + Unpin + 'static>(
|
fn join_two_tasks<T: Future + Unpin + 'static>(
|
||||||
join_handle: T,
|
join_handle: T,
|
||||||
) -> loom::thread::JoinHandle<T::Output> {
|
) -> loom::thread::JoinHandle<T::Output> {
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
// Join handle
|
// Join handle
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::tests::track_drop::track_drop;
|
|||||||
use tokio_test::task::spawn;
|
use tokio_test::task::spawn;
|
||||||
use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok};
|
use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok};
|
||||||
|
|
||||||
use futures_util::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
//! `test-util` feature flag is enabled, the values returned for `now()` are
|
//! `test-util` feature flag is enabled, the values returned for `now()` are
|
||||||
//! configurable.
|
//! configurable.
|
||||||
|
|
||||||
|
#[cfg(feature = "test-util")]
|
||||||
|
pub(crate) use self::variant::now;
|
||||||
|
pub(crate) use self::variant::Clock;
|
||||||
#[cfg(feature = "test-util")]
|
#[cfg(feature = "test-util")]
|
||||||
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
|
||||||
pub use self::variant::{advance, pause, resume};
|
pub use self::variant::{advance, pause, resume};
|
||||||
pub(crate) use self::variant::{now, Clock};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "test-util"))]
|
#[cfg(not(feature = "test-util"))]
|
||||||
mod variant {
|
mod variant {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user