Update Tokio to use std::future. (#1120)

A first pass at updating Tokio to use `std::future`.

Implementations of `Future` from the futures crate are updated to implement
`Future` from std. Implementations of `Stream` are moved to a feature flag.

This commits disables a number of crates that have not yet been updated.
This commit is contained in:
Carl Lerche
2019-06-24 12:34:30 -07:00
committed by GitHub
parent aa99950b9c
commit 06c473e628
150 changed files with 2694 additions and 9825 deletions
+7 -6
View File
@@ -12,7 +12,7 @@ task:
setup_script:
- pkg install -y curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y
- sh rustup.sh -y --default-toolchain nightly
- . $HOME/.cargo/env
- rustup target add i686-unknown-freebsd
- |
@@ -31,13 +31,14 @@ task:
folder: $HOME/.cargo/registry
test_script:
- . $HOME/.cargo/env
- cargo test --all
- cargo test --all --lib && cargo test --all --tests
- (cd tokio-trace/test-log-support && cargo test)
- (cd tokio-trace/test_static_max_level_features && cargo test)
- cargo doc --all
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd
# TODO: Re-enable
# i686_test_script:
# - . $HOME/.cargo/env
# - |
# cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd
before_cache_script:
- rm -rf $HOME/.cargo/registry/index
+11 -11
View File
@@ -2,24 +2,24 @@
members = [
"tokio",
"tokio-buf",
"tokio-codec",
# "tokio-buf",
# "tokio-codec",
"tokio-current-thread",
"tokio-executor",
"tokio-fs",
# "tokio-fs",
"tokio-futures",
"tokio-io",
"tokio-macros",
# "tokio-macros",
"tokio-reactor",
"tokio-signal",
# "tokio-signal",
"tokio-sync",
"tokio-test",
"tokio-threadpool",
# "tokio-threadpool",
"tokio-timer",
"tokio-tcp",
"tokio-tls",
"tokio-trace",
"tokio-trace/tokio-trace-core",
"tokio-udp",
"tokio-uds",
# "tokio-tls",
# "tokio-trace",
# "tokio-trace/tokio-trace-core",
# "tokio-udp",
# "tokio-uds",
]
-2
View File
@@ -1,2 +0,0 @@
[build]
target-dir = "../target"
-31
View File
@@ -1,31 +0,0 @@
[package]
name = "examples"
edition = "2018"
version = "0.1.0"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
# Break out of the parent workspace
[workspace]
[[bin]]
name = "chat"
path = "src/chat.rs"
[[bin]]
name = "echo_client"
path = "src/echo_client.rs"
[[bin]]
name = "echo_server"
path = "src/echo_server.rs"
[[bin]]
name = "hyper"
path = "src/hyper.rs"
[dependencies]
tokio = { version = "0.2.0", features = ["async-await-preview"], path = "../tokio" }
futures = "0.1.23"
bytes = "0.4.9"
hyper = "0.12.8"
-5
View File
@@ -1,5 +0,0 @@
# Tokio async/await examples
These are a separate crate in order to work around some cargo bugs. It also
allows `[patch]` to be used in `Cargo.toml` to ensure the correct lib versions
are being pulled in.
-131
View File
@@ -1,131 +0,0 @@
#![feature(await_macro, async_await)]
use tokio::async_wait;
use tokio::codec::{LinesCodec, Decoder};
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
use futures::sync::mpsc;
use std::collections::HashMap;
use std::io;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
/// Shorthand for the transmit half of the message channel.
type Tx = mpsc::UnboundedSender<String>;
struct Shared {
peers: HashMap<SocketAddr, Tx>,
}
impl Shared {
/// Create a new, empty, instance of `Shared`.
fn new() -> Self {
Shared {
peers: HashMap::new(),
}
}
}
async fn process(stream: TcpStream, state: Arc<Mutex<Shared>>) -> io::Result<()> {
let addr = stream.peer_addr().unwrap();
let mut lines = LinesCodec::new().framed(stream);
// Extract the peer's name
let name = match async_wait!(lines.next()) {
Some(name) => name?,
None => {
// Disconnected early
return Ok(());
}
};
println!("`{}` is joining the chat", name);
let (tx, mut rx) = mpsc::unbounded();
// Register the socket
state.lock().unwrap()
.peers.insert(addr, tx);
// Split the `lines` handle into send and recv handles. This allows spawning
// separate tasks.
let (mut lines_tx, mut lines_rx) = lines.split();
// Spawn a task that receives all lines broadcasted to us from other peers
// and writes it to the client.
tokio::spawn_async(async move {
while let Some(line) = async_wait!(rx.next()) {
let line = line.unwrap();
async_wait!(lines_tx.send_async(line)).unwrap();
}
});
// Use the current task to read lines from the socket and broadcast them to
// other peers.
while let Some(message) = async_wait!(lines_rx.next()) {
// TODO: Error handling
let message = message.unwrap();
let mut line = name.clone();
line.push_str(": ");
line.push_str(&message);
line.push_str("\r\n");
let state = state.lock().unwrap();
for (peer_addr, tx) in &state.peers {
if *peer_addr != addr {
// TODO: Error handling
tx.unbounded_send(line.clone()).unwrap();
}
}
}
// Remove the client from the shared state. Doing so will also result in the
// tx task to terminate.
state.lock().unwrap()
.peers.remove(&addr)
.expect("bug");
Ok(())
}
#[tokio::main]
async fn main() {
// Create the shared state. This is how all the peers communicate.
//
// The server task will hold a handle to this. For every new client, the
// `state` handle is cloned and passed into the task that processes the
// client connection.
let state = Arc::new(Mutex::new(Shared::new()));
let addr = "127.0.0.1:6142".parse().unwrap();
// Bind a TCP listener to the socket address.
//
// Note that this is the Tokio TcpListener, which is fully async.
let listener = TcpListener::bind(&addr).unwrap();
println!("server running on localhost:6142");
// Start the Tokio runtime.
let mut incoming = listener.incoming();
while let Some(stream) = async_wait!(incoming.next()) {
let stream = match stream {
Ok(stream) => stream,
Err(_) => continue,
};
let state = state.clone();
tokio::spawn_async(async move {
if let Err(_) = async_wait!(process(stream, state)) {
eprintln!("failed to process connection");
}
});
}
}
-50
View File
@@ -1,50 +0,0 @@
#![feature(await_macro, async_await)]
use tokio::async_wait;
use tokio::net::TcpStream;
use tokio::prelude::*;
use std::io;
use std::net::SocketAddr;
const MESSAGES: &[&str] = &[
"hello",
"world",
"one two three",
];
async fn run_client(addr: &SocketAddr) -> io::Result<()> {
let mut stream = async_wait!(TcpStream::connect(addr))?;
// Buffer to read into
let mut buf = [0; 128];
for msg in MESSAGES {
println!(" > write = {:?}", msg);
// Write the message to the server
async_wait!(stream.write_all_async(msg.as_bytes()))?;
// Read the message back from the server
async_wait!(stream.read_exact_async(&mut buf[..msg.len()]))?;
assert_eq!(&buf[..msg.len()], msg.as_bytes());
}
Ok(())
}
#[tokio::main]
async fn main() {
use std::env;
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = addr.parse::<SocketAddr>().unwrap();
// Connect to the echo serveer
match async_wait!(run_client(&addr)) {
Ok(_) => println!("done."),
Err(e) => eprintln!("echo client failed; error = {:?}", e),
}
}
-42
View File
@@ -1,42 +0,0 @@
#![feature(await_macro, async_await)]
use tokio::async_wait;
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
use std::net::SocketAddr;
fn handle(mut stream: TcpStream) {
tokio::spawn_async(async move {
let mut buf = [0; 1024];
loop {
match async_wait!(stream.read_async(&mut buf)).unwrap() {
0 => break, // Socket closed
n => {
// Send the data back
async_wait!(stream.write_all_async(&buf[0..n])).unwrap();
}
}
}
});
}
#[tokio::main]
async fn main() {
use std::env;
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = addr.parse::<SocketAddr>().unwrap();
// Bind the TCP listener
let listener = TcpListener::bind(&addr).unwrap();
println!("Listening on: {}", addr);
let mut incoming = listener.incoming();
while let Some(stream) = async_wait!(incoming.next()) {
let stream = stream.unwrap();
handle(stream);
}
}
-29
View File
@@ -1,29 +0,0 @@
#![feature(await_macro, async_await)]
use tokio::async_wait;
use tokio::prelude::*;
use hyper::Client;
use std::time::Duration;
use std::str;
#[tokio::main]
async fn main() {
let client = Client::new();
let uri = "http://httpbin.org/ip".parse().unwrap();
let response = async_wait!({
client.get(uri)
.timeout(Duration::from_secs(10))
}).unwrap();
println!("Response: {}", response.status());
let mut body = response.into_body();
while let Some(chunk) = async_wait!(body.next()) {
let chunk = chunk.unwrap();
println!("chunk = {}", str::from_utf8(&chunk[..]).unwrap());
}
}
-22
View File
@@ -1,22 +0,0 @@
#![feature(await_macro, async_await)]
use tokio::async_wait;
use tokio::timer::Delay;
use std::time::{Duration, Instant};
#[tokio::test]
async fn success_no_async() {
assert!(true);
}
#[tokio::test]
#[should_panic]
async fn fail_no_async() {
assert!(false);
}
#[tokio::test]
async fn use_timer() {
let when = Instant::now() + Duration::from_millis(10);
async_wait!(Delay::new(when));
}
+93 -91
View File
@@ -1,118 +1,120 @@
trigger: ["master"]
pr: ["master"]
trigger: ["master", "std-future"]
pr: ["master", "std-future"]
variables:
nightly: nightly-2019-05-09
nightly: nightly-2019-06-10
jobs:
# Check formatting
- template: ci/azure-rustfmt.yml
parameters:
name: rustfmt
# # Check formatting
# - template: ci/azure-rustfmt.yml
# parameters:
# name: rustfmt
# Test top level crate
- template: ci/azure-test-stable.yml
parameters:
name: test_tokio
displayName: Test tokio
cross: true
crates:
- tokio
# - template: ci/azure-test-stable.yml
# parameters:
# name: test_tokio
# displayName: Test tokio
# cross: true
# crates:
# - tokio
# Test crates that are platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_sub_cross
displayName: Test sub crates -
displayName: Test sub crates (cross) -
cross: true
rust: $(nightly)
crates:
- tokio-fs
# - tokio-fs
- tokio-reactor
- tokio-signal
- tokio-tcp
- tokio-tls
- tokio-udp
- tokio-uds
# - tokio-signal
# - tokio-tcp
# - tokio-tls
# - tokio-udp
# - tokio-uds
# Test crates that are NOT platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_linux
displayName: Test sub crates -
rust: $(nightly)
crates:
- tokio-buf
- tokio-codec
# - tokio-buf
# - tokio-codec
- tokio-current-thread
- tokio-executor
- tokio-io
- tokio-sync
- tokio-threadpool
- tokio-timer
- tokio-test
- tokio-trace
- tokio-trace/tokio-trace-core
- tokio-trace/test-log-support
- tokio-trace/test_static_max_level_features
# - tokio-threadpool
# - tokio-timer
# - tokio-test
# - tokio-trace
# - tokio-trace/tokio-trace-core
# - tokio-trace/test-log-support
# - tokio-trace/test_static_max_level_features
- template: ci/azure-cargo-check.yml
parameters:
name: features
displayName: Check feature permtuations
rust: stable
crates:
tokio:
- codec
- fs
- io
- reactor
- rt-full
- tcp
- timer
- udp
- uds
- sync
tokio-buf:
- util
# Run async-await tests
- template: ci/azure-test-nightly.yml
parameters:
name: test_nightly
displayName: Test Async / Await
rust: $(nightly)
# Try cross compiling
- template: ci/azure-cross-compile.yml
parameters:
name: cross_32bit_linux
target: i686-unknown-linux-gnu
# This represents the minimum Rust version supported by
# Tokio. Updating this should be done in a dedicated PR and
# cannot be greater than two 0.x releases prior to the
# current stable.
# - template: ci/azure-cargo-check.yml
# parameters:
# name: features
# displayName: Check feature permtuations
# rust: stable
# crates:
# tokio:
# - codec
# - fs
# - io
# - reactor
# - rt-full
# - tcp
# - timer
# - udp
# - uds
# - sync
# tokio-buf:
# - util
#
# Tests are not run as tests may require newer versions of
# rust.
- template: ci/azure-check-minrust.yml
parameters:
name: minrust
rust_version: 1.34.0
- template: ci/azure-tsan.yml
parameters:
name: tsan
rust: $(nightly)
- template: ci/azure-deploy-docs.yml
parameters:
dependsOn:
- rustfmt
- test_tokio
- test_sub_cross
- test_linux
- features
- test_nightly
- cross_32bit_linux
- minrust
- tsan
# # Run async-await tests
# - template: ci/azure-test-nightly.yml
# parameters:
# name: test_nightly
# displayName: Test Async / Await
# rust: $(nightly)
#
# # Try cross compiling
# - template: ci/azure-cross-compile.yml
# parameters:
# name: cross_32bit_linux
# target: i686-unknown-linux-gnu
#
# # This represents the minimum Rust version supported by
# # Tokio. Updating this should be done in a dedicated PR and
# # cannot be greater than two 0.x releases prior to the
# # current stable.
# #
# # Tests are not run as tests may require newer versions of
# # rust.
# - template: ci/azure-check-minrust.yml
# parameters:
# name: minrust
# rust_version: 1.34.0
#
# - template: ci/azure-tsan.yml
# parameters:
# name: tsan
# rust: $(nightly)
#
# - template: ci/azure-deploy-docs.yml
# parameters:
# dependsOn:
# - rustfmt
# - test_tokio
# - test_sub_cross
# - test_linux
# - features
# - test_nightly
# - cross_32bit_linux
# - minrust
# - tsan
+3
View File
@@ -27,6 +27,9 @@ steps:
# All platforms.
- script: |
rustup toolchain install nightly
rustup update
rustup toolchain list
rustc -Vv
cargo -V
displayName: Query rust and cargo versions
+1
View File
@@ -10,6 +10,7 @@ jobs:
rust_version: stable
- script: |
rustup component add rustfmt
cargo fmt --version
displayName: Install rustfmt
- script: |
cargo fmt --all -- --check
+13 -12
View File
@@ -17,23 +17,24 @@ jobs:
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
# rust_version: stable
rust_version: ${{ parameters.rust }}
- template: azure-is-release.yml
- ${{ each crate in parameters.crates }}:
- script: cargo test
env:
LOOM_MAX_DURATION: 10
CI: 'True'
displayName: cargo test -p ${{ crate }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
condition: and(succeeded(), ne(variables['isRelease'], 'true'))
# - template: azure-is-release.yml
#
# - ${{ each crate in parameters.crates }}:
# - script: cargo test
# env:
# LOOM_MAX_DURATION: 10
# CI: 'True'
# displayName: cargo test -p ${{ crate }}
# workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
# condition: and(succeeded(), ne(variables['isRelease'], 'true'))
- template: azure-patch-crates.yml
- ${{ each crate in parameters.crates }}:
- script: cargo test
- script: cargo test --lib && cargo test --tests
env:
LOOM_MAX_DURATION: 10
CI: 'True'
+3 -1
View File
@@ -24,4 +24,6 @@ publish = false
[dependencies]
tokio-executor = { version = "0.2.0", path = "../tokio-executor" }
futures = "0.1.19"
[dev-dependencies]
tokio-sync = { version = "0.2.0", path = "../tokio-sync" }
+47 -64
View File
@@ -30,13 +30,14 @@
mod scheduler;
use crate::scheduler::Scheduler;
use futures::future::{ExecuteError, ExecuteErrorKind, Executor};
use futures::{executor, Async, Future};
use std::cell::Cell;
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::{atomic, mpsc, Arc};
use std::task::{Context, Poll, Waker};
use std::thread;
use std::time::{Duration, Instant};
use tokio_executor::park::{Park, ParkThread, Unpark};
@@ -60,7 +61,7 @@ pub struct CurrentThread<P: Park = ParkThread> {
spawn_handle: Handle,
/// Receiver for futures spawned from other threads
spawn_receiver: mpsc::Receiver<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
spawn_receiver: mpsc::Receiver<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>,
/// The thread-local ID assigned to this executor.
id: u64,
@@ -182,11 +183,7 @@ struct Borrow<'a, U> {
}
trait SpawnLocal {
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
);
fn spawn_local(&mut self, future: Pin<Box<dyn Future<Output = ()>>>, already_counted: bool);
}
struct CurrentRunner {
@@ -225,7 +222,7 @@ thread_local! {
///
/// [`CurrentThread`]: struct.CurrentThread.html
/// [mod]: index.html
pub fn block_on_all<F>(future: F) -> Result<F::Item, F::Error>
pub fn block_on_all<F>(future: F) -> F::Output
where
F: Future,
{
@@ -233,8 +230,7 @@ where
let ret = current_thread.block_on(future);
current_thread.run().unwrap();
ret.map_err(|e| e.into_inner().expect("unexpected execution error"))
ret
}
/// Executes a future on the current thread.
@@ -252,10 +248,10 @@ where
/// [`tokio::spawn`]: ../fn.spawn.html
pub fn spawn<F>(future: F)
where
F: Future<Item = (), Error = ()> + 'static,
F: Future<Output = ()> + 'static,
{
TaskExecutor::current()
.spawn_local(Box::new(future))
.spawn_local(Box::pin(future))
.unwrap();
}
@@ -283,7 +279,7 @@ impl<P: Park> CurrentThread<P> {
});
let scheduler = Scheduler::new(unpark);
let notify = scheduler.notify();
let waker = scheduler.waker();
let num_futures = Arc::new(atomic::AtomicUsize::new(0));
@@ -294,10 +290,10 @@ impl<P: Park> CurrentThread<P> {
id,
spawn_handle: Handle {
sender: spawn_sender,
num_futures: num_futures,
notify: notify,
num_futures,
waker,
shut_down: Cell::new(false),
thread: thread,
thread,
id,
},
spawn_receiver: spawn_receiver,
@@ -319,9 +315,9 @@ impl<P: Park> CurrentThread<P> {
/// This internally queues the future to be executed once `run` is called.
pub fn spawn<F>(&mut self, future: F) -> &mut Self
where
F: Future<Item = (), Error = ()> + 'static,
F: Future<Output = ()> + 'static,
{
self.borrow().spawn_local(Box::new(future), false);
self.borrow().spawn_local(Box::pin(future), false);
self
}
@@ -338,7 +334,7 @@ impl<P: Park> CurrentThread<P> {
///
/// The caller is responsible for ensuring that other spawned futures
/// complete execution.
pub fn block_on<F>(&mut self, future: F) -> Result<F::Item, BlockError<F::Error>>
pub fn block_on<F>(&mut self, future: F) -> F::Output
where
F: Future,
{
@@ -424,7 +420,7 @@ impl<P: Park> Drop for CurrentThread<P> {
impl tokio_executor::Executor for CurrentThread {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
future: Pin<Box<dyn Future<Output = ()> + Send>>,
) -> Result<(), SpawnError> {
self.borrow().spawn_local(future, false);
Ok(())
@@ -433,10 +429,10 @@ impl tokio_executor::Executor for CurrentThread {
impl<T> tokio_executor::TypedExecutor<T> for CurrentThread
where
T: Future<Item = (), Error = ()> + 'static,
T: Future<Output = ()> + 'static,
{
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
self.borrow().spawn_local(Box::new(future), false);
self.borrow().spawn_local(Box::pin(future), false);
Ok(())
}
}
@@ -461,9 +457,9 @@ impl<'a, P: Park> Entered<'a, P> {
/// This internally queues the future to be executed once `run` is called.
pub fn spawn<F>(&mut self, future: F) -> &mut Self
where
F: Future<Item = (), Error = ()> + 'static,
F: Future<Output = ()> + 'static,
{
self.executor.borrow().spawn_local(Box::new(future), false);
self.executor.borrow().spawn_local(Box::pin(future), false);
self
}
@@ -480,29 +476,35 @@ impl<'a, P: Park> Entered<'a, P> {
///
/// The caller is responsible for ensuring that other spawned futures
/// complete execution.
pub fn block_on<F>(&mut self, future: F) -> Result<F::Item, BlockError<F::Error>>
///
/// # Panics
///
/// This function will panic if the `Park` call returns an error.
pub fn block_on<F>(&mut self, mut future: F) -> F::Output
where
F: Future,
{
let mut future = executor::spawn(future);
let notify = self.executor.scheduler.notify();
// Safety: we shadow the original `future`, so it will never move
// again.
let mut future = unsafe { Pin::new_unchecked(&mut future) };
let waker = self.executor.scheduler.waker();
let mut cx = Context::from_waker(&waker);
loop {
let res = self
.executor
.borrow()
.enter(self.enter, || future.poll_future_notify(&notify, 0));
.enter(self.enter, || future.as_mut().poll(&mut cx));
match res {
Ok(Async::Ready(e)) => return Ok(e),
Err(e) => return Err(BlockError { inner: Some(e) }),
Ok(Async::NotReady) => {}
Poll::Ready(e) => return e,
Poll::Pending => {}
}
self.tick();
if let Err(_) = self.executor.park.park() {
return Err(BlockError { inner: None });
panic!("block_on park failed");
}
}
}
@@ -629,10 +631,11 @@ impl<'a, P: Park> fmt::Debug for Entered<'a, P> {
/// Handle to spawn a future on the corresponding `CurrentThread` instance
#[derive(Clone)]
pub struct Handle {
sender: mpsc::Sender<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
sender: mpsc::Sender<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>,
num_futures: Arc<atomic::AtomicUsize>,
shut_down: Cell<bool>,
notify: executor::NotifyHandle,
/// Waker to the Scheduler
waker: Waker,
thread: thread::ThreadId,
/// The thread-local ID assigned to this Handle's executor.
@@ -657,12 +660,12 @@ impl Handle {
/// instance of the `Handle` does not exist anymore.
pub fn spawn<F>(&self, future: F) -> Result<(), SpawnError>
where
F: Future<Item = (), Error = ()> + Send + 'static,
F: Future<Output = ()> + Send + 'static,
{
if thread::current().id() == self.thread {
let mut e = TaskExecutor::current();
if e.id() == Some(self.id) {
return e.spawn_local(Box::new(future));
return e.spawn_local(Box::pin(future));
}
}
@@ -683,10 +686,9 @@ impl Handle {
}
self.sender
.send(Box::new(future))
.send(Box::pin(future))
.expect("CurrentThread does not exist anymore");
// use 0 for the id, CurrentThread does not make use of it
self.notify.notify(0);
self.waker.wake_by_ref();
Ok(())
}
@@ -731,7 +733,7 @@ impl TaskExecutor {
/// Spawn a future onto the current `CurrentThread` instance.
pub fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
future: Pin<Box<dyn Future<Output = ()>>>,
) -> Result<(), SpawnError> {
CURRENT.with(|current| match current.spawn.get() {
Some(spawn) => {
@@ -746,7 +748,7 @@ impl TaskExecutor {
impl tokio_executor::Executor for TaskExecutor {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
future: Pin<Box<dyn Future<Output = ()> + Send>>,
) -> Result<(), SpawnError> {
self.spawn_local(future)
}
@@ -754,25 +756,10 @@ impl tokio_executor::Executor for TaskExecutor {
impl<F> tokio_executor::TypedExecutor<F> for TaskExecutor
where
F: Future<Item = (), Error = ()> + 'static,
F: Future<Output = ()> + 'static,
{
fn spawn(&mut self, future: F) -> Result<(), SpawnError> {
self.spawn_local(Box::new(future))
}
}
impl<F> Executor<F> for TaskExecutor
where
F: Future<Item = (), Error = ()> + 'static,
{
fn execute(&self, future: F) -> Result<(), ExecuteError<F>> {
CURRENT.with(|current| match current.spawn.get() {
Some(spawn) => {
unsafe { (*spawn).spawn_local(Box::new(future), false) };
Ok(())
}
None => Err(ExecuteError::new(ExecuteErrorKind::Shutdown, future)),
})
self.spawn_local(Box::pin(future))
}
}
@@ -791,11 +778,7 @@ impl<'a, U: Unpark> Borrow<'a, U> {
}
impl<'a, U: Unpark> SpawnLocal for Borrow<'a, U> {
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
) {
fn spawn_local(&mut self, future: Pin<Box<dyn Future<Output = ()>>>, already_counted: bool) {
if !already_counted {
// NOTE: we have a borrow of the Runtime, so we know that it isn't shut down.
// NOTE: += 2 since LSB is the shutdown bit
+104 -70
View File
@@ -1,14 +1,14 @@
use crate::Borrow;
use futures::executor::{self, NotifyHandle, Spawn, UnsafeNotify};
use futures::{Async, Future};
use std::cell::UnsafeCell;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::ptr;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
use std::sync::{Arc, Weak};
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use std::thread;
use std::usize;
use tokio_executor::park::Unpark;
@@ -22,8 +22,6 @@ pub struct Scheduler<U> {
nodes: List<U>,
}
pub struct Notify<'a, U>(&'a Arc<Node<U>>);
// A linked-list of nodes
struct List<U> {
len: usize,
@@ -78,12 +76,6 @@ struct Inner<U> {
unsafe impl<U: Sync + Send> Send for Inner<U> {}
unsafe impl<U: Sync + Send> Sync for Inner<U> {}
impl<U: Unpark> executor::Notify for Inner<U> {
fn notify(&self, _: usize) {
self.unpark.unpark();
}
}
struct Node<U> {
// The item
item: UnsafeCell<Option<Task>>,
@@ -123,12 +115,12 @@ enum Dequeue<U> {
}
/// Wraps a spawned boxed future
struct Task(Spawn<Box<dyn Future<Item = (), Error = ()>>>);
struct Task(Pin<Box<dyn Future<Output = ()>>>);
/// A task that is scheduled. `turn` must be called
pub struct Scheduled<'a, U> {
task: &'a mut Task,
notify: &'a Notify<'a, U>,
node: &'a Arc<Node<U>>,
done: &'a mut bool,
}
@@ -165,11 +157,11 @@ where
}
}
pub fn notify(&self) -> NotifyHandle {
self.inner.clone().into()
pub fn waker(&self) -> Waker {
waker_inner(self.inner.clone())
}
pub fn schedule(&mut self, item: Box<dyn Future<Item = (), Error = ()>>) {
pub fn schedule(&mut self, item: Pin<Box<dyn Future<Output = ()>>>) {
// Get the current scheduler tick
let tick_num = self.inner.tick_num.load(SeqCst);
@@ -317,11 +309,10 @@ where
// deallocating the node if need be.
let borrow = &mut *bomb.borrow;
let enter = &mut *bomb.enter;
let notify = Notify(bomb.node.as_ref().unwrap());
let mut scheduled = Scheduled {
task: item,
notify: &notify,
node: bomb.node.as_ref().unwrap(),
done: &mut done,
};
@@ -345,10 +336,15 @@ where
impl<'a, U: Unpark> Scheduled<'a, U> {
/// Polls the task, returns `true` if the task has completed.
pub fn tick(&mut self) -> bool {
// Tick the future
let ret = match self.task.0.poll_future_notify(self.notify, 0) {
Ok(Async::Ready(_)) | Err(_) => true,
Ok(Async::NotReady) => false,
let waker = unsafe {
// Safety: we don't hold this waker ref longer than
// this `tick` function
waker_ref(self.node)
};
let mut cx = Context::from_waker(&waker);
let ret = match self.task.0.as_mut().poll(&mut cx) {
Poll::Ready(()) => true,
Poll::Pending => false,
};
*self.done = ret;
@@ -357,8 +353,8 @@ impl<'a, U: Unpark> Scheduled<'a, U> {
}
impl Task {
pub fn new(future: Box<dyn Future<Item = (), Error = ()> + 'static>) -> Self {
Task(executor::spawn(future))
pub fn new(future: Pin<Box<dyn Future<Output = ()> + 'static>>) -> Self {
Task(future)
}
}
@@ -630,63 +626,101 @@ impl<U> List<U> {
}
}
impl<'a, U> Clone for Notify<'a, U> {
fn clone(&self) -> Self {
Notify(self.0)
}
unsafe fn noop(_: *const ()) {}
// ===== Raw Waker Inner<U> ======
fn waker_inner<U: Unpark>(inner: Arc<Inner<U>>) -> Waker {
let ptr = Arc::into_raw(inner) as *const ();
let vtable = &RawWakerVTable::new(
clone_inner::<U>,
wake_inner::<U>,
wake_by_ref_inner::<U>,
drop_inner::<U>,
);
unsafe { Waker::from_raw(RawWaker::new(ptr, vtable)) }
}
impl<'a, U> fmt::Debug for Notify<'a, U> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Notify").finish()
}
unsafe fn clone_inner<U: Unpark>(data: *const ()) -> RawWaker {
let arc: Arc<Inner<U>> = Arc::from_raw(data as *const Inner<U>);
let clone = arc.clone();
// forget both Arcs so the refcounts don't get decremented
mem::forget(arc);
mem::forget(clone);
let vtable = &RawWakerVTable::new(
clone_inner::<U>,
wake_inner::<U>,
wake_by_ref_inner::<U>,
drop_inner::<U>,
);
RawWaker::new(data, vtable)
}
impl<'a, U: Unpark> From<Notify<'a, U>> for NotifyHandle {
fn from(handle: Notify<'a, U>) -> NotifyHandle {
unsafe {
let ptr = handle.0.clone();
let ptr = mem::transmute::<Arc<Node<U>>, *mut ArcNode<U>>(ptr);
NotifyHandle::new(hide_lt(ptr))
}
}
unsafe fn wake_inner<U: Unpark>(data: *const ()) {
let arc: Arc<Inner<U>> = Arc::from_raw(data as *const Inner<U>);
arc.unpark.unpark();
}
struct ArcNode<U>(PhantomData<U>);
// We should never touch `Task` on any thread other than the one owning
// `Scheduler`, so this should be a safe operation.
unsafe impl<U: Sync + Send> Send for ArcNode<U> {}
unsafe impl<U: Sync + Send> Sync for ArcNode<U> {}
impl<U: Unpark> executor::Notify for ArcNode<U> {
fn notify(&self, _id: usize) {
unsafe {
let me: *const ArcNode<U> = self;
let me: *const *const ArcNode<U> = &me;
let me = me as *const Arc<Node<U>>;
Node::notify(&*me)
}
}
unsafe fn wake_by_ref_inner<U: Unpark>(data: *const ()) {
let arc: Arc<Inner<U>> = Arc::from_raw(data as *const Inner<U>);
arc.unpark.unpark();
// by_ref means we don't own the Node, so forget the Arc
mem::forget(arc);
}
unsafe impl<U: Unpark> UnsafeNotify for ArcNode<U> {
unsafe fn clone_raw(&self) -> NotifyHandle {
let me: *const ArcNode<U> = self;
let me: *const *const ArcNode<U> = &me;
let me = &*(me as *const Arc<Node<U>>);
Notify(me).into()
}
unsafe fn drop_inner<U>(data: *const ()) {
drop(Arc::<Inner<U>>::from_raw(data as *const Inner<U>));
}
// ===== Raw Waker Node<U> ======
unsafe fn drop_raw(&self) {
let mut me: *const ArcNode<U> = self;
let me = &mut me as *mut *const ArcNode<U> as *mut Arc<Node<U>>;
ptr::drop_in_place(me);
}
unsafe fn waker_ref<U: Unpark>(node: &Arc<Node<U>>) -> Waker {
let ptr = &*node as &Node<U> as *const Node<U> as *const ();
let vtable = &RawWakerVTable::new(
clone_node::<U>,
wake_unreachable,
wake_by_ref_node::<U>,
noop,
);
Waker::from_raw(RawWaker::new(ptr, vtable))
}
unsafe fn hide_lt<U: Unpark>(p: *mut ArcNode<U>) -> *mut dyn UnsafeNotify {
mem::transmute(p as *mut dyn UnsafeNotify)
unsafe fn wake_unreachable(_data: *const ()) {
unreachable!("waker_ref::wake()");
}
unsafe fn clone_node<U: Unpark>(data: *const ()) -> RawWaker {
let arc: Arc<Node<U>> = Arc::from_raw(data as *const Node<U>);
let clone = arc.clone();
// forget both Arcs so the refcounts don't get decremented
mem::forget(arc);
mem::forget(clone);
let vtable = &RawWakerVTable::new(
clone_node::<U>,
wake_node::<U>,
wake_by_ref_node::<U>,
drop_node::<U>,
);
RawWaker::new(data, vtable)
}
unsafe fn wake_node<U: Unpark>(data: *const ()) {
let arc: Arc<Node<U>> = Arc::from_raw(data as *const Node<U>);
Node::<U>::notify(&arc);
}
unsafe fn wake_by_ref_node<U: Unpark>(data: *const ()) {
let arc: Arc<Node<U>> = Arc::from_raw(data as *const Node<U>);
Node::<U>::notify(&arc);
// by_ref means we don't own the Node, so forget the Arc
mem::forget(arc);
}
unsafe fn drop_node<U>(data: *const ()) {
drop(Arc::<Node<U>>::from_raw(data as *const Node<U>));
}
impl<U: Unpark> Node<U> {
+154 -215
View File
@@ -1,39 +1,34 @@
#![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]
use futures::future::{self, lazy};
// This is not actually unused --- we need this trait to be in scope for
// the tests that sue TaskExecutor::current().execute(). The compiler
// doesn't realise that.
#[allow(unused_imports)]
use futures::future::Executor;
use futures::prelude::*;
use futures::sync::oneshot;
use futures::task;
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use tokio_current_thread::{block_on_all, CurrentThread};
use tokio_executor::TypedExecutor;
use tokio_sync::oneshot;
mod from_block_on_all {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static>(spawn: F) {
fn test<F: Fn(Pin<Box<dyn Future<Output = ()>>>) + 'static>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
let msg = tokio_current_thread::block_on_all(lazy(move || {
let msg = tokio_current_thread::block_on_all(async move {
c.set(1 + c.get());
// Spawn!
spawn(Box::new(lazy(move || {
spawn(Box::pin(async move {
c.set(1 + c.get());
Ok::<(), ()>(())
})));
}));
Ok::<_, ()>("hello")
}))
.unwrap();
"hello"
});
assert_eq!(2, cnt.get());
assert_eq!(msg, "hello");
@@ -48,7 +43,7 @@ mod from_block_on_all {
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
});
}
@@ -66,11 +61,10 @@ fn block_waits() {
let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone();
block_on_all(rx.then(move |_| {
block_on_all(async move {
rx.await.unwrap();
cnt.set(1 + cnt.get());
Ok::<_, ()>(())
}))
.unwrap();
});
assert_eq!(1, cnt2.get());
}
@@ -84,10 +78,9 @@ fn spawn_many() {
for _ in 0..ITER {
let cnt = cnt.clone();
tokio_current_thread.spawn(lazy(move || {
tokio_current_thread.spawn(async move {
cnt.set(1 + cnt.get());
Ok::<(), ()>(())
}));
});
}
tokio_current_thread.run().unwrap();
@@ -98,48 +91,36 @@ fn spawn_many() {
mod does_not_set_global_executor_by_default {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E> + 'static, E>(
fn test<F: Fn(Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<(), E> + 'static, E>(
spawn: F,
) {
block_on_all(lazy(|| {
spawn(Box::new(lazy(|| ok()))).unwrap_err();
ok()
}))
.unwrap()
block_on_all(async {
spawn(Box::pin(async {})).unwrap_err();
});
}
#[test]
fn spawn() {
use tokio_executor::Executor;
test(|f| tokio_executor::DefaultExecutor::current().spawn(f))
}
#[test]
fn execute() {
test(|f| tokio_executor::DefaultExecutor::current().execute(f))
}
}
mod from_block_on_future {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>)>(spawn: F) {
fn test<F: Fn(Pin<Box<dyn Future<Output = ()>>>)>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone();
let mut tokio_current_thread = CurrentThread::new();
tokio_current_thread
.block_on(lazy(|| {
let cnt = cnt.clone();
tokio_current_thread.block_on(async move {
let cnt3 = cnt2.clone();
spawn(Box::new(lazy(move || {
cnt.set(1 + cnt.get());
Ok(())
})));
Ok::<_, ()>(())
}))
.unwrap();
spawn(Box::pin(async move {
cnt3.set(1 + cnt3.get());
}));
});
tokio_current_thread.run().unwrap();
@@ -155,35 +136,30 @@ mod from_block_on_future {
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
});
}
}
struct Never(Rc<()>);
impl Future for Never {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
Ok(Async::NotReady)
}
}
mod outstanding_tasks_are_dropped_when_executor_is_dropped {
use super::*;
async fn never(_rc: Rc<()>) {
loop {
yield_once().await;
}
}
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
F: Fn(Pin<Box<dyn Future<Output = ()>>>) + 'static,
G: Fn(&mut CurrentThread, Pin<Box<dyn Future<Output = ()>>>),
{
let mut rc = Rc::new(());
let mut tokio_current_thread = CurrentThread::new();
dotspawn(&mut tokio_current_thread, Box::new(Never(rc.clone())));
dotspawn(&mut tokio_current_thread, Box::pin(never(rc.clone())));
drop(tokio_current_thread);
@@ -193,15 +169,13 @@ mod outstanding_tasks_are_dropped_when_executor_is_dropped {
// Using the global spawn fn
let mut rc = Rc::new(());
let rc2 = rc.clone();
let mut tokio_current_thread = CurrentThread::new();
tokio_current_thread
.block_on(lazy(|| {
spawn(Box::new(Never(rc.clone())));
Ok::<_, ()>(())
}))
.unwrap();
tokio_current_thread.block_on(async move {
spawn(Box::pin(never(rc2)));
});
drop(tokio_current_thread);
@@ -221,7 +195,7 @@ mod outstanding_tasks_are_dropped_when_executor_is_dropped {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
@@ -238,12 +212,9 @@ mod outstanding_tasks_are_dropped_when_executor_is_dropped {
#[test]
#[should_panic]
fn nesting_run() {
block_on_all(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}))
.unwrap();
block_on_all(async {
block_on_all(async {});
});
}
mod run_in_future {
@@ -252,29 +223,23 @@ mod run_in_future {
#[test]
#[should_panic]
fn spawn() {
block_on_all(lazy(|| {
tokio_current_thread::spawn(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}));
ok()
}))
.unwrap();
block_on_all(async {
tokio_current_thread::spawn(async {
block_on_all(async {});
});
});
}
#[test]
#[should_panic]
fn execute() {
block_on_all(lazy(|| {
block_on_all(async {
tokio_current_thread::TaskExecutor::current()
.execute(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}))
.spawn(async {
block_on_all(async {});
})
.unwrap();
ok()
}))
.unwrap();
});
}
}
@@ -282,23 +247,15 @@ mod run_in_future {
fn tick_on_infini_future() {
let num = Rc::new(Cell::new(0));
struct Infini {
num: Rc<Cell<usize>>,
}
impl Future for Infini {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
self.num.set(1 + self.num.get());
task::current().notify();
Ok(Async::NotReady)
async fn infini(num: Rc<Cell<usize>>) {
loop {
num.set(1 + num.get());
yield_once().await
}
}
CurrentThread::new()
.spawn(Infini { num: num.clone() })
.spawn(infini(num.clone()))
.turn(None)
.unwrap();
@@ -307,56 +264,41 @@ fn tick_on_infini_future() {
mod tasks_are_scheduled_fairly {
use super::*;
struct Spin {
state: Rc<RefCell<[i32; 2]>>,
idx: usize,
}
impl Future for Spin {
type Item = ();
type Error = ();
async fn spin(state: Rc<RefCell<[i32; 2]>>, idx: usize) {
loop {
// borrow_mut scope
{
let mut state = state.borrow_mut();
fn poll(&mut self) -> Poll<(), ()> {
let mut state = self.state.borrow_mut();
if idx == 0 {
let diff = state[0] - state[1];
if self.idx == 0 {
let diff = state[0] - state[1];
assert!(diff.abs() <= 1);
assert!(diff.abs() <= 1);
if state[0] >= 50 {
return;
}
}
if state[0] >= 50 {
return Ok(().into());
state[idx] += 1;
if state[idx] >= 100 {
return;
}
}
state[self.idx] += 1;
if state[self.idx] >= 100 {
return Ok(().into());
}
task::current().notify();
Ok(Async::NotReady)
yield_once().await;
}
}
fn test<F: Fn(Spin)>(spawn: F) {
fn test<F: Fn(Pin<Box<dyn Future<Output = ()>>>)>(spawn: F) {
let state = Rc::new(RefCell::new([0, 0]));
block_on_all(lazy(|| {
spawn(Spin {
state: state.clone(),
idx: 0,
});
spawn(Spin {
state: state,
idx: 1,
});
ok()
}))
.unwrap();
block_on_all(async move {
spawn(Box::pin(spin(state.clone(), 0)));
spawn(Box::pin(spin(state, 1)));
});
}
#[test]
@@ -368,7 +310,7 @@ mod tasks_are_scheduled_fairly {
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
})
}
@@ -379,8 +321,8 @@ mod and_turn {
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
F: Fn(Pin<Box<dyn Future<Output = ()>>>) + 'static,
G: Fn(&mut CurrentThread, Pin<Box<dyn Future<Output = ()>>>),
{
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
@@ -388,24 +330,21 @@ mod and_turn {
let mut tokio_current_thread = CurrentThread::new();
// Spawn a basic task to get the executor to turn
dotspawn(&mut tokio_current_thread, Box::new(lazy(move || Ok(()))));
dotspawn(&mut tokio_current_thread, Box::pin(async {}));
// Turn once...
tokio_current_thread.turn(None).unwrap();
dotspawn(
&mut tokio_current_thread,
Box::new(lazy(move || {
Box::pin(async move {
c.set(1 + c.get());
// Spawn!
spawn(Box::new(lazy(move || {
spawn(Box::pin(async move {
c.set(1 + c.get());
Ok::<(), ()>(())
})));
Ok(())
})),
}));
}),
);
// This does not run the newly spawned thread
@@ -429,7 +368,7 @@ mod and_turn {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
@@ -454,23 +393,12 @@ mod in_drop {
}
}
struct MyFuture {
_data: Box<dyn Any>,
}
impl Future for MyFuture {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
Ok(().into())
}
}
async fn noop(_data: Box<dyn Any>) {}
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
F: Fn(Pin<Box<dyn Future<Output = ()>>>) + 'static,
G: Fn(&mut CurrentThread, Pin<Box<dyn Future<Output = ()>>>),
{
let mut tokio_current_thread = CurrentThread::new();
@@ -478,14 +406,11 @@ mod in_drop {
dotspawn(
&mut tokio_current_thread,
Box::new(MyFuture {
_data: Box::new(OnDrop(Some(move || {
spawn(Box::new(lazy(move || {
tx.send(()).unwrap();
Ok(())
})));
}))),
}),
Box::pin(noop(Box::new(OnDrop(Some(move || {
spawn(Box::pin(async move {
tx.send(()).unwrap();
}));
}))))),
);
tokio_current_thread.block_on(rx).unwrap();
@@ -504,7 +429,7 @@ mod in_drop {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.spawn(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
@@ -519,6 +444,7 @@ mod in_drop {
}
/*
#[test]
fn hammer_turn() {
use futures::sync::mpsc;
@@ -572,6 +498,7 @@ fn hammer_turn() {
}
}
}
*/
#[test]
fn turn_has_polled() {
@@ -579,7 +506,9 @@ fn turn_has_polled() {
// Spawn oneshot receiver
let (sender, receiver) = oneshot::channel::<()>();
tokio_current_thread.spawn(receiver.then(|_| Ok(())));
tokio_current_thread.spawn(async move {
let _ = receiver.await;
});
// Turn once...
let res = tokio_current_thread
@@ -674,30 +603,30 @@ fn turn_fair() {
// Once an item is received on the oneshot channel, it will immediately
// immediately make the second oneshot channel ready
tokio_current_thread.spawn(receiver.map_err(|_| unreachable!()).and_then(move |_| {
tokio_current_thread.spawn(async move {
receiver.await.unwrap();
sender_2.send(()).unwrap();
receiver_1_done_clone.set(true);
Ok(())
}));
});
let receiver_2_done = Rc::new(Cell::new(false));
let receiver_2_done_clone = receiver_2_done.clone();
tokio_current_thread.spawn(receiver_2.map_err(|_| unreachable!()).and_then(move |_| {
tokio_current_thread.spawn(async move {
receiver_2.await.unwrap();
receiver_2_done_clone.set(true);
Ok(())
}));
});
// The third receiver is only woken up from our Park implementation, it simulates
// e.g. a socket that first has to be polled to know if it is ready now
let receiver_3_done = Rc::new(Cell::new(false));
let receiver_3_done_clone = receiver_3_done.clone();
tokio_current_thread.spawn(receiver_3.map_err(|_| unreachable!()).and_then(move |_| {
tokio_current_thread.spawn(async move {
receiver_3.await.unwrap();
receiver_3_done_clone.set(true);
Ok(())
}));
});
// First turn should've polled both and considered them not ready
let res = tokio_current_thread
@@ -760,10 +689,9 @@ fn spawn_from_other_thread() {
thread::spawn(move || {
handle
.spawn(lazy(move || {
.spawn(async move {
sender.send(()).unwrap();
Ok(())
}))
})
.unwrap();
});
@@ -784,10 +712,9 @@ fn spawn_from_other_thread_unpark() {
let _ = receiver_2.recv().unwrap();
handle
.spawn(lazy(move || {
.spawn(async move {
sender_1.send(()).unwrap();
Ok(())
}))
})
.unwrap();
});
@@ -796,15 +723,14 @@ fn spawn_from_other_thread_unpark() {
// lazy future below which will cause the future to be spawned from
// the other thread. Then the executor will park but should be woken
// up because *now* we have a new future to schedule
let _ = current_thread
.block_on(
lazy(move || {
sender_2.send(()).unwrap();
Ok(())
})
.and_then(|_| receiver_1),
)
.unwrap();
let _ = current_thread.block_on(async move {
// inlined 'lazy'
async move {
sender_2.send(()).unwrap();
}
.await;
receiver_1.await.unwrap();
});
}
#[test]
@@ -813,21 +739,34 @@ fn spawn_from_executor_with_handle() {
let handle = current_thread.handle();
let (tx, rx) = oneshot::channel();
current_thread.spawn(lazy(move || {
current_thread.spawn(async move {
handle
.spawn(lazy(move || {
.spawn(async move {
tx.send(()).unwrap();
Ok(())
}))
})
.unwrap();
Ok::<_, ()>(())
}));
});
current_thread.run().unwrap();
rx.wait().unwrap();
current_thread.block_on(rx).unwrap();
}
fn ok() -> future::FutureResult<(), ()> {
future::ok(())
async fn yield_once() {
YieldOnce(false).await
}
struct YieldOnce(bool);
impl Future for YieldOnce {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
self.0 = true;
// Push to the back of the executor's queue
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
+3 -3
View File
@@ -23,8 +23,8 @@ categories = ["concurrency", "asynchronous"]
publish = false
[dependencies]
crossbeam-utils = "0.6.2"
futures = "0.1.19"
# crossbeam-utils = "0.6.2"
crossbeam-utils = { git = "https://github.com/stjepang/crossbeam", branch = "raw-parker" }
[dev-dependencies]
tokio = { version = "0.2.0", path = "../tokio" }
# tokio = { version = "0.2.0", path = "../tokio" }
+20 -4
View File
@@ -1,9 +1,8 @@
use futures::{self, Future};
use std::cell::{Cell, RefCell};
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::prelude::v1::*;
thread_local!(static ENTERED: Cell<bool> = Cell::new(false));
@@ -65,8 +64,25 @@ pub fn enter() -> Result<Enter, EnterError> {
impl Enter {
/// Blocks the thread on the specified future, returning the value with
/// which that future completes.
pub fn block_on<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> {
futures::executor::spawn(f).wait_future()
pub fn block_on<F: Future>(&mut self, mut f: F) -> F::Output {
use crate::park::{Park, ParkThread};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll::Ready;
let park = ParkThread::new();
let waker = park.unpark().into_waker();
let mut cx = Context::from_waker(&waker);
// `block_on` takes ownership of `f`. Once it is pinned here, the original `f` binding can
// no longer be accessed, making the pinning safe.
let mut f = unsafe { Pin::new_unchecked(&mut f) };
loop {
if let Ready(v) = f.as_mut().poll(&mut cx) {
return v;
}
}
}
}
+7 -8
View File
@@ -1,5 +1,6 @@
use crate::SpawnError;
use futures::Future;
use std::future::Future;
use std::pin::Pin;
/// A value that executes futures.
///
@@ -82,16 +83,14 @@ pub trait Executor {
/// use futures::future::lazy;
///
/// # fn docs(my_executor: &mut dyn Executor) {
/// my_executor.spawn(Box::new(lazy(|| {
/// my_executor.spawn(Box::pin(lazy(|| {
/// println!("running on the executor");
/// Ok(())
/// }))).unwrap();
/// # }
/// ```
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError>;
fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>)
-> Result<(), SpawnError>;
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
///
@@ -116,7 +115,7 @@ pub trait Executor {
///
/// # fn docs(my_executor: &mut dyn Executor) {
/// if my_executor.status().is_ok() {
/// my_executor.spawn(Box::new(lazy(|| {
/// my_executor.spawn(Box::pin(lazy(|| {
/// println!("running on the executor");
/// Ok(())
/// }))).unwrap();
@@ -133,7 +132,7 @@ pub trait Executor {
impl<E: Executor + ?Sized> Executor for Box<E> {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
future: Pin<Box<dyn Future<Output = ()> + Send>>,
) -> Result<(), SpawnError> {
(**self).spawn(future)
}
+7 -26
View File
@@ -1,6 +1,7 @@
use super::{Enter, Executor, SpawnError};
use futures::{future, Future};
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
/// Executes futures on the default executor for the current execution context.
///
@@ -70,7 +71,7 @@ thread_local! {
impl super::Executor for DefaultExecutor {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
future: Pin<Box<dyn Future<Output = ()> + Send>>,
) -> Result<(), SpawnError> {
DefaultExecutor::with_current(|executor| executor.spawn(future))
.unwrap_or_else(|| Err(SpawnError::shutdown()))
@@ -84,10 +85,10 @@ impl super::Executor for DefaultExecutor {
impl<T> super::TypedExecutor<T> for DefaultExecutor
where
T: Future<Item = (), Error = ()> + Send + 'static,
T: Future<Output = ()> + Send + 'static,
{
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
super::Executor::spawn(self, Box::new(future))
super::Executor::spawn(self, Box::pin(future))
}
fn status(&self) -> Result<(), SpawnError> {
@@ -95,26 +96,6 @@ where
}
}
impl<T> future::Executor<T> for DefaultExecutor
where
T: Future<Item = (), Error = ()> + Send + 'static,
{
fn execute(&self, future: T) -> Result<(), future::ExecuteError<T>> {
if let Err(e) = super::Executor::status(self) {
let kind = if e.is_at_capacity() {
future::ExecuteErrorKind::NoCapacity
} else {
future::ExecuteErrorKind::Shutdown
};
return Err(future::ExecuteError::new(kind, future));
}
let _ = DefaultExecutor::with_current(|executor| executor.spawn(Box::new(future)));
Ok(())
}
}
// ===== global spawn fns =====
/// Submits a future for execution on the default executor -- usually a
@@ -153,9 +134,9 @@ where
/// ```
pub fn spawn<T>(future: T)
where
T: Future<Item = (), Error = ()> + Send + 'static,
T: Future<Output = ()> + Send + 'static,
{
DefaultExecutor::current().spawn(Box::new(future)).unwrap()
DefaultExecutor::current().spawn(Box::pin(future)).unwrap()
}
/// Set the default executor for the duration of the closure
+43
View File
@@ -46,8 +46,10 @@
use crossbeam_utils::sync::{Parker, Unparker};
use std::marker::PhantomData;
use std::mem;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{RawWaker, RawWakerVTable, Waker};
use std::time::Duration;
/// Block the current thread.
@@ -223,3 +225,44 @@ impl Unpark for UnparkThread {
self.inner.unpark();
}
}
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
impl UnparkThread {
pub(crate) fn into_waker(self) -> Waker {
unsafe {
let raw = unparker_to_raw_waker(self.inner);
Waker::from_raw(raw)
}
}
}
unsafe fn unparker_to_raw_waker(unparker: Unparker) -> RawWaker {
RawWaker::new(Unparker::into_raw(unparker), &VTABLE)
}
unsafe fn clone(raw: *const ()) -> RawWaker {
let unparker = Unparker::from_raw(raw);
// Increment the ref count
mem::forget(unparker.clone());
unparker_to_raw_waker(unparker)
}
unsafe fn wake(raw: *const ()) {
let unparker = Unparker::from_raw(raw);
unparker.unpark();
}
unsafe fn wake_by_ref(raw: *const ()) {
let unparker = Unparker::from_raw(raw);
unparker.unpark();
// We don't actually own a reference to the unparker
mem::forget(unparker);
}
unsafe fn drop(raw: *const ()) {
let _ = Unparker::from_raw(raw);
}
+18
View File
@@ -0,0 +1,18 @@
#![deny(warnings, rust_2018_idioms)]
#![feature(await_macro, async_await)]
#[test]
fn block_on_ready() {
let mut enter = tokio_executor::enter().unwrap();
let val = enter.block_on(async { 123 });
assert_eq!(val, 123);
}
#[test]
fn block_on_pending() {
let mut enter = tokio_executor::enter().unwrap();
let val = enter.block_on(async { 123 });
assert_eq!(val, 123);
}
+6 -9
View File
@@ -1,17 +1,20 @@
#![deny(warnings, rust_2018_idioms)]
#![feature(await_macro, async_await)]
use futures::{self, future::lazy, Future};
use tokio_executor::{self, DefaultExecutor};
use std::future::Future;
use std::pin::Pin;
mod out_of_executor_context {
use super::*;
use tokio_executor::Executor;
fn test<F, E>(spawn: F)
where
F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E>,
F: Fn(Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<(), E>,
{
let res = spawn(Box::new(lazy(|| Ok(()))));
let res = spawn(Box::pin(async {}));
assert!(res.is_err());
}
@@ -19,10 +22,4 @@ mod out_of_executor_context {
fn spawn() {
test(|f| DefaultExecutor::current().spawn(f));
}
#[test]
fn execute() {
use futures::future::Executor as FuturesExecutor;
test(|f| DefaultExecutor::current().execute(f));
}
}
+6 -11
View File
@@ -11,21 +11,16 @@ repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-futures/0.1.0"
description = """
Experimental std::future::Future and async/await support for Tokio
Utilities for working with futures, async, and await.
"""
categories = ["asynchronous"]
publish = false
[features]
# This feature comes with no promise of stability. Things will
# break with each patch release. Use at your own risk.
async-await-preview = ["futures/nightly"]
all = []
default = [
"all",
]
[dependencies]
futures = "0.1.23"
tokio-io = { version = "0.2.0", path = "../tokio-io" }
[dev-dependencies]
bytes = "0.4.9"
hyper = "0.12.8"
tokio = { version = "0.2.0", path = "../tokio" }
futures-core-preview = "0.3.0-alpha.16"
+2 -39
View File
@@ -1,43 +1,6 @@
# Tokio async/await preview
# Tokio Futures
This crate provides a preview of Tokio with async / await support. It is a shim
layer on top of `tokio`.
**This crate requires Rust nightly and does not provide API stability
guarantees. You are living on the edge here.**
## Usage
To use this crate, you need to start with a Rust 2018 edition crate, with rustc
1.35.0-nightly or later.
Add this to your `Cargo.toml`:
```toml
# In the `[packages]` section
edition = "2018"
# In the `[dependencies]` section
tokio = {version = "0.2.0", features = ["async-await-preview"]}
```
Then, get started. In your application, add:
```rust
// The nightly features that are commonly needed with async / await
#![feature(async_await)]
fn main() {
// And we are async...
tokio::run_async(async {
println!("Hello");
});
}
```
Because nightly is required, run the app with `cargo +nightly run`
Check the [examples](/async-await) directory for more.
Asynchronous abstractions for the Tokio stack.
## License
-15
View File
@@ -1,15 +0,0 @@
/// Wait for a future to complete.
#[macro_export]
macro_rules! async_wait {
($e:expr) => {{
#[allow(unused_imports)]
use $crate::compat::backward::IntoAwaitable as IntoAwaitableBackward;
#[allow(unused_imports)]
use $crate::compat::forward::IntoAwaitable as IntoAwaitableForward;
#[allow(unused_mut)]
let mut e = $e;
let e = e.into_awaitable();
e.await
}};
}
-86
View File
@@ -1,86 +0,0 @@
//! Converts a `std::future::Future` into an 0.1 `Future.
use futures::{Future, Poll};
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::ptr;
use std::task::{Context, Poll as StdPoll, RawWaker, RawWakerVTable, Waker};
/// Converts a `std::future::Future` into an 0.1 `Future.
#[derive(Debug)]
pub struct Compat<T>(Pin<Box<T>>);
impl<T> Compat<T> {
/// Create a new `Compat` backed by `future`.
pub(crate) fn new(future: T) -> Compat<T> {
Compat(Box::pin(future))
}
}
#[doc(hidden)]
pub trait IntoAwaitable {
type Awaitable;
fn into_awaitable(self) -> Self::Awaitable;
}
impl<T> IntoAwaitable for T
where
T: StdFuture,
{
type Awaitable = Self;
fn into_awaitable(self) -> Self {
self
}
}
impl<T, Item, Error> Future for Compat<T>
where
T: StdFuture<Output = Result<Item, Error>>,
{
type Item = Item;
type Error = Error;
fn poll(&mut self) -> Poll<Item, Error> {
use futures::Async::*;
let waker = noop_waker();
let mut context = Context::from_waker(&waker);
let res = self.0.as_mut().poll(&mut context);
match res {
StdPoll::Ready(Ok(val)) => Ok(Ready(val)),
StdPoll::Ready(Err(err)) => Err(err),
StdPoll::Pending => Ok(NotReady),
}
}
}
// ===== NoopWaker =====
fn noop_raw_waker() -> RawWaker {
RawWaker::new(ptr::null(), &NOOP_WAKER_VTABLE)
}
fn noop_waker() -> Waker {
unsafe { Waker::from_raw(noop_raw_waker()) }
}
unsafe fn clone_raw(_data: *const ()) -> RawWaker {
noop_raw_waker()
}
unsafe fn drop_raw(_data: *const ()) {}
unsafe fn wake(_data: *const ()) {
unimplemented!(
"async-await-preview currently only supports futures 0.1. Use \
the compatibility layer of futures 0.3 instead, if you want \
to use futures 0.3."
);
}
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake, wake, drop_raw);
-69
View File
@@ -1,69 +0,0 @@
//! Converts an 0.1 `Future` into a `std::future::Future`.
//!
use futures::{Async, Future};
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::task::{Context, Poll as StdPoll};
/// Converts an 0.1 `Future` into a `std::future::Future`.
#[derive(Debug)]
pub struct Compat<T>(T);
pub(crate) fn convert_poll<T, E>(poll: Result<Async<T>, E>) -> StdPoll<Result<T, E>> {
use futures::Async::{NotReady, Ready};
match poll {
Ok(Ready(val)) => StdPoll::Ready(Ok(val)),
Ok(NotReady) => StdPoll::Pending,
Err(err) => StdPoll::Ready(Err(err)),
}
}
pub(crate) fn convert_poll_stream<T, E>(
poll: Result<Async<Option<T>>, E>,
) -> StdPoll<Option<Result<T, E>>> {
use futures::Async::{NotReady, Ready};
match poll {
Ok(Ready(Some(val))) => StdPoll::Ready(Some(Ok(val))),
Ok(Ready(None)) => StdPoll::Ready(None),
Ok(NotReady) => StdPoll::Pending,
Err(err) => StdPoll::Ready(Some(Err(err))),
}
}
#[doc(hidden)]
pub trait IntoAwaitable {
type Awaitable;
/// Convert `self` into a value that can be used with `await!`.
fn into_awaitable(self) -> Self::Awaitable;
}
impl<T: Future + Unpin> IntoAwaitable for T {
type Awaitable = Compat<T>;
fn into_awaitable(self) -> Self::Awaitable {
Compat(self)
}
}
impl<T> StdFuture for Compat<T>
where
T: Future + Unpin,
{
type Output = Result<T::Item, T::Error>;
fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> StdPoll<Self::Output> {
use futures::Async::{NotReady, Ready};
// TODO: wire in cx
match self.0.poll() {
Ok(Ready(val)) => StdPoll::Ready(Ok(val)),
Ok(NotReady) => StdPoll::Pending,
Err(e) => StdPoll::Ready(Err(e)),
}
}
}
-42
View File
@@ -1,42 +0,0 @@
//! Compatibility layer between futures 0.1 and `std`.
pub mod backward;
pub mod forward;
/// Convert a `std::future::Future` yielding `Result` into an 0.1 `Future`.
pub fn into_01<T, Item, Error>(future: T) -> backward::Compat<T>
where
T: std::future::Future<Output = Result<Item, Error>>,
{
backward::Compat::new(future)
}
/// Convert a `std::future::Future` into an 0.1 `Future` with unit error.
pub fn infallible_into_01<T>(future: T) -> impl futures::Future<Item = T::Output, Error = ()>
where
T: std::future::Future,
{
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct Map<T>(T);
impl<T> Map<T> {
fn future<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }
}
}
impl<T: std::future::Future> std::future::Future for Map<T> {
type Output = Result<T::Output, ()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.future().poll(cx) {
Poll::Ready(v) => Poll::Ready(Ok(v)),
Poll::Pending => Poll::Pending,
}
}
}
into_01(Map(future))
}
+3
View File
@@ -0,0 +1,3 @@
//! Futures
pub use core::future::Future;
-29
View File
@@ -1,29 +0,0 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio_io::AsyncWrite;
/// A future used to fully flush an I/O object.
#[derive(Debug)]
pub struct Flush<'a, T: ?Sized> {
writer: &'a mut T,
}
// Pin is never projected to fields
impl<'a, T: ?Sized> Unpin for Flush<'a, T> {}
impl<'a, T: AsyncWrite + ?Sized> Flush<'a, T> {
pub(super) fn new(writer: &'a mut T) -> Flush<'a, T> {
Flush { writer }
}
}
impl<'a, T: AsyncWrite + ?Sized> Future for Flush<'a, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
use crate::compat::forward::convert_poll;
convert_poll(self.writer.poll_flush())
}
}
-192
View File
@@ -1,192 +0,0 @@
//! Use I/O with `async` / `await`.
mod flush;
mod read;
mod read_exact;
mod write;
mod write_all;
pub use self::flush::Flush;
pub use self::read::Read;
pub use self::read_exact::ReadExact;
pub use self::write::Write;
pub use self::write_all::WriteAll;
use tokio_io::{AsyncRead, AsyncWrite};
/// An extension trait which adds utility methods to `AsyncRead` types.
pub trait AsyncReadExt: AsyncRead {
/// Tries to read some bytes directly into the given `buf` in an
/// asynchronous manner, returning a future.
///
/// The returned future will resolve to the number of bytes read once the read
/// operation is completed.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncReadExt;
/// use std::io::Cursor;
///
/// let mut reader = Cursor::new([1, 2, 3, 4]);
/// let mut output = [0u8; 5];
///
/// let bytes = reader.read_async(&mut output[..]).await.unwrap();
///
/// // This is only guaranteed to be 4 because `&[u8]` is a synchronous
/// // reader. In a real system you could get anywhere from 1 to
/// // `output.len()` bytes in a single read.
/// assert_eq!(bytes, 4);
/// assert_eq!(output, [1, 2, 3, 4, 0]);
/// });
/// ```
fn read_async<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
Read::new(self, buf)
}
/// Creates a future which will read exactly enough bytes to fill `buf`,
/// returning an error if end of file (EOF) is hit sooner.
///
/// The returned future will resolve once the read operation is completed.
///
/// In the case of an error the buffer and the object will be discarded, with
/// the error yielded.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncReadExt;
/// use std::io::Cursor;
///
/// let mut reader = Cursor::new([1, 2, 3, 4]);
/// let mut output = [0u8; 4];
///
/// reader.read_exact_async(&mut output).await.unwrap();
///
/// assert_eq!(output, [1, 2, 3, 4]);
/// });
/// ```
///
/// ## EOF is hit before `buf` is filled
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncReadExt;
/// use std::io::{self, Cursor};
///
/// let mut reader = Cursor::new([1, 2, 3, 4]);
/// let mut output = [0u8; 5];
///
/// let result = reader.read_exact_async(&mut output).await;
///
/// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
/// });
/// ```
fn read_exact_async<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> {
ReadExact::new(self, buf)
}
}
/// An extension trait which adds utility methods to `AsyncWrite` types.
pub trait AsyncWriteExt: AsyncWrite {
/// Write data into this object.
///
/// Creates a future that will write the entire contents of the buffer `buf` into
/// this `AsyncWrite`.
///
/// The returned future will not complete until all the data has been written.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncWriteExt;
/// use std::io::Cursor;
///
/// let mut buf = [0u8; 5];
/// let mut writer = Cursor::new(&mut buf[..]);
///
/// let n = writer.write_async(&[1, 2, 3, 4]).await.unwrap();
///
/// assert_eq!(writer.into_inner()[..n], [1, 2, 3, 4, 0][..n]);
/// });
/// ```
fn write_async<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> {
Write::new(self, buf)
}
/// Write an entire buffer into this object.
///
/// Creates a future that will write the entire contents of the buffer `buf` into
/// this `AsyncWrite`.
///
/// The returned future will not complete until all the data has been written.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncWriteExt;
/// use std::io::Cursor;
///
/// let mut buf = [0u8; 5];
/// let mut writer = Cursor::new(&mut buf[..]);
///
/// writer.write_all_async(&[1, 2, 3, 4]).await.unwrap();
///
/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
/// });
/// ```
fn write_all_async<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {
WriteAll::new(self, buf)
}
/// Creates a future which will entirely flush this `AsyncWrite`.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::AsyncWriteExt;
/// use std::io::{BufWriter, Cursor};
///
/// let mut output = [0u8; 5];
///
/// {
/// let mut writer = Cursor::new(&mut output[..]);
/// let mut buffered = BufWriter::new(writer);
/// buffered.write_all_async(&[1, 2]).await.unwrap();
/// buffered.write_all_async(&[3, 4]).await.unwrap();
/// buffered.flush_async().await.unwrap();
/// }
///
/// assert_eq!(output, [1, 2, 3, 4, 0]);
/// });
/// ```
fn flush_async<'a>(&mut self) -> Flush<'_, Self> {
Flush::new(self)
}
}
impl<T: AsyncRead + ?Sized> AsyncReadExt for T {}
impl<T: AsyncWrite + ?Sized> AsyncWriteExt for T {}
-32
View File
@@ -1,32 +0,0 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{self, Poll};
use tokio_io::AsyncRead;
/// A future which can be used to read bytes.
#[derive(Debug)]
pub struct Read<'a, T: ?Sized> {
reader: &'a mut T,
buf: &'a mut [u8],
}
// Pinning is never projected to fields
impl<'a, T: ?Sized> Unpin for Read<'a, T> {}
impl<'a, T: AsyncRead + ?Sized> Read<'a, T> {
pub(super) fn new(reader: &'a mut T, buf: &'a mut [u8]) -> Read<'a, T> {
Read { reader, buf }
}
}
impl<'a, T: AsyncRead + ?Sized> Future for Read<'a, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll<Self::Output> {
use crate::compat::forward::convert_poll;
let this = &mut *self;
convert_poll(this.reader.poll_read(this.buf))
}
}
-50
View File
@@ -1,50 +0,0 @@
use std::future::Future;
use std::io;
use std::mem;
use std::pin::Pin;
use std::task::{self, Poll};
use tokio_io::AsyncRead;
/// A future which can be used to read exactly enough bytes to fill a buffer.
#[derive(Debug)]
pub struct ReadExact<'a, T: ?Sized> {
reader: &'a mut T,
buf: &'a mut [u8],
}
// Pinning is never projected to fields
impl<'a, T: ?Sized> Unpin for ReadExact<'a, T> {}
impl<'a, T: AsyncRead + ?Sized> ReadExact<'a, T> {
pub(super) fn new(reader: &'a mut T, buf: &'a mut [u8]) -> ReadExact<'a, T> {
ReadExact { reader, buf }
}
}
fn eof() -> io::Error {
io::Error::new(io::ErrorKind::UnexpectedEof, "early eof")
}
impl<'a, T: AsyncRead + ?Sized> Future for ReadExact<'a, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll<Self::Output> {
use crate::compat::forward::convert_poll;
let this = &mut *self;
while !this.buf.is_empty() {
let n = try_ready!(convert_poll(this.reader.poll_read(this.buf)));
{
let (_, rest) = mem::replace(&mut this.buf, &mut []).split_at_mut(n);
this.buf = rest;
}
if n == 0 {
return Poll::Ready(Err(eof()));
}
}
Poll::Ready(Ok(()))
}
}
-32
View File
@@ -1,32 +0,0 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{self, Poll};
use tokio_io::AsyncWrite;
/// A future used to write data.
#[derive(Debug)]
pub struct Write<'a, T: ?Sized> {
writer: &'a mut T,
buf: &'a [u8],
}
// Pinning is never projected to fields
impl<'a, T: ?Sized> Unpin for Write<'a, T> {}
impl<'a, T: AsyncWrite + ?Sized> Write<'a, T> {
pub(super) fn new(writer: &'a mut T, buf: &'a [u8]) -> Write<'a, T> {
Write { writer, buf }
}
}
impl<'a, T: AsyncWrite + ?Sized> Future for Write<'a, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll<io::Result<usize>> {
use crate::compat::forward::convert_poll;
let this = &mut *self;
convert_poll(this.writer.poll_write(this.buf))
}
}
-51
View File
@@ -1,51 +0,0 @@
use std::future::Future;
use std::io;
use std::mem;
use std::pin::Pin;
use std::task::{self, Poll};
use tokio_io::AsyncWrite;
/// A future used to write the entire contents of a buffer.
#[derive(Debug)]
pub struct WriteAll<'a, T: ?Sized> {
writer: &'a mut T,
buf: &'a [u8],
}
// Pinning is never projected to fields
impl<'a, T: ?Sized> Unpin for WriteAll<'a, T> {}
impl<'a, T: AsyncWrite + ?Sized> WriteAll<'a, T> {
pub(super) fn new(writer: &'a mut T, buf: &'a [u8]) -> WriteAll<'a, T> {
WriteAll { writer, buf }
}
}
fn zero_write() -> io::Error {
io::Error::new(io::ErrorKind::WriteZero, "zero-length write")
}
impl<'a, T: AsyncWrite + ?Sized> Future for WriteAll<'a, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll<io::Result<()>> {
use crate::compat::forward::convert_poll;
let this = &mut *self;
while !this.buf.is_empty() {
let n = try_ready!(convert_poll(this.writer.poll_write(this.buf)));
{
let (_, rest) = mem::replace(&mut this.buf, &[]).split_at(n);
this.buf = rest;
}
if n == 0 {
return Poll::Ready(Err(zero_write()));
}
}
Poll::Ready(Ok(()))
}
}
+10 -22
View File
@@ -1,28 +1,16 @@
#![cfg(feature = "async-await-preview")]
#![feature(async_await, await_macro)]
#![doc(html_root_url = "https://docs.rs/tokio-futures/0.1.0")]
#![doc(html_root_url = "https://docs.rs/tokio-futures/0.2.0")]
#![cfg(feature = "all")]
#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![cfg_attr(test, deny(warnings))]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
//! A preview of Tokio w/ `async` / `await` support.
//! Futures
/// Extracts the successful type of a `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
macro_rules! try_ready {
($x:expr) => {
match $x {
std::task::Poll::Ready(Ok(x)) => x,
std::task::Poll::Ready(Err(e)) => return std::task::Poll::Ready(Err(e.into())),
std::task::Poll::Pending => return std::task::Poll::Pending,
}
};
}
#[macro_use]
mod async_wait;
pub mod compat;
pub mod io;
pub mod future;
pub mod sink;
pub mod stream;
mod macros;
pub use crate::future::Future;
pub use crate::sink::Sink;
pub use crate::stream::Stream;
+12
View File
@@ -0,0 +1,12 @@
/// Unwrap a ready value or propagate `Async::Pending`.
#[macro_export]
macro_rules! ready {
($e:expr) => {{
use std::task::Poll::{Pending, Ready};
match $e {
Ready(v) => v,
Pending => return Pending,
}
}};
}
+68
View File
@@ -0,0 +1,68 @@
//! Sinks
use core::marker::Unpin;
use core::ops::DerefMut;
use core::pin::Pin;
use core::task::{Context, Poll};
/// Asynchronously send values
pub trait Sink<T> {
/// TODO: Dox
type Error;
/// TODO: Dox
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
/// TODO: Dox
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error>;
/// TODO: Dox
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
/// TODO: Dox
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
}
impl<T, S: ?Sized + Sink<T> + Unpin> Sink<T> for &mut S {
type Error = S::Error;
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut **self).poll_ready(cx)
}
fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
Pin::new(&mut **self).start_send(item)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut **self).poll_flush(cx)
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut **self).poll_close(cx)
}
}
impl<T, S> Sink<T> for Pin<S>
where
S: DerefMut + Unpin,
S::Target: Sink<T>,
{
type Error = <S::Target as Sink<T>>::Error;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::get_mut(self).as_mut().poll_ready(cx)
}
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
Pin::get_mut(self).as_mut().start_send(item)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::get_mut(self).as_mut().poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::get_mut(self).as_mut().poll_close(cx)
}
}
-24
View File
@@ -1,24 +0,0 @@
//! Use sinks with `async` / `await`.
mod send;
pub use self::send::Send;
use futures::Sink;
/// An extension trait which adds utility methods to `Sink` types.
pub trait SinkExt: Sink {
/// Send an item into the sink.
///
/// Note that, **because of the flushing requirement, it is usually better
/// to batch together items to send via `send_all`, rather than flushing
/// between each item.**
fn send_async(&mut self, item: Self::SinkItem) -> Send<'_, Self>
where
Self: Sized + Unpin,
{
Send::new(self, item)
}
}
impl<T: Sink> SinkExt for T {}
-51
View File
@@ -1,51 +0,0 @@
use futures::Sink;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};
/// Future for the `SinkExt::send_async` combinator, which sends a value to a
/// sink and then waits until the sink has fully flushed.
#[derive(Debug)]
pub struct Send<'a, T: Sink + ?Sized> {
sink: &'a mut T,
item: Option<T::SinkItem>,
}
impl<T: Sink + Unpin + ?Sized> Unpin for Send<'_, T> {}
impl<'a, T: Sink + Unpin + ?Sized> Send<'a, T> {
pub(super) fn new(sink: &'a mut T, item: T::SinkItem) -> Self {
Send {
sink,
item: Some(item),
}
}
}
impl<T: Sink + Unpin + ?Sized> Future for Send<'_, T> {
type Output = Result<(), T::SinkError>;
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll<Self::Output> {
use crate::compat::forward::convert_poll;
use futures::AsyncSink::{NotReady, Ready};
if let Some(item) = self.item.take() {
match self.sink.start_send(item) {
Ok(Ready) => {}
Ok(NotReady(val)) => {
self.item = Some(val);
return Poll::Pending;
}
Err(err) => {
return Poll::Ready(Err(err));
}
}
}
// we're done sending the item, but want to block on flushing the
// sink
try_ready!(convert_poll(self.sink.poll_complete()));
Poll::Ready(Ok(()))
}
}
+3
View File
@@ -0,0 +1,3 @@
//! Streams
pub use futures_core::stream::Stream;
-38
View File
@@ -1,38 +0,0 @@
//! Use streams with `async` / `await`.
mod next;
pub use self::next::Next;
use futures::Stream;
/// An extension trait which adds utility methods to `Stream` types.
pub trait StreamExt: Stream {
/// Creates a future that resolves to the next item in the stream.
///
/// # Examples
///
/// ```edition2018
/// #![feature(async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
/// use tokio::prelude::{stream, StreamAsyncExt};
///
/// let mut stream = stream::iter_ok::<_, ()>(1..3);
///
/// assert_eq!(stream.next().await, Some(Ok(1)));
/// assert_eq!(stream.next().await, Some(Ok(2)));
/// assert_eq!(stream.next().await, Some(Ok(3)));
/// assert_eq!(stream.next().await, None);
/// });
/// ```
fn next(&mut self) -> Next<'_, Self>
where
Self: Sized + Unpin,
{
Next::new(self)
}
}
impl<T: Stream> StreamExt for T {}
-28
View File
@@ -1,28 +0,0 @@
use futures::Stream;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
/// A future of the next element of a stream.
#[derive(Debug)]
pub struct Next<'a, T> {
stream: &'a mut T,
}
impl<'a, T: Stream + Unpin> Unpin for Next<'a, T> {}
impl<'a, T: Stream + Unpin> Next<'a, T> {
pub(super) fn new(stream: &'a mut T) -> Next<'a, T> {
Next { stream }
}
}
impl<'a, T: Stream + Unpin> Future for Next<'a, T> {
type Output = Option<Result<T::Item, T::Error>>;
fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
use crate::compat::forward::convert_poll_stream;
convert_poll_stream(self.stream.poll())
}
}
+2 -2
View File
@@ -23,8 +23,8 @@ publish = false
[dependencies]
bytes = "0.4.7"
futures = "0.1.18"
log = "0.4"
[dev-dependencies]
tokio-current-thread = { version = "0.2.0", path = "../tokio-current-thread" }
pin-utils = "0.1.0-alpha.4"
tokio-test = { version = "0.2.0", path = "../tokio-test" }
-3
View File
@@ -1,3 +0,0 @@
// For now, we need to keep the implementation of Encoder in tokio_io.
pub use crate::codec::Decoder;
-3
View File
@@ -1,3 +0,0 @@
// For now, we need to keep the implementation of Encoder in tokio_io.
pub use crate::codec::Encoder;
-281
View File
@@ -1,281 +0,0 @@
#![allow(deprecated)]
use super::framed_read::{framed_read2, framed_read2_with_buffer, FramedRead2};
use super::framed_write::{framed_write2, framed_write2_with_buffer, FramedWrite2};
use crate::codec::{Decoder, Encoder};
use crate::{AsyncRead, AsyncWrite};
use bytes::BytesMut;
use futures::{Poll, Sink, StartSend, Stream};
use std::fmt;
use std::io::{self, Read, Write};
/// A unified `Stream` and `Sink` interface to an underlying I/O object, using
/// the `Encoder` and `Decoder` traits to encode and decode frames.
///
/// You can create a `Framed` instance by using the `AsyncRead::framed` adapter.
pub struct Framed<T, U> {
inner: FramedRead2<FramedWrite2<Fuse<T, U>>>,
}
pub struct Fuse<T, U>(pub T, pub U);
impl<T, U> Framed<T, U>
where
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder,
{
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
///
/// Raw I/O objects work with byte sequences, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of an I/O object, by using the `Codec`
/// traits to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things like gzip or TLS, which require both read and write access to the
/// underlying object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
pub fn new(inner: T, codec: U) -> Framed<T, U> {
Framed {
inner: framed_read2(framed_write2(Fuse(inner, codec))),
}
}
}
impl<T, U> Framed<T, U> {
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
///
/// Raw I/O objects work with byte sequences, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of an I/O object, by using the `Codec`
/// traits to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things like gzip or TLS, which require both read and write access to the
/// underlying object.
///
/// This objects takes a stream and a readbuffer and a writebuffer. These field
/// can be obtained from an existing `Framed` with the `into_parts` method.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
pub fn from_parts(parts: FramedParts<T, U>) -> Framed<T, U> {
Framed {
inner: framed_read2_with_buffer(
framed_write2_with_buffer(Fuse(parts.io, parts.codec), parts.write_buf),
parts.read_buf,
),
}
}
/// Returns a reference to the underlying I/O stream wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.get_ref().get_ref().0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.get_mut().get_mut().0
}
/// Returns a reference to the underlying codec wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying codec
/// as it may corrupt the stream of frames otherwise being worked with.
pub fn codec(&self) -> &U {
&self.inner.get_ref().get_ref().1
}
/// Returns a mutable reference to the underlying codec wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying codec
/// as it may corrupt the stream of frames otherwise being worked with.
pub fn codec_mut(&mut self) -> &mut U {
&mut self.inner.get_mut().get_mut().1
}
/// Consumes the `Frame`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.into_inner().into_inner().0
}
/// Consumes the `Frame`, returning its underlying I/O stream, the buffer
/// with unprocessed data, and the codec.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_parts(self) -> FramedParts<T, U> {
let (inner, read_buf) = self.inner.into_parts();
let (inner, write_buf) = inner.into_parts();
FramedParts {
io: inner.0,
codec: inner.1,
read_buf: read_buf,
write_buf: write_buf,
_priv: (),
}
}
}
impl<T, U> Stream for Framed<T, U>
where
T: AsyncRead,
U: Decoder,
{
type Item = U::Item;
type Error = U::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll()
}
}
impl<T, U> Sink for Framed<T, U>
where
T: AsyncWrite,
U: Encoder,
U::Error: From<io::Error>,
{
type SinkItem = U::Item;
type SinkError = U::Error;
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.get_mut().start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.get_mut().poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.inner.get_mut().close()
}
}
impl<T, U> fmt::Debug for Framed<T, U>
where
T: fmt::Debug,
U: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Framed")
.field("io", &self.inner.get_ref().get_ref().0)
.field("codec", &self.inner.get_ref().get_ref().1)
.finish()
}
}
// ===== impl Fuse =====
impl<T: Read, U> Read for Fuse<T, U> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.0.read(dst)
}
}
impl<T: AsyncRead, U> AsyncRead for Fuse<T, U> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.0.prepare_uninitialized_buffer(buf)
}
}
impl<T: Write, U> Write for Fuse<T, U> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
self.0.write(src)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
impl<T: AsyncWrite, U> AsyncWrite for Fuse<T, U> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.0.shutdown()
}
}
impl<T, U: Decoder> Decoder for Fuse<T, U> {
type Item = U::Item;
type Error = U::Error;
fn decode(&mut self, buffer: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.1.decode(buffer)
}
fn decode_eof(&mut self, buffer: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.1.decode_eof(buffer)
}
}
impl<T, U: Encoder> Encoder for Fuse<T, U> {
type Item = U::Item;
type Error = U::Error;
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
self.1.encode(item, dst)
}
}
/// `FramedParts` contains an export of the data of a Framed transport.
/// It can be used to construct a new `Framed` with a different codec.
/// It contains all current buffers and the inner transport.
#[derive(Debug)]
pub struct FramedParts<T, U> {
/// The inner transport used to read bytes to and write bytes to
pub io: T,
/// The codec
pub codec: U,
/// The buffer with read but unprocessed data.
pub read_buf: BytesMut,
/// A buffer with unprocessed data which are not written yet.
pub write_buf: BytesMut,
/// This private field allows us to add additional fields in the future in a
/// backwards compatible way.
_priv: (),
}
impl<T, U> FramedParts<T, U> {
/// Create a new, default, `FramedParts`
pub fn new(io: T, codec: U) -> FramedParts<T, U> {
FramedParts {
io,
codec,
read_buf: BytesMut::new(),
write_buf: BytesMut::new(),
_priv: (),
}
}
}
-215
View File
@@ -1,215 +0,0 @@
#![allow(deprecated)]
use super::framed::Fuse;
use crate::codec::Decoder;
use crate::AsyncRead;
use bytes::BytesMut;
use futures::{try_ready, Async, Poll, Sink, StartSend, Stream};
use log::trace;
use std::fmt;
/// A `Stream` of messages decoded from an `AsyncRead`.
pub struct FramedRead<T, D> {
inner: FramedRead2<Fuse<T, D>>,
}
pub struct FramedRead2<T> {
inner: T,
eof: bool,
is_readable: bool,
buffer: BytesMut,
}
const INITIAL_CAPACITY: usize = 8 * 1024;
// ===== impl FramedRead =====
impl<T, D> FramedRead<T, D>
where
T: AsyncRead,
D: Decoder,
{
/// Creates a new `FramedRead` with the given `decoder`.
pub fn new(inner: T, decoder: D) -> FramedRead<T, D> {
FramedRead {
inner: framed_read2(Fuse(inner, decoder)),
}
}
}
impl<T, D> FramedRead<T, D> {
/// Returns a reference to the underlying I/O stream wrapped by
/// `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.inner.0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.inner.0
}
/// Consumes the `FramedRead`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.inner.0
}
/// Returns a reference to the underlying decoder.
pub fn decoder(&self) -> &D {
&self.inner.inner.1
}
/// Returns a mutable reference to the underlying decoder.
pub fn decoder_mut(&mut self) -> &mut D {
&mut self.inner.inner.1
}
}
impl<T, D> Stream for FramedRead<T, D>
where
T: AsyncRead,
D: Decoder,
{
type Item = D::Item;
type Error = D::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll()
}
}
impl<T, D> Sink for FramedRead<T, D>
where
T: Sink,
{
type SinkItem = T::SinkItem;
type SinkError = T::SinkError;
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.inner.0.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.inner.0.poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.inner.inner.0.close()
}
}
impl<T, D> fmt::Debug for FramedRead<T, D>
where
T: fmt::Debug,
D: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FramedRead")
.field("inner", &self.inner.inner.0)
.field("decoder", &self.inner.inner.1)
.field("eof", &self.inner.eof)
.field("is_readable", &self.inner.is_readable)
.field("buffer", &self.inner.buffer)
.finish()
}
}
// ===== impl FramedRead2 =====
pub fn framed_read2<T>(inner: T) -> FramedRead2<T> {
FramedRead2 {
inner: inner,
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
}
}
pub fn framed_read2_with_buffer<T>(inner: T, mut buf: BytesMut) -> FramedRead2<T> {
if buf.capacity() < INITIAL_CAPACITY {
let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity();
buf.reserve(bytes_to_reserve);
}
FramedRead2 {
inner: inner,
eof: false,
is_readable: buf.len() > 0,
buffer: buf,
}
}
impl<T> FramedRead2<T> {
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn into_parts(self) -> (T, BytesMut) {
(self.inner, self.buffer)
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T> Stream for FramedRead2<T>
where
T: AsyncRead + Decoder,
{
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop {
// Repeatedly call `decode` or `decode_eof` as long as it is
// "readable". Readable is defined as not having returned `None`. If
// the upstream has returned EOF, and the decoder is no longer
// readable, it can be assumed that the decoder will never become
// readable again, at which point the stream is terminated.
if self.is_readable {
if self.eof {
let frame = self.inner.decode_eof(&mut self.buffer)?;
return Ok(Async::Ready(frame));
}
trace!("attempting to decode a frame");
if let Some(frame) = self.inner.decode(&mut self.buffer)? {
trace!("frame decoded from buffer");
return Ok(Async::Ready(Some(frame)));
}
self.is_readable = false;
}
assert!(!self.eof);
// Otherwise, try to read more data and try again. Make sure we've
// got room for at least one byte to read to ensure that we don't
// get a spurious 0 that looks like EOF
self.buffer.reserve(1);
if 0 == try_ready!(self.inner.read_buf(&mut self.buffer)) {
self.eof = true;
}
self.is_readable = true;
}
}
}
-245
View File
@@ -1,245 +0,0 @@
#![allow(deprecated)]
use super::framed::Fuse;
use crate::codec::{Decoder, Encoder};
use crate::{AsyncRead, AsyncWrite};
use bytes::BytesMut;
use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream};
use log::trace;
use std::fmt;
use std::io::{self, Read};
/// A `Sink` of frames encoded to an `AsyncWrite`.
pub struct FramedWrite<T, E> {
inner: FramedWrite2<Fuse<T, E>>,
}
pub struct FramedWrite2<T> {
inner: T,
buffer: BytesMut,
}
const INITIAL_CAPACITY: usize = 8 * 1024;
const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY;
impl<T, E> FramedWrite<T, E>
where
T: AsyncWrite,
E: Encoder,
{
/// Creates a new `FramedWrite` with the given `encoder`.
pub fn new(inner: T, encoder: E) -> FramedWrite<T, E> {
FramedWrite {
inner: framed_write2(Fuse(inner, encoder)),
}
}
}
impl<T, E> FramedWrite<T, E> {
/// Returns a reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.inner.0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.inner.0
}
/// Consumes the `FramedWrite`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.inner.0
}
/// Returns a reference to the underlying decoder.
pub fn encoder(&self) -> &E {
&self.inner.inner.1
}
/// Returns a mutable reference to the underlying decoder.
pub fn encoder_mut(&mut self) -> &mut E {
&mut self.inner.inner.1
}
}
impl<T, E> Sink for FramedWrite<T, E>
where
T: AsyncWrite,
E: Encoder,
{
type SinkItem = E::Item;
type SinkError = E::Error;
fn start_send(&mut self, item: E::Item) -> StartSend<E::Item, E::Error> {
self.inner.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
Ok(self.inner.close()?)
}
}
impl<T, D> Stream for FramedWrite<T, D>
where
T: Stream,
{
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.inner.0.poll()
}
}
impl<T, U> fmt::Debug for FramedWrite<T, U>
where
T: fmt::Debug,
U: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FramedWrite")
.field("inner", &self.inner.get_ref().0)
.field("encoder", &self.inner.get_ref().1)
.field("buffer", &self.inner.buffer)
.finish()
}
}
// ===== impl FramedWrite2 =====
pub fn framed_write2<T>(inner: T) -> FramedWrite2<T> {
FramedWrite2 {
inner: inner,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
}
}
pub fn framed_write2_with_buffer<T>(inner: T, mut buf: BytesMut) -> FramedWrite2<T> {
if buf.capacity() < INITIAL_CAPACITY {
let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity();
buf.reserve(bytes_to_reserve);
}
FramedWrite2 {
inner: inner,
buffer: buf,
}
}
impl<T> FramedWrite2<T> {
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn into_parts(self) -> (T, BytesMut) {
(self.inner, self.buffer)
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T> Sink for FramedWrite2<T>
where
T: AsyncWrite + Encoder,
{
type SinkItem = T::Item;
type SinkError = T::Error;
fn start_send(&mut self, item: T::Item) -> StartSend<T::Item, T::Error> {
// If the buffer is already over 8KiB, then attempt to flush it. If after flushing it's
// *still* over 8KiB, then apply backpressure (reject the send).
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
self.poll_complete()?;
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
return Ok(AsyncSink::NotReady(item));
}
}
self.inner.encode(item, &mut self.buffer)?;
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
trace!("flushing framed transport");
while !self.buffer.is_empty() {
trace!("writing; remaining={}", self.buffer.len());
let n = try_ready!(self.inner.poll_write(&self.buffer));
if n == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to \
write frame to transport",
)
.into());
}
// TODO: Add a way to `bytes` to do this w/o returning the drained
// data.
let _ = self.buffer.split_to(n);
}
// Try flushing the underlying IO
try_ready!(self.inner.poll_flush());
trace!("framed transport flushed");
return Ok(Async::Ready(()));
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
try_ready!(self.poll_complete());
Ok(self.inner.shutdown()?)
}
}
impl<T: Decoder> Decoder for FramedWrite2<T> {
type Item = T::Item;
type Error = T::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<T::Item>, T::Error> {
self.inner.decode(src)
}
fn decode_eof(&mut self, src: &mut BytesMut) -> Result<Option<T::Item>, T::Error> {
self.inner.decode_eof(src)
}
}
impl<T: Read> Read for FramedWrite2<T> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.inner.read(dst)
}
}
impl<T: AsyncRead> AsyncRead for FramedWrite2<T> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.inner.prepare_uninitialized_buffer(buf)
}
}
-35
View File
@@ -1,35 +0,0 @@
//! Utilities for encoding and decoding frames.
//!
//! Contains adapters to go from streams of bytes, [`AsyncRead`] and
//! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`].
//! Framed streams are also known as [transports].
//!
//! [`AsyncRead`]: #
//! [`AsyncWrite`]: #
//! [`Sink`]: #
//! [`Stream`]: #
//! [transports]: #
#![doc(hidden, html_root_url = "https://docs.rs/tokio-codec/0.1.0")]
// _tokio_codec are the items that belong in the `tokio_codec` crate. However, because we need to
// maintain backward compatibility until the next major breaking change, they are defined here.
// When the next breaking change comes, they should be moved to the `tokio_codec` crate and become
// independent.
//
// The primary reason we can't move these to `tokio-codec` now is because, again for backward
// compatibility reasons, we need to keep `Decoder` and `Encoder` in tokio_io::codec. And `Decoder`
// and `Encoder` needs to reference `Framed`. So they all still need to still be in the same
// module.
mod decoder;
mod encoder;
mod framed;
mod framed_read;
mod framed_write;
pub use self::decoder::Decoder;
pub use self::encoder::Encoder;
pub use self::framed::{Framed, FramedParts};
pub use self::framed_read::FramedRead;
pub use self::framed_write::FramedWrite;
-93
View File
@@ -1,93 +0,0 @@
use crate::{AsyncRead, AsyncWrite};
use futures::{Async, Poll};
use std::{fmt, io};
/// A simple wrapper type which allows types that only implement
/// `std::io::Read` or `std::io::Write` to be used in contexts which expect
/// an `AsyncRead` or `AsyncWrite`.
///
/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`,
/// it is expected that they will notify the current task on readiness.
/// Synchronous `std` types should not issue errors of this kind and
/// are safe to use in this context. However, using these types with
/// `AllowStdIo` will cause the event loop to block, so they should be used
/// with care.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AllowStdIo<T>(T);
impl<T> AllowStdIo<T> {
/// Creates a new `AllowStdIo` from an existing IO object.
pub fn new(io: T) -> Self {
AllowStdIo(io)
}
/// Returns a reference to the contained IO object.
pub fn get_ref(&self) -> &T {
&self.0
}
/// Returns a mutable reference to the contained IO object.
pub fn get_mut(&mut self) -> &mut T {
&mut self.0
}
/// Consumes self and returns the contained IO object.
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> io::Write for AllowStdIo<T>
where
T: io::Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.0.write_all(buf)
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.0.write_fmt(fmt)
}
}
impl<T> AsyncWrite for AllowStdIo<T>
where
T: io::Write,
{
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(Async::Ready(()))
}
}
impl<T> io::Read for AllowStdIo<T>
where
T: io::Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
// TODO: implement the `initializer` fn when it stabilizes.
// See rust-lang/rust #42788
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.0.read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.0.read_exact(buf)
}
}
impl<T> AsyncRead for AllowStdIo<T>
where
T: io::Read,
{
// TODO: override prepare_uninitialized_buffer once `Read::initializer` is stable.
// See rust-lang/rust #42788
}
+55 -71
View File
@@ -1,10 +1,10 @@
#[allow(deprecated)]
use crate::codec::{Decoder, Encoder, Framed};
use crate::split::{ReadHalf, WriteHalf};
use crate::{framed, split, AsyncWrite};
//use crate::split::{ReadHalf, WriteHalf};
//use crate::{framed, split, AsyncWrite};
use bytes::BufMut;
use futures::{try_ready, Async, Poll};
use std::io as std_io;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};
/// Read bytes asynchronously.
///
@@ -15,23 +15,23 @@ use std::io as std_io;
/// Specifically, this means that the `poll_read` function will return one of
/// the following:
///
/// * `Ok(Async::Ready(n))` means that `n` bytes of data was immediately read
/// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately read
/// and placed into the output buffer, where `n` == 0 implies that EOF has
/// been reached.
///
/// * `Ok(Async::NotReady)` means that no data was read into the buffer
/// * `Poll::Pending` means that no data was read into the buffer
/// provided. The I/O object is not currently readable but may become readable
/// in the future. Most importantly, **the current future's task is scheduled
/// to get unparked when the object is readable**. This means that like
/// `Future::poll` you'll receive a notification when the I/O object is
/// readable again.
///
/// * `Err(e)` for other errors are standard I/O errors coming from the
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
/// underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead: std_io::Read {
pub trait AsyncRead {
/// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
/// `true` if the supplied buffer was zeroed out.
///
@@ -70,19 +70,17 @@ pub trait AsyncRead: std_io::Read {
/// Attempt to read from the `AsyncRead` into `buf`.
///
/// On success, returns `Ok(Async::Ready(num_bytes_read))`.
/// On success, returns `Poll::Ready(Ok(num_bytes_read))`.
///
/// If no data is available for reading, the method returns
/// `Ok(Async::NotReady)` and arranges for the current task (via
/// `Poll::Pending` and arranges for the current task (via
/// `cx.waker()`) to receive a notification when the object becomes
/// readable or is closed.
fn poll_read(&mut self, buf: &mut [u8]) -> Poll<usize, std_io::Error> {
match self.read(buf) {
Ok(t) => Ok(Async::Ready(t)),
Err(ref e) if e.kind() == std_io::ErrorKind::WouldBlock => return Ok(Async::NotReady),
Err(e) => return Err(e.into()),
}
}
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>>;
/// Pull some bytes from this source into the specified `BufMut`, returning
/// how many bytes were read.
@@ -90,12 +88,16 @@ pub trait AsyncRead: std_io::Read {
/// The `buf` provided will have bytes read into it and the internal cursor
/// will be advanced if any bytes were read. Note that this method typically
/// will not reallocate the buffer provided.
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
fn poll_read_buf<B: BufMut>(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut B,
) -> Poll<io::Result<usize>>
where
Self: Sized,
{
if !buf.has_remaining_mut() {
return Ok(Async::Ready(0));
return Poll::Ready(Ok(0));
}
unsafe {
@@ -104,69 +106,51 @@ pub trait AsyncRead: std_io::Read {
self.prepare_uninitialized_buffer(b);
try_ready!(self.poll_read(b))
ready!(self.poll_read(cx, b))?
};
buf.advance_mut(n);
Ok(Async::Ready(n))
Poll::Ready(Ok(n))
}
}
}
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// I/O object, using `Decode` and `Encode` to read and write the raw data.
///
/// Raw I/O objects work with byte sequences, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of an I/O object, by using the `Codec`
/// traits to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things like gzip or TLS, which require both read and write access to the
/// underlying object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
#[deprecated(since = "0.1.7", note = "Use tokio_codec::Decoder::framed instead")]
#[allow(deprecated)]
fn framed<T: Encoder + Decoder>(self, codec: T) -> Framed<Self, T>
where
Self: AsyncWrite + Sized,
{
framed::framed(self, codec)
}
macro_rules! deref_async_read {
() => {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
(**self).prepare_uninitialized_buffer(buf)
}
/// Helper method for splitting this read/write object into two halves.
///
/// The two halves returned implement the `Read` and `Write` traits,
/// respectively.
///
/// To restore this read/write object from its `ReadHalf` and `WriteHalf`
/// use `unsplit`.
fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
where
Self: AsyncWrite + Sized,
{
split::split(self)
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8])
-> Poll<io::Result<usize>>
{
Pin::new(&mut **self).poll_read(cx, buf)
}
}
}
impl<T: ?Sized + AsyncRead> AsyncRead for Box<T> {
impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for Box<T> {
deref_async_read!();
}
impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for &mut T {
deref_async_read!();
}
impl<P> AsyncRead for Pin<P>
where
P: DerefMut + Unpin,
P::Target: AsyncRead,
{
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
(**self).prepare_uninitialized_buffer(buf)
}
}
impl<'a, T: ?Sized + AsyncRead> AsyncRead for &'a mut T {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
(**self).prepare_uninitialized_buffer(buf)
}
}
impl<'a> AsyncRead for &'a [u8] {
unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [u8]) -> bool {
false
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
self.get_mut().as_mut().poll_read(cx, buf)
}
}
+56 -86
View File
@@ -1,7 +1,9 @@
use crate::AsyncRead;
//use crate::AsyncRead;
use bytes::Buf;
use futures::{try_ready, Async, Poll};
use std::io as std_io;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};
/// Writes bytes asynchronously.
///
@@ -33,7 +35,7 @@ use std::io as std_io;
/// writer has successfully been flushed, a "would block" error means that the
/// current task is ready to receive a notification when flushing can make more
/// progress, and otherwise normal errors can happen as well.
pub trait AsyncWrite: std_io::Write {
pub trait AsyncWrite {
/// Attempt to write bytes from `buf` into the object.
///
/// On success, returns `Ok(Async::Ready(num_bytes_written))`.
@@ -42,13 +44,11 @@ pub trait AsyncWrite: std_io::Write {
/// `Ok(Async::NotReady)` and arranges for the current task (via
/// `cx.waker()`) to receive a notification when the object becomes
/// readable or is closed.
fn poll_write(&mut self, buf: &[u8]) -> Poll<usize, std_io::Error> {
match self.write(buf) {
Ok(t) => Ok(Async::Ready(t)),
Err(ref e) if e.kind() == std_io::ErrorKind::WouldBlock => return Ok(Async::NotReady),
Err(e) => return Err(e.into()),
}
}
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>>;
/// Attempt to flush the object, ensuring that any buffered data reach
/// their destination.
@@ -59,13 +59,7 @@ pub trait AsyncWrite: std_io::Write {
/// `Ok(Async::NotReady)` and arranges for the current task (via
/// `cx.waker()`) to receive a notification when the object can make
/// progress towards flushing.
fn poll_flush(&mut self) -> Poll<(), std_io::Error> {
match self.flush() {
Ok(t) => Ok(Async::Ready(t)),
Err(ref e) if e.kind() == std_io::ErrorKind::WouldBlock => return Ok(Async::NotReady),
Err(e) => return Err(e.into()),
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>;
/// Initiates or attempts to shut down this writer, returning success when
/// the I/O connection has completely shut down.
@@ -125,97 +119,73 @@ pub trait AsyncWrite: std_io::Write {
///
/// This function will panic if not called within the context of a future's
/// task.
fn shutdown(&mut self) -> Poll<(), std_io::Error>;
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>)
-> Poll<Result<(), io::Error>>;
/// Write a `Buf` into this value, returning how many bytes were written.
///
/// Note that this method will advance the `buf` provided automatically by
/// the number of bytes written.
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
fn poll_write_buf<B: Buf>(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut B,
) -> Poll<Result<usize, io::Error>>
where
Self: Sized,
{
if !buf.has_remaining() {
return Ok(Async::Ready(0));
return Poll::Ready(Ok(0));
}
let n = try_ready!(self.poll_write(buf.bytes()));
let n = ready!(self.poll_write(cx, buf.bytes()))?;
buf.advance(n);
Ok(Async::Ready(n))
Poll::Ready(Ok(n))
}
}
impl<T: ?Sized + AsyncWrite> AsyncWrite for Box<T> {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
(**self).shutdown()
}
}
impl<'a, T: ?Sized + AsyncWrite> AsyncWrite for &'a mut T {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
(**self).shutdown()
macro_rules! deref_async_write {
() => {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
-> Poll<io::Result<usize>>
{
Pin::new(&mut **self).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut **self).poll_flush(cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut **self).poll_shutdown(cx)
}
}
}
impl AsyncRead for std_io::Repeat {
unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
false
}
impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for Box<T> {
deref_async_write!();
}
impl AsyncWrite for std_io::Sink {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
Ok(().into())
}
impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for &mut T {
deref_async_write!();
}
impl<T: AsyncRead> AsyncRead for std_io::Take<T> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.get_ref().prepare_uninitialized_buffer(buf)
}
}
impl<T, U> AsyncRead for std_io::Chain<T, U>
impl<P> AsyncWrite for Pin<P>
where
T: AsyncRead,
U: AsyncRead,
P: DerefMut + Unpin,
P::Target: AsyncWrite,
{
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
let (t, u) = self.get_ref();
// We don't need to execute the second initializer if the first one
// already zeroed the buffer out.
t.prepare_uninitialized_buffer(buf) || u.prepare_uninitialized_buffer(buf)
}
}
impl<T: AsyncWrite> AsyncWrite for std_io::BufWriter<T> {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
try_ready!(self.poll_flush());
self.get_mut().shutdown()
}
}
impl<T: AsyncRead> AsyncRead for std_io::BufReader<T> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.get_ref().prepare_uninitialized_buffer(buf)
}
}
impl<T: AsRef<[u8]>> AsyncRead for std_io::Cursor<T> {}
impl<'a> AsyncWrite for std_io::Cursor<&'a mut [u8]> {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
Ok(().into())
}
}
impl AsyncWrite for std_io::Cursor<Vec<u8>> {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
Ok(().into())
}
}
impl AsyncWrite for std_io::Cursor<Box<[u8]>> {
fn shutdown(&mut self) -> Poll<(), std_io::Error> {
Ok(().into())
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
-> Poll<io::Result<usize>>
{
self.get_mut().as_mut().poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.get_mut().as_mut().poll_flush(cx)
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.get_mut().as_mut().poll_shutdown(cx)
}
}
-42
View File
@@ -1,42 +0,0 @@
#![allow(deprecated)]
use crate::codec::{Decoder, Encoder};
use bytes::{BufMut, Bytes, BytesMut};
use std::io;
/// A simple `Codec` implementation that just ships bytes around.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
pub struct BytesCodec(());
impl BytesCodec {
/// Creates a new `BytesCodec` for shipping around raw bytes.
pub fn new() -> BytesCodec {
BytesCodec(())
}
}
impl Decoder for BytesCodec {
type Item = BytesMut;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<BytesMut>, io::Error> {
if buf.len() > 0 {
let len = buf.len();
Ok(Some(buf.split_to(len)))
} else {
Ok(None)
}
}
}
impl Encoder for BytesCodec {
type Item = Bytes;
type Error = io::Error;
fn encode(&mut self, data: Bytes, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(data.len());
buf.put(data);
Ok(())
}
}
-115
View File
@@ -1,115 +0,0 @@
use super::encoder::Encoder;
use crate::_tokio_codec::Framed;
use crate::{AsyncRead, AsyncWrite};
use bytes::BytesMut;
use std::io;
/// Decoding of frames via buffers.
///
/// This trait is used when constructing an instance of `Framed` or
/// `FramedRead`. An implementation of `Decoder` takes a byte stream that has
/// already been buffered in `src` and decodes the data into a stream of
/// `Self::Item` frames.
///
/// Implementations are able to track state on `self`, which enables
/// implementing stateful streaming parsers. In many cases, though, this type
/// will simply be a unit struct (e.g. `struct HttpDecoder`).
// Note: We can't deprecate this trait, because the deprecation carries through to tokio-codec, and
// there doesn't seem to be a way to un-deprecate the re-export.
pub trait Decoder {
/// The type of decoded frames.
type Item;
/// The type of unrecoverable frame decoding errors.
///
/// If an individual message is ill-formed but can be ignored without
/// interfering with the processing of future messages, it may be more
/// useful to report the failure as an `Item`.
///
/// `From<io::Error>` is required in the interest of making `Error` suitable
/// for returning directly from a `FramedRead`, and to enable the default
/// implementation of `decode_eof` to yield an `io::Error` when the decoder
/// fails to consume all available data.
///
/// Note that implementors of this trait can simply indicate `type Error =
/// io::Error` to use I/O errors as this type.
type Error: From<io::Error>;
/// Attempts to decode a frame from the provided buffer of bytes.
///
/// This method is called by `FramedRead` whenever bytes are ready to be
/// parsed. The provided buffer of bytes is what's been read so far, and
/// this instance of `Decode` can determine whether an entire frame is in
/// the buffer and is ready to be returned.
///
/// If an entire frame is available, then this instance will remove those
/// bytes from the buffer provided and return them as a decoded
/// frame. Note that removing bytes from the provided buffer doesn't always
/// necessarily copy the bytes, so this should be an efficient operation in
/// most circumstances.
///
/// If the bytes look valid, but a frame isn't fully available yet, then
/// `Ok(None)` is returned. This indicates to the `Framed` instance that
/// it needs to read some more bytes before calling this method again.
///
/// Note that the bytes provided may be empty. If a previous call to
/// `decode` consumed all the bytes in the buffer then `decode` will be
/// called again until it returns `Ok(None)`, indicating that more bytes need to
/// be read.
///
/// Finally, if the bytes in the buffer are malformed then an error is
/// returned indicating why. This informs `Framed` that the stream is now
/// corrupt and should be terminated.
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error>;
/// A default method available to be called when there are no more bytes
/// available to be read from the underlying I/O.
///
/// This method defaults to calling `decode` and returns an error if
/// `Ok(None)` is returned while there is unconsumed data in `buf`.
/// Typically this doesn't need to be implemented unless the framing
/// protocol differs near the end of the stream.
///
/// Note that the `buf` argument may be empty. If a previous call to
/// `decode_eof` consumed all the bytes in the buffer, `decode_eof` will be
/// called again until it returns `None`, indicating that there are no more
/// frames to yield. This behavior enables returning finalization frames
/// that may not be based on inbound data.
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match self.decode(buf)? {
Some(frame) => Ok(Some(frame)),
None => {
if buf.is_empty() {
Ok(None)
} else {
Err(io::Error::new(io::ErrorKind::Other, "bytes remaining on stream").into())
}
}
}
}
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
///
/// Raw I/O objects work with byte sequences, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of an I/O object, by using the `Codec`
/// traits to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things like gzip or TLS, which require both read and write access to the
/// underlying object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
fn framed<T: AsyncRead + AsyncWrite + Sized>(self, io: T) -> Framed<T, Self>
where
Self: Encoder + Sized,
{
Framed::new(io, self)
}
}
-25
View File
@@ -1,25 +0,0 @@
use bytes::BytesMut;
use std::io;
/// Trait of helper objects to write out messages as bytes, for use with
/// `FramedWrite`.
// Note: We can't deprecate this trait, because the deprecation carries through to tokio-codec, and
// there doesn't seem to be a way to un-deprecate the re-export.
pub trait Encoder {
/// The type of items consumed by the `Encoder`
type Item;
/// The type of encoding errors.
///
/// `FramedWrite` requires `Encoder`s errors to implement `From<io::Error>`
/// in the interest letting it return `Error`s directly.
type Error: From<io::Error>;
/// Encodes a frame into the buffer provided.
///
/// This method will encode `item` into the byte buffer provided by `dst`.
/// The `dst` provided is an internal buffer of the `Framed` instance and
/// will be written out when possible.
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error>;
}
-88
View File
@@ -1,88 +0,0 @@
#![allow(deprecated)]
use crate::codec::{Decoder, Encoder};
use bytes::{BufMut, BytesMut};
use std::{io, str};
/// A simple `Codec` implementation that splits up data into lines.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
pub struct LinesCodec {
// Stored index of the next index to examine for a `\n` character.
// This is used to optimize searching.
// For example, if `decode` was called with `abc`, it would hold `3`,
// because that is the next index to examine.
// The next time `decode` is called with `abcde\n`, the method will
// only look at `de\n` before returning.
next_index: usize,
}
impl LinesCodec {
/// Returns a `LinesCodec` for splitting up data into lines.
pub fn new() -> LinesCodec {
LinesCodec { next_index: 0 }
}
}
fn utf8(buf: &[u8]) -> Result<&str, io::Error> {
str::from_utf8(buf)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Unable to decode input as UTF8"))
}
fn without_carriage_return(s: &[u8]) -> &[u8] {
if let Some(&b'\r') = s.last() {
&s[..s.len() - 1]
} else {
s
}
}
impl Decoder for LinesCodec {
type Item = String;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
if let Some(newline_offset) = buf[self.next_index..].iter().position(|b| *b == b'\n') {
let newline_index = newline_offset + self.next_index;
let line = buf.split_to(newline_index + 1);
let line = &line[..line.len() - 1];
let line = without_carriage_return(line);
let line = utf8(line)?;
self.next_index = 0;
Ok(Some(line.to_string()))
} else {
self.next_index = buf.len();
Ok(None)
}
}
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
Ok(match self.decode(buf)? {
Some(frame) => Some(frame),
None => {
// No terminating newline - return remaining data, if any
if buf.is_empty() || buf == &b"\r"[..] {
None
} else {
let line = buf.take();
let line = without_carriage_return(&line);
let line = utf8(line)?;
self.next_index = 0;
Some(line.to_string())
}
}
})
}
}
impl Encoder for LinesCodec {
type Item = String;
type Error = io::Error;
fn encode(&mut self, line: String, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(line.len() + 1);
buf.put(line);
buf.put_u8(b'\n');
Ok(())
}
}
-375
View File
@@ -1,375 +0,0 @@
//! Utilities for encoding and decoding frames.
//!
//! Contains adapters to go from streams of bytes, [`AsyncRead`] and
//! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`].
//! Framed streams are also known as [transports].
//!
//! [`AsyncRead`]: #
//! [`AsyncWrite`]: #
//! [`Sink`]: #
//! [`Stream`]: #
//! [transports]: #
// tokio_io::codec originally held all codec-related helpers. This is now intended to be in
// tokio_codec instead. However, for backward compatibility, this remains here. When the next major
// breaking change comes, `Encoder` and `Decoder` need to be moved to `tokio_codec`, and the rest
// of this module should be removed.
#![doc(hidden)]
#![allow(deprecated)]
mod bytes_codec;
mod decoder;
mod encoder;
mod lines_codec;
pub use self::bytes_codec::BytesCodec;
pub use self::decoder::Decoder;
pub use self::encoder::Encoder;
pub use self::lines_codec::LinesCodec;
pub use crate::framed::{Framed, FramedParts};
pub use crate::framed_read::FramedRead;
pub use crate::framed_write::FramedWrite;
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub mod length_delimited {
//! Frame a stream of bytes based on a length prefix
//!
//! Many protocols delimit their frames by prefacing frame data with a
//! frame head that specifies the length of the frame. The
//! `length_delimited` module provides utilities for handling the length
//! based framing. This allows the consumer to work with entire frames
//! without having to worry about buffering or other framing logic.
//!
//! # Getting started
//!
//! If implementing a protocol from scratch, using length delimited framing
//! is an easy way to get started. [`Framed::new()`](length_delimited::Framed::new) will adapt a
//! full-duplex byte stream with a length delimited framer using default
//! configuration values.
//!
//! ```
//! use tokio_io::{AsyncRead, AsyncWrite};
//! use tokio_io::codec::length_delimited;
//!
//! fn bind_transport<T: AsyncRead + AsyncWrite>(io: T)
//! -> length_delimited::Framed<T>
//! {
//! length_delimited::Framed::new(io)
//! }
//! ```
//!
//! The returned transport implements `Sink + Stream` for `BytesMut`. It
//! encodes the frame with a big-endian `u32` header denoting the frame
//! payload length:
//!
//! ```text
//! +----------+--------------------------------+
//! | len: u32 | frame payload |
//! +----------+--------------------------------+
//! ```
//!
//! Specifically, given the following:
//!
//! ```
//! use tokio_io::{AsyncRead, AsyncWrite};
//! use tokio_io::codec::length_delimited;
//! use bytes::BytesMut;
//! use futures::{Sink, Future};
//!
//! fn write_frame<T: AsyncRead + AsyncWrite>(io: T) {
//! let mut transport = length_delimited::Framed::new(io);
//! let frame = BytesMut::from("hello world");
//!
//! transport.send(frame).wait().unwrap();
//! }
//! ```
//!
//! The encoded frame will look like this:
//!
//! ```text
//! +---- len: u32 ----+---- data ----+
//! | \x00\x00\x00\x0b | hello world |
//! +------------------+--------------+
//! ```
//!
//! # Decoding
//!
//! [`FramedRead`] adapts an [`AsyncRead`] into a `Stream` of [`BytesMut`],
//! such that each yielded [`BytesMut`] value contains the contents of an
//! entire frame. There are many configuration parameters enabling
//! [`FramedRead`] to handle a wide range of protocols. Here are some
//! examples that will cover the various options at a high level.
//!
//! ## Example 1
//!
//! The following will parse a `u16` length field at offset 0, including the
//! frame head in the yielded `BytesMut`.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_adjustment(0) // default value
//! .num_skip(0) // Do not strip frame header
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT DECODED
//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+
//! | \x00\x0B | Hello world | --> | \x00\x0B | Hello world |
//! +----------+---------------+ +----------+---------------+
//! ```
//!
//! The value of the length field is 11 (`\x0B`) which represents the length
//! of the payload, `hello world`. By default, [`FramedRead`] assumes that
//! the length field represents the number of bytes that **follows** the
//! length field. Thus, the entire frame has a length of 13: 2 bytes for the
//! frame head + 11 bytes for the payload.
//!
//! ## Example 2
//!
//! The following will parse a `u16` length field at offset 0, omitting the
//! frame head in the yielded `BytesMut`.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_adjustment(0) // default value
//! // `num_skip` is not needed, the default is to skip
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT DECODED
//! +-- len ---+--- Payload ---+ +--- Payload ---+
//! | \x00\x0B | Hello world | --> | Hello world |
//! +----------+---------------+ +---------------+
//! ```
//!
//! This is similar to the first example, the only difference is that the
//! frame head is **not** included in the yielded `BytesMut` value.
//!
//! ## Example 3
//!
//! The following will parse a `u16` length field at offset 0, including the
//! frame head in the yielded `BytesMut`. In this case, the length field
//! **includes** the frame head length.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_adjustment(-2) // size of head
//! .num_skip(0)
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT DECODED
//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+
//! | \x00\x0D | Hello world | --> | \x00\x0D | Hello world |
//! +----------+---------------+ +----------+---------------+
//! ```
//!
//! In most cases, the length field represents the length of the payload
//! only, as shown in the previous examples. However, in some protocols the
//! length field represents the length of the whole frame, including the
//! head. In such cases, we specify a negative `length_adjustment` to adjust
//! the value provided in the frame head to represent the payload length.
//!
//! ## Example 4
//!
//! The following will parse a 3 byte length field at offset 0 in a 5 byte
//! frame head, including the frame head in the yielded `BytesMut`.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(0) // default value
//! .length_field_length(3)
//! .length_adjustment(2) // remaining head
//! .num_skip(0)
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT
//! +---- len -----+- head -+--- Payload ---+
//! | \x00\x00\x0B | \xCAFE | Hello world |
//! +--------------+--------+---------------+
//!
//! DECODED
//! +---- len -----+- head -+--- Payload ---+
//! | \x00\x00\x0B | \xCAFE | Hello world |
//! +--------------+--------+---------------+
//! ```
//!
//! A more advanced example that shows a case where there is extra frame
//! head data between the length field and the payload. In such cases, it is
//! usually desirable to include the frame head as part of the yielded
//! `BytesMut`. This lets consumers of the length delimited framer to
//! process the frame head as needed.
//!
//! The positive `length_adjustment` value lets `FramedRead` factor in the
//! additional head into the frame length calculation.
//!
//! ## Example 5
//!
//! The following will parse a `u16` length field at offset 1 of a 4 byte
//! frame head. The first byte and the length field will be omitted from the
//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be
//! included.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(1) // length of hdr1
//! .length_field_length(2)
//! .length_adjustment(1) // length of hdr2
//! .num_skip(3) // length of hdr1 + LEN
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT
//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+
//! | \xCA | \x00\x0B | \xFE | Hello world |
//! +--------+----------+--------+---------------+
//!
//! DECODED
//! +- hdr2 -+--- Payload ---+
//! | \xFE | Hello world |
//! +--------+---------------+
//! ```
//!
//! The length field is situated in the middle of the frame head. In this
//! case, the first byte in the frame head could be a version or some other
//! identifier that is not needed for processing. On the other hand, the
//! second half of the head is needed.
//!
//! `length_field_offset` indicates how many bytes to skip before starting
//! to read the length field. `length_adjustment` is the number of bytes to
//! skip starting at the end of the length field. In this case, it is the
//! second half of the head.
//!
//! ## Example 6
//!
//! The following will parse a `u16` length field at offset 1 of a 4 byte
//! frame head. The first byte and the length field will be omitted from the
//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be
//! included. In this case, the length field **includes** the frame head
//! length.
//!
//! ```
//! use tokio_io::AsyncRead;
//! use tokio_io::codec::length_delimited;
//!
//! # fn bind_read<T: AsyncRead>(io: T) {
//! length_delimited::Builder::new()
//! .length_field_offset(1) // length of hdr1
//! .length_field_length(2)
//! .length_adjustment(-3) // length of hdr1 + LEN, negative
//! .num_skip(3)
//! .new_read(io);
//! # }
//! ```
//!
//! The following frame will be decoded as such:
//!
//! ```text
//! INPUT
//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+
//! | \xCA | \x00\x0F | \xFE | Hello world |
//! +--------+----------+--------+---------------+
//!
//! DECODED
//! +- hdr2 -+--- Payload ---+
//! | \xFE | Hello world |
//! +--------+---------------+
//! ```
//!
//! Similar to the example above, the difference is that the length field
//! represents the length of the entire frame instead of just the payload.
//! The length of `hdr1` and `len` must be counted in `length_adjustment`.
//! Note that the length of `hdr2` does **not** need to be explicitly set
//! anywhere because it already is factored into the total frame length that
//! is read from the byte stream.
//!
//! # Encoding
//!
//! [`FramedWrite`] adapts an [`AsyncWrite`] into a `Sink` of [`BytesMut`],
//! such that each submitted [`BytesMut`] is prefaced by a length field.
//! There are fewer configuration options than [`FramedRead`]. Given
//! protocols that have more complex frame heads, an encoder should probably
//! be written by hand using [`Encoder`].
//!
//! Here is a simple example, given a `FramedWrite` with the following
//! configuration:
//!
//! ```
//! use tokio_io::AsyncWrite;
//! use tokio_io::codec::length_delimited;
//! use bytes::BytesMut;
//!
//! # fn write_frame<T: AsyncWrite>(io: T) {
//! # let _: length_delimited::FramedWrite<T, BytesMut> =
//! length_delimited::Builder::new()
//! .length_field_length(2)
//! .new_write(io);
//! # }
//! ```
//!
//! A payload of `hello world` will be encoded as:
//!
//! ```text
//! +- len: u16 -+---- data ----+
//! | \x00\x0b | hello world |
//! +------------+--------------+
//! ```
//!
//! [`FramedRead`]: struct.FramedRead.html
//! [`FramedWrite`]: struct.FramedWrite.html
//! [`AsyncRead`]: ../../trait.AsyncRead.html
//! [`AsyncWrite`]: ../../trait.AsyncWrite.html
//! [`Encoder`]: ../trait.Encoder.html
//! [`BytesMut`]: https://docs.rs/bytes/0.4/bytes/struct.BytesMut.html
pub use crate::length_delimited::*;
}
-246
View File
@@ -1,246 +0,0 @@
#![allow(deprecated)]
use crate::codec::{Decoder, Encoder};
use crate::framed_read::{framed_read2, framed_read2_with_buffer, FramedRead2};
use crate::framed_write::{framed_write2, framed_write2_with_buffer, FramedWrite2};
use crate::{AsyncRead, AsyncWrite};
use bytes::BytesMut;
use futures::{Poll, Sink, StartSend, Stream};
use std::fmt;
use std::io::{self, Read, Write};
/// A unified `Stream` and `Sink` interface to an underlying I/O object, using
/// the `Encoder` and `Decoder` traits to encode and decode frames.
///
/// You can create a `Framed` instance by using the `AsyncRead::framed` adapter.
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct Framed<T, U> {
inner: FramedRead2<FramedWrite2<Fuse<T, U>>>,
}
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct Fuse<T, U>(pub T, pub U);
pub fn framed<T, U>(inner: T, codec: U) -> Framed<T, U>
where
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder,
{
Framed {
inner: framed_read2(framed_write2(Fuse(inner, codec))),
}
}
impl<T, U> Framed<T, U> {
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
///
/// Raw I/O objects work with byte sequences, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of an I/O object, by using the `Codec`
/// traits to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things like gzip or TLS, which require both read and write access to the
/// underlying object.
///
/// This objects takes a stream and a readbuffer and a writebuffer. These field
/// can be obtained from an existing `Framed` with the `into_parts` method.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
pub fn from_parts(parts: FramedParts<T>, codec: U) -> Framed<T, U> {
Framed {
inner: framed_read2_with_buffer(
framed_write2_with_buffer(Fuse(parts.inner, codec), parts.writebuf),
parts.readbuf,
),
}
}
/// Returns a reference to the underlying I/O stream wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.get_ref().get_ref().0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `Frame`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.get_mut().get_mut().0
}
/// Consumes the `Frame`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.into_inner().into_inner().0
}
/// Consumes the `Frame`, returning its underlying I/O stream and the buffer
/// with unprocessed data.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_parts(self) -> FramedParts<T> {
let (inner, readbuf) = self.inner.into_parts();
let (inner, writebuf) = inner.into_parts();
FramedParts {
inner: inner.0,
readbuf: readbuf,
writebuf: writebuf,
}
}
/// Consumes the `Frame`, returning its underlying I/O stream and the buffer
/// with unprocessed data, and also the current codec state.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
///
/// Note that this function will be removed once the codec has been
/// integrated into `FramedParts` in a new version (see
/// [#53](https://github.com/tokio-rs/tokio-io/pull/53)).
pub fn into_parts_and_codec(self) -> (FramedParts<T>, U) {
let (inner, readbuf) = self.inner.into_parts();
let (inner, writebuf) = inner.into_parts();
(
FramedParts {
inner: inner.0,
readbuf: readbuf,
writebuf: writebuf,
},
inner.1,
)
}
}
impl<T, U> Stream for Framed<T, U>
where
T: AsyncRead,
U: Decoder,
{
type Item = U::Item;
type Error = U::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll()
}
}
impl<T, U> Sink for Framed<T, U>
where
T: AsyncWrite,
U: Encoder,
U::Error: From<io::Error>,
{
type SinkItem = U::Item;
type SinkError = U::Error;
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.get_mut().start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.get_mut().poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.inner.get_mut().close()
}
}
impl<T, U> fmt::Debug for Framed<T, U>
where
T: fmt::Debug,
U: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Framed")
.field("io", &self.inner.get_ref().get_ref().0)
.field("codec", &self.inner.get_ref().get_ref().1)
.finish()
}
}
// ===== impl Fuse =====
impl<T: Read, U> Read for Fuse<T, U> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.0.read(dst)
}
}
impl<T: AsyncRead, U> AsyncRead for Fuse<T, U> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.0.prepare_uninitialized_buffer(buf)
}
}
impl<T: Write, U> Write for Fuse<T, U> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
self.0.write(src)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
impl<T: AsyncWrite, U> AsyncWrite for Fuse<T, U> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.0.shutdown()
}
}
impl<T, U: Decoder> Decoder for Fuse<T, U> {
type Item = U::Item;
type Error = U::Error;
fn decode(&mut self, buffer: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.1.decode(buffer)
}
fn decode_eof(&mut self, buffer: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.1.decode_eof(buffer)
}
}
impl<T, U: Encoder> Encoder for Fuse<T, U> {
type Item = U::Item;
type Error = U::Error;
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
self.1.encode(item, dst)
}
}
/// `FramedParts` contains an export of the data of a Framed transport.
/// It can be used to construct a new `Framed` with a different codec.
/// It contains all current buffers and the inner transport.
#[derive(Debug)]
pub struct FramedParts<T> {
/// The inner transport used to read bytes to and write bytes to
pub inner: T,
/// The buffer with read but unprocessed data.
pub readbuf: BytesMut,
/// A buffer with unprocessed data which are not written yet.
pub writebuf: BytesMut,
}
-219
View File
@@ -1,219 +0,0 @@
#![allow(deprecated)]
use crate::codec::Decoder;
use crate::framed::Fuse;
use crate::AsyncRead;
use bytes::BytesMut;
use futures::{try_ready, Async, Poll, Sink, StartSend, Stream};
use log::trace;
use std::fmt;
/// A `Stream` of messages decoded from an `AsyncRead`.
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FramedRead<T, D> {
inner: FramedRead2<Fuse<T, D>>,
}
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FramedRead2<T> {
inner: T,
eof: bool,
is_readable: bool,
buffer: BytesMut,
}
const INITIAL_CAPACITY: usize = 8 * 1024;
// ===== impl FramedRead =====
impl<T, D> FramedRead<T, D>
where
T: AsyncRead,
D: Decoder,
{
/// Creates a new `FramedRead` with the given `decoder`.
pub fn new(inner: T, decoder: D) -> FramedRead<T, D> {
FramedRead {
inner: framed_read2(Fuse(inner, decoder)),
}
}
}
impl<T, D> FramedRead<T, D> {
/// Returns a reference to the underlying I/O stream wrapped by
/// `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.inner.0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.inner.0
}
/// Consumes the `FramedRead`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.inner.0
}
/// Returns a reference to the underlying decoder.
pub fn decoder(&self) -> &D {
&self.inner.inner.1
}
/// Returns a mutable reference to the underlying decoder.
pub fn decoder_mut(&mut self) -> &mut D {
&mut self.inner.inner.1
}
}
impl<T, D> Stream for FramedRead<T, D>
where
T: AsyncRead,
D: Decoder,
{
type Item = D::Item;
type Error = D::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll()
}
}
impl<T, D> Sink for FramedRead<T, D>
where
T: Sink,
{
type SinkItem = T::SinkItem;
type SinkError = T::SinkError;
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.inner.0.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.inner.0.poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.inner.inner.0.close()
}
}
impl<T, D> fmt::Debug for FramedRead<T, D>
where
T: fmt::Debug,
D: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FramedRead")
.field("inner", &self.inner.inner.0)
.field("decoder", &self.inner.inner.1)
.field("eof", &self.inner.eof)
.field("is_readable", &self.inner.is_readable)
.field("buffer", &self.inner.buffer)
.finish()
}
}
// ===== impl FramedRead2 =====
pub fn framed_read2<T>(inner: T) -> FramedRead2<T> {
FramedRead2 {
inner: inner,
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
}
}
pub fn framed_read2_with_buffer<T>(inner: T, mut buf: BytesMut) -> FramedRead2<T> {
if buf.capacity() < INITIAL_CAPACITY {
let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity();
buf.reserve(bytes_to_reserve);
}
FramedRead2 {
inner: inner,
eof: false,
is_readable: buf.len() > 0,
buffer: buf,
}
}
impl<T> FramedRead2<T> {
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn into_parts(self) -> (T, BytesMut) {
(self.inner, self.buffer)
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T> Stream for FramedRead2<T>
where
T: AsyncRead + Decoder,
{
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop {
// Repeatedly call `decode` or `decode_eof` as long as it is
// "readable". Readable is defined as not having returned `None`. If
// the upstream has returned EOF, and the decoder is no longer
// readable, it can be assumed that the decoder will never become
// readable again, at which point the stream is terminated.
if self.is_readable {
if self.eof {
let frame = self.inner.decode_eof(&mut self.buffer)?;
return Ok(Async::Ready(frame));
}
trace!("attempting to decode a frame");
if let Some(frame) = self.inner.decode(&mut self.buffer)? {
trace!("frame decoded from buffer");
return Ok(Async::Ready(Some(frame)));
}
self.is_readable = false;
}
assert!(!self.eof);
// Otherwise, try to read more data and try again. Make sure we've
// got room for at least one byte to read to ensure that we don't
// get a spurious 0 that looks like EOF
self.buffer.reserve(1);
if 0 == try_ready!(self.inner.read_buf(&mut self.buffer)) {
self.eof = true;
}
self.is_readable = true;
}
}
}
-249
View File
@@ -1,249 +0,0 @@
#![allow(deprecated)]
use crate::codec::{Decoder, Encoder};
use crate::framed::Fuse;
use crate::{AsyncRead, AsyncWrite};
use bytes::BytesMut;
use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream};
use log::trace;
use std::fmt;
use std::io::{self, Read};
/// A `Sink` of frames encoded to an `AsyncWrite`.
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FramedWrite<T, E> {
inner: FramedWrite2<Fuse<T, E>>,
}
#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FramedWrite2<T> {
inner: T,
buffer: BytesMut,
}
const INITIAL_CAPACITY: usize = 8 * 1024;
const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY;
impl<T, E> FramedWrite<T, E>
where
T: AsyncWrite,
E: Encoder,
{
/// Creates a new `FramedWrite` with the given `encoder`.
pub fn new(inner: T, encoder: E) -> FramedWrite<T, E> {
FramedWrite {
inner: framed_write2(Fuse(inner, encoder)),
}
}
}
impl<T, E> FramedWrite<T, E> {
/// Returns a reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner.inner.0
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner.inner.0
}
/// Consumes the `FramedWrite`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn into_inner(self) -> T {
self.inner.inner.0
}
/// Returns a reference to the underlying decoder.
pub fn encoder(&self) -> &E {
&self.inner.inner.1
}
/// Returns a mutable reference to the underlying decoder.
pub fn encoder_mut(&mut self) -> &mut E {
&mut self.inner.inner.1
}
}
impl<T, E> Sink for FramedWrite<T, E>
where
T: AsyncWrite,
E: Encoder,
{
type SinkItem = E::Item;
type SinkError = E::Error;
fn start_send(&mut self, item: E::Item) -> StartSend<E::Item, E::Error> {
self.inner.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.poll_complete()
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
Ok(self.inner.close()?)
}
}
impl<T, D> Stream for FramedWrite<T, D>
where
T: Stream,
{
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.inner.0.poll()
}
}
impl<T, U> fmt::Debug for FramedWrite<T, U>
where
T: fmt::Debug,
U: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FramedWrite")
.field("inner", &self.inner.get_ref().0)
.field("encoder", &self.inner.get_ref().1)
.field("buffer", &self.inner.buffer)
.finish()
}
}
// ===== impl FramedWrite2 =====
pub fn framed_write2<T>(inner: T) -> FramedWrite2<T> {
FramedWrite2 {
inner: inner,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
}
}
pub fn framed_write2_with_buffer<T>(inner: T, mut buf: BytesMut) -> FramedWrite2<T> {
if buf.capacity() < INITIAL_CAPACITY {
let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity();
buf.reserve(bytes_to_reserve);
}
FramedWrite2 {
inner: inner,
buffer: buf,
}
}
impl<T> FramedWrite2<T> {
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn into_parts(self) -> (T, BytesMut) {
(self.inner, self.buffer)
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T> Sink for FramedWrite2<T>
where
T: AsyncWrite + Encoder,
{
type SinkItem = T::Item;
type SinkError = T::Error;
fn start_send(&mut self, item: T::Item) -> StartSend<T::Item, T::Error> {
// If the buffer is already over 8KiB, then attempt to flush it. If after flushing it's
// *still* over 8KiB, then apply backpressure (reject the send).
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
self.poll_complete()?;
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
return Ok(AsyncSink::NotReady(item));
}
}
self.inner.encode(item, &mut self.buffer)?;
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
trace!("flushing framed transport");
while !self.buffer.is_empty() {
trace!("writing; remaining={}", self.buffer.len());
let n = try_ready!(self.inner.poll_write(&self.buffer));
if n == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to
write frame to transport",
)
.into());
}
// TODO: Add a way to `bytes` to do this w/o returning the drained
// data.
let _ = self.buffer.split_to(n);
}
// Try flushing the underlying IO
try_ready!(self.inner.poll_flush());
trace!("framed transport flushed");
return Ok(Async::Ready(()));
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
try_ready!(self.poll_complete());
Ok(self.inner.shutdown()?)
}
}
impl<T: Decoder> Decoder for FramedWrite2<T> {
type Item = T::Item;
type Error = T::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<T::Item>, T::Error> {
self.inner.decode(src)
}
fn decode_eof(&mut self, src: &mut BytesMut) -> Result<Option<T::Item>, T::Error> {
self.inner.decode_eof(src)
}
}
impl<T: Read> Read for FramedWrite2<T> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.inner.read(dst)
}
}
impl<T: AsyncRead> AsyncRead for FramedWrite2<T> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.inner.prepare_uninitialized_buffer(buf)
}
}
-98
View File
@@ -1,98 +0,0 @@
use crate::{AsyncRead, AsyncWrite};
use futures::{try_ready, Future, Poll};
use std::io;
/// A future which will copy all data from a reader into a writer.
///
/// Created by the [`copy`] function, this future will resolve to the number of
/// bytes copied or an error if one happens.
///
/// [`copy`]: fn.copy.html
#[derive(Debug)]
pub struct Copy<R, W> {
reader: Option<R>,
read_done: bool,
writer: Option<W>,
pos: usize,
cap: usize,
amt: u64,
buf: Box<[u8]>,
}
/// Creates a future which represents copying all the bytes from one object to
/// another.
///
/// The returned future will copy all the bytes read from `reader` into the
/// `writer` specified. This future will only complete once the `reader` has hit
/// EOF and all bytes have been written to and flushed from the `writer`
/// provided.
///
/// On success the number of bytes is returned and the `reader` and `writer` are
/// consumed. On error the error is returned and the I/O objects are consumed as
/// well.
pub fn copy<R, W>(reader: R, writer: W) -> Copy<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
Copy {
reader: Some(reader),
read_done: false,
writer: Some(writer),
amt: 0,
pos: 0,
cap: 0,
buf: Box::new([0; 2048]),
}
}
impl<R, W> Future for Copy<R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
type Item = (u64, R, W);
type Error = io::Error;
fn poll(&mut self) -> Poll<(u64, R, W), io::Error> {
loop {
// If our buffer is empty, then we need to read some data to
// continue.
if self.pos == self.cap && !self.read_done {
let reader = self.reader.as_mut().unwrap();
let n = try_ready!(reader.poll_read(&mut self.buf));
if n == 0 {
self.read_done = true;
} else {
self.pos = 0;
self.cap = n;
}
}
// If our buffer has some data, let's write it out!
while self.pos < self.cap {
let writer = self.writer.as_mut().unwrap();
let i = try_ready!(writer.poll_write(&self.buf[self.pos..self.cap]));
if i == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"write zero byte into writer",
));
} else {
self.pos += i;
self.amt += i as u64;
}
}
// If we've written al the data and we've seen EOF, flush out the
// data and finish the transfer.
// done with the entire transfer.
if self.pos == self.cap && self.read_done {
try_ready!(self.writer.as_mut().unwrap().poll_flush());
let reader = self.reader.take().unwrap();
let writer = self.writer.take().unwrap();
return Ok((self.amt, reader, writer).into());
}
}
}
}
-41
View File
@@ -1,41 +0,0 @@
use crate::AsyncWrite;
use futures::{try_ready, Async, Future, Poll};
use std::io;
/// A future used to fully flush an I/O object.
///
/// Resolves to the underlying I/O object once the flush operation is complete.
///
/// Created by the [`flush`] function.
///
/// [`flush`]: fn.flush.html
#[derive(Debug)]
pub struct Flush<A> {
a: Option<A>,
}
/// Creates a future which will entirely flush an I/O object and then yield the
/// object itself.
///
/// This function will consume the object provided if an error happens, and
/// otherwise it will repeatedly call `flush` until it sees `Ok(())`, scheduling
/// a retry if `WouldBlock` is seen along the way.
pub fn flush<A>(a: A) -> Flush<A>
where
A: AsyncWrite,
{
Flush { a: Some(a) }
}
impl<A> Future for Flush<A>
where
A: AsyncWrite,
{
type Item = A;
type Error = io::Error;
fn poll(&mut self) -> Poll<A, io::Error> {
try_ready!(self.a.as_mut().unwrap().poll_flush());
Ok(Async::Ready(self.a.take().unwrap()))
}
}
-32
View File
@@ -1,32 +0,0 @@
//! I/O conveniences when working with primitives in `tokio-core`
//!
//! Contains various combinators to work with I/O objects and type definitions
//! as well.
//!
//! A description of the high-level I/O combinators can be [found online] in
//! addition to a description of the [low level details].
//!
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper-tokio/core-low-level/
mod copy;
mod flush;
mod read;
mod read_exact;
mod read_to_end;
mod read_until;
mod shutdown;
mod write_all;
pub use self::copy::{copy, Copy};
pub use self::flush::{flush, Flush};
pub use self::read::{read, Read};
pub use self::read_exact::{read_exact, ReadExact};
pub use self::read_to_end::{read_to_end, ReadToEnd};
pub use self::read_until::{read_until, ReadUntil};
pub use self::shutdown::{shutdown, Shutdown};
pub use self::write_all::{write_all, WriteAll};
pub use crate::allow_std::AllowStdIo;
pub use crate::lines::{lines, Lines};
pub use crate::split::{ReadHalf, WriteHalf};
pub use crate::window::Window;
-58
View File
@@ -1,58 +0,0 @@
use crate::AsyncRead;
use futures::{try_ready, Future, Poll};
use std::io;
use std::mem;
#[derive(Debug)]
enum State<R, T> {
Pending { rd: R, buf: T },
Empty,
}
/// Tries to read some bytes directly into the given `buf` in asynchronous
/// manner, returning a future type.
///
/// The returned future will resolve to both the I/O stream and the buffer
/// as well as the number of bytes read once the read operation is completed.
pub fn read<R, T>(rd: R, buf: T) -> Read<R, T>
where
R: AsyncRead,
T: AsMut<[u8]>,
{
Read {
state: State::Pending { rd: rd, buf: buf },
}
}
/// A future which can be used to easily read available number of bytes to fill
/// a buffer.
///
/// Created by the [`read`] function.
#[derive(Debug)]
pub struct Read<R, T> {
state: State<R, T>,
}
impl<R, T> Future for Read<R, T>
where
R: AsyncRead,
T: AsMut<[u8]>,
{
type Item = (R, T, usize);
type Error = io::Error;
fn poll(&mut self) -> Poll<(R, T, usize), io::Error> {
let nread = match self.state {
State::Pending {
ref mut rd,
ref mut buf,
} => try_ready!(rd.poll_read(&mut buf.as_mut()[..])),
State::Empty => panic!("poll a Read after it's done"),
};
match mem::replace(&mut self.state, State::Empty) {
State::Pending { rd, buf } => Ok((rd, buf, nread).into()),
State::Empty => panic!("invalid internal state"),
}
}
}
-83
View File
@@ -1,83 +0,0 @@
use crate::AsyncRead;
use futures::{try_ready, Future, Poll};
use std::io;
use std::mem;
/// A future which can be used to easily read exactly enough bytes to fill
/// a buffer.
///
/// Created by the [`read_exact`] function.
///
/// [`read_exact`]: fn.read_exact.html
#[derive(Debug)]
pub struct ReadExact<A, T> {
state: State<A, T>,
}
#[derive(Debug)]
enum State<A, T> {
Reading { a: A, buf: T, pos: usize },
Empty,
}
/// Creates a future which will read exactly enough bytes to fill `buf`,
/// returning an error if EOF is hit sooner.
///
/// The returned future will resolve to both the I/O stream as well as the
/// buffer once the read operation is completed.
///
/// In the case of an error the buffer and the object will be discarded, with
/// the error yielded. In the case of success the object will be destroyed and
/// the buffer will be returned, with all data read from the stream appended to
/// the buffer.
pub fn read_exact<A, T>(a: A, buf: T) -> ReadExact<A, T>
where
A: AsyncRead,
T: AsMut<[u8]>,
{
ReadExact {
state: State::Reading {
a: a,
buf: buf,
pos: 0,
},
}
}
fn eof() -> io::Error {
io::Error::new(io::ErrorKind::UnexpectedEof, "early eof")
}
impl<A, T> Future for ReadExact<A, T>
where
A: AsyncRead,
T: AsMut<[u8]>,
{
type Item = (A, T);
type Error = io::Error;
fn poll(&mut self) -> Poll<(A, T), io::Error> {
match self.state {
State::Reading {
ref mut a,
ref mut buf,
ref mut pos,
} => {
let buf = buf.as_mut();
while *pos < buf.len() {
let n = try_ready!(a.poll_read(&mut buf[*pos..]));
*pos += n;
if n == 0 {
return Err(eof());
}
}
}
State::Empty => panic!("poll a ReadExact after it's done"),
}
match mem::replace(&mut self.state, State::Empty) {
State::Reading { a, buf, .. } => Ok((a, buf).into()),
State::Empty => panic!(),
}
}
}
-64
View File
@@ -1,64 +0,0 @@
use crate::AsyncRead;
use futures::{Future, Poll};
use std::io;
use std::mem;
/// A future which can be used to easily read the entire contents of a stream
/// into a vector.
///
/// Created by the [`read_to_end`] function.
///
/// [`read_to_end`]: fn.read_to_end.html
#[derive(Debug)]
pub struct ReadToEnd<A> {
state: State<A>,
}
#[derive(Debug)]
enum State<A> {
Reading { a: A, buf: Vec<u8> },
Empty,
}
/// Creates a future which will read all the bytes associated with the I/O
/// object `A` into the buffer provided.
///
/// In the case of an error the buffer and the object will be discarded, with
/// the error yielded. In the case of success both the object and the buffer
/// will be returned, with all data read from the stream appended to the buffer.
pub fn read_to_end<A>(a: A, buf: Vec<u8>) -> ReadToEnd<A>
where
A: AsyncRead,
{
ReadToEnd {
state: State::Reading { a: a, buf: buf },
}
}
impl<A> Future for ReadToEnd<A>
where
A: AsyncRead,
{
type Item = (A, Vec<u8>);
type Error = io::Error;
fn poll(&mut self) -> Poll<(A, Vec<u8>), io::Error> {
match self.state {
State::Reading {
ref mut a,
ref mut buf,
} => {
// If we get `Ok`, then we know the stream hit EOF and we're done. If we
// hit "would block" then all the read data so far is in our buffer, and
// otherwise we propagate errors
try_nb!(a.read_to_end(buf));
}
State::Empty => panic!("poll ReadToEnd after it's done"),
}
match mem::replace(&mut self.state, State::Empty) {
State::Reading { a, buf } => Ok((a, buf).into()),
State::Empty => unreachable!(),
}
}
}
-74
View File
@@ -1,74 +0,0 @@
use crate::AsyncRead;
use futures::{Future, Poll};
use std::io::{self, BufRead};
use std::mem;
/// A future which can be used to easily read the contents of a stream into a
/// vector until the delimiter is reached.
///
/// Created by the [`read_until`] function.
///
/// [`read_until`]: fn.read_until.html
#[derive(Debug)]
pub struct ReadUntil<A> {
state: State<A>,
}
#[derive(Debug)]
enum State<A> {
Reading { a: A, byte: u8, buf: Vec<u8> },
Empty,
}
/// Creates a future which will read all the bytes associated with the I/O
/// object `A` into the buffer provided until the delimiter `byte` is reached.
/// This method is the async equivalent to [`BufRead::read_until`].
///
/// In case of an error the buffer and the object will be discarded, with
/// the error yielded. In the case of success the object will be destroyed and
/// the buffer will be returned, with all bytes up to, and including, the delimiter
/// (if found).
///
/// [`BufRead::read_until`]: https://doc.rust-lang.org/std/io/trait.BufRead.html#method.read_until
pub fn read_until<A>(a: A, byte: u8, buf: Vec<u8>) -> ReadUntil<A>
where
A: AsyncRead + BufRead,
{
ReadUntil {
state: State::Reading {
a: a,
byte: byte,
buf: buf,
},
}
}
impl<A> Future for ReadUntil<A>
where
A: AsyncRead + BufRead,
{
type Item = (A, Vec<u8>);
type Error = io::Error;
fn poll(&mut self) -> Poll<(A, Vec<u8>), io::Error> {
match self.state {
State::Reading {
ref mut a,
byte,
ref mut buf,
} => {
// If we get `Ok(n)`, then we know the stream hit EOF or the delimiter.
// and just return it, as we are finished.
// If we hit "would block" then all the read data so far
// is in our buffer, and otherwise we propagate errors.
try_nb!(a.read_until(byte, buf));
}
State::Empty => panic!("poll ReadUntil after it's done"),
}
match mem::replace(&mut self.state, State::Empty) {
State::Reading { a, byte: _, buf } => Ok((a, buf).into()),
State::Empty => unreachable!(),
}
}
}
-42
View File
@@ -1,42 +0,0 @@
use crate::AsyncWrite;
use futures::{try_ready, Async, Future, Poll};
use std::io;
/// A future used to fully shutdown an I/O object.
///
/// Resolves to the underlying I/O object once the shutdown operation is
/// complete.
///
/// Created by the [`shutdown`] function.
///
/// [`shutdown`]: fn.shutdown.html
#[derive(Debug)]
pub struct Shutdown<A> {
a: Option<A>,
}
/// Creates a future which will entirely shutdown an I/O object and then yield
/// the object itself.
///
/// This function will consume the object provided if an error happens, and
/// otherwise it will repeatedly call `shutdown` until it sees `Ok(())`,
/// scheduling a retry if `WouldBlock` is seen along the way.
pub fn shutdown<A>(a: A) -> Shutdown<A>
where
A: AsyncWrite,
{
Shutdown { a: Some(a) }
}
impl<A> Future for Shutdown<A>
where
A: AsyncWrite,
{
type Item = A;
type Error = io::Error;
fn poll(&mut self) -> Poll<A, io::Error> {
try_ready!(self.a.as_mut().unwrap().shutdown());
Ok(Async::Ready(self.a.take().unwrap()))
}
}
-86
View File
@@ -1,86 +0,0 @@
use crate::AsyncWrite;
use futures::{try_ready, Future, Poll};
use std::io;
use std::mem;
/// A future used to write the entire contents of some data to a stream.
///
/// This is created by the [`write_all`] top-level method.
///
/// [`write_all`]: fn.write_all.html
#[derive(Debug)]
pub struct WriteAll<A, T> {
state: State<A, T>,
}
#[derive(Debug)]
enum State<A, T> {
Writing { a: A, buf: T, pos: usize },
Empty,
}
/// Creates a future that will write the entire contents of the buffer `buf` to
/// the stream `a` provided.
///
/// The returned future will not return until all the data has been written, and
/// the future will resolve to the stream as well as the buffer (for reuse if
/// needed).
///
/// Any error which happens during writing will cause both the stream and the
/// buffer to get destroyed.
///
/// The `buf` parameter here only requires the `AsRef<[u8]>` trait, which should
/// be broadly applicable to accepting data which can be converted to a slice.
/// The `Window` struct is also available in this crate to provide a different
/// window into a slice if necessary.
pub fn write_all<A, T>(a: A, buf: T) -> WriteAll<A, T>
where
A: AsyncWrite,
T: AsRef<[u8]>,
{
WriteAll {
state: State::Writing {
a: a,
buf: buf,
pos: 0,
},
}
}
fn zero_write() -> io::Error {
io::Error::new(io::ErrorKind::WriteZero, "zero-length write")
}
impl<A, T> Future for WriteAll<A, T>
where
A: AsyncWrite,
T: AsRef<[u8]>,
{
type Item = (A, T);
type Error = io::Error;
fn poll(&mut self) -> Poll<(A, T), io::Error> {
match self.state {
State::Writing {
ref mut a,
ref buf,
ref mut pos,
} => {
let buf = buf.as_ref();
while *pos < buf.len() {
let n = try_ready!(a.poll_write(&buf[*pos..]));
*pos += n;
if n == 0 {
return Err(zero_write());
}
}
}
State::Empty => panic!("poll a WriteAll after it's done"),
}
match mem::replace(&mut self.state, State::Empty) {
State::Writing { a, buf, .. } => Ok((a, buf).into()),
State::Empty => panic!(),
}
}
}
-936
View File
@@ -1,936 +0,0 @@
#![allow(deprecated)]
use crate::{codec, AsyncRead, AsyncWrite};
use bytes::buf::Chain;
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream};
use std::error::Error as StdError;
use std::io::{self, Cursor};
use std::{cmp, fmt};
/// Configure length delimited `FramedRead`, `FramedWrite`, and `Framed` values.
///
/// `Builder` enables constructing configured length delimited framers. Note
/// that not all configuration settings apply to both encoding and decoding. See
/// the documentation for specific methods for more detail.
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct Builder {
// Maximum frame length
max_frame_len: usize,
// Number of bytes representing the field length
length_field_len: usize,
// Number of bytes in the header before the length field
length_field_offset: usize,
// Adjust the length specified in the header field by this amount
length_adjustment: isize,
// Total number of bytes to skip before reading the payload, if not set,
// `length_field_len + length_field_offset`
num_skip: Option<usize>,
// Length field byte order (little or big endian)
length_field_is_big_endian: bool,
}
/// Adapts a byte stream into a unified `Stream` and `Sink` that works over
/// entire frame values.
///
/// See [module level] documentation for more detail.
///
/// [module level]: index.html
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct Framed<T, B: IntoBuf = BytesMut> {
inner: FramedRead<FramedWrite<T, B>>,
}
/// Adapts a byte stream to a `Stream` yielding entire frame values.
///
/// See [module level] documentation for more detail.
///
/// [module level]: index.html
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
#[derive(Debug)]
pub struct FramedRead<T> {
inner: codec::FramedRead<T, Decoder>,
}
/// An error when the number of bytes read is more than max frame length.
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FrameTooBig {
_priv: (),
}
#[derive(Debug)]
struct Decoder {
// Configuration values
builder: Builder,
// Read state
state: DecodeState,
}
#[derive(Debug, Clone, Copy)]
enum DecodeState {
Head,
Data(usize),
}
/// Adapts a byte stream to a `Sink` accepting entire frame values.
///
/// See [module level] documentation for more detail.
///
/// [module level]: index.html
#[deprecated(since = "0.1.8", note = "Moved to tokio-codec")]
#[doc(hidden)]
pub struct FramedWrite<T, B: IntoBuf = BytesMut> {
// I/O type
inner: T,
// Configuration values
builder: Builder,
// Current frame being written
frame: Option<Chain<Cursor<BytesMut>, B::Buf>>,
}
// ===== impl Framed =====
impl<T: AsyncRead + AsyncWrite, B: IntoBuf> Framed<T, B> {
/// Creates a new `Framed` with default configuration values.
pub fn new(inner: T) -> Framed<T, B> {
Builder::new().new_framed(inner)
}
}
impl<T, B: IntoBuf> Framed<T, B> {
/// Returns a reference to the underlying I/O stream wrapped by `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
self.inner.get_ref().get_ref()
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_mut(&mut self) -> &mut T {
self.inner.get_mut().get_mut()
}
/// Consumes the `Framed`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn into_inner(self) -> T {
self.inner.into_inner().into_inner()
}
}
impl<T: AsyncRead, B: IntoBuf> Stream for Framed<T, B> {
type Item = BytesMut;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<BytesMut>, io::Error> {
self.inner.poll()
}
}
impl<T: AsyncWrite, B: IntoBuf> Sink for Framed<T, B> {
type SinkItem = B;
type SinkError = io::Error;
fn start_send(&mut self, item: B) -> StartSend<B, io::Error> {
self.inner.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), io::Error> {
self.inner.poll_complete()
}
fn close(&mut self) -> Poll<(), io::Error> {
self.inner.close()
}
}
impl<T, B: IntoBuf> fmt::Debug for Framed<T, B>
where
T: fmt::Debug,
B::Buf: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Framed")
.field("inner", &self.inner)
.finish()
}
}
// ===== impl FramedRead =====
impl<T: AsyncRead> FramedRead<T> {
/// Creates a new `FramedRead` with default configuration values.
pub fn new(inner: T) -> FramedRead<T> {
Builder::new().new_read(inner)
}
}
impl<T> FramedRead<T> {
/// Returns the current max frame setting
///
/// This is the largest size this codec will accept from the wire. Larger
/// frames will be rejected.
pub fn max_frame_length(&self) -> usize {
self.inner.decoder().builder.max_frame_len
}
/// Updates the max frame setting.
///
/// The change takes effect the next time a frame is decoded. In other
/// words, if a frame is currently in process of being decoded with a frame
/// size greater than `val` but less than the max frame length in effect
/// before calling this function, then the frame will be allowed.
pub fn set_max_frame_length(&mut self, val: usize) {
self.inner.decoder_mut().builder.max_frame_length(val);
}
/// Returns a reference to the underlying I/O stream wrapped by `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
self.inner.get_ref()
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedRead`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_mut(&mut self) -> &mut T {
self.inner.get_mut()
}
/// Consumes the `FramedRead`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn into_inner(self) -> T {
self.inner.into_inner()
}
}
impl<T: AsyncRead> Stream for FramedRead<T> {
type Item = BytesMut;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<BytesMut>, io::Error> {
self.inner.poll()
}
}
impl<T: Sink> Sink for FramedRead<T> {
type SinkItem = T::SinkItem;
type SinkError = T::SinkError;
fn start_send(&mut self, item: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> {
self.inner.start_send(item)
}
fn poll_complete(&mut self) -> Poll<(), T::SinkError> {
self.inner.poll_complete()
}
fn close(&mut self) -> Poll<(), T::SinkError> {
self.inner.close()
}
}
impl<T: io::Write> io::Write for FramedRead<T> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
self.inner.get_mut().write(src)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.get_mut().flush()
}
}
impl<T: AsyncWrite> AsyncWrite for FramedRead<T> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.inner.get_mut().shutdown()
}
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
self.inner.get_mut().write_buf(buf)
}
}
// ===== impl Decoder ======
impl Decoder {
fn decode_head(&mut self, src: &mut BytesMut) -> io::Result<Option<usize>> {
let head_len = self.builder.num_head_bytes();
let field_len = self.builder.length_field_len;
if src.len() < head_len {
// Not enough data
return Ok(None);
}
let n = {
let mut src = Cursor::new(&mut *src);
// Skip the required bytes
src.advance(self.builder.length_field_offset);
// match endianess
let n = if self.builder.length_field_is_big_endian {
src.get_uint_be(field_len)
} else {
src.get_uint_le(field_len)
};
if n > self.builder.max_frame_len as u64 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
FrameTooBig { _priv: () },
));
}
// The check above ensures there is no overflow
let n = n as usize;
// Adjust `n` with bounds checking
let n = if self.builder.length_adjustment < 0 {
n.checked_sub(-self.builder.length_adjustment as usize)
} else {
n.checked_add(self.builder.length_adjustment as usize)
};
// Error handling
match n {
Some(n) => n,
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"provided length would overflow after adjustment",
));
}
}
};
let num_skip = self.builder.get_num_skip();
if num_skip > 0 {
let _ = src.split_to(num_skip);
}
// Ensure that the buffer has enough space to read the incoming
// payload
src.reserve(n);
return Ok(Some(n));
}
fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
// At this point, the buffer has already had the required capacity
// reserved. All there is to do is read.
if src.len() < n {
return Ok(None);
}
Ok(Some(src.split_to(n)))
}
}
impl codec::Decoder for Decoder {
type Item = BytesMut;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
let n = match self.state {
DecodeState::Head => match self.decode_head(src)? {
Some(n) => {
self.state = DecodeState::Data(n);
n
}
None => return Ok(None),
},
DecodeState::Data(n) => n,
};
match self.decode_data(n, src)? {
Some(data) => {
// Update the decode state
self.state = DecodeState::Head;
// Make sure the buffer has enough space to read the next head
src.reserve(self.builder.num_head_bytes());
Ok(Some(data))
}
None => Ok(None),
}
}
}
// ===== impl FramedWrite =====
impl<T: AsyncWrite, B: IntoBuf> FramedWrite<T, B> {
/// Creates a new `FramedWrite` with default configuration values.
pub fn new(inner: T) -> FramedWrite<T, B> {
Builder::new().new_write(inner)
}
}
impl<T, B: IntoBuf> FramedWrite<T, B> {
/// Returns the current max frame setting
///
/// This is the largest size this codec will write to the wire. Larger
/// frames will be rejected.
pub fn max_frame_length(&self) -> usize {
self.builder.max_frame_len
}
/// Updates the max frame setting.
///
/// The change takes effect the next time a frame is encoded. In other
/// words, if a frame is currently in process of being encoded with a frame
/// size greater than `val` but less than the max frame length in effect
/// before calling this function, then the frame will be allowed.
pub fn set_max_frame_length(&mut self, val: usize) {
self.builder.max_frame_length(val);
}
/// Returns a reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise
/// being worked with.
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `FramedWrite`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Consumes the `FramedWrite`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: AsyncWrite, B: IntoBuf> FramedWrite<T, B> {
// If there is a buffered frame, try to write it to `T`
fn do_write(&mut self) -> Poll<(), io::Error> {
if self.frame.is_none() {
return Ok(Async::Ready(()));
}
loop {
let frame = self.frame.as_mut().unwrap();
if try_ready!(self.inner.write_buf(frame)) == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write frame to transport",
));
}
if !frame.has_remaining() {
break;
}
}
self.frame = None;
Ok(Async::Ready(()))
}
fn set_frame(&mut self, buf: B::Buf) -> io::Result<()> {
let mut head = BytesMut::with_capacity(8);
let n = buf.remaining();
if n > self.builder.max_frame_len {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
FrameTooBig { _priv: () },
));
}
// Adjust `n` with bounds checking
let n = if self.builder.length_adjustment < 0 {
n.checked_add(-self.builder.length_adjustment as usize)
} else {
n.checked_sub(self.builder.length_adjustment as usize)
};
// Error handling
let n = match n {
Some(n) => n,
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"provided length would overflow after adjustment",
));
}
};
if self.builder.length_field_is_big_endian {
head.put_uint_be(n as u64, self.builder.length_field_len);
} else {
head.put_uint_le(n as u64, self.builder.length_field_len);
}
debug_assert!(self.frame.is_none());
self.frame = Some(head.into_buf().chain(buf));
Ok(())
}
}
impl<T: AsyncWrite, B: IntoBuf> Sink for FramedWrite<T, B> {
type SinkItem = B;
type SinkError = io::Error;
fn start_send(&mut self, item: B) -> StartSend<B, io::Error> {
if !self.do_write()?.is_ready() {
return Ok(AsyncSink::NotReady(item));
}
self.set_frame(item.into_buf())?;
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), io::Error> {
// Write any buffered frame to T
try_ready!(self.do_write());
// Try flushing the underlying IO
try_ready!(self.inner.poll_flush());
return Ok(Async::Ready(()));
}
fn close(&mut self) -> Poll<(), io::Error> {
try_ready!(self.poll_complete());
self.inner.shutdown()
}
}
impl<T: Stream, B: IntoBuf> Stream for FramedWrite<T, B> {
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> {
self.inner.poll()
}
}
impl<T: io::Read, B: IntoBuf> io::Read for FramedWrite<T, B> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.get_mut().read(dst)
}
}
impl<T: AsyncRead, U: IntoBuf> AsyncRead for FramedWrite<T, U> {
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
self.get_mut().read_buf(buf)
}
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.get_ref().prepare_uninitialized_buffer(buf)
}
}
impl<T, B: IntoBuf> fmt::Debug for FramedWrite<T, B>
where
T: fmt::Debug,
B::Buf: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FramedWrite")
.field("inner", &self.inner)
.field("builder", &self.builder)
.field("frame", &self.frame)
.finish()
}
}
// ===== impl Builder =====
impl Builder {
/// Creates a new length delimited framer builder with default configuration
/// values.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .length_field_offset(0)
/// .length_field_length(2)
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
/// # }
/// ```
pub fn new() -> Builder {
Builder {
// Default max frame length of 8MB
max_frame_len: 8 * 1_024 * 1_024,
// Default byte length of 4
length_field_len: 4,
// Default to the header field being at the start of the header.
length_field_offset: 0,
length_adjustment: 0,
// Total number of bytes to skip before reading the payload, if not set,
// `length_field_len + length_field_offset`
num_skip: None,
// Default to reading the length field in network (big) endian.
length_field_is_big_endian: true,
}
}
/// Read the length field as a big endian integer
///
/// This is the default setting.
///
/// This configuration option applies to both encoding and decoding.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .big_endian()
/// .new_read(io);
/// # }
/// ```
pub fn big_endian(&mut self) -> &mut Self {
self.length_field_is_big_endian = true;
self
}
/// Read the length field as a little endian integer
///
/// The default setting is big endian.
///
/// This configuration option applies to both encoding and decoding.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .little_endian()
/// .new_read(io);
/// # }
/// ```
pub fn little_endian(&mut self) -> &mut Self {
self.length_field_is_big_endian = false;
self
}
/// Read the length field as a native endian integer
///
/// The default setting is big endian.
///
/// This configuration option applies to both encoding and decoding.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .native_endian()
/// .new_read(io);
/// # }
/// ```
pub fn native_endian(&mut self) -> &mut Self {
if cfg!(target_endian = "big") {
self.big_endian()
} else {
self.little_endian()
}
}
/// Sets the max frame length
///
/// This configuration option applies to both encoding and decoding. The
/// default value is 8MB.
///
/// When decoding, the length field read from the byte stream is checked
/// against this setting **before** any adjustments are applied. When
/// encoding, the length of the submitted payload is checked against this
/// setting.
///
/// When frames exceed the max length, an `io::Error` with the custom value
/// of the `FrameTooBig` type will be returned.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .max_frame_length(8 * 1024)
/// .new_read(io);
/// # }
/// ```
pub fn max_frame_length(&mut self, val: usize) -> &mut Self {
self.max_frame_len = val;
self
}
/// Sets the number of bytes used to represent the length field
///
/// The default value is `4`. The max value is `8`.
///
/// This configuration option applies to both encoding and decoding.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .length_field_length(4)
/// .new_read(io);
/// # }
/// ```
pub fn length_field_length(&mut self, val: usize) -> &mut Self {
assert!(val > 0 && val <= 8, "invalid length field length");
self.length_field_len = val;
self
}
/// Sets the number of bytes in the header before the length field
///
/// This configuration option only applies to decoding.
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .length_field_offset(1)
/// .new_read(io);
/// # }
/// ```
pub fn length_field_offset(&mut self, val: usize) -> &mut Self {
self.length_field_offset = val;
self
}
/// Delta between the payload length specified in the header and the real
/// payload length
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .length_adjustment(-2)
/// .new_read(io);
/// # }
/// ```
pub fn length_adjustment(&mut self, val: isize) -> &mut Self {
self.length_adjustment = val;
self
}
/// Sets the number of bytes to skip before reading the payload
///
/// Default value is `length_field_len + length_field_offset`
///
/// This configuration option only applies to decoding
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .num_skip(4)
/// .new_read(io);
/// # }
/// ```
pub fn num_skip(&mut self, val: usize) -> &mut Self {
self.num_skip = Some(val);
self
}
/// Create a configured length delimited `FramedRead`
///
/// # Examples
///
/// ```
/// # use tokio_io::AsyncRead;
/// use tokio_io::codec::length_delimited::Builder;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// Builder::new()
/// .length_field_offset(0)
/// .length_field_length(2)
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
/// # }
/// ```
pub fn new_read<T>(&self, upstream: T) -> FramedRead<T>
where
T: AsyncRead,
{
FramedRead {
inner: codec::FramedRead::new(
upstream,
Decoder {
builder: *self,
state: DecodeState::Head,
},
),
}
}
/// Create a configured length delimited `FramedWrite`
///
/// # Examples
///
/// ```
/// use tokio_io::AsyncWrite;
/// use tokio_io::codec::length_delimited;
/// use bytes::BytesMut;
///
/// # fn write_frame<T: AsyncWrite>(io: T) {
/// # let _: length_delimited::FramedWrite<T, BytesMut> =
/// length_delimited::Builder::new()
/// .length_field_length(2)
/// .new_write(io);
/// # }
/// ```
pub fn new_write<T, B>(&self, inner: T) -> FramedWrite<T, B>
where
T: AsyncWrite,
B: IntoBuf,
{
FramedWrite {
inner: inner,
builder: *self,
frame: None,
}
}
/// Create a configured length delimited `Framed`
///
/// # Examples
///
/// ```
/// use tokio_io::{AsyncRead, AsyncWrite};
/// use tokio_io::codec::length_delimited;
/// use bytes::BytesMut;
///
/// # fn write_frame<T: AsyncRead + AsyncWrite>(io: T) {
/// # let _: length_delimited::Framed<T, BytesMut> =
/// length_delimited::Builder::new()
/// .length_field_length(2)
/// .new_framed(io);
/// # }
/// ```
pub fn new_framed<T, B>(&self, inner: T) -> Framed<T, B>
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
let inner = self.new_read(self.new_write(inner));
Framed { inner: inner }
}
fn num_head_bytes(&self) -> usize {
let num = self.length_field_offset + self.length_field_len;
cmp::max(num, self.num_skip.unwrap_or(0))
}
fn get_num_skip(&self) -> usize {
self.num_skip
.unwrap_or(self.length_field_offset + self.length_field_len)
}
}
// ===== impl FrameTooBig =====
impl fmt::Debug for FrameTooBig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FrameTooBig").finish()
}
}
impl fmt::Display for FrameTooBig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.description())
}
}
impl StdError for FrameTooBig {
fn description(&self) -> &str {
"frame size too big"
}
}
+4 -40
View File
@@ -2,6 +2,7 @@
#![deny(missing_debug_implementations, missing_docs, rust_2018_idioms)]
#![cfg_attr(test, deny(warnings))]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
//#![feature(async_await)]
//! Core I/O traits and combinators when working with Tokio.
//!
@@ -11,54 +12,17 @@
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper-tokio/core-low-level/
use futures::{Future, Stream};
use std::io as std_io;
/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = Box<dyn Future<Item = T, Error = std_io::Error> + Send>;
/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = Box<dyn Stream<Item = T, Error = std_io::Error> + Send>;
/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
///
/// This macro takes `io::Result<T>` as input, and returns `T` as the output. If
/// the input type is of the `Err` variant, then `Poll::NotReady` is returned if
/// it indicates `WouldBlock` or otherwise `Err` is returned.
#[macro_export]
macro_rules! try_nb {
macro_rules! ready {
($e:expr) => {
match $e {
Ok(t) => t,
Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => {
return Ok(::futures::Async::NotReady);
}
Err(e) => return Err(e.into()),
::std::task::Poll::Ready(t) => t,
::std::task::Poll::Pending => return ::std::task::Poll::Pending,
}
};
}
pub mod codec;
pub mod io;
pub mod _tokio_codec;
mod allow_std;
mod async_read;
mod async_write;
mod framed;
mod framed_read;
mod framed_write;
mod length_delimited;
mod lines;
mod split;
mod window;
pub use self::async_read::AsyncRead;
pub use self::async_write::AsyncWrite;
fn _assert_objects() {
fn _assert<T>() {}
_assert::<Box<dyn AsyncRead>>();
_assert::<Box<dyn AsyncWrite>>();
}
-60
View File
@@ -1,60 +0,0 @@
use crate::AsyncRead;
use futures::{Poll, Stream};
use std::io::{self, BufRead};
use std::mem;
/// Combinator created by the top-level `lines` method which is a stream over
/// the lines of text on an I/O object.
#[derive(Debug)]
pub struct Lines<A> {
io: A,
line: String,
}
/// Creates a new stream from the I/O object given representing the lines of
/// input that are found on `A`.
///
/// This method takes an asynchronous I/O object, `a`, and returns a `Stream` of
/// lines that the object contains. The returned stream will reach its end once
/// `a` reaches EOF.
pub fn lines<A>(a: A) -> Lines<A>
where
A: AsyncRead + BufRead,
{
Lines {
io: a,
line: String::new(),
}
}
impl<A> Lines<A> {
/// Returns the underlying I/O object.
///
/// Note that this may lose data already read into internal buffers. It's
/// recommended to only call this once the stream has reached its end.
pub fn into_inner(self) -> A {
self.io
}
}
impl<A> Stream for Lines<A>
where
A: AsyncRead + BufRead,
{
type Item = String;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<String>, io::Error> {
let n = try_nb!(self.io.read_line(&mut self.line));
if n == 0 && self.line.len() == 0 {
return Ok(None.into());
}
if self.line.ends_with("\n") {
self.line.pop();
if self.line.ends_with("\r") {
self.line.pop();
}
}
Ok(Some(mem::replace(&mut self.line, String::new())).into())
}
}
-243
View File
@@ -1,243 +0,0 @@
use crate::{AsyncRead, AsyncWrite};
use bytes::{Buf, BufMut};
use futures::sync::BiLock;
use futures::{try_ready, Async, Poll};
use std::io::{self, Read, Write};
/// The readable half of an object returned from `AsyncRead::split`.
#[derive(Debug)]
pub struct ReadHalf<T> {
handle: BiLock<T>,
}
impl<T: AsyncRead + AsyncWrite> ReadHalf<T> {
/// Reunite with a previously split `WriteHalf`.
///
/// # Panics
///
/// If this `ReadHalf` and the given `WriteHalf` do not originate from
/// the same `AsyncRead::split` operation this method will panic.
pub fn unsplit(self, w: WriteHalf<T>) -> T {
if let Ok(x) = self.handle.reunite(w.handle) {
x
} else {
panic!("Unrelated `WriteHalf` passed to `ReadHalf::unsplit`.")
}
}
}
/// The writable half of an object returned from `AsyncRead::split`.
#[derive(Debug)]
pub struct WriteHalf<T> {
handle: BiLock<T>,
}
impl<T: AsyncRead + AsyncWrite> WriteHalf<T> {
/// Reunite with a previously split `ReadHalf`.
///
/// # panics
///
/// If this `WriteHalf` and the given `ReadHalf` do not originate from
/// the same `AsyncRead::split` operation this method will panic.
pub fn unsplit(self, r: ReadHalf<T>) -> T {
if let Ok(x) = self.handle.reunite(r.handle) {
x
} else {
panic!("Unrelated `ReadHalf` passed to `WriteHalf::unsplit`.")
}
}
}
pub fn split<T: AsyncRead + AsyncWrite>(t: T) -> (ReadHalf<T>, WriteHalf<T>) {
let (a, b) = BiLock::new(t);
(ReadHalf { handle: a }, WriteHalf { handle: b })
}
fn would_block() -> io::Error {
io::Error::new(io::ErrorKind::WouldBlock, "would block")
}
impl<T: AsyncRead> Read for ReadHalf<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.handle.poll_lock() {
Async::Ready(mut l) => l.read(buf),
Async::NotReady => Err(would_block()),
}
}
}
impl<T: AsyncRead> AsyncRead for ReadHalf<T> {
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
let mut l = try_ready!(wrap_as_io(self.handle.poll_lock()));
l.read_buf(buf)
}
}
impl<T: AsyncWrite> Write for WriteHalf<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self.handle.poll_lock() {
Async::Ready(mut l) => l.write(buf),
Async::NotReady => Err(would_block()),
}
}
fn flush(&mut self) -> io::Result<()> {
match self.handle.poll_lock() {
Async::Ready(mut l) => l.flush(),
Async::NotReady => Err(would_block()),
}
}
}
impl<T: AsyncWrite> AsyncWrite for WriteHalf<T> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
let mut l = try_ready!(wrap_as_io(self.handle.poll_lock()));
l.shutdown()
}
fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
where
Self: Sized,
{
let mut l = try_ready!(wrap_as_io(self.handle.poll_lock()));
l.write_buf(buf)
}
}
fn wrap_as_io<T>(t: Async<T>) -> Result<Async<T>, io::Error> {
Ok(t)
}
#[cfg(test)]
mod tests {
use super::{AsyncRead, AsyncWrite, ReadHalf, WriteHalf};
use bytes::{BytesMut, IntoBuf};
use futures::sync::BiLock;
use futures::{future::lazy, future::ok, Async, Poll};
use std::io::{self, Read, Write};
use tokio_current_thread;
struct RW;
impl Read for RW {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Ok(1)
}
}
impl AsyncRead for RW {}
impl Write for RW {
fn write(&mut self, _: &[u8]) -> io::Result<usize> {
Ok(1)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl AsyncWrite for RW {
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(Async::Ready(()))
}
}
#[test]
fn split_readhalf_translate_wouldblock_to_not_ready() {
tokio_current_thread::block_on_all(lazy(move || {
let rw = RW {};
let (a, b) = BiLock::new(rw);
let mut rx = ReadHalf { handle: a };
let mut buf = BytesMut::with_capacity(64);
// First read is uncontended, should go through.
assert!(rx.read_buf(&mut buf).unwrap().is_ready());
// Take lock from write side.
let lock = b.poll_lock();
// Second read should be NotReady.
assert!(!rx.read_buf(&mut buf).unwrap().is_ready());
drop(lock);
// Back to uncontended.
assert!(rx.read_buf(&mut buf).unwrap().is_ready());
ok::<(), ()>(())
}))
.unwrap();
}
#[test]
fn split_writehalf_translate_wouldblock_to_not_ready() {
tokio_current_thread::block_on_all(lazy(move || {
let rw = RW {};
let (a, b) = BiLock::new(rw);
let mut tx = WriteHalf { handle: a };
let bufmut = BytesMut::with_capacity(64);
let mut buf = bufmut.into_buf();
// First write is uncontended, should go through.
assert!(tx.write_buf(&mut buf).unwrap().is_ready());
// Take lock from read side.
let lock = b.poll_lock();
// Second write should be NotReady.
assert!(!tx.write_buf(&mut buf).unwrap().is_ready());
drop(lock);
// Back to uncontended.
assert!(tx.write_buf(&mut buf).unwrap().is_ready());
ok::<(), ()>(())
}))
.unwrap();
}
#[test]
fn unsplit_ok() {
let (r, w) = RW.split();
r.unsplit(w);
let (r, w) = RW.split();
w.unsplit(r);
}
#[test]
#[should_panic]
fn unsplit_err1() {
let (r, _) = RW.split();
let (_, w) = RW.split();
r.unsplit(w);
}
#[test]
#[should_panic]
fn unsplit_err2() {
let (_, w) = RW.split();
let (r, _) = RW.split();
r.unsplit(w);
}
#[test]
#[should_panic]
fn unsplit_err3() {
let (_, w) = RW.split();
let (r, _) = RW.split();
w.unsplit(r);
}
#[test]
#[should_panic]
fn unsplit_err4() {
let (r, _) = RW.split();
let (_, w) = RW.split();
w.unsplit(r);
}
}
-117
View File
@@ -1,117 +0,0 @@
use std::ops;
/// A owned window around an underlying buffer.
///
/// Normally slices work great for considering sub-portions of a buffer, but
/// unfortunately a slice is a *borrowed* type in Rust which has an associated
/// lifetime. When working with future and async I/O these lifetimes are not
/// always appropriate, and are sometimes difficult to store in tasks. This
/// type strives to fill this gap by providing an "owned slice" around an
/// underlying buffer of bytes.
///
/// A `Window<T>` wraps an underlying buffer, `T`, and has configurable
/// start/end indexes to alter the behavior of the `AsRef<[u8]>` implementation
/// that this type carries.
///
/// This type can be particularly useful when working with the `write_all`
/// combinator in this crate. Data can be sliced via `Window`, consumed by
/// `write_all`, and then earned back once the write operation finishes through
/// the `into_inner` method on this type.
#[derive(Debug)]
pub struct Window<T> {
inner: T,
range: ops::Range<usize>,
}
impl<T: AsRef<[u8]>> Window<T> {
/// Creates a new window around the buffer `t` defaulting to the entire
/// slice.
///
/// Further methods can be called on the returned `Window<T>` to alter the
/// window into the data provided.
pub fn new(t: T) -> Window<T> {
Window {
range: 0..t.as_ref().len(),
inner: t,
}
}
/// Gets a shared reference to the underlying buffer inside of this
/// `Window`.
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying buffer inside of this
/// `Window`.
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Consumes this `Window`, returning the underlying buffer.
pub fn into_inner(self) -> T {
self.inner
}
/// Returns the starting index of this window into the underlying buffer
/// `T`.
pub fn start(&self) -> usize {
self.range.start
}
/// Returns the end index of this window into the underlying buffer
/// `T`.
pub fn end(&self) -> usize {
self.range.end
}
/// Changes the starting index of this window to the index specified.
///
/// Returns the windows back to chain multiple calls to this method.
///
/// # Panics
///
/// This method will panic if `start` is out of bounds for the underlying
/// slice or if it comes after the `end` configured in this window.
pub fn set_start(&mut self, start: usize) -> &mut Window<T> {
assert!(start <= self.inner.as_ref().len());
assert!(start <= self.range.end);
self.range.start = start;
self
}
/// Changes the end index of this window to the index specified.
///
/// Returns the windows back to chain multiple calls to this method.
///
/// # Panics
///
/// This method will panic if `end` is out of bounds for the underlying
/// slice or if it comes before the `start` configured in this window.
pub fn set_end(&mut self, end: usize) -> &mut Window<T> {
assert!(end <= self.inner.as_ref().len());
assert!(self.range.start <= end);
self.range.end = end;
self
}
// TODO: how about a generic set() method along the lines of:
//
// buffer.set(..3)
// .set(0..2)
// .set(4..)
//
// etc.
}
impl<T: AsRef<[u8]>> AsRef<[u8]> for Window<T> {
fn as_ref(&self) -> &[u8] {
&self.inner.as_ref()[self.range.start..self.range.end]
}
}
impl<T: AsMut<[u8]>> AsMut<[u8]> for Window<T> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.inner.as_mut()[self.range.start..self.range.end]
}
}
+97 -75
View File
@@ -1,144 +1,166 @@
use bytes::{BufMut, BytesMut};
use futures::Async;
use std::io::{self, Read};
use tokio_io::AsyncRead;
use tokio_test::{assert_ready_ok, assert_ready_err};
use tokio_test::task::MockTask;
use bytes::{BufMut, BytesMut};
use pin_utils::pin_mut;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
#[test]
fn assert_obj_safe() {
fn _assert<T>() {}
_assert::<Box<dyn AsyncRead>>();
}
#[test]
fn read_buf_success() {
struct R;
struct Rd;
impl Read for R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
impl AsyncRead for Rd {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8]) -> Poll<io::Result<usize>>
{
buf[0..11].copy_from_slice(b"hello world");
Ok(11)
Poll::Ready(Ok(11))
}
}
impl AsyncRead for R {}
let mut buf = BytesMut::with_capacity(65);
let mut task = MockTask::new();
let n = match R.read_buf(&mut buf).unwrap() {
Async::Ready(n) => n,
_ => panic!(),
};
task.enter(|cx| {
let rd = Rd;
pin_mut!(rd);
assert_eq!(11, n);
assert_eq!(buf[..], b"hello world"[..]);
let n = assert_ready_ok!(rd.poll_read_buf(cx, &mut buf));
assert_eq!(11, n);
assert_eq!(buf[..], b"hello world"[..]);
});
}
#[test]
fn read_buf_error() {
struct R;
struct Rd;
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::Other, "other"))
impl AsyncRead for Rd {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
_buf: &mut [u8]) -> Poll<io::Result<usize>>
{
let err = io::ErrorKind::Other.into();
Poll::Ready(Err(err))
}
}
impl AsyncRead for R {}
let mut buf = BytesMut::with_capacity(65);
let mut task = MockTask::new();
let err = R.read_buf(&mut buf).unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::Other);
task.enter(|cx| {
let rd = Rd;
pin_mut!(rd);
let err = assert_ready_err!(rd.poll_read_buf(cx, &mut buf));
assert_eq!(err.kind(), io::ErrorKind::Other);
});
}
#[test]
fn read_buf_no_capacity() {
struct R;
struct Rd;
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
impl AsyncRead for Rd {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
_buf: &mut [u8]) -> Poll<io::Result<usize>>
{
unimplemented!();
}
}
impl AsyncRead for R {}
// Can't create BytesMut w/ zero capacity, so fill it up
let mut buf = BytesMut::with_capacity(64);
let mut task = MockTask::new();
buf.put(&[0; 64][..]);
let n = match R.read_buf(&mut buf).unwrap() {
Async::Ready(n) => n,
_ => panic!(),
};
task.enter(|cx| {
let rd = Rd;
pin_mut!(rd);
assert_eq!(0, n);
let n = assert_ready_ok!(rd.poll_read_buf(cx, &mut buf));
assert_eq!(0, n);
});
}
#[test]
fn read_buf_no_uninitialized() {
struct R;
struct Rd;
impl Read for R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
impl AsyncRead for Rd {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8]) -> Poll<io::Result<usize>>
{
for b in buf {
assert_eq!(0, *b);
}
Ok(0)
Poll::Ready(Ok(0))
}
}
impl AsyncRead for R {}
// Can't create BytesMut w/ zero capacity, so fill it up
let mut buf = BytesMut::with_capacity(64);
let mut task = MockTask::new();
let n = match R.read_buf(&mut buf).unwrap() {
Async::Ready(n) => n,
_ => panic!(),
};
task.enter(|cx| {
let rd = Rd;
pin_mut!(rd);
assert_eq!(0, n);
let n = assert_ready_ok!(rd.poll_read_buf(cx, &mut buf));
assert_eq!(0, n);
});
}
#[test]
fn read_buf_uninitialized_ok() {
struct R;
struct Rd;
impl Read for R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
assert_eq!(buf[0..11], b"hello world"[..]);
Ok(0)
}
}
impl AsyncRead for R {
impl AsyncRead for Rd {
unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
false
}
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8]) -> Poll<io::Result<usize>>
{
assert_eq!(buf[0..11], b"hello world"[..]);
Poll::Ready(Ok(0))
}
}
// Can't create BytesMut w/ zero capacity, so fill it up
let mut buf = BytesMut::with_capacity(64);
let mut task = MockTask::new();
unsafe {
buf.bytes_mut()[0..11].copy_from_slice(b"hello world");
}
let n = match R.read_buf(&mut buf).unwrap() {
Async::Ready(n) => n,
_ => panic!(),
};
task.enter(|cx| {
let rd = Rd;
pin_mut!(rd);
assert_eq!(0, n);
}
#[test]
fn read_buf_translate_wouldblock_to_not_ready() {
struct R;
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
}
}
impl AsyncRead for R {}
let mut buf = BytesMut::with_capacity(65);
assert!(!R.read_buf(&mut buf).unwrap().is_ready());
let n = assert_ready_ok!(rd.poll_read_buf(cx, &mut buf));
assert_eq!(0, n);
});
}
-548
View File
@@ -1,548 +0,0 @@
// This file is testing deprecated code.
#![allow(deprecated)]
use futures::Async::*;
use futures::{Poll, Sink, Stream};
use std::collections::VecDeque;
use std::io;
use tokio_io::codec::length_delimited::*;
use tokio_io::{AsyncRead, AsyncWrite};
macro_rules! mock {
($($x:expr,)*) => {{
let mut v = VecDeque::new();
v.extend(vec![$($x),*]);
Mock { calls: v }
}};
}
#[test]
fn read_empty_io_yields_nothing() {
let mut io = FramedRead::new(mock!());
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_frame_one_packet() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00\x00\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_frame_one_packet_little_endian() {
let mut io = Builder::new().little_endian().new_read(mock! {
Ok(b"\x09\x00\x00\x00abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_frame_one_packet_native_endian() {
let data = if cfg!(target_endian = "big") {
b"\x00\x00\x00\x09abcdefghi"
} else {
b"\x09\x00\x00\x00abcdefghi"
};
let mut io = Builder::new().native_endian().new_read(mock! {
Ok(data[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_multi_frame_one_packet() {
let mut data: Vec<u8> = vec![];
data.extend_from_slice(b"\x00\x00\x00\x09abcdefghi");
data.extend_from_slice(b"\x00\x00\x00\x03123");
data.extend_from_slice(b"\x00\x00\x00\x0bhello world");
let mut io = FramedRead::new(mock! {
Ok(data.into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"123"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"hello world"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_frame_multi_packet() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00"[..].into()),
Ok(b"\x00\x09abc"[..].into()),
Ok(b"defghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_multi_frame_multi_packet() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00"[..].into()),
Ok(b"\x00\x09abc"[..].into()),
Ok(b"defghi"[..].into()),
Ok(b"\x00\x00\x00\x0312"[..].into()),
Ok(b"3\x00\x00\x00\x0bhello world"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"123"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"hello world"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_frame_multi_packet_wait() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00"[..].into()),
Err(would_block()),
Ok(b"\x00\x09abc"[..].into()),
Err(would_block()),
Ok(b"defghi"[..].into()),
Err(would_block()),
});
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_multi_frame_multi_packet_wait() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00"[..].into()),
Err(would_block()),
Ok(b"\x00\x09abc"[..].into()),
Err(would_block()),
Ok(b"defghi"[..].into()),
Err(would_block()),
Ok(b"\x00\x00\x00\x0312"[..].into()),
Err(would_block()),
Ok(b"3\x00\x00\x00\x0bhello world"[..].into()),
Err(would_block()),
});
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), Ready(Some(b"123"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"hello world"[..].into())));
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_incomplete_head() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00"[..].into()),
});
assert!(io.poll().is_err());
}
#[test]
fn read_incomplete_head_multi() {
let mut io = FramedRead::new(mock! {
Err(would_block()),
Ok(b"\x00"[..].into()),
Err(would_block()),
});
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), NotReady);
assert!(io.poll().is_err());
}
#[test]
fn read_incomplete_payload() {
let mut io = FramedRead::new(mock! {
Ok(b"\x00\x00\x00\x09ab"[..].into()),
Err(would_block()),
Ok(b"cd"[..].into()),
Err(would_block()),
});
assert_eq!(io.poll().unwrap(), NotReady);
assert_eq!(io.poll().unwrap(), NotReady);
assert!(io.poll().is_err());
}
#[test]
fn read_max_frame_len() {
let mut io = Builder::new().max_frame_length(5).new_read(mock! {
Ok(b"\x00\x00\x00\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap_err().kind(), io::ErrorKind::InvalidData);
}
#[test]
fn read_update_max_frame_len_at_rest() {
let mut io = Builder::new().new_read(mock! {
Ok(b"\x00\x00\x00\x09abcdefghi"[..].into()),
Ok(b"\x00\x00\x00\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
io.set_max_frame_length(5);
assert_eq!(io.poll().unwrap_err().kind(), io::ErrorKind::InvalidData);
}
#[test]
fn read_update_max_frame_len_in_flight() {
let mut io = Builder::new().new_read(mock! {
Ok(b"\x00\x00\x00\x09abcd"[..].into()),
Err(would_block()),
Ok(b"efghi"[..].into()),
Ok(b"\x00\x00\x00\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), NotReady);
io.set_max_frame_length(5);
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap_err().kind(), io::ErrorKind::InvalidData);
}
#[test]
fn read_one_byte_length_field() {
let mut io = Builder::new().length_field_length(1).new_read(mock! {
Ok(b"\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_header_offset() {
let mut io = Builder::new()
.length_field_length(2)
.length_field_offset(4)
.new_read(mock! {
Ok(b"zzzz\x00\x09abcdefghi"[..].into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_multi_frame_one_packet_skip_none_adjusted() {
let mut data: Vec<u8> = vec![];
data.extend_from_slice(b"xx\x00\x09abcdefghi");
data.extend_from_slice(b"yy\x00\x03123");
data.extend_from_slice(b"zz\x00\x0bhello world");
let mut io = Builder::new()
.length_field_length(2)
.length_field_offset(2)
.num_skip(0)
.length_adjustment(4)
.new_read(mock! {
Ok(data.into()),
});
assert_eq!(
io.poll().unwrap(),
Ready(Some(b"xx\x00\x09abcdefghi"[..].into()))
);
assert_eq!(io.poll().unwrap(), Ready(Some(b"yy\x00\x03123"[..].into())));
assert_eq!(
io.poll().unwrap(),
Ready(Some(b"zz\x00\x0bhello world"[..].into()))
);
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn read_single_multi_frame_one_packet_length_includes_head() {
let mut data: Vec<u8> = vec![];
data.extend_from_slice(b"\x00\x0babcdefghi");
data.extend_from_slice(b"\x00\x05123");
data.extend_from_slice(b"\x00\x0dhello world");
let mut io = Builder::new()
.length_field_length(2)
.length_adjustment(-2)
.new_read(mock! {
Ok(data.into()),
});
assert_eq!(io.poll().unwrap(), Ready(Some(b"abcdefghi"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"123"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(Some(b"hello world"[..].into())));
assert_eq!(io.poll().unwrap(), Ready(None));
}
#[test]
fn write_single_frame_length_adjusted() {
let mut io = Builder::new().length_adjustment(-2).new_write(mock! {
Ok(b"\x00\x00\x00\x0b"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_nothing_yields_nothing() {
let mut io: FramedWrite<_, &'static [u8]> = FramedWrite::new(mock!());
assert!(io.poll_complete().unwrap().is_ready());
}
#[test]
fn write_single_frame_one_packet() {
let mut io = FramedWrite::new(mock! {
Ok(b"\x00\x00\x00\x09"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_single_multi_frame_one_packet() {
let mut io = FramedWrite::new(mock! {
Ok(b"\x00\x00\x00\x09"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(b"\x00\x00\x00\x03"[..].into()),
Ok(b"123"[..].into()),
Ok(b"\x00\x00\x00\x0b"[..].into()),
Ok(b"hello world"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.start_send("123").unwrap().is_ready());
assert!(io.start_send("hello world").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_single_multi_frame_multi_packet() {
let mut io = FramedWrite::new(mock! {
Ok(b"\x00\x00\x00\x09"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
Ok(b"\x00\x00\x00\x03"[..].into()),
Ok(b"123"[..].into()),
Ok(Flush),
Ok(b"\x00\x00\x00\x0b"[..].into()),
Ok(b"hello world"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.start_send("123").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.start_send("hello world").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_single_frame_would_block() {
let mut io = FramedWrite::new(mock! {
Err(would_block()),
Ok(b"\x00\x00"[..].into()),
Err(would_block()),
Ok(b"\x00\x09"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(!io.poll_complete().unwrap().is_ready());
assert!(!io.poll_complete().unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_single_frame_little_endian() {
let mut io = Builder::new().little_endian().new_write(mock! {
Ok(b"\x09\x00\x00\x00"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_single_frame_with_short_length_field() {
let mut io = Builder::new().length_field_length(1).new_write(mock! {
Ok(b"\x09"[..].into()),
Ok(b"abcdefghi"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdefghi").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_max_frame_len() {
let mut io = Builder::new().max_frame_length(5).new_write(mock! {});
assert_eq!(
io.start_send("abcdef").unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_zero() {
let mut io = Builder::new().new_write(mock! {});
assert!(io.start_send("abcdef").unwrap().is_ready());
assert_eq!(
io.poll_complete().unwrap_err().kind(),
io::ErrorKind::WriteZero
);
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_update_max_frame_len_at_rest() {
let mut io = Builder::new().new_write(mock! {
Ok(b"\x00\x00\x00\x06"[..].into()),
Ok(b"abcdef"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdef").unwrap().is_ready());
assert!(io.poll_complete().unwrap().is_ready());
io.set_max_frame_length(5);
assert_eq!(
io.start_send("abcdef").unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
assert!(io.get_ref().calls.is_empty());
}
#[test]
fn write_update_max_frame_len_in_flight() {
let mut io = Builder::new().new_write(mock! {
Ok(b"\x00\x00\x00\x06"[..].into()),
Ok(b"ab"[..].into()),
Err(would_block()),
Ok(b"cdef"[..].into()),
Ok(Flush),
});
assert!(io.start_send("abcdef").unwrap().is_ready());
assert!(!io.poll_complete().unwrap().is_ready());
io.set_max_frame_length(5);
assert!(io.poll_complete().unwrap().is_ready());
assert_eq!(
io.start_send("abcdef").unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
assert!(io.get_ref().calls.is_empty());
}
// ===== Test utils =====
fn would_block() -> io::Error {
io::Error::new(io::ErrorKind::WouldBlock, "would block")
}
struct Mock {
calls: VecDeque<io::Result<Op>>,
}
enum Op {
Data(Vec<u8>),
Flush,
}
use self::Op::*;
impl io::Read for Mock {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
match self.calls.pop_front() {
Some(Ok(Op::Data(data))) => {
debug_assert!(dst.len() >= data.len());
dst[..data.len()].copy_from_slice(&data[..]);
Ok(data.len())
}
Some(Ok(_)) => panic!(),
Some(Err(e)) => Err(e),
None => Ok(0),
}
}
}
impl AsyncRead for Mock {}
impl io::Write for Mock {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
match self.calls.pop_front() {
Some(Ok(Op::Data(data))) => {
let len = data.len();
assert!(src.len() >= len, "expect={:?}; actual={:?}", data, src);
assert_eq!(&data[..], &src[..len]);
Ok(len)
}
Some(Ok(_)) => panic!(),
Some(Err(e)) => Err(e),
None => Ok(0),
}
}
fn flush(&mut self) -> io::Result<()> {
match self.calls.pop_front() {
Some(Ok(Op::Flush)) => Ok(()),
Some(Ok(_)) => panic!(),
Some(Err(e)) => Err(e),
None => Ok(()),
}
}
}
impl AsyncWrite for Mock {
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(Ready(()))
}
}
impl<'a> From<&'a [u8]> for Op {
fn from(src: &'a [u8]) -> Op {
Op::Data(src.into())
}
}
impl From<Vec<u8>> for Op {
fn from(src: Vec<u8>) -> Op {
Op::Data(src)
}
}
-3
View File
@@ -17,9 +17,6 @@ publish = false
proc-macro = true
[features]
# This feature comes with no promise of stability. Things will
# break with each patch release. Use at your own risk.
async-await-preview = []
[dependencies]
proc-macro2 = "0.4.27"
-1
View File
@@ -1,4 +1,3 @@
#![cfg(feature = "async-await-preview")]
#![deny(missing_debug_implementations, unreachable_pub, rust_2018_idioms)]
#![cfg_attr(test, deny(warnings))]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
+1 -2
View File
@@ -24,9 +24,8 @@ publish = false
[dependencies]
crossbeam-utils = "0.6.0"
futures = "0.1.19"
lazy_static = "1.0.2"
log = "0.4.1"
log = "0.4.6"
mio = "0.6.14"
num_cpus = "1.8.0"
parking_lot = "0.8"
+2
View File
@@ -1,6 +1,7 @@
#![feature(test)]
#![deny(warnings, rust_2018_idioms)]
/*
extern crate test;
const NUM_YIELD: usize = 500;
@@ -129,3 +130,4 @@ mod io_pool {
})
}
}
*/
-214
View File
@@ -1,214 +0,0 @@
use crate::{AtomicTask, Handle, Reactor};
use futures::{task, Async, Future, Poll};
use log::debug;
use std::io;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc;
use std::thread;
/// Handle to the reactor running on a background thread.
///
/// Instances are created by calling [`Reactor::background`].
///
/// [`Reactor::background`]: struct.Reactor.html#method.background
#[derive(Debug)]
pub struct Background {
/// When `None`, the reactor thread will run until the process terminates.
inner: Option<Inner>,
}
/// Future that resolves when the reactor thread has shutdown.
#[derive(Debug)]
pub struct Shutdown {
inner: Inner,
}
/// Actual Background handle.
#[derive(Debug)]
struct Inner {
/// Handle to the reactor
handle: Handle,
/// Shared state between the background handle and the reactor thread.
shared: Arc<Shared>,
}
#[derive(Debug)]
struct Shared {
/// Signal the reactor thread to shutdown.
shutdown: AtomicUsize,
/// Task to notify when the reactor thread enters a shutdown state.
shutdown_task: AtomicTask,
}
/// Notifies the reactor thread to shutdown once the reactor becomes idle.
const SHUTDOWN_IDLE: usize = 1;
/// Notifies the reactor thread to shutdown immediately.
const SHUTDOWN_NOW: usize = 2;
/// The reactor is currently shutdown.
const SHUTDOWN: usize = 3;
// ===== impl Background =====
impl Background {
/// Launch a reactor in the background and return a handle to the thread.
pub(crate) fn new(reactor: Reactor) -> io::Result<Background> {
// Grab a handle to the reactor
let handle = reactor.handle().clone();
// Create the state shared between the background handle and the reactor
// thread.
let shared = Arc::new(Shared {
shutdown: AtomicUsize::new(0),
shutdown_task: AtomicTask::new(),
});
// For the reactor thread
let shared2 = shared.clone();
// Start the reactor thread
thread::Builder::new().spawn(move || run(reactor, shared2))?;
Ok(Background {
inner: Some(Inner { handle, shared }),
})
}
/// Returns a reference to the reactor handle.
pub fn handle(&self) -> &Handle {
&self.inner.as_ref().unwrap().handle
}
/// Shutdown the reactor on idle.
///
/// Returns a future that completes once the reactor thread has shutdown.
pub fn shutdown_on_idle(mut self) -> Shutdown {
let inner = self.inner.take().unwrap();
inner.shutdown_on_idle();
Shutdown { inner }
}
/// Shutdown the reactor immediately
///
/// Returns a future that completes once the reactor thread has shutdown.
pub fn shutdown_now(mut self) -> Shutdown {
let inner = self.inner.take().unwrap();
inner.shutdown_now();
Shutdown { inner }
}
/// Run the reactor on its thread until the process terminates.
pub fn forget(mut self) {
drop(self.inner.take());
}
}
impl Drop for Background {
fn drop(&mut self) {
let inner = match self.inner.take() {
Some(i) => i,
None => return,
};
inner.shutdown_now();
let shutdown = Shutdown { inner };
let _ = shutdown.wait();
}
}
// ===== impl Shutdown =====
impl Future for Shutdown {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
let task = task::current();
self.inner.shared.shutdown_task.register_task(task);
if !self.inner.is_shutdown() {
return Ok(Async::NotReady);
}
Ok(().into())
}
}
// ===== impl Inner =====
impl Inner {
/// Returns true if the reactor thread is shutdown.
fn is_shutdown(&self) -> bool {
self.shared.shutdown.load(SeqCst) == SHUTDOWN
}
/// Notify the reactor thread to shutdown once the reactor transitions to an
/// idle state.
fn shutdown_on_idle(&self) {
self.shared
.shutdown
.compare_and_swap(0, SHUTDOWN_IDLE, SeqCst);
self.handle.wakeup();
}
/// Notify the reactor thread to shutdown immediately.
fn shutdown_now(&self) {
let mut curr = self.shared.shutdown.load(SeqCst);
loop {
if curr >= SHUTDOWN_NOW {
return;
}
let act = self
.shared
.shutdown
.compare_and_swap(curr, SHUTDOWN_NOW, SeqCst);
if act == curr {
self.handle.wakeup();
return;
}
curr = act;
}
}
}
// ===== impl Reactor thread =====
fn run(mut reactor: Reactor, shared: Arc<Shared>) {
debug!("starting background reactor");
loop {
let shutdown = shared.shutdown.load(SeqCst);
if shutdown == SHUTDOWN_NOW {
debug!("shutting background reactor down NOW");
break;
}
if shutdown == SHUTDOWN_IDLE && reactor.is_idle() {
debug!("shutting background reactor on idle");
break;
}
reactor.turn(None).unwrap();
}
drop(reactor);
// Transition the state to shutdown
shared.shutdown.store(SHUTDOWN, SeqCst);
// Notify any waiters
shared.shutdown_task.notify();
debug!("background reactor has shutdown");
}
+28 -178
View File
@@ -32,38 +32,43 @@
//! [`PollEvented`]: struct.PollEvented.html
//! [reactor module]: https://docs.rs/tokio/0.1/tokio/reactor/index.html
pub(crate) mod background;
macro_rules! ready {
($e:expr) => {
match $e {
::std::task::Poll::Ready(v) => v,
::std::task::Poll::Pending => return ::std::task::Poll::Pending,
}
};
}
mod poll_evented;
mod registration;
mod sharded_rwlock;
// ===== Public re-exports =====
pub use self::background::{Background, Shutdown};
pub use self::poll_evented::PollEvented;
pub use self::registration::Registration;
// ===== Private imports =====
use crate::sharded_rwlock::RwLock;
use futures::task::Task;
use log::{debug, log_enabled, trace, Level};
use mio::event::Evented;
use slab::Slab;
use std::cell::RefCell;
use std::error::Error;
use std::io;
use std::mem;
#[cfg(all(unix, not(target_os = "fuchsia")))]
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{Relaxed, SeqCst};
use std::sync::{Arc, Weak};
use std::task::Waker;
use std::time::{Duration, Instant};
use std::{fmt, usize};
use tokio_executor::park::{Park, Unpark};
use tokio_executor::Enter;
use tokio_sync::task::AtomicTask;
use tokio_sync::task::AtomicWaker;
/// The core reactor, or event loop.
///
@@ -109,14 +114,6 @@ pub struct Turn {
_priv: (),
}
/// Error returned from `Handle::set_fallback`.
#[derive(Clone, Debug)]
pub struct SetFallbackError(());
#[deprecated(since = "0.1.2", note = "use SetFallbackError instead")]
#[doc(hidden)]
pub type SetDefaultError = SetFallbackError;
#[test]
fn test_handle_size() {
use std::mem;
@@ -140,8 +137,8 @@ struct Inner {
struct ScheduledIo {
aba_guard: usize,
readiness: AtomicUsize,
reader: AtomicTask,
writer: AtomicTask,
reader: AtomicWaker,
writer: AtomicWaker,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
@@ -150,9 +147,6 @@ pub(crate) enum Direction {
Write,
}
/// The global fallback reactor.
static HANDLE_FALLBACK: AtomicUsize = AtomicUsize::new(0);
thread_local! {
/// Tracks the reactor for the current execution context.
static CURRENT_REACTOR: RefCell<Option<HandlePriv>> = RefCell::new(None)
@@ -262,33 +256,6 @@ impl Reactor {
}
}
/// Configures the fallback handle to be returned from `Handle::default`.
///
/// The `Handle::default()` function will by default lazily spin up a global
/// thread and run a reactor on this global thread. This behavior is not
/// always desirable in all applications, however, and sometimes a different
/// fallback reactor is desired.
///
/// This function will attempt to globally alter the return value of
/// `Handle::default()` to return the `handle` specified rather than a
/// lazily initialized global thread. If successful then all future calls to
/// `Handle::default()` which would otherwise fall back to the global thread
/// will instead return a clone of the handle specified.
///
/// # Errors
///
/// This function may not always succeed in configuring the fallback handle.
/// If this function was previously called (or perhaps concurrently called
/// on many threads) only the *first* invocation of this function will
/// succeed. All other invocations will return an error.
///
/// Additionally if the global reactor thread has already been initialized
/// then this function will also return an error. (aka if `Handle::default`
/// has been called previously in this program).
pub fn set_fallback(&self) -> Result<(), SetFallbackError> {
set_fallback(self.handle().into_priv().unwrap())
}
/// Performs one iteration of the event loop, blocking on waiting for events
/// for at most `max_wait` (forever if `None`).
///
@@ -328,16 +295,6 @@ impl Reactor {
self.inner.io_dispatch.read().is_empty()
}
/// Run this reactor on a background thread.
///
/// This function takes ownership, spawns a new thread, and moves the
/// reactor to this new thread. It then runs the reactor, driving all
/// associated I/O resources, until the `Background` handle is dropped or
/// explicitly shutdown.
pub fn background(self) -> io::Result<Background> {
Background::new(self)
}
fn poll(&mut self, max_wait: Option<Duration>) -> io::Result<()> {
// Block waiting for an event to happen, peeling out how many events
// happened.
@@ -406,20 +363,20 @@ impl Reactor {
io.readiness.fetch_or(ready.as_usize(), Relaxed);
if ready.is_writable() || platform::is_hup(&ready) {
wr = io.writer.take_task();
wr = io.writer.take_waker();
}
if !(ready & (!mio::Ready::writable())).is_empty() {
rd = io.reader.take_task();
rd = io.reader.take_waker();
}
}
if let Some(task) = rd {
task.notify();
if let Some(w) = rd {
w.wake();
}
if let Some(task) = wr {
task.notify();
if let Some(w) = wr {
w.wake();
}
}
}
@@ -475,16 +432,6 @@ impl Handle {
fn as_priv(&self) -> Option<&HandlePriv> {
self.inner.as_ref()
}
fn into_priv(self) -> Option<HandlePriv> {
self.inner
}
fn wakeup(&self) {
if let Some(handle) = self.as_priv() {
handle.wakeup();
}
}
}
impl Unpark for Handle {
@@ -508,19 +455,6 @@ impl fmt::Debug for Handle {
}
}
fn set_fallback(handle: HandlePriv) -> Result<(), SetFallbackError> {
unsafe {
let val = handle.into_usize();
match HANDLE_FALLBACK.compare_exchange(0, val, SeqCst, SeqCst) {
Ok(_) => Ok(()),
Err(_) => {
drop(HandlePriv::from_usize(val));
Err(SetFallbackError(()))
}
}
}
}
// ===== impl HandlePriv =====
impl HandlePriv {
@@ -530,71 +464,10 @@ impl HandlePriv {
pub(crate) fn try_current() -> io::Result<HandlePriv> {
CURRENT_REACTOR.with(|current| match *current.borrow() {
Some(ref handle) => Ok(handle.clone()),
None => HandlePriv::fallback(),
None => Err(io::Error::new(io::ErrorKind::Other, "no current reactor")),
})
}
/// Returns a handle to the fallback reactor.
fn fallback() -> io::Result<HandlePriv> {
let mut fallback = HANDLE_FALLBACK.load(SeqCst);
// If the fallback hasn't been previously initialized then let's spin
// up a helper thread and try to initialize with that. If we can't
// actually create a helper thread then we'll just return a "defunct"
// handle which will return errors when I/O objects are attempted to be
// associated.
if fallback == 0 {
let reactor = match Reactor::new() {
Ok(reactor) => reactor,
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::Other,
"failed to create reactor",
));
}
};
// If we successfully set ourselves as the actual fallback then we
// want to `forget` the helper thread to ensure that it persists
// globally. If we fail to set ourselves as the fallback that means
// that someone was racing with this call to `Handle::default`.
// They ended up winning so we'll destroy our helper thread (which
// shuts down the thread) and reload the fallback.
if set_fallback(reactor.handle().into_priv().unwrap()).is_ok() {
let ret = reactor.handle().into_priv().unwrap();
match reactor.background() {
Ok(bg) => bg.forget(),
// The global handle is fubar, but y'all probably got bigger
// problems if a thread can't spawn.
Err(_) => {}
}
return Ok(ret);
}
fallback = HANDLE_FALLBACK.load(SeqCst);
}
// At this point our fallback handle global was configured so we use
// its value to reify a handle, clone it, and then forget our reified
// handle as we don't actually have an owning reference to it.
assert!(fallback != 0);
let ret = unsafe {
let handle = HandlePriv::from_usize(fallback);
let ret = handle.clone();
// This prevents `handle` from being dropped and having the ref
// count decremented.
drop(handle.into_usize());
ret
};
Ok(ret)
}
/// Forces a reactor blocked in a call to `turn` to wakeup, or otherwise
/// makes the next call to `turn` return immediately.
///
@@ -610,15 +483,6 @@ impl HandlePriv {
}
}
fn into_usize(self) -> usize {
unsafe { mem::transmute::<Weak<Inner>, usize>(self.inner) }
}
unsafe fn from_usize(val: usize) -> HandlePriv {
let inner = mem::transmute::<usize, Weak<Inner>>(val);;
HandlePriv { inner }
}
fn inner(&self) -> Option<Arc<Inner>> {
self.inner.upgrade()
}
@@ -655,8 +519,8 @@ impl Inner {
io_dispatch.insert(ScheduledIo {
aba_guard,
readiness: AtomicUsize::new(0),
reader: AtomicTask::new(),
writer: AtomicTask::new(),
reader: AtomicWaker::new(),
writer: AtomicWaker::new(),
})
};
@@ -684,20 +548,20 @@ impl Inner {
}
/// Registers interest in the I/O resource associated with `token`.
fn register(&self, token: usize, dir: Direction, t: Task) {
fn register(&self, token: usize, dir: Direction, w: Waker) {
debug!("scheduling {:?} for: {}", dir, token);
let io_dispatch = self.io_dispatch.read();
let sched = io_dispatch.get(token).unwrap();
let (task, ready) = match dir {
let (waker, ready) = match dir {
Direction::Read => (&sched.reader, !mio::Ready::writable()),
Direction::Write => (&sched.writer, mio::Ready::writable()),
};
task.register_task(t);
waker.register(w);
if sched.readiness.load(SeqCst) & ready.as_usize() != 0 {
task.notify();
waker.wake();
}
}
}
@@ -709,8 +573,8 @@ impl Drop for Inner {
// will start returning errors pretty quickly.
let io = self.io_dispatch.read();
for (_, io) in io.iter() {
io.writer.notify();
io.reader.notify();
io.writer.wake();
io.reader.wake();
}
}
}
@@ -753,17 +617,3 @@ mod platform {
false
}
}
// ===== impl SetFallbackError =====
impl fmt::Display for SetFallbackError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for SetFallbackError {
fn description(&self) -> &str {
"attempted to set fallback reactor while already configured"
}
}
+54 -120
View File
@@ -1,11 +1,13 @@
use crate::{Handle, Registration};
use futures::{task, try_ready, Async, Poll};
use mio;
use mio::event::Evented;
use std::fmt;
use std::io::{self, Read, Write};
use std::marker::Unpin;
use std::pin::Pin;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
use std::task::{Context, Poll};
use tokio_io::{AsyncRead, AsyncWrite};
/// Associates an I/O resource that implements the [`std::io::Read`] and/or
@@ -116,7 +118,10 @@ macro_rules! poll_ready {
// stream. This happens in a loop to ensure that the stream gets
// drained.
loop {
let ready = try_ready!($poll);
let ready = match $poll? {
Poll::Ready(v) => v,
Poll::Pending => return Poll::Pending,
};
cached |= ready.as_usize();
// Update the cache store
@@ -125,7 +130,7 @@ macro_rules! poll_ready {
ret |= ready & mask;
if !ret.is_empty() {
return Ok(ret.into());
return Poll::Ready(Ok(ret));
}
}
} else {
@@ -136,7 +141,7 @@ macro_rules! poll_ready {
$me.inner.$cache.store(cached, Relaxed);
}
Ok(mio::Ready::from_usize(cached).into())
Poll::Ready(Ok(mio::Ready::from_usize(cached)))
}
}};
}
@@ -217,14 +222,18 @@ where
///
/// * `ready` includes writable.
/// * called from outside of a task context.
pub fn poll_read_ready(&self, mask: mio::Ready) -> Poll<mio::Ready, io::Error> {
pub fn poll_read_ready(
&self,
cx: &mut Context<'_>,
mask: mio::Ready,
) -> Poll<io::Result<mio::Ready>> {
assert!(!mask.is_writable(), "cannot poll for write readiness");
poll_ready!(
self,
mask,
read_readiness,
take_read_ready,
self.inner.registration.poll_read_ready()
self.inner.registration.poll_read_ready(cx)
)
}
@@ -243,7 +252,7 @@ where
///
/// * `ready` includes writable or HUP
/// * called from outside of a task context.
pub fn clear_read_ready(&self, ready: mio::Ready) -> io::Result<()> {
pub fn clear_read_ready(&self, cx: &mut Context<'_>, ready: mio::Ready) -> io::Result<()> {
// Cannot clear write readiness
assert!(!ready.is_writable(), "cannot clear write readiness");
assert!(
@@ -255,9 +264,9 @@ where
.read_readiness
.fetch_and(!ready.as_usize(), Relaxed);
if self.poll_read_ready(ready)?.is_ready() {
if self.poll_read_ready(cx, ready)?.is_ready() {
// Notify the current task
task::current().notify();
cx.waker().wake_by_ref();
}
Ok(())
@@ -282,13 +291,13 @@ where
///
/// * `ready` contains bits besides `writable` and `hup`.
/// * called from outside of a task context.
pub fn poll_write_ready(&self) -> Poll<mio::Ready, io::Error> {
pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<mio::Ready>> {
poll_ready!(
self,
mio::Ready::writable(),
write_readiness,
take_write_ready,
self.inner.registration.poll_write_ready()
self.inner.registration.poll_write_ready(cx)
)
}
@@ -304,16 +313,16 @@ where
/// # Panics
///
/// This function will panic if called from outside of a task context.
pub fn clear_write_ready(&self) -> io::Result<()> {
pub fn clear_write_ready(&self, cx: &mut Context<'_>) -> io::Result<()> {
let ready = mio::Ready::writable();
self.inner
.write_readiness
.fetch_and(!ready.as_usize(), Relaxed);
if self.poll_write_ready()?.is_ready() {
if self.poll_write_ready(cx)?.is_ready() {
// Notify the current task
task::current().notify();
cx.waker().wake_by_ref();
}
Ok(())
@@ -330,139 +339,64 @@ where
// ===== Read / Write impls =====
impl<E> Read for PollEvented<E>
impl<E> AsyncRead for PollEvented<E>
where
E: Evented + Read,
E: Evented + Read + Unpin,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_read_ready(mio::Ready::readable())? {
return Err(io::ErrorKind::WouldBlock.into());
}
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
ready!(self.poll_read_ready(cx, mio::Ready::readable()))?;
let r = self.get_mut().read(buf);
let r = (*self).get_mut().read(buf);
if is_wouldblock(&r) {
self.clear_read_ready(mio::Ready::readable())?;
self.clear_read_ready(cx, mio::Ready::readable())?;
return Poll::Pending;
}
return r;
Poll::Ready(r)
}
}
impl<E> Write for PollEvented<E>
where
E: Evented + Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into());
}
let r = self.get_mut().write(buf);
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r;
}
fn flush(&mut self) -> io::Result<()> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into());
}
let r = self.get_mut().flush();
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r;
}
}
impl<E> AsyncRead for PollEvented<E> where E: Evented + Read {}
impl<E> AsyncWrite for PollEvented<E>
where
E: Evented + Write,
E: Evented + Write + Unpin,
{
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
}
}
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
ready!(self.poll_write_ready(cx))?;
// ===== &'a Read / &'a Write impls =====
impl<'a, E> Read for &'a PollEvented<E>
where
E: Evented,
&'a E: Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_read_ready(mio::Ready::readable())? {
return Err(io::ErrorKind::WouldBlock.into());
}
let r = self.get_ref().read(buf);
let r = (*self).get_mut().write(buf);
if is_wouldblock(&r) {
self.clear_read_ready(mio::Ready::readable())?;
self.clear_write_ready(cx)?;
return Poll::Pending;
}
return r;
Poll::Ready(r)
}
}
impl<'a, E> Write for &'a PollEvented<E>
where
E: Evented,
&'a E: Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into());
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
ready!(self.poll_write_ready(cx))?;
let r = self.get_ref().write(buf);
let r = (*self).get_mut().flush();
if is_wouldblock(&r) {
self.clear_write_ready()?;
self.clear_write_ready(cx)?;
return Poll::Pending;
}
return r;
Poll::Ready(r)
}
fn flush(&mut self) -> io::Result<()> {
if let Async::NotReady = self.poll_write_ready()? {
return Err(io::ErrorKind::WouldBlock.into());
}
let r = self.get_ref().flush();
if is_wouldblock(&r) {
self.clear_write_ready()?;
}
return r;
}
}
impl<'a, E> AsyncRead for &'a PollEvented<E>
where
E: Evented,
&'a E: Read,
{
}
impl<'a, E> AsyncWrite for &'a PollEvented<E>
where
E: Evented,
&'a E: Write,
{
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
+52 -48
View File
@@ -1,10 +1,10 @@
use crate::{Direction, Handle, HandlePriv, Task};
use futures::{task, Async, Poll};
use crate::{Direction, Handle, HandlePriv};
use log::debug;
use mio::{self, Evented};
use std::cell::UnsafeCell;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::task::{Context, Poll, Waker};
use std::{io, ptr, usize};
/// Associates an I/O resource with the reactor instance that drives it.
@@ -59,17 +59,11 @@ struct Inner {
token: usize,
}
#[derive(PartialEq)]
enum Notify {
Yes,
No,
}
/// Tasks waiting on readiness notifications.
#[derive(Debug)]
struct Node {
direction: Direction,
task: Task,
waker: Waker,
next: *mut Node,
}
@@ -228,7 +222,7 @@ impl Registration {
let node = *node;
let Node {
direction,
task,
waker,
next,
} = node;
@@ -240,7 +234,7 @@ impl Registration {
if !*flag {
*flag = true;
inner.register(direction, task);
inner.register(direction, waker);
}
ptr = next;
@@ -285,12 +279,12 @@ impl Registration {
/// # Panics
///
/// This function will panic if called from outside of a task context.
pub fn poll_read_ready(&self) -> Poll<mio::Ready, io::Error> {
self.poll_ready(Direction::Read, Notify::Yes)
.map(|v| match v {
Some(v) => Async::Ready(v),
_ => Async::NotReady,
})
pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<mio::Ready>> {
let v = self.poll_ready(Direction::Read, Some(cx))?;
match v {
Some(v) => Poll::Ready(Ok(v)),
None => Poll::Pending,
}
}
/// Consume any pending read readiness event.
@@ -301,7 +295,7 @@ impl Registration {
///
/// [`poll_read_ready`]: #method.poll_read_ready
pub fn take_read_ready(&self) -> io::Result<Option<mio::Ready>> {
self.poll_ready(Direction::Read, Notify::No)
self.poll_ready(Direction::Read, None)
}
/// Poll for events on the I/O resource's write readiness stream.
@@ -336,12 +330,12 @@ impl Registration {
/// # Panics
///
/// This function will panic if called from outside of a task context.
pub fn poll_write_ready(&self) -> Poll<mio::Ready, io::Error> {
self.poll_ready(Direction::Write, Notify::Yes)
.map(|v| match v {
Some(v) => Async::Ready(v),
_ => Async::NotReady,
})
pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<mio::Ready>> {
let v = self.poll_ready(Direction::Write, Some(cx))?;
match v {
Some(v) => Poll::Ready(Ok(v)),
None => Poll::Pending,
}
}
/// Consume any pending write readiness event.
@@ -352,10 +346,14 @@ impl Registration {
///
/// [`poll_write_ready`]: #method.poll_write_ready
pub fn take_write_ready(&self) -> io::Result<Option<mio::Ready>> {
self.poll_ready(Direction::Write, Notify::No)
self.poll_ready(Direction::Write, None)
}
fn poll_ready(&self, direction: Direction, notify: Notify) -> io::Result<Option<mio::Ready>> {
fn poll_ready(
&self,
direction: Direction,
cx: Option<&mut Context<'_>>,
) -> io::Result<Option<mio::Ready>> {
let mut state = self.state.load(SeqCst);
// Cache the node pointer
@@ -366,29 +364,28 @@ impl Registration {
INIT => {
return Err(io::Error::new(
io::ErrorKind::Other,
"must call `register`
before poll_read_ready",
"must call register before poll_read_ready",
));
}
READY => {
let inner = unsafe { (*self.inner.get()).as_ref().unwrap() };
return inner.poll_ready(direction, notify);
return inner.poll_ready(direction, cx);
}
LOCKED => {
if let Notify::No = notify {
let cx = if let Some(ref cx) = cx {
cx
} else {
// Skip the notification tracking junk.
return Ok(None);
}
};
let next_ptr = (state & !LIFECYCLE_MASK) as *mut Node;
let task = task::current();
// Get the node
let mut n = node.take().unwrap_or_else(|| {
Box::new(Node {
direction,
task: task,
waker: cx.waker().clone(),
next: ptr::null_mut(),
})
});
@@ -450,21 +447,21 @@ impl Inner {
(inner, res)
}
fn register(&self, direction: Direction, task: Task) {
fn register(&self, direction: Direction, waker: Waker) {
if self.token == ERROR {
task.notify();
waker.wake();
return;
}
let inner = match self.handle.inner() {
Some(inner) => inner,
None => {
task.notify();
waker.wake();
return;
}
};
inner.register(self.token, direction, task);
inner.register(self.token, direction, waker);
}
fn deregister<E: Evented>(&self, io: &E) -> io::Result<()> {
@@ -483,7 +480,11 @@ impl Inner {
inner.deregister_source(io)
}
fn poll_ready(&self, direction: Direction, notify: Notify) -> io::Result<Option<mio::Ready>> {
fn poll_ready(
&self,
direction: Direction,
cx: Option<&mut Context<'_>>,
) -> io::Result<Option<mio::Ready>> {
if self.token == ERROR {
return Err(io::Error::new(
io::ErrorKind::Other,
@@ -513,16 +514,19 @@ impl Inner {
let mut ready =
mask & mio::Ready::from_usize(sched.readiness.fetch_and(!mask_no_hup, SeqCst));
if ready.is_empty() && notify == Notify::Yes {
debug!("scheduling {:?} for: {}", direction, self.token);
// Update the task info
match direction {
Direction::Read => sched.reader.register(),
Direction::Write => sched.writer.register(),
}
if ready.is_empty() {
if let Some(cx) = cx {
debug!("scheduling {:?} for: {}", direction, self.token);
// Update the task info
match direction {
Direction::Read => sched.reader.register_by_ref(cx.waker()),
Direction::Write => sched.writer.register_by_ref(cx.waker()),
}
// Try again
ready = mask & mio::Ready::from_usize(sched.readiness.fetch_and(!mask_no_hup, SeqCst));
// Try again
ready =
mask & mio::Ready::from_usize(sched.readiness.fetch_and(!mask_no_hup, SeqCst));
}
}
if ready.is_empty() {
+10 -4
View File
@@ -21,12 +21,18 @@ Synchronization utilities.
categories = ["asynchronous"]
publish = false
[features]
async-traits = ["async-sink", "futures-core-preview"]
[dependencies]
fnv = "1.0.6"
futures = "0.1.19"
async-sink = { git = "https://github.com/tokio-rs/async", optional = true }
futures-core-preview = { version = "0.3.0-alpha.16", optional = true }
[dev-dependencies]
async-util = { git = "https://github.com/tokio-rs/async" }
env_logger = { version = "0.5", default-features = false }
tokio = { version = "0.2.0", path = "../tokio" }
tokio-mock-task = "0.1.1"
loom = { version = "0.1.1", features = ["futures"] }
pin-utils = "0.1.0-alpha.4"
# tokio = { version = "0.2.0", path = "../tokio" }
tokio-test = { version = "0.2.0", path = "../tokio-test" }
loom = { git = "https://github.com/carllerche/loom", branch = "std-future2", features = ["futures"] }
+13
View File
@@ -20,6 +20,19 @@ macro_rules! debug {
}
}
/// Unwrap a ready value or propagate `Poll::Pending`.
#[macro_export]
macro_rules! ready {
($e:expr) => {{
use std::task::Poll::{Pending, Ready};
match $e {
Ready(v) => v,
Pending => return Pending,
}
}};
}
macro_rules! if_fuzz {
($($t:tt)*) => {{
if false { $($t)* }
+7 -7
View File
@@ -41,11 +41,13 @@
//! [`LockGuard`]: struct.LockGuard.html
use crate::semaphore;
use futures::Async;
use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::task::Poll::Ready;
use std::task::{Context, Poll};
/// An asynchronous mutual exclusion primitive useful for protecting shared data
///
@@ -103,14 +105,12 @@ impl<T> Lock<T> {
/// Try to acquire the lock.
///
/// If the lock is already held, the current task is notified when it is released.
pub fn poll_lock(&mut self) -> Async<LockGuard<T>> {
if let Async::NotReady = self.permit.poll_acquire(&self.inner.s).unwrap_or_else(|_| {
pub fn poll_lock(&mut self, cx: &mut Context<'_>) -> Poll<LockGuard<T>> {
ready!(self.permit.poll_acquire(cx, &self.inner.s)).unwrap_or_else(|_| {
// The semaphore was closed. but, we never explicitly close it, and we have a
// handle to it through the Arc, which means that this can never happen.
unreachable!()
}) {
return Async::NotReady;
}
});
// We want to move the acquired permit into the guard,
// and leave an unacquired one in self.
@@ -118,7 +118,7 @@ impl<T> Lock<T> {
inner: self.inner.clone(),
permit: ::std::mem::replace(&mut self.permit, semaphore::Permit::new()),
};
Async::Ready(LockGuard(acquired))
Ready(LockGuard(acquired))
}
}
+1 -2
View File
@@ -1,6 +1,5 @@
pub(crate) mod futures {
pub(crate) use crate::task::AtomicTask;
pub(crate) use futures::task;
pub(crate) use crate::task::AtomicWaker;
}
pub(crate) mod sync {
+37 -30
View File
@@ -1,6 +1,10 @@
use super::chan;
use futures::{Poll, Sink, StartSend, Stream};
use std::fmt;
use std::task::{Context, Poll};
#[cfg(feature = "async-traits")]
use std::pin::Pin;
/// Send values to the associated `Receiver`.
///
@@ -127,6 +131,11 @@ impl<T> Receiver<T> {
Receiver { chan }
}
/// TODO: Dox
pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
self.chan.recv(cx)
}
/// Closes the receiving half of a channel, without dropping it.
///
/// This prevents any further messages from being sent on the channel while
@@ -136,12 +145,12 @@ impl<T> Receiver<T> {
}
}
impl<T> Stream for Receiver<T> {
#[cfg(feature = "async-traits")]
impl<T> futures_core::Stream for Receiver<T> {
type Item = T;
type Error = RecvError;
fn poll(&mut self) -> Poll<Option<T>, Self::Error> {
self.chan.recv().map_err(|_| RecvError(()))
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
Receiver::poll_next(self.get_mut(), cx)
}
}
@@ -165,13 +174,13 @@ impl<T> Sender<T> {
///
/// This method returns:
///
/// - `Ok(Async::Ready(_))` if capacity is reserved for a single message.
/// - `Ok(Async::NotReady)` if the channel may not have capacity, in which
/// - `Poll::Ready(Ok(_))` if capacity is reserved for a single message.
/// - `Poll::Pending` if the channel may not have capacity, in which
/// case the current task is queued to be notified once
/// capacity is available;
/// - `Err(SendError)` if the receiver has been dropped.
pub fn poll_ready(&mut self) -> Poll<(), SendError> {
self.chan.poll_ready().map_err(|_| SendError(()))
/// - `Poll::Ready(Err(SendError))` if the receiver has been dropped.
pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), SendError>> {
self.chan.poll_ready(cx).map_err(|_| SendError(()))
}
/// Attempts to send a message on this `Sender`, returning the message
@@ -182,31 +191,29 @@ impl<T> Sender<T> {
}
}
impl<T> Sink for Sender<T> {
type SinkItem = T;
type SinkError = SendError;
#[cfg(feature = "async-traits")]
impl<T> async_sink::Sink<T> for Sender<T> {
type Error = SendError;
fn start_send(&mut self, msg: T) -> StartSend<T, Self::SinkError> {
use futures::Async::*;
use futures::AsyncSink;
match self.poll_ready()? {
Ready(_) => {
self.try_send(msg).map_err(|_| SendError(()))?;
Ok(AsyncSink::Ready)
}
NotReady => Ok(AsyncSink::NotReady(msg)),
}
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Sender::poll_ready(self.get_mut(), cx)
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
use futures::Async::Ready;
Ok(Ready(()))
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 close(&mut self) -> Poll<(), Self::SinkError> {
use futures::Async::Ready;
Ok(Ready(()))
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(()))
}
}
+23 -23
View File
@@ -1,13 +1,14 @@
use super::list;
use crate::loom::{
futures::AtomicTask,
futures::AtomicWaker,
sync::atomic::AtomicUsize,
sync::{Arc, CausalCell},
};
use futures::Poll;
use std::fmt;
use std::process;
use std::sync::atomic::Ordering::{AcqRel, Relaxed};
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Poll};
/// Channel sender
pub(crate) struct Tx<T, S: Semaphore> {
@@ -61,7 +62,8 @@ pub(crate) trait Semaphore {
fn add_permit(&self);
fn poll_acquire(&self, permit: &mut Self::Permit) -> Poll<(), ()>;
fn poll_acquire(&self, cx: &mut Context<'_>, permit: &mut Self::Permit)
-> Poll<Result<(), ()>>;
fn try_acquire(&self, permit: &mut Self::Permit) -> Result<(), TrySendError>;
@@ -81,8 +83,8 @@ struct Chan<T, S> {
/// Coordinates access to channel's capacity.
semaphore: S,
/// Receiver task. Notified when a value is pushed into the channel.
rx_task: AtomicTask,
/// Receiver waker. Notified when a value is pushed into the channel.
rx_waker: AtomicWaker,
/// Tracks the number of outstanding sender handles.
///
@@ -101,7 +103,7 @@ where
fmt.debug_struct("Chan")
.field("tx", &self.tx)
.field("semaphore", &self.semaphore)
.field("rx_task", &self.rx_task)
.field("rx_waker", &self.rx_waker)
.field("tx_count", &self.tx_count)
.field("rx_fields", &"...")
.finish()
@@ -138,7 +140,7 @@ where
let chan = Arc::new(Chan {
tx,
semaphore,
rx_task: AtomicTask::new(),
rx_waker: AtomicWaker::new(),
tx_count: AtomicUsize::new(1),
rx_fields: CausalCell::new(RxFields {
list: rx,
@@ -163,8 +165,8 @@ where
}
/// TODO: Docs
pub(crate) fn poll_ready(&mut self) -> Poll<(), ()> {
self.inner.semaphore.poll_acquire(&mut self.permit)
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.semaphore.poll_acquire(cx, &mut self.permit)
}
/// Send a message and notify the receiver.
@@ -177,7 +179,7 @@ where
self.inner.tx.push(value);
// Notify the rx task
self.inner.rx_task.notify();
self.inner.rx_waker.wake();
// Release the permit
self.inner.semaphore.forget(&mut self.permit);
@@ -217,7 +219,7 @@ where
self.inner.tx.close();
// Notify the receiver
self.inner.rx_task.notify();
self.inner.rx_waker.wake();
}
}
@@ -246,9 +248,8 @@ where
}
/// Receive the next value
pub(crate) fn recv(&mut self) -> Poll<Option<T>, ()> {
pub(crate) fn recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
use super::block::Read::*;
use futures::Async::*;
self.inner.rx_fields.with_mut(|rx_fields_ptr| {
let rx_fields = unsafe { &mut *rx_fields_ptr };
@@ -258,7 +259,7 @@ where
match rx_fields.list.pop(&self.inner.tx) {
Some(Value(value)) => {
self.inner.semaphore.add_permit();
return Ok(Ready(Some(value)));
return Ready(Some(value));
}
Some(Closed) => {
// TODO: This check may not be required as it most
@@ -268,7 +269,7 @@ where
// which ensures that if dropping the tx handle is
// visible, then all messages sent are also visible.
assert!(self.inner.semaphore.is_idle());
return Ok(Ready(None));
return Ready(None);
}
None => {} // fall through
}
@@ -277,7 +278,7 @@ where
try_recv!();
self.inner.rx_task.register();
self.inner.rx_waker.register_by_ref(cx.waker());
// It is possible that a value was pushed between attempting to read
// and registering the task, so we have to check the channel a
@@ -291,9 +292,9 @@ where
);
if rx_fields.rx_closed && self.inner.semaphore.is_idle() {
Ok(Ready(None))
Ready(None)
} else {
Ok(NotReady)
Pending
}
})
}
@@ -372,8 +373,8 @@ impl Semaphore for (crate::semaphore::Semaphore, usize) {
self.0.available_permits() == self.1
}
fn poll_acquire(&self, permit: &mut Permit) -> Poll<(), ()> {
permit.poll_acquire(&self.0).map_err(|_| ())
fn poll_acquire(&self, cx: &mut Context<'_>, permit: &mut Permit) -> Poll<Result<(), ()>> {
permit.poll_acquire(cx, &self.0).map_err(|_| ())
}
fn try_acquire(&self, permit: &mut Permit) -> Result<(), TrySendError> {
@@ -415,9 +416,8 @@ impl Semaphore for AtomicUsize {
self.load(Acquire) >> 1 == 0
}
fn poll_acquire(&self, permit: &mut ()) -> Poll<(), ()> {
use futures::Async::Ready;
self.try_acquire(permit).map(Ready).map_err(|_| ())
fn poll_acquire(&self, _cx: &mut Context<'_>, permit: &mut ()) -> Poll<Result<(), ()>> {
Ready(self.try_acquire(permit).map_err(|_| ()))
}
fn try_acquire(&self, _permit: &mut ()) -> Result<(), TrySendError> {
+27 -19
View File
@@ -1,7 +1,11 @@
use super::chan;
use crate::loom::sync::atomic::AtomicUsize;
use futures::{Poll, Sink, StartSend, Stream};
use std::fmt;
use std::task::{Context, Poll};
#[cfg(feature = "async-traits")]
use std::pin::Pin;
/// Send values to the associated `UnboundedReceiver`.
///
@@ -83,6 +87,11 @@ impl<T> UnboundedReceiver<T> {
UnboundedReceiver { chan }
}
/// TODO: dox
pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
self.chan.recv(cx)
}
/// Closes the receiving half of a channel, without dropping it.
///
/// This prevents any further messages from being sent on the channel while
@@ -92,12 +101,12 @@ impl<T> UnboundedReceiver<T> {
}
}
impl<T> Stream for UnboundedReceiver<T> {
#[cfg(feature = "async-traits")]
impl<T> futures_core::Stream for UnboundedReceiver<T> {
type Item = T;
type Error = UnboundedRecvError;
fn poll(&mut self) -> Poll<Option<T>, Self::Error> {
self.chan.recv().map_err(|_| UnboundedRecvError(()))
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
self.chan.recv(cx)
}
}
@@ -113,25 +122,24 @@ impl<T> UnboundedSender<T> {
}
}
impl<T> Sink for UnboundedSender<T> {
type SinkItem = T;
type SinkError = UnboundedSendError;
#[cfg(feature = "async-traits")]
impl<T> async_sink::Sink<T> for UnboundedSender<T> {
type Error = UnboundedSendError;
fn start_send(&mut self, msg: T) -> StartSend<T, Self::SinkError> {
use futures::AsyncSink;
self.try_send(msg).map_err(|_| UnboundedSendError(()))?;
Ok(AsyncSink::Ready)
fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
use futures::Async::Ready;
Ok(Ready(()))
fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
self.try_send(msg).map_err(|_| UnboundedSendError(()))
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
use futures::Async::Ready;
Ok(Ready(()))
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(()))
}
}
+41 -49
View File
@@ -1,15 +1,15 @@
//! A channel for sending a single message between asynchronous tasks.
use crate::loom::{
futures::task::{self, Task},
sync::atomic::AtomicUsize,
sync::CausalCell,
};
use futures::{Async, Future, Poll};
use crate::loom::{sync::atomic::AtomicUsize, sync::CausalCell};
use std::fmt;
use std::future::Future;
use std::mem::{self, ManuallyDrop};
use std::pin::Pin;
use std::sync::atomic::Ordering::{self, AcqRel, Acquire};
use std::sync::Arc;
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Poll, Waker};
/// Sends a value to the associated `Receiver`.
///
@@ -82,10 +82,10 @@ struct Inner<T> {
value: CausalCell<Option<T>>,
/// The task to notify when the receiver drops without consuming the value.
tx_task: CausalCell<ManuallyDrop<Task>>,
tx_task: CausalCell<ManuallyDrop<Waker>>,
/// The task to notify when the value is sent.
rx_task: CausalCell<ManuallyDrop<Task>>,
rx_task: CausalCell<ManuallyDrop<Waker>>,
}
#[derive(Clone, Copy)]
@@ -167,33 +167,33 @@ impl<T> Sender<T> {
///
/// # Return values
///
/// If `Ok(Ready)` is returned then the associated `Receiver` has been
/// If `Ready(Ok(_))` is returned then the associated `Receiver` has been
/// dropped, which means any work required for sending should be canceled.
///
/// If `Ok(NotReady)` is returned then the associated `Receiver` is still
/// If `Pending` is returned then the associated `Receiver` is still
/// alive and may be able to receive a message if sent. The current task is
/// registered to receive a notification if the `Receiver` handle goes away.
///
/// [`Receiver`]: struct.Receiver.html
pub fn poll_close(&mut self) -> Poll<(), ()> {
pub fn poll_close(&mut self, cx: &mut Context<'_>) -> Poll<()> {
let inner = self.inner.as_ref().unwrap();
let mut state = State::load(&inner.state, Acquire);
if state.is_closed() {
return Ok(Async::Ready(()));
return Poll::Ready(());
}
if state.is_tx_task_set() {
let will_notify = inner
.tx_task
.with(|ptr| unsafe { (&*ptr).will_notify_current() });
.with(|ptr| unsafe { (&*ptr).will_wake(cx.waker()) });
if !will_notify {
state = State::unset_tx_task(&inner.state);
if state.is_closed() {
return Ok(Async::Ready(()));
return Ready(());
} else {
unsafe { inner.drop_tx_task() };
}
@@ -203,18 +203,18 @@ impl<T> Sender<T> {
if !state.is_tx_task_set() {
// Attempt to set the task
unsafe {
inner.set_tx_task();
inner.set_tx_task(cx);
}
// Update the state
state = State::set_tx_task(&inner.state);
if state.is_closed() {
return Ok(Async::Ready(()));
return Ready(());
}
}
Ok(Async::NotReady)
Pending
}
/// Check if the associated [`Receiver`] handle has been dropped.
@@ -297,25 +297,18 @@ impl<T> Drop for Receiver<T> {
}
impl<T> Future for Receiver<T> {
type Item = T;
type Error = RecvError;
fn poll(&mut self) -> Poll<T, RecvError> {
use futures::Async::{NotReady, Ready};
type Output = Result<T, RecvError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// If `inner` is `None`, then `poll()` has already completed.
let ret = if let Some(inner) = self.inner.as_ref() {
match inner.poll_recv() {
Ok(Ready(v)) => Ok(Ready(v)),
Ok(NotReady) => return Ok(NotReady),
Err(e) => Err(e),
}
let ret = if let Some(inner) = self.as_ref().get_ref().inner.as_ref() {
ready!(inner.poll_recv(cx))?
} else {
panic!("called after complete");
};
self.inner = None;
ret
Ready(Ok(ret))
}
}
@@ -328,30 +321,29 @@ impl<T> Inner<T> {
}
if prev.is_rx_task_set() {
self.rx_task.with(|ptr| unsafe { (&*ptr).notify() });
// TODO: Consume waker?
self.rx_task.with(|ptr| unsafe { (&*ptr).wake_by_ref() });
}
true
}
fn poll_recv(&self) -> Poll<T, RecvError> {
use futures::Async::{NotReady, Ready};
fn poll_recv(&self, cx: &mut Context<'_>) -> Poll<Result<T, RecvError>> {
// Load the state
let mut state = State::load(&self.state, Acquire);
if state.is_complete() {
match unsafe { self.consume_value() } {
Some(value) => Ok(Ready(value)),
None => Err(RecvError(())),
Some(value) => Ready(Ok(value)),
None => Ready(Err(RecvError(()))),
}
} else if state.is_closed() {
Err(RecvError(()))
Ready(Err(RecvError(())))
} else {
if state.is_rx_task_set() {
let will_notify = self
.rx_task
.with(|ptr| unsafe { (&*ptr).will_notify_current() });
.with(|ptr| unsafe { (&*ptr).will_wake(cx.waker()) });
// Check if the task is still the same
if !will_notify {
@@ -359,8 +351,8 @@ impl<T> Inner<T> {
state = State::unset_rx_task(&self.state);
if state.is_complete() {
return match unsafe { self.consume_value() } {
Some(value) => Ok(Ready(value)),
None => Err(RecvError(())),
Some(value) => Ready(Ok(value)),
None => Ready(Err(RecvError(()))),
};
} else {
unsafe { self.drop_rx_task() };
@@ -371,7 +363,7 @@ impl<T> Inner<T> {
if !state.is_rx_task_set() {
// Attempt to set the task
unsafe {
self.set_rx_task();
self.set_rx_task(cx);
}
// Update the state
@@ -379,14 +371,14 @@ impl<T> Inner<T> {
if state.is_complete() {
match unsafe { self.consume_value() } {
Some(value) => Ok(Ready(value)),
None => Err(RecvError(())),
Some(value) => Ready(Ok(value)),
None => Ready(Err(RecvError(()))),
}
} else {
return Ok(NotReady);
return Pending;
}
} else {
return Ok(NotReady);
return Pending;
}
}
}
@@ -396,7 +388,7 @@ impl<T> Inner<T> {
let prev = State::set_closed(&self.state);
if prev.is_tx_task_set() && !prev.is_complete() {
self.tx_task.with(|ptr| unsafe { (&*ptr).notify() });
self.tx_task.with(|ptr| unsafe { (&*ptr).wake_by_ref() });
}
}
@@ -413,14 +405,14 @@ impl<T> Inner<T> {
self.tx_task.with_mut(|ptr| ManuallyDrop::drop(&mut *ptr))
}
unsafe fn set_rx_task(&self) {
unsafe fn set_rx_task(&self, cx: &mut Context<'_>) {
self.rx_task
.with_mut(|ptr| *ptr = ManuallyDrop::new(task::current()));
.with_mut(|ptr| *ptr = ManuallyDrop::new(cx.waker().clone()));
}
unsafe fn set_tx_task(&self) {
unsafe fn set_tx_task(&self, cx: &mut Context<'_>) {
self.tx_task
.with_mut(|ptr| *ptr = ManuallyDrop::new(task::current()));
.with_mut(|ptr| *ptr = ManuallyDrop::new(cx.waker().clone()));
}
}
+38 -35
View File
@@ -6,21 +6,23 @@
//! Before accessing the shared resource, callers acquire a permit from the
//! semaphore. Once the permit is acquired, the caller then enters the critical
//! section. If no permits are available, then acquiring the semaphore returns
//! `NotReady`. The task is notified once a permit becomes available.
//! `Pending`. The task is woken once a permit becomes available.
use crate::loom::{
futures::AtomicTask,
futures::AtomicWaker,
sync::{
atomic::{AtomicPtr, AtomicUsize},
CausalCell,
},
yield_now,
};
use futures::Poll;
use std::fmt;
use std::ptr::{self, NonNull};
use std::sync::atomic::Ordering::{self, AcqRel, Acquire, Relaxed, Release};
use std::sync::Arc;
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Poll};
use std::usize;
/// Futures-aware semaphore.
@@ -80,8 +82,8 @@ struct WaiterNode {
/// See `NodeState` for more details.
state: AtomicUsize,
/// Task to notify when a permit is made available.
task: AtomicTask,
/// Task to wake when a permit is made available.
waker: AtomicWaker,
/// Next pointer in the queue of waiting senders.
next: AtomicPtr<WaiterNode>,
@@ -174,9 +176,10 @@ impl Semaphore {
}
/// Poll for a permit
fn poll_permit(&self, mut permit: Option<&mut Permit>) -> Poll<(), AcquireError> {
use futures::Async::*;
fn poll_permit(
&self,
mut permit: Option<(&mut Context<'_>, &mut Permit)>,
) -> Poll<Result<(), AcquireError>> {
// Load the current state
let mut curr = SemState::load(&self.state, Acquire);
@@ -205,7 +208,7 @@ impl Semaphore {
if curr.is_closed() {
undo_strong!();
return Err(AcquireError::closed());
return Ready(Err(AcquireError::closed()));
}
if !next.acquire_permit(&self.stub) {
@@ -214,13 +217,13 @@ impl Semaphore {
debug_assert!(curr.waiter().is_some());
if maybe_strong.is_none() {
if let Some(ref mut permit) = permit {
if let Some((ref mut cx, ref mut permit)) = permit {
// Get the Sender's waiter node, or initialize one
let waiter = permit
.waiter
.get_or_insert_with(|| Arc::new(WaiterNode::new()));
waiter.register();
waiter.register(cx);
debug!(" + poll_permit -- to_queued_waiting");
@@ -228,14 +231,14 @@ impl Semaphore {
debug!(" + poll_permit; waiter already queued");
// The node is alrady queued, there is no further work
// to do.
return Ok(NotReady);
return Pending;
}
maybe_strong = Some(WaiterNode::into_non_null(waiter.clone()));
} else {
// If no `waiter`, then the task is not registered and there
// is no further work to do.
return Ok(NotReady);
return Pending;
}
}
@@ -261,14 +264,14 @@ impl Semaphore {
debug!(" + poll_permit -- waiter pushed");
return Ok(NotReady);
return Pending;
}
None => {
debug!(" + poll_permit -- permit acquired");
undo_strong!();
return Ok(Ready(()));
return Ready(Ok(()));
}
}
}
@@ -571,42 +574,42 @@ impl Permit {
/// Try to acquire the permit. If no permits are available, the current task
/// is notified once a new permit becomes available.
pub fn poll_acquire(&mut self, semaphore: &Semaphore) -> Poll<(), AcquireError> {
use futures::Async::*;
pub fn poll_acquire(
&mut self,
cx: &mut Context<'_>,
semaphore: &Semaphore,
) -> Poll<Result<(), AcquireError>> {
match self.state {
PermitState::Idle => {}
PermitState::Waiting => {
let waiter = self.waiter.as_ref().unwrap();
if waiter.acquire()? {
if waiter.acquire(cx)? {
self.state = PermitState::Acquired;
return Ok(Ready(()));
return Ready(Ok(()));
} else {
return Ok(NotReady);
return Pending;
}
}
PermitState::Acquired => {
return Ok(Ready(()));
return Ready(Ok(()));
}
}
match semaphore.poll_permit(Some(self))? {
match semaphore.poll_permit(Some((cx, self)))? {
Ready(v) => {
self.state = PermitState::Acquired;
Ok(Ready(v))
Ready(Ok(v))
}
NotReady => {
Pending => {
self.state = PermitState::Waiting;
Ok(NotReady)
Pending
}
}
}
/// Try to acquire the permit.
pub fn try_acquire(&mut self, semaphore: &Semaphore) -> Result<(), TryAcquireError> {
use futures::Async::*;
match self.state {
PermitState::Idle => {}
PermitState::Waiting => {
@@ -629,7 +632,7 @@ impl Permit {
self.state = PermitState::Acquired;
Ok(())
}
NotReady => Err(TryAcquireError::no_permits()),
Pending => Err(TryAcquireError::no_permits()),
}
}
@@ -748,17 +751,17 @@ impl WaiterNode {
fn new() -> WaiterNode {
WaiterNode {
state: AtomicUsize::new(NodeState::new().to_usize()),
task: AtomicTask::new(),
waker: AtomicWaker::new(),
next: AtomicPtr::new(ptr::null_mut()),
}
}
fn acquire(&self) -> Result<bool, AcquireError> {
fn acquire(&self, cx: &mut Context<'_>) -> Result<bool, AcquireError> {
if self.acquire2()? {
return Ok(true);
}
self.task.register();
self.waker.register_by_ref(cx.waker());
self.acquire2()
}
@@ -773,8 +776,8 @@ impl WaiterNode {
}
}
fn register(&self) {
self.task.register()
fn register(&self, cx: &mut Context<'_>) {
self.waker.register_by_ref(cx.waker())
}
/// Returns `true` if the permit has been acquired
@@ -860,7 +863,7 @@ impl WaiterNode {
Ok(_) => match curr {
QueuedWaiting => {
debug!(" + notify -- task notified");
self.task.notify();
self.waker.wake();
return true;
}
other => {
-336
View File
@@ -1,336 +0,0 @@
use crate::loom::{
futures::task::{self, Task},
sync::atomic::AtomicUsize,
sync::CausalCell,
};
use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
/// A synchronization primitive for task notification.
///
/// `AtomicTask` will coordinate concurrent notifications with the consumer
/// potentially "updating" the underlying task to notify. This is useful in
/// scenarios where a computation completes in another thread and wants to
/// notify the consumer, but the consumer is in the process of being migrated to
/// a new logical task.
///
/// Consumers should call `register` before checking the result of a computation
/// and producers should call `notify` after producing the computation (this
/// differs from the usual `thread::park` pattern). It is also permitted for
/// `notify` to be called **before** `register`. This results in a no-op.
///
/// A single `AtomicTask` may be reused for any number of calls to `register` or
/// `notify`.
///
/// `AtomicTask` does not provide any memory ordering guarantees, as such the
/// user should use caution and use other synchronization primitives to guard
/// the result of the underlying computation.
pub struct AtomicTask {
state: AtomicUsize,
task: CausalCell<Option<Task>>,
}
// `AtomicTask` is a multi-consumer, single-producer transfer cell. The cell
// stores a `Task` value produced by calls to `register` and many threads can
// race to take the task (to notify it) by calling `notify.
//
// If a new `Task` instance is produced by calling `register` before an existing
// one is consumed, then the existing one is overwritten.
//
// While `AtomicTask` is single-producer, the implementation ensures memory
// safety. In the event of concurrent calls to `register`, there will be a
// single winner whose task will get stored in the cell. The losers will not
// have their tasks notified. As such, callers should ensure to add
// synchronization to calls to `register`.
//
// The implementation uses a single `AtomicUsize` value to coordinate access to
// the `Task` cell. There are two bits that are operated on independently. These
// are represented by `REGISTERING` and `NOTIFYING`.
//
// The `REGISTERING` bit is set when a producer enters the critical section. The
// `NOTIFYING` bit is set when a consumer enters the critical section. Neither
// bit being set is represented by `WAITING`.
//
// A thread obtains an exclusive lock on the task cell by transitioning the
// state from `WAITING` to `REGISTERING` or `NOTIFYING`, depending on the
// operation the thread wishes to perform. When this transition is made, it is
// guaranteed that no other thread will access the task cell.
//
// # Registering
//
// On a call to `register`, an attempt to transition the state from WAITING to
// REGISTERING is made. On success, the caller obtains a lock on the task cell.
//
// If the lock is obtained, then the thread sets the task cell to the task
// provided as an argument. Then it attempts to transition the state back from
// `REGISTERING` -> `WAITING`.
//
// If this transition is successful, then the registering process is complete
// and the next call to `notify` will observe the task.
//
// If the transition fails, then there was a concurrent call to `notify` that
// was unable to access the task cell (due to the registering thread holding the
// lock). To handle this, the registering thread removes the task it just set
// from the cell and calls `notify` on it. This call to notify represents the
// attempt to notify by the other thread (that set the `NOTIFYING` bit). The
// state is then transitioned from `REGISTERING | NOTIFYING` back to `WAITING`.
// This transition must succeed because, at this point, the state cannot be
// transitioned by another thread.
//
// # Notifying
//
// On a call to `notify`, an attempt to transition the state from `WAITING` to
// `NOTIFYING` is made. On success, the caller obtains a lock on the task cell.
//
// If the lock is obtained, then the thread takes ownership of the current value
// in teh task cell, and calls `notify` on it. The state is then transitioned
// back to `WAITING`. This transition must succeed as, at this point, the state
// cannot be transitioned by another thread.
//
// If the thread is unable to obtain the lock, the `NOTIFYING` bit is still.
// This is because it has either been set by the current thread but the previous
// value included the `REGISTERING` bit **or** a concurrent thread is in the
// `NOTIFYING` critical section. Either way, no action must be taken.
//
// If the current thread is the only concurrent call to `notify` and another
// thread is in the `register` critical section, when the other thread **exits**
// the `register` critical section, it will observe the `NOTIFYING` bit and
// handle the notify itself.
//
// If another thread is in the `notify` critical section, then it will handle
// notifying the task.
//
// # A potential race (is safely handled).
//
// Imagine the following situation:
//
// * Thread A obtains the `notify` lock and notifies a task.
//
// * Before thread A releases the `notify` lock, the notified task is scheduled.
//
// * Thread B attempts to notify the task. In theory this should result in the
// task being notified, but it cannot because thread A still holds the notify
// lock.
//
// This case is handled by requiring users of `AtomicTask` to call `register`
// **before** attempting to observe the application state change that resulted
// in the task being notified. The notifiers also change the application state
// before calling notify.
//
// Because of this, the task will do one of two things.
//
// 1) Observe the application state change that Thread B is notifying on. In
// this case, it is OK for Thread B's notification to be lost.
//
// 2) Call register before attempting to observe the application state. Since
// Thread A still holds the `notify` lock, the call to `register` will result
// in the task notifying itself and get scheduled again.
/// Idle state
const WAITING: usize = 0;
/// A new task value is being registered with the `AtomicTask` cell.
const REGISTERING: usize = 0b01;
/// The task currently registered with the `AtomicTask` cell is being notified.
const NOTIFYING: usize = 0b10;
impl AtomicTask {
/// Create an `AtomicTask` initialized with the given `Task`
pub fn new() -> AtomicTask {
AtomicTask {
state: AtomicUsize::new(WAITING),
task: CausalCell::new(None),
}
}
/// Registers the current task to be notified on calls to `notify`.
///
/// This is the same as calling `register_task` with `task::current()`.
pub fn register(&self) {
self.do_register(CurrentTask);
}
/// Registers the provided task to be notified on calls to `notify`.
///
/// The new task will take place of any previous tasks that were registered
/// by previous calls to `register`. Any calls to `notify` that happen after
/// a call to `register` (as defined by the memory ordering rules), will
/// notify the `register` caller's task.
///
/// It is safe to call `register` with multiple other threads concurrently
/// calling `notify`. This will result in the `register` caller's current
/// task being notified once.
///
/// This function is safe to call concurrently, but this is generally a bad
/// idea. Concurrent calls to `register` will attempt to register different
/// tasks to be notified. One of the callers will win and have its task set,
/// but there is no guarantee as to which caller will succeed.
pub fn register_task(&self, task: Task) {
self.do_register(ExactTask(task));
}
fn do_register<R>(&self, reg: R)
where
R: Register,
{
debug!(" + register_task");
match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) {
WAITING => {
unsafe {
// Locked acquired, update the waker cell
self.task.with_mut(|t| reg.register(&mut *t));
// Release the lock. If the state transitioned to include
// the `NOTIFYING` bit, this means that a notify has been
// called concurrently, so we have to remove the task and
// notify it.`
//
// Start by assuming that the state is `REGISTERING` as this
// is what we jut set it to.
let res = self
.state
.compare_exchange(REGISTERING, WAITING, AcqRel, Acquire);
match res {
Ok(_) => {}
Err(actual) => {
// This branch can only be reached if a
// concurrent thread called `notify`. In this
// case, `actual` **must** be `REGISTERING |
// `NOTIFYING`.
debug_assert_eq!(actual, REGISTERING | NOTIFYING);
// Take the task to notify once the atomic operation has
// completed.
let notify = self.task.with_mut(|t| (*t).take()).unwrap();
// Just swap, because no one could change state
// while state == `Registering | `Waking`
self.state.swap(WAITING, AcqRel);
// The atomic swap was complete, now
// notify the task and return.
notify.notify();
}
}
}
}
NOTIFYING => {
// Currently in the process of notifying the task, i.e.,
// `notify` is currently being called on the old task handle.
// So, we call notify on the new task handle
reg.notify();
}
state => {
// In this case, a concurrent thread is holding the
// "registering" lock. This probably indicates a bug in the
// caller's code as racing to call `register` doesn't make much
// sense.
//
// We just want to maintain memory safety. It is ok to drop the
// call to `register`.
debug_assert!(state == REGISTERING || state == REGISTERING | NOTIFYING);
}
}
}
/// Notifies the task that last called `register`.
///
/// If `register` has not been called yet, then this does nothing.
pub fn notify(&self) {
debug!(" + notify");
if let Some(task) = self.take_task() {
task.notify();
}
}
/// Attempts to take the `Task` value out of the `AtomicTask` with the
/// intention that the caller will notify the task later.
pub fn take_task(&self) -> Option<Task> {
debug!(" + take_task");
// AcqRel ordering is used in order to acquire the value of the `task`
// cell as well as to establish a `release` ordering with whatever
// memory the `AtomicTask` is associated with.
match self.state.fetch_or(NOTIFYING, AcqRel) {
WAITING => {
debug!(" + WAITING");
// The notifying lock has been acquired.
let task = unsafe { self.task.with_mut(|t| (*t).take()) };
// Release the lock
self.state.fetch_and(!NOTIFYING, Release);
debug!(" + Done taking");
task
}
state => {
debug!(" + state = {:?}", state);
// There is a concurrent thread currently updating the
// associated task.
//
// Nothing more to do as the `NOTIFYING` bit has been set. It
// doesn't matter if there are concurrent registering threads or
// not.
//
debug_assert!(
state == REGISTERING || state == REGISTERING | NOTIFYING || state == NOTIFYING
);
None
}
}
}
}
impl Default for AtomicTask {
fn default() -> Self {
AtomicTask::new()
}
}
impl fmt::Debug for AtomicTask {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "AtomicTask")
}
}
unsafe impl Send for AtomicTask {}
unsafe impl Sync for AtomicTask {}
trait Register {
fn register(self, slot: &mut Option<Task>);
fn notify(self);
}
struct CurrentTask;
impl Register for CurrentTask {
fn register(self, slot: &mut Option<Task>) {
let should_update = (&*slot)
.as_ref()
.map(|prev| !prev.will_notify_current())
.unwrap_or(true);
if should_update {
*slot = Some(task::current());
}
}
fn notify(self) {
task::current().notify();
}
}
struct ExactTask(Task);
impl Register for ExactTask {
fn register(self, slot: &mut Option<Task>) {
// When calling register_task with an exact task, it doesn't matter
// if the previous task would have notified current. We *always* want
// to save that exact task.
*slot = Some(self.0);
}
fn notify(self) {
self.0.notify();
}
}
+317
View File
@@ -0,0 +1,317 @@
use crate::loom::{sync::atomic::AtomicUsize, sync::CausalCell};
use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::task::Waker;
/// A synchronization primitive for task waking.
///
/// `AtomicWaker` will coordinate concurrent wakes with the consumer
/// potentially "waking" the underlying task. This is useful in scenarios
/// where a computation completes in another thread and wants to wake the
/// consumer, but the consumer is in the process of being migrated to a new
/// logical task.
///
/// Consumers should call `register` before checking the result of a computation
/// and producers should call `wake` after producing the computation (this
/// differs from the usual `thread::park` pattern). It is also permitted for
/// `wake` to be called **before** `register`. This results in a no-op.
///
/// A single `AtomicWaker` may be reused for any number of calls to `register` or
/// `wake`.
pub struct AtomicWaker {
state: AtomicUsize,
waker: CausalCell<Option<Waker>>,
}
// `AtomicWaker` is a multi-consumer, single-producer transfer cell. The cell
// stores a `Waker` value produced by calls to `register` and many threads can
// race to take the waker by calling `wake.
//
// If a new `Waker` instance is produced by calling `register` before an existing
// one is consumed, then the existing one is overwritten.
//
// While `AtomicWaker` is single-producer, the implementation ensures memory
// safety. In the event of concurrent calls to `register`, there will be a
// single winner whose waker will get stored in the cell. The losers will not
// have their tasks woken. As such, callers should ensure to add synchronization
// to calls to `register`.
//
// The implementation uses a single `AtomicUsize` value to coordinate access to
// the `Waker` cell. There are two bits that are operated on independently. These
// are represented by `REGISTERING` and `WAKING`.
//
// The `REGISTERING` bit is set when a producer enters the critical section. The
// `WAKING` bit is set when a consumer enters the critical section. Neither
// bit being set is represented by `WAITING`.
//
// A thread obtains an exclusive lock on the waker cell by transitioning the
// state from `WAITING` to `REGISTERING` or `WAKING`, depending on the
// operation the thread wishes to perform. When this transition is made, it is
// guaranteed that no other thread will access the waker cell.
//
// # Registering
//
// On a call to `register`, an attempt to transition the state from WAITING to
// REGISTERING is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread sets the waker cell to the waker
// provided as an argument. Then it attempts to transition the state back from
// `REGISTERING` -> `WAITING`.
//
// If this transition is successful, then the registering process is complete
// and the next call to `wake` will observe the waker.
//
// If the transition fails, then there was a concurrent call to `wake` that
// was unable to access the waker cell (due to the registering thread holding the
// lock). To handle this, the registering thread removes the waker it just set
// from the cell and calls `wake` on it. This call to wake represents the
// attempt to wake by the other thread (that set the `WAKING` bit). The
// state is then transitioned from `REGISTERING | WAKING` back to `WAITING`.
// This transition must succeed because, at this point, the state cannot be
// transitioned by another thread.
//
// # Waking
//
// On a call to `wake`, an attempt to transition the state from `WAITING` to
// `WAKING` is made. On success, the caller obtains a lock on the waker cell.
//
// If the lock is obtained, then the thread takes ownership of the current value
// in the waker cell, and calls `wake` on it. The state is then transitioned
// back to `WAITING`. This transition must succeed as, at this point, the state
// cannot be transitioned by another thread.
//
// If the thread is unable to obtain the lock, the `WAKING` bit is still.
// This is because it has either been set by the current thread but the previous
// value included the `REGISTERING` bit **or** a concurrent thread is in the
// `WAKING` critical section. Either way, no action must be taken.
//
// If the current thread is the only concurrent call to `wake` and another
// thread is in the `register` critical section, when the other thread **exits**
// the `register` critical section, it will observe the `WAKING` bit and
// handle the waker itself.
//
// If another thread is in the `waker` critical section, then it will handle
// waking the caller task.
//
// # A potential race (is safely handled).
//
// Imagine the following situation:
//
// * Thread A obtains the `wake` lock and wakes a task.
//
// * Before thread A releases the `wake` lock, the woken task is scheduled.
//
// * Thread B attempts to wake the task. In theory this should result in the
// task being woken, but it cannot because thread A still holds the wake
// lock.
//
// This case is handled by requiring users of `AtomicWaker` to call `register`
// **before** attempting to observe the application state change that resulted
// in the task being woken. The wakers also change the application state
// before calling wake.
//
// Because of this, the task will do one of two things.
//
// 1) Observe the application state change that Thread B is waking on. In
// this case, it is OK for Thread B's wake to be lost.
//
// 2) Call register before attempting to observe the application state. Since
// Thread A still holds the `wake` lock, the call to `register` will result
// in the task waking itself and get scheduled again.
/// Idle state
const WAITING: usize = 0;
/// A new waker value is being registered with the `AtomicWaker` cell.
const REGISTERING: usize = 0b01;
/// The task currently registered with the `AtomicWaker` cell is being woken.
const WAKING: usize = 0b10;
impl AtomicWaker {
/// Create an `AtomicWaker`
pub fn new() -> AtomicWaker {
AtomicWaker {
state: AtomicUsize::new(WAITING),
waker: CausalCell::new(None),
}
}
/// Registers the current waker to be notified on calls to `wake`.
///
/// This is the same as calling `register_task` with `task::current()`.
pub fn register(&self, waker: Waker) {
self.do_register(waker);
}
/// Registers the provided waker to be notified on calls to `wake`.
///
/// The new waker will take place of any previous wakers that were registered
/// by previous calls to `register`. Any calls to `wake` that happen after
/// a call to `register` (as defined by the memory ordering rules), will
/// wake the `register` caller's task.
///
/// It is safe to call `register` with multiple other threads concurrently
/// calling `wake`. This will result in the `register` caller's current
/// task being woken once.
///
/// This function is safe to call concurrently, but this is generally a bad
/// idea. Concurrent calls to `register` will attempt to register different
/// tasks to be woken. One of the callers will win and have its task set,
/// but there is no guarantee as to which caller will succeed.
pub fn register_by_ref(&self, waker: &Waker) {
self.do_register(waker);
}
fn do_register<W>(&self, waker: W)
where
W: WakerRef,
{
debug!(" + register_task");
match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) {
WAITING => {
unsafe {
// Locked acquired, update the waker cell
self.waker.with_mut(|t| *t = Some(waker.into_waker()));
// Release the lock. If the state transitioned to include
// the `WAKING` bit, this means that a wake has been
// called concurrently, so we have to remove the waker and
// wake it.`
//
// Start by assuming that the state is `REGISTERING` as this
// is what we jut set it to.
let res = self
.state
.compare_exchange(REGISTERING, WAITING, AcqRel, Acquire);
match res {
Ok(_) => {}
Err(actual) => {
// This branch can only be reached if a
// concurrent thread called `wake`. In this
// case, `actual` **must** be `REGISTERING |
// `WAKING`.
debug_assert_eq!(actual, REGISTERING | WAKING);
// Take the waker to wake once the atomic operation has
// completed.
let waker = self.waker.with_mut(|t| (*t).take()).unwrap();
// Just swap, because no one could change state
// while state == `Registering | `Waking`
self.state.swap(WAITING, AcqRel);
// The atomic swap was complete, now
// wake the waker and return.
waker.wake();
}
}
}
}
WAKING => {
// Currently in the process of waking the task, i.e.,
// `wake` is currently being called on the old waker.
// So, we call wake on the new waker.
waker.wake();
}
state => {
// In this case, a concurrent thread is holding the
// "registering" lock. This probably indicates a bug in the
// caller's code as racing to call `register` doesn't make much
// sense.
//
// We just want to maintain memory safety. It is ok to drop the
// call to `register`.
debug_assert!(state == REGISTERING || state == REGISTERING | WAKING);
}
}
}
/// Wakes the task that last called `register`.
///
/// If `register` has not been called yet, then this does nothing.
pub fn wake(&self) {
debug!(" + wake");
if let Some(waker) = self.take_waker() {
waker.wake();
}
}
/// Attempts to take the `Waker` value out of the `AtomicWaker` with the
/// intention that the caller will wake the task later.
pub fn take_waker(&self) -> Option<Waker> {
debug!(" + take_waker");
// AcqRel ordering is used in order to acquire the value of the `waker`
// cell as well as to establish a `release` ordering with whatever
// memory the `AtomicWaker` is associated with.
match self.state.fetch_or(WAKING, AcqRel) {
WAITING => {
debug!(" + WAITING");
// The waking lock has been acquired.
let waker = unsafe { self.waker.with_mut(|t| (*t).take()) };
// Release the lock
self.state.fetch_and(!WAKING, Release);
debug!(" + Done taking");
waker
}
state => {
debug!(" + state = {:?}", state);
// There is a concurrent thread currently updating the
// associated waker.
//
// Nothing more to do as the `WAKING` bit has been set. It
// doesn't matter if there are concurrent registering threads or
// not.
//
debug_assert!(
state == REGISTERING || state == REGISTERING | WAKING || state == WAKING
);
None
}
}
}
}
impl Default for AtomicWaker {
fn default() -> Self {
AtomicWaker::new()
}
}
impl fmt::Debug for AtomicWaker {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "AtomicWaker")
}
}
unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}
trait WakerRef {
fn wake(self);
fn into_waker(self) -> Waker;
}
impl WakerRef for Waker {
fn wake(self) {
self.wake()
}
fn into_waker(self) -> Waker {
self
}
}
impl<'a> WakerRef for &'a Waker {
fn wake(self) {
self.wake_by_ref()
}
fn into_waker(self) -> Waker {
self.clone()
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
//! Thread-safe task notification primitives.
mod atomic_task;
mod atomic_waker;
pub use self::atomic_task::AtomicTask;
pub use self::atomic_waker::AtomicWaker;

Some files were not shown because too many files have changed in this diff Show More