diff --git a/.cirrus.yml b/.cirrus.yml index 89161f5c9..75eccc81b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -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 diff --git a/Cargo.toml b/Cargo.toml index bf2fe1e13..e522bc7d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", ] diff --git a/async-await/.cargo/config b/async-await/.cargo/config deleted file mode 100644 index ec6a5d0a2..000000000 --- a/async-await/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target-dir = "../target" diff --git a/async-await/Cargo.toml b/async-await/Cargo.toml deleted file mode 100644 index 52933b28d..000000000 --- a/async-await/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "examples" -edition = "2018" -version = "0.1.0" -authors = ["Carl Lerche "] -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" diff --git a/async-await/README.md b/async-await/README.md deleted file mode 100644 index bd360f0e1..000000000 --- a/async-await/README.md +++ /dev/null @@ -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. diff --git a/async-await/src/chat.rs b/async-await/src/chat.rs deleted file mode 100644 index d3a0c9928..000000000 --- a/async-await/src/chat.rs +++ /dev/null @@ -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; - -struct Shared { - peers: HashMap, -} - -impl Shared { - /// Create a new, empty, instance of `Shared`. - fn new() -> Self { - Shared { - peers: HashMap::new(), - } - } -} - -async fn process(stream: TcpStream, state: Arc>) -> 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"); - } - }); - } -} - diff --git a/async-await/src/echo_client.rs b/async-await/src/echo_client.rs deleted file mode 100644 index 302b7ea22..000000000 --- a/async-await/src/echo_client.rs +++ /dev/null @@ -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::().unwrap(); - - // Connect to the echo serveer - - match async_wait!(run_client(&addr)) { - Ok(_) => println!("done."), - Err(e) => eprintln!("echo client failed; error = {:?}", e), - } -} diff --git a/async-await/src/echo_server.rs b/async-await/src/echo_server.rs deleted file mode 100644 index 63e10e31a..000000000 --- a/async-await/src/echo_server.rs +++ /dev/null @@ -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::().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); - } -} diff --git a/async-await/src/hyper.rs b/async-await/src/hyper.rs deleted file mode 100644 index 37332ee40..000000000 --- a/async-await/src/hyper.rs +++ /dev/null @@ -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()); - } -} diff --git a/async-await/tests/macros.rs b/async-await/tests/macros.rs deleted file mode 100644 index 1fcbf77bc..000000000 --- a/async-await/tests/macros.rs +++ /dev/null @@ -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)); -} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1ad71db8a..be5d1e9b5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -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 diff --git a/ci/azure-install-rust.yml b/ci/azure-install-rust.yml index 43d806e7f..2892ab897 100644 --- a/ci/azure-install-rust.yml +++ b/ci/azure-install-rust.yml @@ -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 diff --git a/ci/azure-rustfmt.yml b/ci/azure-rustfmt.yml index 60bb51aa5..0f50b6c26 100644 --- a/ci/azure-rustfmt.yml +++ b/ci/azure-rustfmt.yml @@ -10,6 +10,7 @@ jobs: rust_version: stable - script: | rustup component add rustfmt + cargo fmt --version displayName: Install rustfmt - script: | cargo fmt --all -- --check diff --git a/ci/azure-test-stable.yml b/ci/azure-test-stable.yml index f53ca0eb5..f2fa78975 100644 --- a/ci/azure-test-stable.yml +++ b/ci/azure-test-stable.yml @@ -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' diff --git a/tokio-current-thread/Cargo.toml b/tokio-current-thread/Cargo.toml index af54d114e..f25a59c81 100644 --- a/tokio-current-thread/Cargo.toml +++ b/tokio-current-thread/Cargo.toml @@ -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" } diff --git a/tokio-current-thread/src/lib.rs b/tokio-current-thread/src/lib.rs index a9800d8c8..289f9af1e 100644 --- a/tokio-current-thread/src/lib.rs +++ b/tokio-current-thread/src/lib.rs @@ -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 { spawn_handle: Handle, /// Receiver for futures spawned from other threads - spawn_receiver: mpsc::Receiver + Send + 'static>>, + spawn_receiver: mpsc::Receiver + 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>, - already_counted: bool, - ); + fn spawn_local(&mut self, future: Pin>>, already_counted: bool); } struct CurrentRunner { @@ -225,7 +222,7 @@ thread_local! { /// /// [`CurrentThread`]: struct.CurrentThread.html /// [mod]: index.html -pub fn block_on_all(future: F) -> Result +pub fn block_on_all(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(future: F) where - F: Future + 'static, + F: Future + 'static, { TaskExecutor::current() - .spawn_local(Box::new(future)) + .spawn_local(Box::pin(future)) .unwrap(); } @@ -283,7 +279,7 @@ impl CurrentThread

{ }); 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 CurrentThread

{ 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 CurrentThread

{ /// This internally queues the future to be executed once `run` is called. pub fn spawn(&mut self, future: F) -> &mut Self where - F: Future + 'static, + F: Future + 'static, { - self.borrow().spawn_local(Box::new(future), false); + self.borrow().spawn_local(Box::pin(future), false); self } @@ -338,7 +334,7 @@ impl CurrentThread

{ /// /// The caller is responsible for ensuring that other spawned futures /// complete execution. - pub fn block_on(&mut self, future: F) -> Result> + pub fn block_on(&mut self, future: F) -> F::Output where F: Future, { @@ -424,7 +420,7 @@ impl Drop for CurrentThread

{ impl tokio_executor::Executor for CurrentThread { fn spawn( &mut self, - future: Box + Send>, + future: Pin + Send>>, ) -> Result<(), SpawnError> { self.borrow().spawn_local(future, false); Ok(()) @@ -433,10 +429,10 @@ impl tokio_executor::Executor for CurrentThread { impl tokio_executor::TypedExecutor for CurrentThread where - T: Future + 'static, + T: Future + '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(&mut self, future: F) -> &mut Self where - F: Future + 'static, + F: Future + '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(&mut self, future: F) -> Result> + /// + /// # Panics + /// + /// This function will panic if the `Park` call returns an error. + pub fn block_on(&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(¬ify, 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 + Send + 'static>>, + sender: mpsc::Sender + Send + 'static>>>, num_futures: Arc, shut_down: Cell, - 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(&self, future: F) -> Result<(), SpawnError> where - F: Future + Send + 'static, + F: Future + 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>, + future: Pin>>, ) -> 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 + Send>, + future: Pin + Send>>, ) -> Result<(), SpawnError> { self.spawn_local(future) } @@ -754,25 +756,10 @@ impl tokio_executor::Executor for TaskExecutor { impl tokio_executor::TypedExecutor for TaskExecutor where - F: Future + 'static, + F: Future + 'static, { fn spawn(&mut self, future: F) -> Result<(), SpawnError> { - self.spawn_local(Box::new(future)) - } -} - -impl Executor for TaskExecutor -where - F: Future + 'static, -{ - fn execute(&self, future: F) -> Result<(), ExecuteError> { - 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>, - already_counted: bool, - ) { + fn spawn_local(&mut self, future: Pin>>, 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 diff --git a/tokio-current-thread/src/scheduler.rs b/tokio-current-thread/src/scheduler.rs index decef395b..709ac415d 100644 --- a/tokio-current-thread/src/scheduler.rs +++ b/tokio-current-thread/src/scheduler.rs @@ -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 { nodes: List, } -pub struct Notify<'a, U>(&'a Arc>); - // A linked-list of nodes struct List { len: usize, @@ -78,12 +76,6 @@ struct Inner { unsafe impl Send for Inner {} unsafe impl Sync for Inner {} -impl executor::Notify for Inner { - fn notify(&self, _: usize) { - self.unpark.unpark(); - } -} - struct Node { // The item item: UnsafeCell>, @@ -123,12 +115,12 @@ enum Dequeue { } /// Wraps a spawned boxed future -struct Task(Spawn>>); +struct Task(Pin>>); /// 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>, 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>) { + pub fn schedule(&mut self, item: Pin>>) { // 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: ¬ify, + 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 + 'static>) -> Self { - Task(executor::spawn(future)) + pub fn new(future: Pin + 'static>>) -> Self { + Task(future) } } @@ -630,63 +626,101 @@ impl List { } } -impl<'a, U> Clone for Notify<'a, U> { - fn clone(&self) -> Self { - Notify(self.0) - } +unsafe fn noop(_: *const ()) {} + +// ===== Raw Waker Inner ====== + +fn waker_inner(inner: Arc>) -> Waker { + let ptr = Arc::into_raw(inner) as *const (); + let vtable = &RawWakerVTable::new( + clone_inner::, + wake_inner::, + wake_by_ref_inner::, + drop_inner::, + ); + + 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(data: *const ()) -> RawWaker { + let arc: Arc> = Arc::from_raw(data as *const Inner); + 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::, + wake_inner::, + wake_by_ref_inner::, + drop_inner::, + ); + RawWaker::new(data, vtable) } -impl<'a, U: Unpark> From> for NotifyHandle { - fn from(handle: Notify<'a, U>) -> NotifyHandle { - unsafe { - let ptr = handle.0.clone(); - let ptr = mem::transmute::>, *mut ArcNode>(ptr); - NotifyHandle::new(hide_lt(ptr)) - } - } +unsafe fn wake_inner(data: *const ()) { + let arc: Arc> = Arc::from_raw(data as *const Inner); + arc.unpark.unpark(); } -struct ArcNode(PhantomData); - -// We should never touch `Task` on any thread other than the one owning -// `Scheduler`, so this should be a safe operation. -unsafe impl Send for ArcNode {} -unsafe impl Sync for ArcNode {} - -impl executor::Notify for ArcNode { - fn notify(&self, _id: usize) { - unsafe { - let me: *const ArcNode = self; - let me: *const *const ArcNode = &me; - let me = me as *const Arc>; - Node::notify(&*me) - } - } +unsafe fn wake_by_ref_inner(data: *const ()) { + let arc: Arc> = Arc::from_raw(data as *const Inner); + arc.unpark.unpark(); + // by_ref means we don't own the Node, so forget the Arc + mem::forget(arc); } -unsafe impl UnsafeNotify for ArcNode { - unsafe fn clone_raw(&self) -> NotifyHandle { - let me: *const ArcNode = self; - let me: *const *const ArcNode = &me; - let me = &*(me as *const Arc>); - Notify(me).into() - } +unsafe fn drop_inner(data: *const ()) { + drop(Arc::>::from_raw(data as *const Inner)); +} +// ===== Raw Waker Node ====== - unsafe fn drop_raw(&self) { - let mut me: *const ArcNode = self; - let me = &mut me as *mut *const ArcNode as *mut Arc>; - ptr::drop_in_place(me); - } +unsafe fn waker_ref(node: &Arc>) -> Waker { + let ptr = &*node as &Node as *const Node as *const (); + let vtable = &RawWakerVTable::new( + clone_node::, + wake_unreachable, + wake_by_ref_node::, + noop, + ); + + Waker::from_raw(RawWaker::new(ptr, vtable)) } -unsafe fn hide_lt(p: *mut ArcNode) -> *mut dyn UnsafeNotify { - mem::transmute(p as *mut dyn UnsafeNotify) +unsafe fn wake_unreachable(_data: *const ()) { + unreachable!("waker_ref::wake()"); +} + +unsafe fn clone_node(data: *const ()) -> RawWaker { + let arc: Arc> = Arc::from_raw(data as *const Node); + 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::, + wake_node::, + wake_by_ref_node::, + drop_node::, + ); + RawWaker::new(data, vtable) +} + +unsafe fn wake_node(data: *const ()) { + let arc: Arc> = Arc::from_raw(data as *const Node); + Node::::notify(&arc); +} + +unsafe fn wake_by_ref_node(data: *const ()) { + let arc: Arc> = Arc::from_raw(data as *const Node); + Node::::notify(&arc); + // by_ref means we don't own the Node, so forget the Arc + mem::forget(arc); +} + +unsafe fn drop_node(data: *const ()) { + drop(Arc::>::from_raw(data as *const Node)); } impl Node { diff --git a/tokio-current-thread/tests/current_thread.rs b/tokio-current-thread/tests/current_thread.rs index 7336baf6e..794345cdb 100644 --- a/tokio-current-thread/tests/current_thread.rs +++ b/tokio-current-thread/tests/current_thread.rs @@ -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>) + 'static>(spawn: F) { + fn test>>) + '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 + Send>) -> Result<(), E> + 'static, E>( + fn test + 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>)>(spawn: F) { + fn test>>)>(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(spawn: F, dotspawn: G) where - F: Fn(Box>) + 'static, - G: Fn(&mut CurrentThread, Box>), + F: Fn(Pin>>) + 'static, + G: Fn(&mut CurrentThread, Pin>>), { 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>, - } - - 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>) { + 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>, - idx: usize, - } - impl Future for Spin { - type Item = (); - type Error = (); + async fn spin(state: Rc>, 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(spawn: F) { + fn test>>)>(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(spawn: F, dotspawn: G) where - F: Fn(Box>) + 'static, - G: Fn(&mut CurrentThread, Box>), + F: Fn(Pin>>) + 'static, + G: Fn(&mut CurrentThread, Pin>>), { 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, - } - - impl Future for MyFuture { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll<(), ()> { - Ok(().into()) - } - } + async fn noop(_data: Box) {} fn test(spawn: F, dotspawn: G) where - F: Fn(Box>) + 'static, - G: Fn(&mut CurrentThread, Box>), + F: Fn(Pin>>) + 'static, + G: Fn(&mut CurrentThread, Pin>>), { 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 + } + } } diff --git a/tokio-executor/Cargo.toml b/tokio-executor/Cargo.toml index 5f8ae6a42..da2303469 100644 --- a/tokio-executor/Cargo.toml +++ b/tokio-executor/Cargo.toml @@ -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" } diff --git a/tokio-executor/src/enter.rs b/tokio-executor/src/enter.rs index 0ef6ddcb1..02b354201 100644 --- a/tokio-executor/src/enter.rs +++ b/tokio-executor/src/enter.rs @@ -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 = Cell::new(false)); @@ -65,8 +64,25 @@ pub fn enter() -> Result { impl Enter { /// Blocks the thread on the specified future, returning the value with /// which that future completes. - pub fn block_on(&mut self, f: F) -> Result { - futures::executor::spawn(f).wait_future() + pub fn block_on(&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; + } + } } } diff --git a/tokio-executor/src/executor.rs b/tokio-executor/src/executor.rs index c0b156f08..45a65ca15 100644 --- a/tokio-executor/src/executor.rs +++ b/tokio-executor/src/executor.rs @@ -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 + Send>, - ) -> Result<(), SpawnError>; + fn spawn(&mut self, future: Pin + 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 Executor for Box { fn spawn( &mut self, - future: Box + Send>, + future: Pin + Send>>, ) -> Result<(), SpawnError> { (**self).spawn(future) } diff --git a/tokio-executor/src/global.rs b/tokio-executor/src/global.rs index 1c4c53ff8..f2745123d 100644 --- a/tokio-executor/src/global.rs +++ b/tokio-executor/src/global.rs @@ -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 + Send>, + future: Pin + 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 super::TypedExecutor for DefaultExecutor where - T: Future + Send + 'static, + T: Future + 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 future::Executor for DefaultExecutor -where - T: Future + Send + 'static, -{ - fn execute(&self, future: T) -> Result<(), future::ExecuteError> { - 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(future: T) where - T: Future + Send + 'static, + T: Future + 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 diff --git a/tokio-executor/src/park.rs b/tokio-executor/src/park.rs index b7c4dbf05..35cd846b4 100644 --- a/tokio-executor/src/park.rs +++ b/tokio-executor/src/park.rs @@ -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); +} diff --git a/tokio-executor/tests/enter.rs b/tokio-executor/tests/enter.rs new file mode 100644 index 000000000..c0586d666 --- /dev/null +++ b/tokio-executor/tests/enter.rs @@ -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); +} diff --git a/tokio-executor/tests/executor.rs b/tokio-executor/tests/executor.rs index c424df50f..930f91162 100644 --- a/tokio-executor/tests/executor.rs +++ b/tokio-executor/tests/executor.rs @@ -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(spawn: F) where - F: Fn(Box + Send>) -> Result<(), E>, + F: Fn(Pin + 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)); - } } diff --git a/tokio-futures/Cargo.toml b/tokio-futures/Cargo.toml index 46ebda170..ad8247116 100644 --- a/tokio-futures/Cargo.toml +++ b/tokio-futures/Cargo.toml @@ -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" diff --git a/tokio-futures/README.md b/tokio-futures/README.md index 6d9455448..c919b02c9 100644 --- a/tokio-futures/README.md +++ b/tokio-futures/README.md @@ -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 diff --git a/tokio-futures/src/async_wait.rs b/tokio-futures/src/async_wait.rs deleted file mode 100644 index e626f99e6..000000000 --- a/tokio-futures/src/async_wait.rs +++ /dev/null @@ -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 - }}; -} diff --git a/tokio-futures/src/compat/backward.rs b/tokio-futures/src/compat/backward.rs deleted file mode 100644 index 566451ae7..000000000 --- a/tokio-futures/src/compat/backward.rs +++ /dev/null @@ -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(Pin>); - -impl Compat { - /// Create a new `Compat` backed by `future`. - pub(crate) fn new(future: T) -> Compat { - Compat(Box::pin(future)) - } -} - -#[doc(hidden)] -pub trait IntoAwaitable { - type Awaitable; - - fn into_awaitable(self) -> Self::Awaitable; -} - -impl IntoAwaitable for T -where - T: StdFuture, -{ - type Awaitable = Self; - - fn into_awaitable(self) -> Self { - self - } -} - -impl Future for Compat -where - T: StdFuture>, -{ - type Item = Item; - type Error = Error; - - fn poll(&mut self) -> Poll { - 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); diff --git a/tokio-futures/src/compat/forward.rs b/tokio-futures/src/compat/forward.rs deleted file mode 100644 index f6cb68750..000000000 --- a/tokio-futures/src/compat/forward.rs +++ /dev/null @@ -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); - -pub(crate) fn convert_poll(poll: Result, E>) -> StdPoll> { - 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( - poll: Result>, E>, -) -> StdPoll>> { - 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 IntoAwaitable for T { - type Awaitable = Compat; - - fn into_awaitable(self) -> Self::Awaitable { - Compat(self) - } -} - -impl StdFuture for Compat -where - T: Future + Unpin, -{ - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> StdPoll { - 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)), - } - } -} diff --git a/tokio-futures/src/compat/mod.rs b/tokio-futures/src/compat/mod.rs deleted file mode 100644 index 86940dafb..000000000 --- a/tokio-futures/src/compat/mod.rs +++ /dev/null @@ -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(future: T) -> backward::Compat -where - T: std::future::Future>, -{ - backward::Compat::new(future) -} - -/// Convert a `std::future::Future` into an 0.1 `Future` with unit error. -pub fn infallible_into_01(future: T) -> impl futures::Future -where - T: std::future::Future, -{ - use std::pin::Pin; - use std::task::{Context, Poll}; - - pub struct Map(T); - - impl Map { - fn future<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { - unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) } - } - } - - impl std::future::Future for Map { - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.future().poll(cx) { - Poll::Ready(v) => Poll::Ready(Ok(v)), - Poll::Pending => Poll::Pending, - } - } - } - - into_01(Map(future)) -} diff --git a/tokio-futures/src/future.rs b/tokio-futures/src/future.rs new file mode 100644 index 000000000..eb7c261f4 --- /dev/null +++ b/tokio-futures/src/future.rs @@ -0,0 +1,3 @@ +//! Futures + +pub use core::future::Future; diff --git a/tokio-futures/src/io/flush.rs b/tokio-futures/src/io/flush.rs deleted file mode 100644 index 9984bf28e..000000000 --- a/tokio-futures/src/io/flush.rs +++ /dev/null @@ -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 { - use crate::compat::forward::convert_poll; - convert_poll(self.writer.poll_flush()) - } -} diff --git a/tokio-futures/src/io/mod.rs b/tokio-futures/src/io/mod.rs deleted file mode 100644 index b0a26e310..000000000 --- a/tokio-futures/src/io/mod.rs +++ /dev/null @@ -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 AsyncReadExt for T {} -impl AsyncWriteExt for T {} diff --git a/tokio-futures/src/io/read.rs b/tokio-futures/src/io/read.rs deleted file mode 100644 index 7a467b8df..000000000 --- a/tokio-futures/src/io/read.rs +++ /dev/null @@ -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; - - fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll { - use crate::compat::forward::convert_poll; - - let this = &mut *self; - convert_poll(this.reader.poll_read(this.buf)) - } -} diff --git a/tokio-futures/src/io/read_exact.rs b/tokio-futures/src/io/read_exact.rs deleted file mode 100644 index 82344beaf..000000000 --- a/tokio-futures/src/io/read_exact.rs +++ /dev/null @@ -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 { - 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(())) - } -} diff --git a/tokio-futures/src/io/write.rs b/tokio-futures/src/io/write.rs deleted file mode 100644 index 26f0a4a1b..000000000 --- a/tokio-futures/src/io/write.rs +++ /dev/null @@ -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; - - fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll> { - use crate::compat::forward::convert_poll; - - let this = &mut *self; - convert_poll(this.writer.poll_write(this.buf)) - } -} diff --git a/tokio-futures/src/io/write_all.rs b/tokio-futures/src/io/write_all.rs deleted file mode 100644 index d207a3c90..000000000 --- a/tokio-futures/src/io/write_all.rs +++ /dev/null @@ -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> { - 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(())) - } -} diff --git a/tokio-futures/src/lib.rs b/tokio-futures/src/lib.rs index 37ffd1b90..c6c3afa25 100644 --- a/tokio-futures/src/lib.rs +++ b/tokio-futures/src/lib.rs @@ -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>`. -/// -/// 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; diff --git a/tokio-futures/src/macros.rs b/tokio-futures/src/macros.rs new file mode 100644 index 000000000..30505ef1c --- /dev/null +++ b/tokio-futures/src/macros.rs @@ -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, + } + }}; +} diff --git a/tokio-futures/src/sink.rs b/tokio-futures/src/sink.rs new file mode 100644 index 000000000..86facf393 --- /dev/null +++ b/tokio-futures/src/sink.rs @@ -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 { + /// TODO: Dox + type Error; + + /// TODO: Dox + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; + + /// 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>; + + /// TODO: Dox + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; +} + +impl + Unpin> Sink for &mut S { + type Error = S::Error; + + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + 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> { + Pin::new(&mut **self).poll_flush(cx) + } + + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut **self).poll_close(cx) + } +} + +impl Sink for Pin +where + S: DerefMut + Unpin, + S::Target: Sink, +{ + type Error = >::Error; + + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + 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> { + Pin::get_mut(self).as_mut().poll_flush(cx) + } + + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::get_mut(self).as_mut().poll_close(cx) + } +} diff --git a/tokio-futures/src/sink/mod.rs b/tokio-futures/src/sink/mod.rs deleted file mode 100644 index 90382951e..000000000 --- a/tokio-futures/src/sink/mod.rs +++ /dev/null @@ -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 SinkExt for T {} diff --git a/tokio-futures/src/sink/send.rs b/tokio-futures/src/sink/send.rs deleted file mode 100644 index b2e28c249..000000000 --- a/tokio-futures/src/sink/send.rs +++ /dev/null @@ -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, -} - -impl 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 Future for Send<'_, T> { - type Output = Result<(), T::SinkError>; - - fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context<'_>) -> Poll { - 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(())) - } -} diff --git a/tokio-futures/src/stream.rs b/tokio-futures/src/stream.rs new file mode 100644 index 000000000..0f4131058 --- /dev/null +++ b/tokio-futures/src/stream.rs @@ -0,0 +1,3 @@ +//! Streams + +pub use futures_core::stream::Stream; diff --git a/tokio-futures/src/stream/mod.rs b/tokio-futures/src/stream/mod.rs deleted file mode 100644 index a6d987d61..000000000 --- a/tokio-futures/src/stream/mod.rs +++ /dev/null @@ -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 StreamExt for T {} diff --git a/tokio-futures/src/stream/next.rs b/tokio-futures/src/stream/next.rs deleted file mode 100644 index ab56fd874..000000000 --- a/tokio-futures/src/stream/next.rs +++ /dev/null @@ -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>; - - fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll { - use crate::compat::forward::convert_poll_stream; - - convert_poll_stream(self.stream.poll()) - } -} diff --git a/tokio-io/Cargo.toml b/tokio-io/Cargo.toml index 2ccbe4fe2..8f4204959 100644 --- a/tokio-io/Cargo.toml +++ b/tokio-io/Cargo.toml @@ -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" } diff --git a/tokio-io/src/_tokio_codec/decoder.rs b/tokio-io/src/_tokio_codec/decoder.rs deleted file mode 100644 index da34aeeed..000000000 --- a/tokio-io/src/_tokio_codec/decoder.rs +++ /dev/null @@ -1,3 +0,0 @@ -// For now, we need to keep the implementation of Encoder in tokio_io. - -pub use crate::codec::Decoder; diff --git a/tokio-io/src/_tokio_codec/encoder.rs b/tokio-io/src/_tokio_codec/encoder.rs deleted file mode 100644 index b84a3ba77..000000000 --- a/tokio-io/src/_tokio_codec/encoder.rs +++ /dev/null @@ -1,3 +0,0 @@ -// For now, we need to keep the implementation of Encoder in tokio_io. - -pub use crate::codec::Encoder; diff --git a/tokio-io/src/_tokio_codec/framed.rs b/tokio-io/src/_tokio_codec/framed.rs deleted file mode 100644 index 88426c990..000000000 --- a/tokio-io/src/_tokio_codec/framed.rs +++ /dev/null @@ -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 { - inner: FramedRead2>>, -} - -pub struct Fuse(pub T, pub U); - -impl Framed -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 { - Framed { - inner: framed_read2(framed_write2(Fuse(inner, codec))), - } - } -} - -impl Framed { - /// 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) -> Framed { - 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 { - 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 Stream for Framed -where - T: AsyncRead, - U: Decoder, -{ - type Item = U::Item; - type Error = U::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.poll() - } -} - -impl Sink for Framed -where - T: AsyncWrite, - U: Encoder, - U::Error: From, -{ - type SinkItem = U::Item; - type SinkError = U::Error; - - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - 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 fmt::Debug for Framed -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 Read for Fuse { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - self.0.read(dst) - } -} - -impl AsyncRead for Fuse { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.0.prepare_uninitialized_buffer(buf) - } -} - -impl Write for Fuse { - fn write(&mut self, src: &[u8]) -> io::Result { - self.0.write(src) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } -} - -impl AsyncWrite for Fuse { - fn shutdown(&mut self) -> Poll<(), io::Error> { - self.0.shutdown() - } -} - -impl Decoder for Fuse { - type Item = U::Item; - type Error = U::Error; - - fn decode(&mut self, buffer: &mut BytesMut) -> Result, Self::Error> { - self.1.decode(buffer) - } - - fn decode_eof(&mut self, buffer: &mut BytesMut) -> Result, Self::Error> { - self.1.decode_eof(buffer) - } -} - -impl Encoder for Fuse { - 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 { - /// 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 FramedParts { - /// Create a new, default, `FramedParts` - pub fn new(io: T, codec: U) -> FramedParts { - FramedParts { - io, - codec, - read_buf: BytesMut::new(), - write_buf: BytesMut::new(), - _priv: (), - } - } -} diff --git a/tokio-io/src/_tokio_codec/framed_read.rs b/tokio-io/src/_tokio_codec/framed_read.rs deleted file mode 100644 index a12851700..000000000 --- a/tokio-io/src/_tokio_codec/framed_read.rs +++ /dev/null @@ -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 { - inner: FramedRead2>, -} - -pub struct FramedRead2 { - inner: T, - eof: bool, - is_readable: bool, - buffer: BytesMut, -} - -const INITIAL_CAPACITY: usize = 8 * 1024; - -// ===== impl FramedRead ===== - -impl FramedRead -where - T: AsyncRead, - D: Decoder, -{ - /// Creates a new `FramedRead` with the given `decoder`. - pub fn new(inner: T, decoder: D) -> FramedRead { - FramedRead { - inner: framed_read2(Fuse(inner, decoder)), - } - } -} - -impl FramedRead { - /// 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 Stream for FramedRead -where - T: AsyncRead, - D: Decoder, -{ - type Item = D::Item; - type Error = D::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.poll() - } -} - -impl Sink for FramedRead -where - T: Sink, -{ - type SinkItem = T::SinkItem; - type SinkError = T::SinkError; - - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - 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 fmt::Debug for FramedRead -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(inner: T) -> FramedRead2 { - FramedRead2 { - inner: inner, - eof: false, - is_readable: false, - buffer: BytesMut::with_capacity(INITIAL_CAPACITY), - } -} - -pub fn framed_read2_with_buffer(inner: T, mut buf: BytesMut) -> FramedRead2 { - 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 FramedRead2 { - 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 Stream for FramedRead2 -where - T: AsyncRead + Decoder, -{ - type Item = T::Item; - type Error = T::Error; - - fn poll(&mut self) -> Poll, 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; - } - } -} diff --git a/tokio-io/src/_tokio_codec/framed_write.rs b/tokio-io/src/_tokio_codec/framed_write.rs deleted file mode 100644 index 7ea7e6262..000000000 --- a/tokio-io/src/_tokio_codec/framed_write.rs +++ /dev/null @@ -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 { - inner: FramedWrite2>, -} - -pub struct FramedWrite2 { - inner: T, - buffer: BytesMut, -} - -const INITIAL_CAPACITY: usize = 8 * 1024; -const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY; - -impl FramedWrite -where - T: AsyncWrite, - E: Encoder, -{ - /// Creates a new `FramedWrite` with the given `encoder`. - pub fn new(inner: T, encoder: E) -> FramedWrite { - FramedWrite { - inner: framed_write2(Fuse(inner, encoder)), - } - } -} - -impl FramedWrite { - /// 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 Sink for FramedWrite -where - T: AsyncWrite, - E: Encoder, -{ - type SinkItem = E::Item; - type SinkError = E::Error; - - fn start_send(&mut self, item: E::Item) -> StartSend { - 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 Stream for FramedWrite -where - T: Stream, -{ - type Item = T::Item; - type Error = T::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.inner.0.poll() - } -} - -impl fmt::Debug for FramedWrite -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(inner: T) -> FramedWrite2 { - FramedWrite2 { - inner: inner, - buffer: BytesMut::with_capacity(INITIAL_CAPACITY), - } -} - -pub fn framed_write2_with_buffer(inner: T, mut buf: BytesMut) -> FramedWrite2 { - if buf.capacity() < INITIAL_CAPACITY { - let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity(); - buf.reserve(bytes_to_reserve); - } - FramedWrite2 { - inner: inner, - buffer: buf, - } -} - -impl FramedWrite2 { - 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 Sink for FramedWrite2 -where - T: AsyncWrite + Encoder, -{ - type SinkItem = T::Item; - type SinkError = T::Error; - - fn start_send(&mut self, item: T::Item) -> StartSend { - // 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 Decoder for FramedWrite2 { - type Item = T::Item; - type Error = T::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, T::Error> { - self.inner.decode(src) - } - - fn decode_eof(&mut self, src: &mut BytesMut) -> Result, T::Error> { - self.inner.decode_eof(src) - } -} - -impl Read for FramedWrite2 { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - self.inner.read(dst) - } -} - -impl AsyncRead for FramedWrite2 { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.inner.prepare_uninitialized_buffer(buf) - } -} diff --git a/tokio-io/src/_tokio_codec/mod.rs b/tokio-io/src/_tokio_codec/mod.rs deleted file mode 100644 index 269fee26b..000000000 --- a/tokio-io/src/_tokio_codec/mod.rs +++ /dev/null @@ -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; diff --git a/tokio-io/src/allow_std.rs b/tokio-io/src/allow_std.rs deleted file mode 100644 index c86ccca43..000000000 --- a/tokio-io/src/allow_std.rs +++ /dev/null @@ -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); - -impl AllowStdIo { - /// 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 io::Write for AllowStdIo -where - T: io::Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - 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 AsyncWrite for AllowStdIo -where - T: io::Write, -{ - fn shutdown(&mut self) -> Poll<(), io::Error> { - Ok(Async::Ready(())) - } -} - -impl io::Read for AllowStdIo -where - T: io::Read, -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result { - 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) -> io::Result { - self.0.read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.0.read_to_string(buf) - } - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.0.read_exact(buf) - } -} - -impl AsyncRead for AllowStdIo -where - T: io::Read, -{ - // TODO: override prepare_uninitialized_buffer once `Read::initializer` is stable. - // See rust-lang/rust #42788 -} diff --git a/tokio-io/src/async_read.rs b/tokio-io/src/async_read.rs index e2251ef60..9a29500a2 100644 --- a/tokio-io/src/async_read.rs +++ b/tokio-io/src/async_read.rs @@ -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 { - 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>; /// 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(&mut self, buf: &mut B) -> Poll + fn poll_read_buf( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut B, + ) -> Poll> 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(self, codec: T) -> Framed - 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, WriteHalf) - where - Self: AsyncWrite + Sized, - { - split::split(self) + fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) + -> Poll> + { + Pin::new(&mut **self).poll_read(cx, buf) + } } } -impl AsyncRead for Box { +impl AsyncRead for Box { + deref_async_read!(); +} + +impl AsyncRead for &mut T { + deref_async_read!(); +} + +impl

AsyncRead for Pin

+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> { + self.get_mut().as_mut().poll_read(cx, buf) } } diff --git a/tokio-io/src/async_write.rs b/tokio-io/src/async_write.rs index fe5585018..98f9c8493 100644 --- a/tokio-io/src/async_write.rs +++ b/tokio-io/src/async_write.rs @@ -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 { - 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>; /// 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>; /// 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>; /// 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(&mut self, buf: &mut B) -> Poll + fn poll_write_buf( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut B, + ) -> Poll> 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 AsyncWrite for Box { - 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> + { + Pin::new(&mut **self).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut **self).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut **self).poll_shutdown(cx) + } } } -impl AsyncRead for std_io::Repeat { - unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { - false - } +impl AsyncWrite for Box { + deref_async_write!(); } -impl AsyncWrite for std_io::Sink { - fn shutdown(&mut self) -> Poll<(), std_io::Error> { - Ok(().into()) - } +impl AsyncWrite for &mut T { + deref_async_write!(); } -impl AsyncRead for std_io::Take { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.get_ref().prepare_uninitialized_buffer(buf) - } -} - -impl AsyncRead for std_io::Chain +impl

AsyncWrite for Pin

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 AsyncWrite for std_io::BufWriter { - fn shutdown(&mut self) -> Poll<(), std_io::Error> { - try_ready!(self.poll_flush()); - self.get_mut().shutdown() - } -} - -impl AsyncRead for std_io::BufReader { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.get_ref().prepare_uninitialized_buffer(buf) - } -} - -impl> AsyncRead for std_io::Cursor {} - -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> { - fn shutdown(&mut self) -> Poll<(), std_io::Error> { - Ok(().into()) - } -} - -impl AsyncWrite for std_io::Cursor> { - fn shutdown(&mut self) -> Poll<(), std_io::Error> { - Ok(().into()) + fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) + -> Poll> + { + self.get_mut().as_mut().poll_write(cx, buf) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.get_mut().as_mut().poll_flush(cx) + } + + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.get_mut().as_mut().poll_shutdown(cx) } } diff --git a/tokio-io/src/codec/bytes_codec.rs b/tokio-io/src/codec/bytes_codec.rs deleted file mode 100644 index 66369478e..000000000 --- a/tokio-io/src/codec/bytes_codec.rs +++ /dev/null @@ -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, 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(()) - } -} diff --git a/tokio-io/src/codec/decoder.rs b/tokio-io/src/codec/decoder.rs deleted file mode 100644 index f4c2d2cf6..000000000 --- a/tokio-io/src/codec/decoder.rs +++ /dev/null @@ -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` 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; - - /// 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, 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, 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(self, io: T) -> Framed - where - Self: Encoder + Sized, - { - Framed::new(io, self) - } -} diff --git a/tokio-io/src/codec/encoder.rs b/tokio-io/src/codec/encoder.rs deleted file mode 100644 index 506508032..000000000 --- a/tokio-io/src/codec/encoder.rs +++ /dev/null @@ -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` - /// in the interest letting it return `Error`s directly. - type Error: From; - - /// 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>; -} diff --git a/tokio-io/src/codec/lines_codec.rs b/tokio-io/src/codec/lines_codec.rs deleted file mode 100644 index 650489119..000000000 --- a/tokio-io/src/codec/lines_codec.rs +++ /dev/null @@ -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, 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, 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(()) - } -} diff --git a/tokio-io/src/codec/mod.rs b/tokio-io/src/codec/mod.rs deleted file mode 100644 index 20bac0827..000000000 --- a/tokio-io/src/codec/mod.rs +++ /dev/null @@ -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(io: T) - //! -> length_delimited::Framed - //! { - //! 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(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(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(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(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(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(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(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(io: T) { - //! # let _: length_delimited::FramedWrite = - //! 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::*; -} diff --git a/tokio-io/src/framed.rs b/tokio-io/src/framed.rs deleted file mode 100644 index 9764e1f44..000000000 --- a/tokio-io/src/framed.rs +++ /dev/null @@ -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 { - inner: FramedRead2>>, -} - -#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")] -#[doc(hidden)] -pub struct Fuse(pub T, pub U); - -pub fn framed(inner: T, codec: U) -> Framed -where - T: AsyncRead + AsyncWrite, - U: Decoder + Encoder, -{ - Framed { - inner: framed_read2(framed_write2(Fuse(inner, codec))), - } -} - -impl Framed { - /// 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, codec: U) -> Framed { - 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 { - 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, 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 Stream for Framed -where - T: AsyncRead, - U: Decoder, -{ - type Item = U::Item; - type Error = U::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.poll() - } -} - -impl Sink for Framed -where - T: AsyncWrite, - U: Encoder, - U::Error: From, -{ - type SinkItem = U::Item; - type SinkError = U::Error; - - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - 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 fmt::Debug for Framed -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 Read for Fuse { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - self.0.read(dst) - } -} - -impl AsyncRead for Fuse { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.0.prepare_uninitialized_buffer(buf) - } -} - -impl Write for Fuse { - fn write(&mut self, src: &[u8]) -> io::Result { - self.0.write(src) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } -} - -impl AsyncWrite for Fuse { - fn shutdown(&mut self) -> Poll<(), io::Error> { - self.0.shutdown() - } -} - -impl Decoder for Fuse { - type Item = U::Item; - type Error = U::Error; - - fn decode(&mut self, buffer: &mut BytesMut) -> Result, Self::Error> { - self.1.decode(buffer) - } - - fn decode_eof(&mut self, buffer: &mut BytesMut) -> Result, Self::Error> { - self.1.decode_eof(buffer) - } -} - -impl Encoder for Fuse { - 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 { - /// 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, -} diff --git a/tokio-io/src/framed_read.rs b/tokio-io/src/framed_read.rs deleted file mode 100644 index 911af1509..000000000 --- a/tokio-io/src/framed_read.rs +++ /dev/null @@ -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 { - inner: FramedRead2>, -} - -#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")] -#[doc(hidden)] -pub struct FramedRead2 { - inner: T, - eof: bool, - is_readable: bool, - buffer: BytesMut, -} - -const INITIAL_CAPACITY: usize = 8 * 1024; - -// ===== impl FramedRead ===== - -impl FramedRead -where - T: AsyncRead, - D: Decoder, -{ - /// Creates a new `FramedRead` with the given `decoder`. - pub fn new(inner: T, decoder: D) -> FramedRead { - FramedRead { - inner: framed_read2(Fuse(inner, decoder)), - } - } -} - -impl FramedRead { - /// 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 Stream for FramedRead -where - T: AsyncRead, - D: Decoder, -{ - type Item = D::Item; - type Error = D::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.poll() - } -} - -impl Sink for FramedRead -where - T: Sink, -{ - type SinkItem = T::SinkItem; - type SinkError = T::SinkError; - - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - 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 fmt::Debug for FramedRead -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(inner: T) -> FramedRead2 { - FramedRead2 { - inner: inner, - eof: false, - is_readable: false, - buffer: BytesMut::with_capacity(INITIAL_CAPACITY), - } -} - -pub fn framed_read2_with_buffer(inner: T, mut buf: BytesMut) -> FramedRead2 { - 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 FramedRead2 { - 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 Stream for FramedRead2 -where - T: AsyncRead + Decoder, -{ - type Item = T::Item; - type Error = T::Error; - - fn poll(&mut self) -> Poll, 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; - } - } -} diff --git a/tokio-io/src/framed_write.rs b/tokio-io/src/framed_write.rs deleted file mode 100644 index 34b3330b9..000000000 --- a/tokio-io/src/framed_write.rs +++ /dev/null @@ -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 { - inner: FramedWrite2>, -} - -#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")] -#[doc(hidden)] -pub struct FramedWrite2 { - inner: T, - buffer: BytesMut, -} - -const INITIAL_CAPACITY: usize = 8 * 1024; -const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY; - -impl FramedWrite -where - T: AsyncWrite, - E: Encoder, -{ - /// Creates a new `FramedWrite` with the given `encoder`. - pub fn new(inner: T, encoder: E) -> FramedWrite { - FramedWrite { - inner: framed_write2(Fuse(inner, encoder)), - } - } -} - -impl FramedWrite { - /// 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 Sink for FramedWrite -where - T: AsyncWrite, - E: Encoder, -{ - type SinkItem = E::Item; - type SinkError = E::Error; - - fn start_send(&mut self, item: E::Item) -> StartSend { - 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 Stream for FramedWrite -where - T: Stream, -{ - type Item = T::Item; - type Error = T::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.inner.0.poll() - } -} - -impl fmt::Debug for FramedWrite -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(inner: T) -> FramedWrite2 { - FramedWrite2 { - inner: inner, - buffer: BytesMut::with_capacity(INITIAL_CAPACITY), - } -} - -pub fn framed_write2_with_buffer(inner: T, mut buf: BytesMut) -> FramedWrite2 { - if buf.capacity() < INITIAL_CAPACITY { - let bytes_to_reserve = INITIAL_CAPACITY - buf.capacity(); - buf.reserve(bytes_to_reserve); - } - FramedWrite2 { - inner: inner, - buffer: buf, - } -} - -impl FramedWrite2 { - 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 Sink for FramedWrite2 -where - T: AsyncWrite + Encoder, -{ - type SinkItem = T::Item; - type SinkError = T::Error; - - fn start_send(&mut self, item: T::Item) -> StartSend { - // 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 Decoder for FramedWrite2 { - type Item = T::Item; - type Error = T::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, T::Error> { - self.inner.decode(src) - } - - fn decode_eof(&mut self, src: &mut BytesMut) -> Result, T::Error> { - self.inner.decode_eof(src) - } -} - -impl Read for FramedWrite2 { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - self.inner.read(dst) - } -} - -impl AsyncRead for FramedWrite2 { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.inner.prepare_uninitialized_buffer(buf) - } -} diff --git a/tokio-io/src/io/copy.rs b/tokio-io/src/io/copy.rs deleted file mode 100644 index 369800db9..000000000 --- a/tokio-io/src/io/copy.rs +++ /dev/null @@ -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 { - reader: Option, - read_done: bool, - writer: Option, - 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(reader: R, writer: W) -> Copy -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 Future for Copy -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()); - } - } - } -} diff --git a/tokio-io/src/io/flush.rs b/tokio-io/src/io/flush.rs deleted file mode 100644 index 5001d680d..000000000 --- a/tokio-io/src/io/flush.rs +++ /dev/null @@ -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: Option, -} - -/// 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) -> Flush -where - A: AsyncWrite, -{ - Flush { a: Some(a) } -} - -impl Future for Flush -where - A: AsyncWrite, -{ - type Item = A; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - try_ready!(self.a.as_mut().unwrap().poll_flush()); - Ok(Async::Ready(self.a.take().unwrap())) - } -} diff --git a/tokio-io/src/io/mod.rs b/tokio-io/src/io/mod.rs deleted file mode 100644 index ebda8ecab..000000000 --- a/tokio-io/src/io/mod.rs +++ /dev/null @@ -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; diff --git a/tokio-io/src/io/read.rs b/tokio-io/src/io/read.rs deleted file mode 100644 index 7731256d0..000000000 --- a/tokio-io/src/io/read.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::AsyncRead; -use futures::{try_ready, Future, Poll}; -use std::io; -use std::mem; - -#[derive(Debug)] -enum State { - 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(rd: R, buf: T) -> Read -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 { - state: State, -} - -impl Future for Read -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"), - } - } -} diff --git a/tokio-io/src/io/read_exact.rs b/tokio-io/src/io/read_exact.rs deleted file mode 100644 index 43e8bc0a1..000000000 --- a/tokio-io/src/io/read_exact.rs +++ /dev/null @@ -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 { - state: State, -} - -#[derive(Debug)] -enum State { - 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: A, buf: T) -> ReadExact -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 Future for ReadExact -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!(), - } - } -} diff --git a/tokio-io/src/io/read_to_end.rs b/tokio-io/src/io/read_to_end.rs deleted file mode 100644 index 8f65eb534..000000000 --- a/tokio-io/src/io/read_to_end.rs +++ /dev/null @@ -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 { - state: State, -} - -#[derive(Debug)] -enum State { - Reading { a: A, buf: Vec }, - 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, buf: Vec) -> ReadToEnd -where - A: AsyncRead, -{ - ReadToEnd { - state: State::Reading { a: a, buf: buf }, - } -} - -impl Future for ReadToEnd -where - A: AsyncRead, -{ - type Item = (A, Vec); - type Error = io::Error; - - fn poll(&mut self) -> Poll<(A, Vec), 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!(), - } - } -} diff --git a/tokio-io/src/io/read_until.rs b/tokio-io/src/io/read_until.rs deleted file mode 100644 index 4d7165cc5..000000000 --- a/tokio-io/src/io/read_until.rs +++ /dev/null @@ -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 { - state: State, -} - -#[derive(Debug)] -enum State { - Reading { a: A, byte: u8, buf: Vec }, - 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, byte: u8, buf: Vec) -> ReadUntil -where - A: AsyncRead + BufRead, -{ - ReadUntil { - state: State::Reading { - a: a, - byte: byte, - buf: buf, - }, - } -} - -impl Future for ReadUntil -where - A: AsyncRead + BufRead, -{ - type Item = (A, Vec); - type Error = io::Error; - - fn poll(&mut self) -> Poll<(A, Vec), 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!(), - } - } -} diff --git a/tokio-io/src/io/shutdown.rs b/tokio-io/src/io/shutdown.rs deleted file mode 100644 index a7e092c0a..000000000 --- a/tokio-io/src/io/shutdown.rs +++ /dev/null @@ -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: Option, -} - -/// 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) -> Shutdown -where - A: AsyncWrite, -{ - Shutdown { a: Some(a) } -} - -impl Future for Shutdown -where - A: AsyncWrite, -{ - type Item = A; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - try_ready!(self.a.as_mut().unwrap().shutdown()); - Ok(Async::Ready(self.a.take().unwrap())) - } -} diff --git a/tokio-io/src/io/write_all.rs b/tokio-io/src/io/write_all.rs deleted file mode 100644 index 6867a193f..000000000 --- a/tokio-io/src/io/write_all.rs +++ /dev/null @@ -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 { - state: State, -} - -#[derive(Debug)] -enum State { - 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: A, buf: T) -> WriteAll -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 Future for WriteAll -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!(), - } - } -} diff --git a/tokio-io/src/length_delimited.rs b/tokio-io/src/length_delimited.rs deleted file mode 100644 index 99d271807..000000000 --- a/tokio-io/src/length_delimited.rs +++ /dev/null @@ -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, - - // 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 { - inner: FramedRead>, -} - -/// 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 { - inner: codec::FramedRead, -} - -/// 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 { - // I/O type - inner: T, - - // Configuration values - builder: Builder, - - // Current frame being written - frame: Option, B::Buf>>, -} - -// ===== impl Framed ===== - -impl Framed { - /// Creates a new `Framed` with default configuration values. - pub fn new(inner: T) -> Framed { - Builder::new().new_framed(inner) - } -} - -impl Framed { - /// 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 Stream for Framed { - type Item = BytesMut; - type Error = io::Error; - - fn poll(&mut self) -> Poll, io::Error> { - self.inner.poll() - } -} - -impl Sink for Framed { - type SinkItem = B; - type SinkError = io::Error; - - fn start_send(&mut self, item: B) -> StartSend { - 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 fmt::Debug for Framed -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 FramedRead { - /// Creates a new `FramedRead` with default configuration values. - pub fn new(inner: T) -> FramedRead { - Builder::new().new_read(inner) - } -} - -impl FramedRead { - /// 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 Stream for FramedRead { - type Item = BytesMut; - type Error = io::Error; - - fn poll(&mut self) -> Poll, io::Error> { - self.inner.poll() - } -} - -impl Sink for FramedRead { - type SinkItem = T::SinkItem; - type SinkError = T::SinkError; - - fn start_send(&mut self, item: T::SinkItem) -> StartSend { - 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 io::Write for FramedRead { - fn write(&mut self, src: &[u8]) -> io::Result { - self.inner.get_mut().write(src) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.get_mut().flush() - } -} - -impl AsyncWrite for FramedRead { - fn shutdown(&mut self) -> Poll<(), io::Error> { - self.inner.get_mut().shutdown() - } - - fn write_buf(&mut self, buf: &mut B) -> Poll { - self.inner.get_mut().write_buf(buf) - } -} - -// ===== impl Decoder ====== - -impl Decoder { - fn decode_head(&mut self, src: &mut BytesMut) -> io::Result> { - 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> { - // 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> { - 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 FramedWrite { - /// Creates a new `FramedWrite` with default configuration values. - pub fn new(inner: T) -> FramedWrite { - Builder::new().new_write(inner) - } -} - -impl FramedWrite { - /// 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 FramedWrite { - // 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 Sink for FramedWrite { - type SinkItem = B; - type SinkError = io::Error; - - fn start_send(&mut self, item: B) -> StartSend { - 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 Stream for FramedWrite { - type Item = T::Item; - type Error = T::Error; - - fn poll(&mut self) -> Poll, T::Error> { - self.inner.poll() - } -} - -impl io::Read for FramedWrite { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - self.get_mut().read(dst) - } -} - -impl AsyncRead for FramedWrite { - fn read_buf(&mut self, buf: &mut B) -> Poll { - self.get_mut().read_buf(buf) - } - - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - self.get_ref().prepare_uninitialized_buffer(buf) - } -} - -impl fmt::Debug for FramedWrite -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(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(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(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(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(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(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(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(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(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(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(&self, upstream: T) -> FramedRead - 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(io: T) { - /// # let _: length_delimited::FramedWrite = - /// length_delimited::Builder::new() - /// .length_field_length(2) - /// .new_write(io); - /// # } - /// ``` - pub fn new_write(&self, inner: T) -> FramedWrite - 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(io: T) { - /// # let _: length_delimited::Framed = - /// length_delimited::Builder::new() - /// .length_field_length(2) - /// .new_framed(io); - /// # } - /// ``` - pub fn new_framed(&self, inner: T) -> Framed - 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" - } -} diff --git a/tokio-io/src/lib.rs b/tokio-io/src/lib.rs index d0fe8af85..cd097ae6c 100644 --- a/tokio-io/src/lib.rs +++ b/tokio-io/src/lib.rs @@ -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 = Box + Send>; - -/// A convenience typedef around a `Stream` whose error component is `io::Error` -pub type IoStream = Box + Send>; - -/// A convenience macro for working with `io::Result` from the `Read` and -/// `Write` traits. -/// -/// This macro takes `io::Result` 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() {} - _assert::>(); - _assert::>(); -} diff --git a/tokio-io/src/lines.rs b/tokio-io/src/lines.rs deleted file mode 100644 index ebe1ed5ea..000000000 --- a/tokio-io/src/lines.rs +++ /dev/null @@ -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 { - 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) -> Lines -where - A: AsyncRead + BufRead, -{ - Lines { - io: a, - line: String::new(), - } -} - -impl Lines { - /// 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 Stream for Lines -where - A: AsyncRead + BufRead, -{ - type Item = String; - type Error = io::Error; - - fn poll(&mut self) -> Poll, 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()) - } -} diff --git a/tokio-io/src/split.rs b/tokio-io/src/split.rs deleted file mode 100644 index b9bd326ba..000000000 --- a/tokio-io/src/split.rs +++ /dev/null @@ -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 { - handle: BiLock, -} - -impl ReadHalf { - /// 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 { - 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 { - handle: BiLock, -} - -impl WriteHalf { - /// 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 { - if let Ok(x) = self.handle.reunite(r.handle) { - x - } else { - panic!("Unrelated `ReadHalf` passed to `WriteHalf::unsplit`.") - } - } -} - -pub fn split(t: T) -> (ReadHalf, WriteHalf) { - 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 Read for ReadHalf { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.handle.poll_lock() { - Async::Ready(mut l) => l.read(buf), - Async::NotReady => Err(would_block()), - } - } -} - -impl AsyncRead for ReadHalf { - fn read_buf(&mut self, buf: &mut B) -> Poll { - let mut l = try_ready!(wrap_as_io(self.handle.poll_lock())); - l.read_buf(buf) - } -} - -impl Write for WriteHalf { - fn write(&mut self, buf: &[u8]) -> io::Result { - 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 AsyncWrite for WriteHalf { - fn shutdown(&mut self) -> Poll<(), io::Error> { - let mut l = try_ready!(wrap_as_io(self.handle.poll_lock())); - l.shutdown() - } - - fn write_buf(&mut self, buf: &mut B) -> Poll - where - Self: Sized, - { - let mut l = try_ready!(wrap_as_io(self.handle.poll_lock())); - l.write_buf(buf) - } -} - -fn wrap_as_io(t: Async) -> Result, 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 { - Ok(1) - } - } - - impl AsyncRead for RW {} - - impl Write for RW { - fn write(&mut self, _: &[u8]) -> io::Result { - 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); - } -} diff --git a/tokio-io/src/window.rs b/tokio-io/src/window.rs deleted file mode 100644 index 4ded9ad40..000000000 --- a/tokio-io/src/window.rs +++ /dev/null @@ -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` 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 { - inner: T, - range: ops::Range, -} - -impl> Window { - /// Creates a new window around the buffer `t` defaulting to the entire - /// slice. - /// - /// Further methods can be called on the returned `Window` to alter the - /// window into the data provided. - pub fn new(t: T) -> Window { - 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 { - 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 { - 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> AsRef<[u8]> for Window { - fn as_ref(&self) -> &[u8] { - &self.inner.as_ref()[self.range.start..self.range.end] - } -} - -impl> AsMut<[u8]> for Window { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner.as_mut()[self.range.start..self.range.end] - } -} diff --git a/tokio-io/tests/async_read.rs b/tokio-io/tests/async_read.rs index 430c935ea..1e159588f 100644 --- a/tokio-io/tests/async_read.rs +++ b/tokio-io/tests/async_read.rs @@ -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() {} + _assert::>(); +} #[test] fn read_buf_success() { - struct R; + struct Rd; - impl Read for R { - fn read(&mut self, buf: &mut [u8]) -> io::Result { + impl AsyncRead for Rd { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &mut [u8]) -> Poll> + { 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 { - 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> + { + 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 { + impl AsyncRead for Rd { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: &mut [u8]) -> Poll> + { 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 { + impl AsyncRead for Rd { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &mut [u8]) -> Poll> + { 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 { - 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> + { + 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 { - 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); + }); } diff --git a/tokio-io/tests/length_delimited.rs b/tokio-io/tests/length_delimited.rs deleted file mode 100644 index d217a178a..000000000 --- a/tokio-io/tests/length_delimited.rs +++ /dev/null @@ -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 = 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 = 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 = 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>, -} - -enum Op { - Data(Vec), - Flush, -} - -use self::Op::*; - -impl io::Read for Mock { - fn read(&mut self, dst: &mut [u8]) -> io::Result { - 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 { - 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> for Op { - fn from(src: Vec) -> Op { - Op::Data(src) - } -} diff --git a/tokio-macros/Cargo.toml b/tokio-macros/Cargo.toml index 66b30338b..d32becbcd 100644 --- a/tokio-macros/Cargo.toml +++ b/tokio-macros/Cargo.toml @@ -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" diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index eafed6dd7..000b3773e 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -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))))] diff --git a/tokio-reactor/Cargo.toml b/tokio-reactor/Cargo.toml index e745872bf..4ad3a1814 100644 --- a/tokio-reactor/Cargo.toml +++ b/tokio-reactor/Cargo.toml @@ -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" diff --git a/tokio-reactor/benches/basic.rs b/tokio-reactor/benches/basic.rs index a126d1330..23424229f 100644 --- a/tokio-reactor/benches/basic.rs +++ b/tokio-reactor/benches/basic.rs @@ -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 { }) } } +*/ diff --git a/tokio-reactor/src/background.rs b/tokio-reactor/src/background.rs deleted file mode 100644 index 70e8ebd36..000000000 --- a/tokio-reactor/src/background.rs +++ /dev/null @@ -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, -} - -/// 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, -} - -#[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 { - // 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) { - 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"); -} diff --git a/tokio-reactor/src/lib.rs b/tokio-reactor/src/lib.rs index fb8f35312..ff2ab6864 100644 --- a/tokio-reactor/src/lib.rs +++ b/tokio-reactor/src/lib.rs @@ -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> = 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::new(self) - } - fn poll(&mut self, max_wait: Option) -> 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 { - 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 { 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 { - 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::, usize>(self.inner) } - } - - unsafe fn from_usize(val: usize) -> HandlePriv { - let inner = mem::transmute::>(val);; - HandlePriv { inner } - } - fn inner(&self) -> Option> { 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" - } -} diff --git a/tokio-reactor/src/poll_evented.rs b/tokio-reactor/src/poll_evented.rs index 140ac4caf..5b2802942 100644 --- a/tokio-reactor/src/poll_evented.rs +++ b/tokio-reactor/src/poll_evented.rs @@ -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 { + pub fn poll_read_ready( + &self, + cx: &mut Context<'_>, + mask: mio::Ready, + ) -> Poll> { 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 { + pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> { 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 Read for PollEvented +impl AsyncRead for PollEvented where - E: Evented + Read, + E: Evented + Read + Unpin, { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - 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> { + 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 Write for PollEvented -where - E: Evented + Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - 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 AsyncRead for PollEvented where E: Evented + Read {} - impl AsyncWrite for PollEvented 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> { + ready!(self.poll_write_ready(cx))?; -// ===== &'a Read / &'a Write impls ===== - -impl<'a, E> Read for &'a PollEvented -where - E: Evented, - &'a E: Read, -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result { - 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 -where - E: Evented, - &'a E: Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - 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> { + 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 -where - E: Evented, - &'a E: Read, -{ -} - -impl<'a, E> AsyncWrite for &'a PollEvented -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> { + Poll::Ready(Ok(())) } } diff --git a/tokio-reactor/src/registration.rs b/tokio-reactor/src/registration.rs index 3b7e8391b..9592f6c80 100644 --- a/tokio-reactor/src/registration.rs +++ b/tokio-reactor/src/registration.rs @@ -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 { - 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> { + 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> { - 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 { - 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> { + 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> { - self.poll_ready(Direction::Write, Notify::No) + self.poll_ready(Direction::Write, None) } - fn poll_ready(&self, direction: Direction, notify: Notify) -> io::Result> { + fn poll_ready( + &self, + direction: Direction, + cx: Option<&mut Context<'_>>, + ) -> io::Result> { 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(&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> { + fn poll_ready( + &self, + direction: Direction, + cx: Option<&mut Context<'_>>, + ) -> io::Result> { 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() { diff --git a/tokio-sync/Cargo.toml b/tokio-sync/Cargo.toml index 7217b8a1d..aedd4c626 100644 --- a/tokio-sync/Cargo.toml +++ b/tokio-sync/Cargo.toml @@ -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"] } diff --git a/tokio-sync/src/lib.rs b/tokio-sync/src/lib.rs index 1131899c0..67903acec 100644 --- a/tokio-sync/src/lib.rs +++ b/tokio-sync/src/lib.rs @@ -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)* } diff --git a/tokio-sync/src/lock.rs b/tokio-sync/src/lock.rs index 3cfa1beb2..3b8ce36f9 100644 --- a/tokio-sync/src/lock.rs +++ b/tokio-sync/src/lock.rs @@ -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 Lock { /// 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> { - if let Async::NotReady = self.permit.poll_acquire(&self.inner.s).unwrap_or_else(|_| { + pub fn poll_lock(&mut self, cx: &mut Context<'_>) -> Poll> { + 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 Lock { inner: self.inner.clone(), permit: ::std::mem::replace(&mut self.permit, semaphore::Permit::new()), }; - Async::Ready(LockGuard(acquired)) + Ready(LockGuard(acquired)) } } diff --git a/tokio-sync/src/loom.rs b/tokio-sync/src/loom.rs index c46a5f544..92a21e5ba 100644 --- a/tokio-sync/src/loom.rs +++ b/tokio-sync/src/loom.rs @@ -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 { diff --git a/tokio-sync/src/mpsc/bounded.rs b/tokio-sync/src/mpsc/bounded.rs index b2fce168b..7f8cb9053 100644 --- a/tokio-sync/src/mpsc/bounded.rs +++ b/tokio-sync/src/mpsc/bounded.rs @@ -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 Receiver { Receiver { chan } } + /// TODO: Dox + pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll> { + 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 Receiver { } } -impl Stream for Receiver { +#[cfg(feature = "async-traits")] +impl futures_core::Stream for Receiver { type Item = T; - type Error = RecvError; - fn poll(&mut self) -> Poll, Self::Error> { - self.chan.recv().map_err(|_| RecvError(())) + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Receiver::poll_next(self.get_mut(), cx) } } @@ -165,13 +174,13 @@ impl Sender { /// /// 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> { + self.chan.poll_ready(cx).map_err(|_| SendError(())) } /// Attempts to send a message on this `Sender`, returning the message @@ -182,31 +191,29 @@ impl Sender { } } -impl Sink for Sender { - type SinkItem = T; - type SinkError = SendError; +#[cfg(feature = "async-traits")] +impl async_sink::Sink for Sender { + type Error = SendError; - fn start_send(&mut self, msg: T) -> StartSend { - 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> { + 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> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } } diff --git a/tokio-sync/src/mpsc/chan.rs b/tokio-sync/src/mpsc/chan.rs index fae3159aa..93e628240 100644 --- a/tokio-sync/src/mpsc/chan.rs +++ b/tokio-sync/src/mpsc/chan.rs @@ -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 { @@ -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>; fn try_acquire(&self, permit: &mut Self::Permit) -> Result<(), TrySendError>; @@ -81,8 +83,8 @@ struct Chan { /// 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> { + 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, ()> { + pub(crate) fn recv(&mut self, cx: &mut Context<'_>) -> Poll> { 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> { + 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> { + Ready(self.try_acquire(permit).map_err(|_| ())) } fn try_acquire(&self, _permit: &mut ()) -> Result<(), TrySendError> { diff --git a/tokio-sync/src/mpsc/unbounded.rs b/tokio-sync/src/mpsc/unbounded.rs index 58967c915..960bee416 100644 --- a/tokio-sync/src/mpsc/unbounded.rs +++ b/tokio-sync/src/mpsc/unbounded.rs @@ -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 UnboundedReceiver { UnboundedReceiver { chan } } + /// TODO: dox + pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll> { + 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 UnboundedReceiver { } } -impl Stream for UnboundedReceiver { +#[cfg(feature = "async-traits")] +impl futures_core::Stream for UnboundedReceiver { type Item = T; - type Error = UnboundedRecvError; - fn poll(&mut self) -> Poll, Self::Error> { - self.chan.recv().map_err(|_| UnboundedRecvError(())) + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.chan.recv(cx) } } @@ -113,25 +122,24 @@ impl UnboundedSender { } } -impl Sink for UnboundedSender { - type SinkItem = T; - type SinkError = UnboundedSendError; +#[cfg(feature = "async-traits")] +impl async_sink::Sink for UnboundedSender { + type Error = UnboundedSendError; - fn start_send(&mut self, msg: T) -> StartSend { - use futures::AsyncSink; - - self.try_send(msg).map_err(|_| UnboundedSendError(()))?; - Ok(AsyncSink::Ready) + fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + 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> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) } } diff --git a/tokio-sync/src/oneshot.rs b/tokio-sync/src/oneshot.rs index d3531bd97..c38bb0cec 100644 --- a/tokio-sync/src/oneshot.rs +++ b/tokio-sync/src/oneshot.rs @@ -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 { value: CausalCell>, /// The task to notify when the receiver drops without consuming the value. - tx_task: CausalCell>, + tx_task: CausalCell>, /// The task to notify when the value is sent. - rx_task: CausalCell>, + rx_task: CausalCell>, } #[derive(Clone, Copy)] @@ -167,33 +167,33 @@ impl Sender { /// /// # 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 Sender { 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 Drop for Receiver { } impl Future for Receiver { - type Item = T; - type Error = RecvError; - - fn poll(&mut self) -> Poll { - use futures::Async::{NotReady, Ready}; + type Output = Result; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // 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 Inner { } 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 { - use futures::Async::{NotReady, Ready}; - + fn poll_recv(&self, cx: &mut Context<'_>) -> Poll> { // 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 Inner { 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 Inner { 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 Inner { 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 Inner { 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 Inner { 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())); } } diff --git a/tokio-sync/src/semaphore.rs b/tokio-sync/src/semaphore.rs index 43e89c371..33fd2318b 100644 --- a/tokio-sync/src/semaphore.rs +++ b/tokio-sync/src/semaphore.rs @@ -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, @@ -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> { // 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> { 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 { + fn acquire(&self, cx: &mut Context<'_>) -> Result { 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 => { diff --git a/tokio-sync/src/task/atomic_task.rs b/tokio-sync/src/task/atomic_task.rs deleted file mode 100644 index 73110da2a..000000000 --- a/tokio-sync/src/task/atomic_task.rs +++ /dev/null @@ -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>, -} - -// `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(&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 { - 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); - fn notify(self); -} - -struct CurrentTask; - -impl Register for CurrentTask { - fn register(self, slot: &mut Option) { - 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) { - // 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(); - } -} diff --git a/tokio-sync/src/task/atomic_waker.rs b/tokio-sync/src/task/atomic_waker.rs new file mode 100644 index 000000000..6f741d386 --- /dev/null +++ b/tokio-sync/src/task/atomic_waker.rs @@ -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>, +} + +// `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(&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 { + 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() + } +} diff --git a/tokio-sync/src/task/mod.rs b/tokio-sync/src/task/mod.rs index 42c40de5d..cff96656b 100644 --- a/tokio-sync/src/task/mod.rs +++ b/tokio-sync/src/task/mod.rs @@ -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; diff --git a/tokio-sync/src/watch.rs b/tokio-sync/src/watch.rs index aab016b50..ce275b4e7 100644 --- a/tokio-sync/src/watch.rs +++ b/tokio-sync/src/watch.rs @@ -53,14 +53,19 @@ //! [`Receiver::poll`]: struct.Receiver.html#method.poll //! [`Receiver::poll_ref`]: struct.Receiver.html#method.poll_ref +use crate::task::AtomicWaker; + +use core::task::Poll::{Pending, Ready}; +use core::task::{Context, Poll}; use fnv::FnvHashMap; -use futures::task::AtomicTask; -use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream}; use std::ops; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak}; +#[cfg(feature = "async-traits")] +use std::pin::Pin; + /// Receives values from the associated `Sender`. /// /// Instances are created by the [`channel`](fn.channel.html) function. @@ -102,33 +107,12 @@ pub mod error { use std::fmt; - /// Error produced when receiving a value fails. - #[derive(Debug)] - pub struct RecvError { - pub(crate) _p: (), - } - /// Error produced when sending a value fails. #[derive(Debug)] pub struct SendError { pub(crate) inner: T, } - // ===== impl RecvError ===== - - impl fmt::Display for RecvError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::error::Error; - write!(fmt, "{}", self.description()) - } - } - - impl ::std::error::Error for RecvError { - fn description(&self) -> &str { - "channel closed" - } - } - // ===== impl SendError ===== impl fmt::Display for SendError { @@ -160,7 +144,7 @@ struct Shared { watchers: Mutex, /// Task to notify when all watchers drop - cancel: AtomicTask, + cancel: AtomicWaker, } #[derive(Debug)] @@ -171,7 +155,7 @@ struct Watchers { #[derive(Debug)] struct WatchInner { - task: AtomicTask, + waker: AtomicWaker, } const CLOSED: usize = 1; @@ -216,7 +200,7 @@ pub fn channel(init: T) -> (Sender, Receiver) { next_id: INIT_ID + 1, watchers, }), - cancel: AtomicTask::new(), + cancel: AtomicWaker::new(), }); let tx = Sender { @@ -256,14 +240,14 @@ impl Receiver { /// Attempts to receive the latest value sent via the channel. /// /// If a new, unobserved, value has been sent, a reference to it is - /// returned. If no new value has been sent, then `NotReady` is returned and + /// returned. If no new value has been sent, then `Pending` is returned and /// the current task is notified once a new value is sent. /// /// Only the **most recent** value is returned. If the receiver is falling /// behind the sender, intermediate values are dropped. - pub fn poll_ref(&mut self) -> Poll>, error::RecvError> { + pub fn poll_ref(&mut self, cx: &mut Context<'_>) -> Poll>> { // Make sure the task is up to date - self.inner.task.register(); + self.inner.waker.register_by_ref(cx.waker()); let state = self.shared.version.load(SeqCst); let version = state & !CLOSED; @@ -274,25 +258,35 @@ impl Receiver { let inner = self.shared.value.read().unwrap(); - return Ok(Some(Ref { inner }).into()); + return Ready(Some(Ref { inner })); } if CLOSED == state & CLOSED { // The `Store` handle has been dropped. - return Ok(None.into()); + return Ready(None); } - Ok(Async::NotReady) + Pending } } -impl Stream for Receiver { - type Item = T; - type Error = error::RecvError; +impl Receiver { + /// Attempts to clone the latest value sent via the channel. + /// + /// This is equivalent to calling `Clone` on the value returned by `poll_ref`. + pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll> { + let item = ready!(self.poll_ref(cx)); + Ready(item.map(|v_ref| v_ref.clone())) + } +} - fn poll(&mut self) -> Poll, error::RecvError> { - let item = try_ready!(self.poll_ref()); - Ok(Async::Ready(item.map(|v_ref| v_ref.clone()))) +#[cfg(feature = "async-traits")] +impl futures_core::Stream for Receiver { + type Item = T; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let item = ready!(self.poll_ref(cx)); + Ready(item.map(|v_ref| v_ref.clone())) } } @@ -332,14 +326,14 @@ impl Drop for Receiver { impl WatchInner { fn new() -> Self { WatchInner { - task: AtomicTask::new(), + waker: AtomicWaker::new(), } } } impl Sender { /// Broadcast a new value via the channel, notifying all receivers. - pub fn broadcast(&mut self, value: T) -> Result<(), error::SendError> { + pub fn broadcast(&self, value: T) -> Result<(), error::SendError> { let shared = match self.shared.upgrade() { Some(shared) => shared, // All `Watch` handles have been canceled @@ -366,28 +360,36 @@ impl Sender { /// /// This allows the producer to get notified when interest in the produced /// values is canceled and immediately stop doing work. - pub fn poll_close(&mut self) -> Poll<(), ()> { + pub fn poll_close(&mut self, cx: &mut Context<'_>) -> Poll<()> { match self.shared.upgrade() { Some(shared) => { - shared.cancel.register(); - Ok(Async::NotReady) + shared.cancel.register_by_ref(cx.waker()); + Pending } - None => Ok(Async::Ready(())), + None => Ready(()), } } } -impl Sink for Sender { - type SinkItem = T; - type SinkError = error::SendError; +#[cfg(feature = "async-traits")] +impl async_sink::Sink for Sender { + type Error = error::SendError; - fn start_send(&mut self, item: T) -> StartSend> { - let _ = self.broadcast(item)?; - Ok(AsyncSink::Ready) + fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Ready(Ok(())) } - fn poll_complete(&mut self) -> Poll<(), error::SendError> { - Ok(().into()) + fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { + let _ = self.as_ref().get_ref().broadcast(item)?; + Ok(()) + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Ready(Ok(())) } } @@ -397,7 +399,7 @@ fn notify_all(shared: &Shared) { for watcher in watchers.watchers.values() { // Notify the task - watcher.task.notify(); + watcher.waker.wake(); } } @@ -424,6 +426,6 @@ impl<'a, T: 'a> ops::Deref for Ref<'a, T> { impl Drop for Shared { fn drop(&mut self) { - self.cancel.notify(); + self.cancel.wake(); } } diff --git a/tokio-sync/tests/atomic_task.rs b/tokio-sync/tests/atomic_task.rs deleted file mode 100644 index 8e77d624f..000000000 --- a/tokio-sync/tests/atomic_task.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![deny(warnings, rust_2018_idioms)] - -use futures::task::{self, Task}; -use tokio_mock_task::*; -use tokio_sync::task::AtomicTask; - -trait AssertSend: Send {} -trait AssertSync: Send {} - -impl AssertSend for AtomicTask {} -impl AssertSync for AtomicTask {} - -impl AssertSend for Task {} -impl AssertSync for Task {} - -#[test] -fn register_task() { - // AtomicTask::register_task should *always* register the - // arbitrary task. - - let atomic = AtomicTask::new(); - - let mut mock1 = MockTask::new(); - let mut mock2 = MockTask::new(); - - // Register once... - mock1.enter(|| atomic.register()); - - // Grab the actual 2nd task from the mock... - let task2 = mock2.enter(task::current); - - // Now register the 2nd task, even though in the context where - // the first task would be considered 'current'... - { - // Need a block to grab a reference, so that we only move - // task2 into the closure, not the AtomicTask... - let atomic = &atomic; - mock1.enter(move || { - atomic.register_task(task2); - }); - } - - // Just proving that they haven't been notified yet... - assert!(!mock1.is_notified(), "mock1 shouldn't be notified yet"); - assert!(!mock2.is_notified(), "mock2 shouldn't be notified yet"); - - // Now trigger the notify, and ensure it was task2 - atomic.notify(); - - assert!(!mock1.is_notified(), "mock1 shouldn't be notified"); - assert!(mock2.is_notified(), "mock2 should be notified"); -} diff --git a/tokio-sync/tests/atomic_waker.rs b/tokio-sync/tests/atomic_waker.rs new file mode 100644 index 000000000..28a9f40dd --- /dev/null +++ b/tokio-sync/tests/atomic_waker.rs @@ -0,0 +1,37 @@ +#![deny(warnings, rust_2018_idioms)] + +use std::task::Waker; +use tokio_sync::task::AtomicWaker; +use tokio_test::task::MockTask; + +trait AssertSend: Send {} +trait AssertSync: Send {} + +impl AssertSend for AtomicWaker {} +impl AssertSync for AtomicWaker {} + +impl AssertSend for Waker {} +impl AssertSync for Waker {} + +#[test] +fn basic_usage() { + let waker = AtomicWaker::new(); + let mut task = MockTask::new(); + + task.enter(|cx| waker.register_by_ref(cx.waker())); + waker.wake(); + + assert!(task.is_woken()); +} + +#[test] +fn wake_without_register() { + let waker = AtomicWaker::new(); + waker.wake(); + + // Registering should not result in a notification + let mut task = MockTask::new(); + task.enter(|cx| waker.register_by_ref(cx.waker())); + + assert!(!task.is_woken()); +} diff --git a/tokio-sync/tests/errors.rs b/tokio-sync/tests/errors.rs index 97ab7e578..2afafc1f6 100644 --- a/tokio-sync/tests/errors.rs +++ b/tokio-sync/tests/errors.rs @@ -6,7 +6,6 @@ fn is_error() {} fn mpsc_error_bound() { use tokio_sync::mpsc::error; - is_error::(); is_error::(); is_error::>(); is_error::(); @@ -26,6 +25,5 @@ fn oneshot_error_bound() { fn watch_error_bound() { use tokio_sync::watch::error; - is_error::(); is_error::>(); } diff --git a/tokio-sync/tests/fuzz_atomic_task.rs b/tokio-sync/tests/fuzz_atomic_waker.rs similarity index 62% rename from tokio-sync/tests/fuzz_atomic_task.rs rename to tokio-sync/tests/fuzz_atomic_waker.rs index 12d3fb74b..1a2ef1cc5 100644 --- a/tokio-sync/tests/fuzz_atomic_task.rs +++ b/tokio-sync/tests/fuzz_atomic_waker.rs @@ -4,21 +4,21 @@ extern crate loom; #[allow(dead_code)] -#[path = "../src/task/atomic_task.rs"] -mod atomic_task; +#[path = "../src/task/atomic_waker.rs"] +mod atomic_waker; +use crate::atomic_waker::AtomicWaker; -use crate::atomic_task::AtomicTask; -use futures::future::poll_fn; -use futures::Async; +use async_util::future::poll_fn; use loom::futures::block_on; use loom::sync::atomic::AtomicUsize; use loom::thread; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; +use std::task::Poll::{Pending, Ready}; struct Chan { num: AtomicUsize, - task: AtomicTask, + task: AtomicWaker, } #[test] @@ -28,7 +28,7 @@ fn basic_notification() { loom::fuzz(|| { let chan = Arc::new(Chan { num: AtomicUsize::new(0), - task: AtomicTask::new(), + task: AtomicWaker::new(), }); for _ in 0..NUM_NOTIFY { @@ -36,19 +36,18 @@ fn basic_notification() { thread::spawn(move || { chan.num.fetch_add(1, Relaxed); - chan.task.notify(); + chan.task.wake(); }); } - block_on(poll_fn(move || { - chan.task.register(); + block_on(poll_fn(move |cx| { + chan.task.register_by_ref(cx.waker()); if NUM_NOTIFY == chan.num.load(Relaxed) { - return Ok(Async::Ready(())); + return Ready(()); } - Ok::<_, ()>(Async::NotReady) - })) - .unwrap(); + Pending + })); }); } diff --git a/tokio-sync/tests/fuzz_mpsc.rs b/tokio-sync/tests/fuzz_mpsc.rs index 2a7b75528..4a0b6441d 100644 --- a/tokio-sync/tests/fuzz_mpsc.rs +++ b/tokio-sync/tests/fuzz_mpsc.rs @@ -17,7 +17,8 @@ mod mpsc; #[allow(warnings)] mod semaphore; -use futures::{future::poll_fn, Stream}; +// use futures::{future::poll_fn, Stream}; +use async_util::future::poll_fn; use loom::futures::block_on; use loom::thread; @@ -31,10 +32,10 @@ fn closing_tx() { drop(tx); }); - let v = block_on(poll_fn(|| rx.poll())).unwrap(); + let v = block_on(poll_fn(|cx| rx.poll_next(cx))); assert!(v.is_some()); - let v = block_on(poll_fn(|| rx.poll())).unwrap(); + let v = block_on(poll_fn(|cx| rx.poll_next(cx))); assert!(v.is_none()); }); } diff --git a/tokio-sync/tests/fuzz_oneshot.rs b/tokio-sync/tests/fuzz_oneshot.rs index d1e4eeed9..9e0a1c40a 100644 --- a/tokio-sync/tests/fuzz_oneshot.rs +++ b/tokio-sync/tests/fuzz_oneshot.rs @@ -1,14 +1,29 @@ #![deny(warnings, rust_2018_idioms)] +/// 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, + } + }}; +} + #[path = "../src/oneshot.rs"] #[allow(warnings)] mod oneshot; -use futures::{self, Async, Future}; +// use futures::{self, Async, Future}; use loom; -use loom::futures::block_on; +use loom::futures::{block_on, poll_future}; use loom::thread; +use std::task::Poll::{Pending, Ready}; + #[test] fn smoke() { loom::fuzz(|| { @@ -33,16 +48,14 @@ fn changing_rx_task() { }); let rx = thread::spawn(move || { - let t1 = block_on(futures::future::poll_fn(|| Ok::<_, ()>(rx.poll().into()))).unwrap(); - - match t1 { - Ok(Async::Ready(value)) => { + match poll_future(&mut rx) { + Ready(Ok(value)) => { // ok assert_eq!(1, value); None } - Ok(Async::NotReady) => Some(rx), - Err(_) => unreachable!(), + Ready(Err(_)) => unimplemented!(), + Pending => Some(rx), } }) .join() @@ -56,6 +69,30 @@ fn changing_rx_task() { }); } +// TODO: Move this into `oneshot` proper. + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +struct OnClose<'a> { + tx: &'a mut oneshot::Sender, +} + +impl<'a> OnClose<'a> { + fn new(tx: &'a mut oneshot::Sender) -> Self { + OnClose { tx } + } +} + +impl<'a> Future for OnClose<'a> { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + self.get_mut().tx.poll_close(cx) + } +} + #[test] fn changing_tx_task() { loom::fuzz(|| { @@ -66,15 +103,11 @@ fn changing_tx_task() { }); let tx = thread::spawn(move || { - let t1 = block_on(futures::future::poll_fn(|| { - Ok::<_, ()>(tx.poll_close().into()) - })) - .unwrap(); + let t1 = poll_future(&mut OnClose::new(&mut tx)); match t1 { - Ok(Async::Ready(())) => None, - Ok(Async::NotReady) => Some(tx), - Err(_) => unreachable!(), + Ready(()) => None, + Pending => Some(tx), } }) .join() @@ -82,7 +115,7 @@ fn changing_tx_task() { if let Some(mut tx) = tx { // Previous task parked, use a new task... - block_on(futures::future::poll_fn(move || tx.poll_close())).unwrap(); + block_on(OnClose::new(&mut tx)); } }); } diff --git a/tokio-sync/tests/fuzz_semaphore.rs b/tokio-sync/tests/fuzz_semaphore.rs index 58c67dc39..ca2fda8b9 100644 --- a/tokio-sync/tests/fuzz_semaphore.rs +++ b/tokio-sync/tests/fuzz_semaphore.rs @@ -8,12 +8,30 @@ extern crate loom; mod semaphore; use crate::semaphore::*; -use futures::{future, try_ready, Async, Future, Poll}; + +use async_util::future::poll_fn; use loom::futures::block_on; use loom::thread; +use std::future::Future; +use std::pin::Pin; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::Arc; +use std::task::Poll::Ready; +use std::task::{Context, Poll}; + +/// 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, + } + }}; +} #[test] fn basic_usage() { @@ -30,24 +48,22 @@ fn basic_usage() { } impl Future for Actor { - type Item = (); - type Error = (); + type Output = (); - fn poll(&mut self) -> Poll<(), ()> { - try_ready!(self - .waiter - .poll_acquire(&self.shared.semaphore) - .map_err(|_| ())); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let me = &mut *self; - let actual = self.shared.active.fetch_add(1, SeqCst); + ready!(me.waiter.poll_acquire(cx, &me.shared.semaphore)).unwrap(); + + let actual = me.shared.active.fetch_add(1, SeqCst); assert!(actual <= NUM - 1); - let actual = self.shared.active.fetch_sub(1, SeqCst); + let actual = me.shared.active.fetch_sub(1, SeqCst); assert!(actual <= NUM); - self.waiter.release(&self.shared.semaphore); + me.waiter.release(&me.shared.semaphore); - Ok(Async::Ready(())) + Ready(()) } } @@ -64,16 +80,14 @@ fn basic_usage() { block_on(Actor { waiter: Permit::new(), shared, - }) - .unwrap(); + }); }); } block_on(Actor { waiter: Permit::new(), shared, - }) - .unwrap(); + }); }); } @@ -87,11 +101,7 @@ fn release() { thread::spawn(move || { let mut permit = Permit::new(); - block_on(future::lazy(|| { - permit.poll_acquire(&semaphore).unwrap(); - Ok::<_, ()>(()) - })) - .unwrap(); + block_on(poll_fn(|cx| permit.poll_acquire(cx, &semaphore))).unwrap(); permit.release(&semaphore); }); @@ -99,7 +109,7 @@ fn release() { let mut permit = Permit::new(); - block_on(future::poll_fn(|| permit.poll_acquire(&semaphore))).unwrap(); + block_on(poll_fn(|cx| permit.poll_acquire(cx, &semaphore))).unwrap(); permit.release(&semaphore); }); @@ -119,9 +129,10 @@ fn basic_closing() { let mut permit = Permit::new(); for _ in 0..2 { - block_on(future::poll_fn(|| { - permit.poll_acquire(&semaphore).map_err(|_| ()) + block_on(poll_fn(|cx| { + permit.poll_acquire(cx, &semaphore).map_err(|_| ()) }))?; + permit.release(&semaphore); } @@ -146,8 +157,8 @@ fn concurrent_close() { thread::spawn(move || { let mut permit = Permit::new(); - block_on(future::poll_fn(|| { - permit.poll_acquire(&semaphore).map_err(|_| ()) + block_on(poll_fn(|cx| { + permit.poll_acquire(cx, &semaphore).map_err(|_| ()) }))?; permit.release(&semaphore); diff --git a/tokio-sync/tests/lock.rs b/tokio-sync/tests/lock.rs index 0e74efa0b..33cebef53 100644 --- a/tokio-sync/tests/lock.rs +++ b/tokio-sync/tests/lock.rs @@ -1,65 +1,50 @@ #![deny(warnings, rust_2018_idioms)] -use futures; -use tokio_mock_task::*; use tokio_sync::lock::Lock; - -macro_rules! assert_ready { - ($e:expr) => {{ - match $e { - futures::Async::Ready(v) => v, - futures::Async::NotReady => panic!("not ready"), - } - }}; -} - -macro_rules! assert_not_ready { - ($e:expr) => {{ - match $e { - futures::Async::NotReady => {} - futures::Async::Ready(v) => panic!("ready; value = {:?}", v), - } - }}; -} +use tokio_test::task::MockTask; +use tokio_test::{assert_pending, assert_ready}; #[test] fn straight_execution() { + let mut task = MockTask::new(); let mut l = Lock::new(100); // We can immediately acquire the lock and take the value - let mut g = assert_ready!(l.poll_lock()); - assert_eq!(&*g, &100); - *g = 99; - drop(g); + task.enter(|cx| { + let mut g = assert_ready!(l.poll_lock(cx)); + assert_eq!(&*g, &100); + *g = 99; + drop(g); - let mut g = assert_ready!(l.poll_lock()); - assert_eq!(&*g, &99); - *g = 98; - drop(g); + let mut g = assert_ready!(l.poll_lock(cx)); + assert_eq!(&*g, &99); + *g = 98; + drop(g); - let mut g = assert_ready!(l.poll_lock()); - assert_eq!(&*g, &98); + let mut g = assert_ready!(l.poll_lock(cx)); + assert_eq!(&*g, &98); - // We can continue to access the guard even if the lock is dropped - drop(l); - *g = 97; - assert_eq!(&*g, &97); + // We can continue to access the guard even if the lock is dropped + drop(l); + *g = 97; + assert_eq!(&*g, &97); + }); } #[test] fn readiness() { - let mut task = MockTask::new(); + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); let mut l = Lock::new(100); - let g = assert_ready!(l.poll_lock()); + + let g = assert_ready!(t1.enter(|cx| l.poll_lock(cx))); // We can't now acquire the lease since it's already held in g - task.enter(|| { - assert_not_ready!(l.poll_lock()); - }); + assert_pending!(t2.enter(|cx| l.poll_lock(cx))); // But once g unlocks, we can acquire it drop(g); - assert!(task.is_notified()); - assert_ready!(l.poll_lock()); + assert!(t2.is_woken()); + assert_ready!(t2.enter(|cx| l.poll_lock(cx))); } diff --git a/tokio-sync/tests/mpsc.rs b/tokio-sync/tests/mpsc.rs index af2d1dd7a..17dd3e648 100644 --- a/tokio-sync/tests/mpsc.rs +++ b/tokio-sync/tests/mpsc.rs @@ -1,98 +1,111 @@ #![deny(warnings, rust_2018_idioms)] -use futures; -use futures::prelude::*; -use std::sync::Arc; -use std::thread; -use tokio_mock_task::*; use tokio_sync::mpsc; +use tokio_test::task::MockTask; +use tokio_test::{ + assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok, +}; + +use std::sync::Arc; trait AssertSend: Send {} impl AssertSend for mpsc::Sender {} impl AssertSend for mpsc::Receiver {} -macro_rules! assert_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::Ready(v)) => v, - Ok(_) => panic!("not ready"), - Err(e) => panic!("error = {:?}", e), - } - }}; -} - -macro_rules! assert_not_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::NotReady) => {} - Ok(futures::Async::Ready(v)) => panic!("ready; value = {:?}", v), - Err(e) => panic!("error = {:?}", e), - } - }}; -} - #[test] fn send_recv_with_buffer() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + let (mut tx, mut rx) = mpsc::channel::(16); // Using poll_ready / try_send - assert_ready!(tx.poll_ready()); + assert_ready_ok!(t1.enter(|cx| tx.poll_ready(cx))); tx.try_send(1).unwrap(); // Without poll_ready tx.try_send(2).unwrap(); - // Sink API - assert!(tx.start_send(3).unwrap().is_ready()); - assert_ready!(tx.poll_complete()); - assert_ready!(tx.close()); - drop(tx); - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t2.enter(|cx| rx.poll_next(cx))); assert_eq!(val, Some(1)); - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t2.enter(|cx| rx.poll_next(cx))); assert_eq!(val, Some(2)); - let val = assert_ready!(rx.poll()); - assert_eq!(val, Some(3)); - - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t2.enter(|cx| rx.poll_next(cx))); assert!(val.is_none()); } +#[test] +#[cfg(feature = "async-traits")] +fn send_sink_recv_with_buffer() { + use async_sink::Sink; + use futures_core::Stream; + use pin_utils::pin_mut; + + let mut t1 = MockTask::new(); + + let (tx, rx) = mpsc::channel::(16); + + t1.enter(|cx| { + pin_mut!(tx); + + assert_ready_ok!(tx.as_mut().poll_ready(cx)); + assert_ok!(tx.as_mut().start_send(1)); + + assert_ready_ok!(tx.as_mut().poll_ready(cx)); + assert_ok!(tx.as_mut().start_send(2)); + + assert_ready_ok!(tx.as_mut().poll_flush(cx)); + assert_ready_ok!(tx.as_mut().poll_close(cx)); + }); + + t1.enter(|cx| { + pin_mut!(rx); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert_eq!(val, Some(1)); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert_eq!(val, Some(2)); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert!(val.is_none()); + }); +} + #[test] fn start_send_past_cap() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + let mut t3 = MockTask::new(); + let (mut tx1, mut rx) = mpsc::channel(1); let mut tx2 = tx1.clone(); - let mut task1 = MockTask::new(); - let mut task2 = MockTask::new(); + assert_ok!(tx1.try_send(())); - let res = tx1.start_send(()).unwrap(); - assert!(res.is_ready()); - - task1.enter(|| { - let res = tx1.start_send(()).unwrap(); - assert!(!res.is_ready()); + t1.enter(|cx| { + assert_pending!(tx1.poll_ready(cx)); }); - task2.enter(|| { - assert_not_ready!(tx2.poll_ready()); + t2.enter(|cx| { + assert_pending!(tx2.poll_ready(cx)); }); drop(tx1); - let val = assert_ready!(rx.poll()); + let val = t3.enter(|cx| assert_ready!(rx.poll_next(cx))); assert!(val.is_some()); - assert!(task2.is_notified()); - assert!(!task1.is_notified()); + assert!(t2.is_woken()); + assert!(!t1.is_woken()); drop(tx2); - let val = assert_ready!(rx.poll()); + let val = t3.enter(|cx| assert_ready!(rx.poll_next(cx))); assert!(val.is_none()); } @@ -104,33 +117,69 @@ fn buffer_gteq_one() { #[test] fn send_recv_unbounded() { + let mut t1 = MockTask::new(); + let (mut tx, mut rx) = mpsc::unbounded_channel::(); // Using `try_send` - tx.try_send(1).unwrap(); + assert_ok!(tx.try_send(1)); + assert_ok!(tx.try_send(2)); - // Using `Sink` API - assert!(tx.start_send(2).unwrap().is_ready()); - assert_ready!(tx.poll_complete()); - - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); assert_eq!(val, Some(1)); - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); assert_eq!(val, Some(2)); - assert_ready!(tx.poll_complete()); - assert_ready!(tx.close()); - drop(tx); - let val = assert_ready!(rx.poll()); + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); assert!(val.is_none()); } +#[test] +#[cfg(feature = "async-traits")] +fn sink_send_recv_unbounded() { + use async_sink::Sink; + use futures_core::Stream; + use pin_utils::pin_mut; + + let mut t1 = MockTask::new(); + + let (tx, rx) = mpsc::unbounded_channel::(); + + t1.enter(|cx| { + pin_mut!(tx); + + assert_ready_ok!(tx.as_mut().poll_ready(cx)); + assert_ok!(tx.as_mut().start_send(1)); + + assert_ready_ok!(tx.as_mut().poll_ready(cx)); + assert_ok!(tx.as_mut().start_send(2)); + + assert_ready_ok!(tx.as_mut().poll_flush(cx)); + assert_ready_ok!(tx.as_mut().poll_close(cx)); + }); + + t1.enter(|cx| { + pin_mut!(rx); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert_eq!(val, Some(1)); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert_eq!(val, Some(2)); + + let val = assert_ready!(Stream::poll_next(rx.as_mut(), cx)); + assert!(val.is_none()); + }); +} + #[test] fn no_t_bounds_buffer() { struct NoImpls; + + let mut t1 = MockTask::new(); let (tx, mut rx) = mpsc::channel(100); // sender should be Debug even though T isn't Debug @@ -139,12 +188,16 @@ fn no_t_bounds_buffer() { println!("{:?}", rx); // and sender should be Clone even though T isn't Clone assert!(tx.clone().try_send(NoImpls).is_ok()); - assert!(assert_ready!(rx.poll()).is_some()); + + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); + assert!(val.is_some()); } #[test] fn no_t_bounds_unbounded() { struct NoImpls; + + let mut t1 = MockTask::new(); let (tx, mut rx) = mpsc::unbounded_channel(); // sender should be Debug even though T isn't Debug @@ -153,186 +206,188 @@ fn no_t_bounds_unbounded() { println!("{:?}", rx); // and sender should be Clone even though T isn't Clone assert!(tx.clone().try_send(NoImpls).is_ok()); - assert!(assert_ready!(rx.poll()).is_some()); + + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); + assert!(val.is_some()); } #[test] fn send_recv_buffer_limited() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + let (mut tx, mut rx) = mpsc::channel::(1); - let mut task = MockTask::new(); // Run on a task context - task.enter(|| { - assert!(tx.poll_complete().unwrap().is_ready()); - assert!(tx.poll_ready().unwrap().is_ready()); + t1.enter(|cx| { + assert_ready_ok!(tx.poll_ready(cx)); // Send first message - let res = tx.start_send(1).unwrap(); - assert!(is_ready(&res)); - assert!(tx.poll_ready().unwrap().is_not_ready()); + assert_ok!(tx.try_send(1)); + + // Not ready + assert_pending!(tx.poll_ready(cx)); // Send second message - let res = tx.start_send(2).unwrap(); - assert!(!is_ready(&res)); - - // Take the value - assert_eq!(rx.poll().unwrap(), Async::Ready(Some(1))); - assert!(tx.poll_ready().unwrap().is_ready()); - - let res = tx.start_send(2).unwrap(); - assert!(is_ready(&res)); - assert!(tx.poll_ready().unwrap().is_not_ready()); - - // Take the value - assert_eq!(rx.poll().unwrap(), Async::Ready(Some(2))); - assert!(tx.poll_ready().unwrap().is_ready()); - }); -} - -#[test] -fn send_shared_recv() { - let (tx1, rx) = mpsc::channel::(16); - let tx2 = tx1.clone(); - let mut rx = rx.wait(); - - tx1.send(1).wait().unwrap(); - assert_eq!(rx.next().unwrap().unwrap(), 1); - - tx2.send(2).wait().unwrap(); - assert_eq!(rx.next().unwrap().unwrap(), 2); -} - -#[test] -fn send_recv_threads() { - let (tx, rx) = mpsc::channel::(16); - let mut rx = rx.wait(); - - thread::spawn(move || { - tx.send(1).wait().unwrap(); + assert_err!(tx.try_send(1337)); }); - assert_eq!(rx.next().unwrap().unwrap(), 1); + t2.enter(|cx| { + // Take the value + let val = assert_ready!(rx.poll_next(cx)); + assert_eq!(Some(1), val); + }); + + assert!(t1.is_woken()); + + t1.enter(|cx| { + assert_ready_ok!(tx.poll_ready(cx)); + + assert_ok!(tx.try_send(2)); + + // Not ready + assert_pending!(tx.poll_ready(cx)); + }); + + t2.enter(|cx| { + // Take the value + let val = assert_ready!(rx.poll_next(cx)); + assert_eq!(Some(2), val); + }); + + t1.enter(|cx| { + assert_ready_ok!(tx.poll_ready(cx)); + }); } #[test] fn recv_close_gets_none_idle() { + let mut t1 = MockTask::new(); + let (mut tx, mut rx) = mpsc::channel::(10); - let mut task = MockTask::new(); rx.close(); - task.enter(|| { - let val = assert_ready!(rx.poll()); + t1.enter(|cx| { + let val = assert_ready!(rx.poll_next(cx)); assert!(val.is_none()); - assert!(tx.poll_ready().is_err()); + assert_ready_err!(tx.poll_ready(cx)); }); } #[test] fn recv_close_gets_none_reserved() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + let mut t3 = MockTask::new(); + let (mut tx1, mut rx) = mpsc::channel::(1); let mut tx2 = tx1.clone(); - assert_ready!(tx1.poll_ready()); + assert_ready_ok!(t1.enter(|cx| tx1.poll_ready(cx))); - let mut task = MockTask::new(); - - task.enter(|| { - assert_not_ready!(tx2.poll_ready()); + t2.enter(|cx| { + assert_pending!(tx2.poll_ready(cx)); }); rx.close(); - assert!(task.is_notified()); + assert!(t2.is_woken()); - task.enter(|| { - assert!(tx2.poll_ready().is_err()); - assert_not_ready!(rx.poll()); + t2.enter(|cx| { + assert_ready_err!(tx2.poll_ready(cx)); }); - assert!(!task.is_notified()); + t3.enter(|cx| assert_pending!(rx.poll_next(cx))); - assert!(tx1.try_send(123).is_ok()); + assert!(!t1.is_woken()); + assert!(!t2.is_woken()); - assert!(task.is_notified()); + assert_ok!(tx1.try_send(123)); - task.enter(|| { - let v = assert_ready!(rx.poll()); + assert!(t3.is_woken()); + + t3.enter(|cx| { + let v = assert_ready!(rx.poll_next(cx)); assert_eq!(v, Some(123)); - let v = assert_ready!(rx.poll()); + let v = assert_ready!(rx.poll_next(cx)); assert!(v.is_none()); }); } #[test] fn tx_close_gets_none() { + let mut t1 = MockTask::new(); + let (_, mut rx) = mpsc::channel::(10); - let mut task = MockTask::new(); // Run on a task context - task.enter(|| { - let v = assert_ready!(rx.poll()); + t1.enter(|cx| { + let v = assert_ready!(rx.poll_next(cx)); assert!(v.is_none()); }); } -fn is_ready(res: &AsyncSink) -> bool { - match *res { - AsyncSink::Ready => true, - _ => false, - } -} - #[test] fn try_send_fail() { - let (mut tx, rx) = mpsc::channel(1); - let mut rx = rx.wait(); + let mut t1 = MockTask::new(); + + let (mut tx, mut rx) = mpsc::channel(1); tx.try_send("hello").unwrap(); // This should fail - assert!(tx.try_send("fail").unwrap_err().is_full()); + let err = assert_err!(tx.try_send("fail")); + assert!(err.is_full()); - assert_eq!(rx.next().unwrap().unwrap(), "hello"); + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); + assert_eq!(val, Some("hello")); - tx.try_send("goodbye").unwrap(); + assert_ok!(tx.try_send("goodbye")); drop(tx); - assert_eq!(rx.next().unwrap().unwrap(), "goodbye"); - assert!(rx.next().is_none()); + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); + assert_eq!(val, Some("goodbye")); + + let val = assert_ready!(t1.enter(|cx| rx.poll_next(cx))); + assert!(val.is_none()); } #[test] fn drop_tx_with_permit_releases_permit() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + // poll_ready reserves capacity, ensure that the capacity is released if tx // is dropped w/o sending a value. let (mut tx1, _rx) = mpsc::channel::(1); let mut tx2 = tx1.clone(); - let mut task = MockTask::new(); - assert_ready!(tx1.poll_ready()); + assert_ready_ok!(t1.enter(|cx| tx1.poll_ready(cx))); - task.enter(|| { - assert_not_ready!(tx2.poll_ready()); + t2.enter(|cx| { + assert_pending!(tx2.poll_ready(cx)); }); drop(tx1); - assert!(task.is_notified()); + assert!(t2.is_woken()); - assert_ready!(tx2.poll_ready()); + assert_ready_ok!(t2.enter(|cx| tx2.poll_ready(cx))); } #[test] fn dropping_rx_closes_channel() { + let mut t1 = MockTask::new(); + let (mut tx, rx) = mpsc::channel(100); let msg = Arc::new(()); - tx.try_send(msg.clone()).unwrap(); + assert_ok!(tx.try_send(msg.clone())); drop(rx); - assert!(tx.poll_ready().is_err()); + assert_ready_err!(t1.enter(|cx| tx.poll_ready(cx))); assert_eq!(1, Arc::strong_count(&msg)); } @@ -345,7 +400,11 @@ fn dropping_rx_closes_channel_for_try() { tx.try_send(msg.clone()).unwrap(); drop(rx); - assert!(tx.try_send(msg.clone()).unwrap_err().is_closed()); + + { + let err = assert_err!(tx.try_send(msg.clone())); + assert!(err.is_closed()); + } assert_eq!(1, Arc::strong_count(&msg)); } diff --git a/tokio-sync/tests/oneshot.rs b/tokio-sync/tests/oneshot.rs index cc14dc958..fc78bd2e5 100644 --- a/tokio-sync/tests/oneshot.rs +++ b/tokio-sync/tests/oneshot.rs @@ -1,29 +1,8 @@ #![deny(warnings, rust_2018_idioms)] -use futures; -use futures::prelude::*; -use tokio_mock_task::*; use tokio_sync::oneshot; - -macro_rules! assert_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::Ready(v)) => v, - Ok(_) => panic!("not ready"), - Err(e) => panic!("error = {:?}", e), - } - }}; -} - -macro_rules! assert_not_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::NotReady) => {} - Ok(futures::Async::Ready(v)) => panic!("ready; value = {:?}", v), - Err(e) => panic!("error = {:?}", e), - } - }}; -} +use tokio_test::task::MockTask; +use tokio_test::*; trait AssertSend: Send {} impl AssertSend for oneshot::Sender {} @@ -34,15 +13,13 @@ fn send_recv() { let (tx, mut rx) = oneshot::channel(); let mut task = MockTask::new(); - task.enter(|| { - assert_not_ready!(rx.poll()); - }); + assert_pending!(task.poll(&mut rx)); - assert!(tx.send(1).is_ok()); + assert_ok!(tx.send(1)); - assert!(task.is_notified()); + assert!(task.is_woken()); - let val = assert_ready!(rx.poll()); + let val = assert_ready_ok!(task.poll(&mut rx)); assert_eq!(val, 1); } @@ -51,14 +28,12 @@ fn close_tx() { let (tx, mut rx) = oneshot::channel::(); let mut task = MockTask::new(); - task.enter(|| { - assert_not_ready!(rx.poll()); - }); + assert_pending!(task.poll(&mut rx)); drop(tx); - assert!(task.is_notified()); - assert!(rx.poll().is_err()); + assert!(task.is_woken()); + assert_ready_err!(task.poll(&mut rx)); } #[test] @@ -67,67 +42,64 @@ fn close_rx() { // let (tx, _) = oneshot::channel(); - assert!(tx.send(1).is_err()); + assert_err!(tx.send(1)); // Second, via poll_close(); let (mut tx, rx) = oneshot::channel(); let mut task = MockTask::new(); - task.enter(|| assert_not_ready!(tx.poll_close())); + assert_pending!(task.enter(|cx| tx.poll_close(cx))); drop(rx); - assert!(task.is_notified()); + assert!(task.is_woken()); assert!(tx.is_closed()); - assert_ready!(tx.poll_close()); + assert_ready!(task.enter(|cx| tx.poll_close(cx))); - assert!(tx.send(1).is_err()); + assert_err!(tx.send(1)); } #[test] fn explicit_close_poll() { // First, with message sent let (tx, mut rx) = oneshot::channel(); + let mut task = MockTask::new(); - assert!(tx.send(1).is_ok()); + assert_ok!(tx.send(1)); rx.close(); - let value = assert_ready!(rx.poll()); + let value = assert_ready_ok!(task.poll(&mut rx)); assert_eq!(value, 1); - println!("~~~~~~~~~ TWO ~~~~~~~~~~"); - // Second, without the message sent let (mut tx, mut rx) = oneshot::channel::(); - let mut task = MockTask::new(); - task.enter(|| assert_not_ready!(tx.poll_close())); + assert_pending!(task.enter(|cx| tx.poll_close(cx))); rx.close(); - assert!(task.is_notified()); + assert!(task.is_woken()); assert!(tx.is_closed()); - assert_ready!(tx.poll_close()); + assert_ready!(task.enter(|cx| tx.poll_close(cx))); - assert!(tx.send(1).is_err()); - - assert!(rx.poll().is_err()); + assert_err!(tx.send(1)); + assert_ready_err!(task.poll(&mut rx)); // Again, but without sending the value this time let (mut tx, mut rx) = oneshot::channel::(); let mut task = MockTask::new(); - task.enter(|| assert_not_ready!(tx.poll_close())); + assert_pending!(task.enter(|cx| tx.poll_close(cx))); rx.close(); - assert!(task.is_notified()); + assert!(task.is_woken()); assert!(tx.is_closed()); - assert_ready!(tx.poll_close()); + assert_ready!(task.enter(|cx| tx.poll_close(cx))); - assert!(rx.poll().is_err()); + assert_ready_err!(task.poll(&mut rx)); } #[test] @@ -135,27 +107,26 @@ fn explicit_close_try_recv() { // First, with message sent let (tx, mut rx) = oneshot::channel(); - assert!(tx.send(1).is_ok()); + assert_ok!(tx.send(1)); rx.close(); - assert_eq!(rx.try_recv().unwrap(), 1); - - println!("~~~~~~~~~ TWO ~~~~~~~~~~"); + let val = assert_ok!(rx.try_recv()); + assert_eq!(1, val); // Second, without the message sent let (mut tx, mut rx) = oneshot::channel::(); let mut task = MockTask::new(); - task.enter(|| assert_not_ready!(tx.poll_close())); + assert_pending!(task.enter(|cx| tx.poll_close(cx))); rx.close(); - assert!(task.is_notified()); + assert!(task.is_woken()); assert!(tx.is_closed()); - assert_ready!(tx.poll_close()); + assert_ready!(task.enter(|cx| tx.poll_close(cx))); - assert!(rx.try_recv().is_err()); + assert_err!(rx.try_recv()); } #[test] @@ -166,11 +137,9 @@ fn close_try_recv_poll() { rx.close(); - assert!(rx.try_recv().is_err()); + assert_err!(rx.try_recv()); - task.enter(|| { - let _ = rx.poll(); - }); + let _ = task.poll(&mut rx); } #[test] @@ -179,19 +148,14 @@ fn drops_tasks() { let mut tx_task = MockTask::new(); let mut rx_task = MockTask::new(); - tx_task.enter(|| { - assert_not_ready!(tx.poll_close()); - }); - - rx_task.enter(|| { - assert_not_ready!(rx.poll()); - }); + assert_pending!(tx_task.enter(|cx| tx.poll_close(cx))); + assert_pending!(rx_task.poll(&mut rx)); drop(tx); drop(rx); - assert_eq!(1, tx_task.notifier_ref_count()); - assert_eq!(1, rx_task.notifier_ref_count()); + assert_eq!(1, tx_task.waker_ref_count()); + assert_eq!(1, rx_task.waker_ref_count()); } #[test] @@ -201,26 +165,22 @@ fn receiver_changes_task() { let mut task1 = MockTask::new(); let mut task2 = MockTask::new(); - task1.enter(|| { - assert_not_ready!(rx.poll()); - }); + assert_pending!(task1.poll(&mut rx)); - assert_eq!(2, task1.notifier_ref_count()); - assert_eq!(1, task2.notifier_ref_count()); + assert_eq!(2, task1.waker_ref_count()); + assert_eq!(1, task2.waker_ref_count()); - task2.enter(|| { - assert_not_ready!(rx.poll()); - }); + assert_pending!(task2.poll(&mut rx)); - assert_eq!(1, task1.notifier_ref_count()); - assert_eq!(2, task2.notifier_ref_count()); + assert_eq!(1, task1.waker_ref_count()); + assert_eq!(2, task2.waker_ref_count()); - tx.send(1).unwrap(); + assert_ok!(tx.send(1)); - assert!(!task1.is_notified()); - assert!(task2.is_notified()); + assert!(!task1.is_woken()); + assert!(task2.is_woken()); - assert_ready!(rx.poll()); + assert_ready_ok!(task2.poll(&mut rx)); } #[test] @@ -230,24 +190,20 @@ fn sender_changes_task() { let mut task1 = MockTask::new(); let mut task2 = MockTask::new(); - task1.enter(|| { - assert_not_ready!(tx.poll_close()); - }); + assert_pending!(task1.enter(|cx| tx.poll_close(cx))); - assert_eq!(2, task1.notifier_ref_count()); - assert_eq!(1, task2.notifier_ref_count()); + assert_eq!(2, task1.waker_ref_count()); + assert_eq!(1, task2.waker_ref_count()); - task2.enter(|| { - assert_not_ready!(tx.poll_close()); - }); + assert_pending!(task2.enter(|cx| tx.poll_close(cx))); - assert_eq!(1, task1.notifier_ref_count()); - assert_eq!(2, task2.notifier_ref_count()); + assert_eq!(1, task1.waker_ref_count()); + assert_eq!(2, task2.waker_ref_count()); drop(rx); - assert!(!task1.is_notified()); - assert!(task2.is_notified()); + assert!(!task1.is_woken()); + assert!(task2.is_woken()); - assert_ready!(tx.poll_close()); + assert_ready!(task2.enter(|cx| tx.poll_close(cx))); } diff --git a/tokio-sync/tests/semaphore.rs b/tokio-sync/tests/semaphore.rs index c775bf1a0..a19f261a4 100644 --- a/tokio-sync/tests/semaphore.rs +++ b/tokio-sync/tests/semaphore.rs @@ -1,31 +1,13 @@ #![deny(warnings, rust_2018_idioms)] -use futures; -use tokio_mock_task::*; use tokio_sync::semaphore::{Permit, Semaphore}; - -macro_rules! assert_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::Ready(v)) => v, - Ok(_) => panic!("not ready"), - Err(e) => panic!("error = {:?}", e), - } - }}; -} - -macro_rules! assert_not_ready { - ($e:expr) => {{ - match $e { - Ok(futures::Async::NotReady) => {} - Ok(futures::Async::Ready(v)) => panic!("ready; value = {:?}", v), - Err(e) => panic!("error = {:?}", e), - } - }}; -} +use tokio_test::task::MockTask; +use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok}; #[test] fn available_permits() { + let mut t1 = MockTask::new(); + let s = Semaphore::new(100); assert_eq!(s.available_permits(), 100); @@ -33,39 +15,39 @@ fn available_permits() { let mut permit = Permit::new(); assert!(!permit.is_acquired()); - assert_ready!(permit.poll_acquire(&s)); + assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s))); assert_eq!(s.available_permits(), 99); assert!(permit.is_acquired()); // Polling again on the same waiter does not claim a new permit - assert_ready!(permit.poll_acquire(&s)); + assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s))); assert_eq!(s.available_permits(), 99); assert!(permit.is_acquired()); } #[test] fn unavailable_permits() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); let s = Semaphore::new(1); let mut permit_1 = Permit::new(); let mut permit_2 = Permit::new(); // Acquire the first permit - assert_ready!(permit_1.poll_acquire(&s)); + assert_ready_ok!(t1.enter(|cx| permit_1.poll_acquire(cx, &s))); assert_eq!(s.available_permits(), 0); - let mut task = MockTask::new(); - - task.enter(|| { + t2.enter(|cx| { // Try to acquire the second permit - assert_not_ready!(permit_2.poll_acquire(&s)); + assert_pending!(permit_2.poll_acquire(cx, &s)); }); permit_1.release(&s); assert_eq!(s.available_permits(), 0); - assert!(task.is_notified()); - assert_ready!(permit_2.poll_acquire(&s)); + assert!(t2.is_woken()); + assert_ready_ok!(t2.enter(|cx| permit_2.poll_acquire(cx, &s))); permit_2.release(&s); assert_eq!(s.available_permits(), 1); @@ -73,21 +55,22 @@ fn unavailable_permits() { #[test] fn zero_permits() { + let mut t1 = MockTask::new(); + let s = Semaphore::new(0); assert_eq!(s.available_permits(), 0); let mut permit = Permit::new(); - let mut task = MockTask::new(); // Try to acquire the permit - task.enter(|| { - assert_not_ready!(permit.poll_acquire(&s)); + t1.enter(|cx| { + assert_pending!(permit.poll_acquire(cx, &s)); }); s.add_permits(1); - assert!(task.is_notified()); - assert_ready!(permit.poll_acquire(&s)); + assert!(t1.is_woken()); + assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s))); } #[test] @@ -99,6 +82,8 @@ fn validates_max_permits() { #[test] fn close_semaphore_prevents_acquire() { + let mut t1 = MockTask::new(); + let s = Semaphore::new(1); s.close(); @@ -106,29 +91,32 @@ fn close_semaphore_prevents_acquire() { let mut permit = Permit::new(); - assert!(permit.poll_acquire(&s).is_err()); + assert_ready_err!(t1.enter(|cx| permit.poll_acquire(cx, &s))); assert_eq!(1, s.available_permits()); } #[test] fn close_semaphore_notifies_permit1() { + let mut t1 = MockTask::new(); + let s = Semaphore::new(0); - let mut permit = Permit::new(); - let mut task = MockTask::new(); - task.enter(|| { - assert_not_ready!(permit.poll_acquire(&s)); - }); + assert_pending!(t1.enter(|cx| permit.poll_acquire(cx, &s))); s.close(); - assert!(task.is_notified()); - assert!(permit.poll_acquire(&s).is_err()); + assert!(t1.is_woken()); + assert_ready_err!(t1.enter(|cx| permit.poll_acquire(cx, &s))); } #[test] fn close_semaphore_notifies_permit2() { + let mut t1 = MockTask::new(); + let mut t2 = MockTask::new(); + let mut t3 = MockTask::new(); + let mut t4 = MockTask::new(); + let s = Semaphore::new(2); let mut permit1 = Permit::new(); @@ -137,27 +125,19 @@ fn close_semaphore_notifies_permit2() { let mut permit4 = Permit::new(); // Acquire a couple of permits - assert_ready!(permit1.poll_acquire(&s)); - assert_ready!(permit2.poll_acquire(&s)); + assert_ready_ok!(t1.enter(|cx| permit1.poll_acquire(cx, &s))); + assert_ready_ok!(t2.enter(|cx| permit2.poll_acquire(cx, &s))); - let mut task1 = MockTask::new(); - let mut task2 = MockTask::new(); - - task1.enter(|| { - assert_not_ready!(permit3.poll_acquire(&s)); - }); - - task2.enter(|| { - assert_not_ready!(permit4.poll_acquire(&s)); - }); + assert_pending!(t3.enter(|cx| permit3.poll_acquire(cx, &s))); + assert_pending!(t4.enter(|cx| permit4.poll_acquire(cx, &s))); s.close(); - assert!(task1.is_notified()); - assert!(task2.is_notified()); + assert!(t3.is_woken()); + assert!(t4.is_woken()); - assert!(permit3.poll_acquire(&s).is_err()); - assert!(permit4.poll_acquire(&s).is_err()); + assert_ready_err!(t3.enter(|cx| permit3.poll_acquire(cx, &s))); + assert_ready_err!(t4.enter(|cx| permit4.poll_acquire(cx, &s))); assert_eq!(0, s.available_permits()); @@ -165,7 +145,7 @@ fn close_semaphore_notifies_permit2() { assert_eq!(1, s.available_permits()); - assert!(permit1.poll_acquire(&s).is_err()); + assert_ready_err!(t1.enter(|cx| permit1.poll_acquire(cx, &s))); permit2.release(&s); diff --git a/tokio-sync/tests/watch.rs b/tokio-sync/tests/watch.rs index 8424a181d..10a6a8226 100644 --- a/tokio-sync/tests/watch.rs +++ b/tokio-sync/tests/watch.rs @@ -1,9 +1,10 @@ #![deny(warnings, rust_2018_idioms)] -use futures; -use tokio_mock_task::*; use tokio_sync::watch; +use tokio_test::task::MockTask; +use tokio_test::{assert_pending, assert_ready}; +/* macro_rules! assert_ready { ($e:expr) => {{ match $e { @@ -23,143 +24,179 @@ macro_rules! assert_not_ready { } }}; } +*/ #[test] -fn single_rx() { - let (mut tx, mut rx) = watch::channel("one"); +fn single_rx_poll_ref() { + let (tx, mut rx) = watch::channel("one"); let mut task = MockTask::new(); - task.enter(|| { - let v = assert_ready!(rx.poll_ref()).unwrap(); - assert_eq!(*v, "one"); + task.enter(|cx| { + { + let v = assert_ready!(rx.poll_ref(cx)).unwrap(); + assert_eq!(*v, "one"); + } + assert_pending!(rx.poll_ref(cx)); }); - task.enter(|| assert_not_ready!(rx.poll_ref())); - - assert!(!task.is_notified()); - tx.broadcast("two").unwrap(); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| { - let v = assert_ready!(rx.poll_ref()).unwrap(); - assert_eq!(*v, "two"); + task.enter(|cx| { + { + let v = assert_ready!(rx.poll_ref(cx)).unwrap(); + assert_eq!(*v, "two"); + } + assert_pending!(rx.poll_ref(cx)); }); - task.enter(|| assert_not_ready!(rx.poll_ref())); - drop(tx); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_ref(cx)); assert!(res.is_none()); }); } #[test] -fn stream_impl() { - use futures::Stream; - - let (mut tx, mut rx) = watch::channel("one"); +fn single_rx_poll_next() { + let (tx, mut rx) = watch::channel("one"); let mut task = MockTask::new(); - task.enter(|| { - let v = assert_ready!(rx.poll()).unwrap(); + task.enter(|cx| { + let v = assert_ready!(rx.poll_next(cx)).unwrap(); assert_eq!(v, "one"); + assert_pending!(rx.poll_ref(cx)); }); - task.enter(|| assert_not_ready!(rx.poll())); - - assert!(!task.is_notified()); - tx.broadcast("two").unwrap(); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| { - let v = assert_ready!(rx.poll()).unwrap(); + task.enter(|cx| { + let v = assert_ready!(rx.poll_next(cx)).unwrap(); assert_eq!(v, "two"); + assert_pending!(rx.poll_ref(cx)); }); - task.enter(|| assert_not_ready!(rx.poll())); - drop(tx); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| { - let res = assert_ready!(rx.poll()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_next(cx)); + assert!(res.is_none()); + }); +} + +#[test] +#[cfg(feature = "async-traits")] +fn stream_impl() { + use futures_core::Stream; + use pin_utils::pin_mut; + + let (tx, rx) = watch::channel("one"); + let mut task = MockTask::new(); + + pin_mut!(rx); + + task.enter(|cx| { + { + let v = assert_ready!(Stream::poll_next(rx.as_mut(), cx)).unwrap(); + assert_eq!(v, "one"); + } + assert_pending!(rx.poll_ref(cx)); + }); + + tx.broadcast("two").unwrap(); + + assert!(task.is_woken()); + + task.enter(|cx| { + { + let v = assert_ready!(Stream::poll_next(rx.as_mut(), cx)).unwrap(); + assert_eq!(v, "two"); + } + assert_pending!(rx.poll_ref(cx)); + }); + + drop(tx); + + assert!(task.is_woken()); + + task.enter(|cx| { + let res = assert_ready!(Stream::poll_next(rx, cx)); assert!(res.is_none()); }); } #[test] fn multi_rx() { - let (mut tx, mut rx1) = watch::channel("one"); + let (tx, mut rx1) = watch::channel("one"); let mut rx2 = rx1.clone(); let mut task1 = MockTask::new(); let mut task2 = MockTask::new(); - task1.enter(|| { - let res = assert_ready!(rx1.poll_ref()); + task1.enter(|cx| { + let res = assert_ready!(rx1.poll_ref(cx)); assert_eq!(*res.unwrap(), "one"); }); - task2.enter(|| { - let res = assert_ready!(rx2.poll_ref()); + task2.enter(|cx| { + let res = assert_ready!(rx2.poll_ref(cx)); assert_eq!(*res.unwrap(), "one"); }); tx.broadcast("two").unwrap(); - assert!(task1.is_notified()); - assert!(task2.is_notified()); + assert!(task1.is_woken()); + assert!(task2.is_woken()); - task1.enter(|| { - let res = assert_ready!(rx1.poll_ref()); + task1.enter(|cx| { + let res = assert_ready!(rx1.poll_ref(cx)); assert_eq!(*res.unwrap(), "two"); }); tx.broadcast("three").unwrap(); - assert!(task1.is_notified()); - assert!(task2.is_notified()); + assert!(task1.is_woken()); + assert!(task2.is_woken()); - task1.enter(|| { - let res = assert_ready!(rx1.poll_ref()); + task1.enter(|cx| { + let res = assert_ready!(rx1.poll_ref(cx)); assert_eq!(*res.unwrap(), "three"); }); - task2.enter(|| { - let res = assert_ready!(rx2.poll_ref()); + task2.enter(|cx| { + let res = assert_ready!(rx2.poll_ref(cx)); assert_eq!(*res.unwrap(), "three"); }); tx.broadcast("four").unwrap(); - task1.enter(|| { - let res = assert_ready!(rx1.poll_ref()); + task1.enter(|cx| { + let res = assert_ready!(rx1.poll_ref(cx)); assert_eq!(*res.unwrap(), "four"); }); drop(tx); - task1.enter(|| { - let res = assert_ready!(rx1.poll_ref()); + task1.enter(|cx| { + let res = assert_ready!(rx1.poll_ref(cx)); assert!(res.is_none()); }); - task2.enter(|| { - let res = assert_ready!(rx2.poll_ref()); + task2.enter(|cx| { + let res = assert_ready!(rx2.poll_ref(cx)); assert_eq!(*res.unwrap(), "four"); }); - task2.enter(|| { - let res = assert_ready!(rx2.poll_ref()); + task2.enter(|cx| { + let res = assert_ready!(rx2.poll_ref(cx)); assert!(res.is_none()); }); } @@ -173,45 +210,47 @@ fn rx_observes_final_value() { drop(tx); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_ref(cx)); assert!(res.is_some()); assert_eq!(*res.unwrap(), "one"); }); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_ref(cx)); assert!(res.is_none()); }); // Sending a value - let (mut tx, mut rx) = watch::channel("one"); + let (tx, mut rx) = watch::channel("one"); let mut task = MockTask::new(); tx.broadcast("two").unwrap(); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); - assert!(res.is_some()); - assert_eq!(*res.unwrap(), "two"); - }); + task.enter(|cx| { + { + let res = assert_ready!(rx.poll_ref(cx)); + assert!(res.is_some()); + assert_eq!(*res.unwrap(), "two"); + } - task.enter(|| assert_not_ready!(rx.poll_ref())); + assert_pending!(rx.poll_ref(cx)); + }); tx.broadcast("three").unwrap(); drop(tx); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_ref(cx)); assert!(res.is_some()); assert_eq!(*res.unwrap(), "three"); }); - task.enter(|| { - let res = assert_ready!(rx.poll_ref()); + task.enter(|cx| { + let res = assert_ready!(rx.poll_ref(cx)); assert!(res.is_none()); }); } @@ -221,13 +260,13 @@ fn poll_close() { let (mut tx, rx) = watch::channel("one"); let mut task = MockTask::new(); - task.enter(|| assert_not_ready!(tx.poll_close())); + assert_pending!(task.enter(|cx| tx.poll_close(cx))); drop(rx); - assert!(task.is_notified()); + assert!(task.is_woken()); - task.enter(|| assert_ready!(tx.poll_close())); + assert_ready!(task.enter(|cx| tx.poll_close(cx))); assert!(tx.broadcast("two").is_err()); } diff --git a/tokio-tcp/Cargo.toml b/tokio-tcp/Cargo.toml index 55f3e43e8..a6c672f42 100644 --- a/tokio-tcp/Cargo.toml +++ b/tokio-tcp/Cargo.toml @@ -21,15 +21,20 @@ TCP bindings for tokio. categories = ["asynchronous"] publish = false +[features] +incoming = ["futures-core-preview"] + [dependencies] tokio-io = { version = "0.2.0", path = "../tokio-io" } tokio-reactor = { version = "0.2.0", path = "../tokio-reactor" } bytes = "0.4" mio = "0.6.14" iovec = "0.1" -futures = "0.1.19" + +# optionals +futures-core-preview = { version = "0.3.0-alpha.16", optional = true } [dev-dependencies] -env_logger = { version = "0.5", default-features = false } -net2 = "*" -tokio = { version = "0.2.0", path = "../tokio" } +#env_logger = { version = "0.5", default-features = false } +#net2 = "*" +#tokio = { version = "0.2.0", path = "../tokio" } diff --git a/tokio-tcp/src/incoming.rs b/tokio-tcp/src/incoming.rs index dd1414c85..566734de5 100644 --- a/tokio-tcp/src/incoming.rs +++ b/tokio-tcp/src/incoming.rs @@ -1,8 +1,9 @@ use super::TcpListener; use super::TcpStream; -use futures::stream::Stream; -use futures::{try_ready, Async, Poll}; +use futures_core::stream::Stream; use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; /// Stream returned by the `TcpListener::incoming` function representing the /// stream of sockets received from a listener. @@ -19,11 +20,10 @@ impl Incoming { } impl Stream for Incoming { - type Item = TcpStream; - type Error = io::Error; + type Item = io::Result; - fn poll(&mut self) -> Poll, io::Error> { - let (socket, _) = try_ready!(self.inner.poll_accept()); - Ok(Async::Ready(Some(socket))) + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let (socket, _) = ready!(self.inner.poll_accept(cx))?; + Poll::Ready(Some(Ok(socket))) } } diff --git a/tokio-tcp/src/lib.rs b/tokio-tcp/src/lib.rs index 979d6d295..d88b50a45 100644 --- a/tokio-tcp/src/lib.rs +++ b/tokio-tcp/src/lib.rs @@ -9,8 +9,7 @@ //! library, which can be used to implement networking protocols. //! //! Connecting to an address, via TCP, can be done using [`TcpStream`]'s -//! [`connect`] method, which returns [`ConnectFuture`]. `ConnectFuture` -//! implements a future which returns a `TcpStream`. +//! [`connect`] method, which returns a future which returns a `TcpStream`. //! //! To listen on an address [`TcpListener`] can be used. `TcpListener`'s //! [`incoming`][incoming_method] method can be used to accept new connections. @@ -19,16 +18,23 @@ //! //! [`TcpStream`]: struct.TcpStream.html //! [`connect`]: struct.TcpStream.html#method.connect -//! [`ConnectFuture`]: struct.ConnectFuture.html //! [`TcpListener`]: struct.TcpListener.html //! [incoming_method]: struct.TcpListener.html#method.incoming //! [`Incoming`]: struct.Incoming.html +macro_rules! ready { + ($e:expr) => { + match $e { + ::std::task::Poll::Ready(t) => t, + ::std::task::Poll::Pending => return ::std::task::Poll::Pending, + } + }; +} + +#[cfg(feature = "incoming")] mod incoming; mod listener; mod stream; -pub use self::incoming::Incoming; pub use self::listener::TcpListener; -pub use self::stream::ConnectFuture; pub use self::stream::TcpStream; diff --git a/tokio-tcp/src/listener.rs b/tokio-tcp/src/listener.rs index 0da00dc9a..39a7af7de 100644 --- a/tokio-tcp/src/listener.rs +++ b/tokio-tcp/src/listener.rs @@ -1,10 +1,11 @@ -use super::Incoming; +#[cfg(feature = "incoming")] +use super::incoming::Incoming; use super::TcpStream; -use futures::{try_ready, Async, Poll}; use mio; use std::fmt; use std::io; use std::net::{self, SocketAddr}; +use std::task::{Context, Poll}; use tokio_reactor::{Handle, PollEvented}; /// An I/O object representing a TCP socket listening for incoming connections. @@ -61,15 +62,6 @@ impl TcpListener { Ok(TcpListener::new(l)) } - #[deprecated(since = "0.1.2", note = "use poll_accept instead")] - #[doc(hidden)] - pub fn accept(&mut self) -> io::Result<(TcpStream, SocketAddr)> { - match self.poll_accept()? { - Async::Ready(ret) => Ok(ret), - Async::NotReady => Err(io::ErrorKind::WouldBlock.into()), - } - } - /// Attempt to accept a connection and create a new connected `TcpStream` if /// successful. /// @@ -105,22 +97,13 @@ impl TcpListener { /// } /// # Ok::<_, Box>(()) /// ``` - pub fn poll_accept(&mut self) -> Poll<(TcpStream, SocketAddr), io::Error> { - let (io, addr) = try_ready!(self.poll_accept_std()); + pub fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll> { + let (io, addr) = ready!(self.poll_accept_std(cx))?; let io = mio::net::TcpStream::from_stream(io)?; let io = TcpStream::new(io); - Ok((io, addr).into()) - } - - #[deprecated(since = "0.1.2", note = "use poll_accept_std instead")] - #[doc(hidden)] - pub fn accept_std(&mut self) -> io::Result<(net::TcpStream, SocketAddr)> { - match self.poll_accept_std()? { - Async::Ready(ret) => Ok(ret), - Async::NotReady => Err(io::ErrorKind::WouldBlock.into()), - } + Poll::Ready(Ok((io, addr))) } /// Attempt to accept a connection and create a new connected `TcpStream` if @@ -159,16 +142,16 @@ impl TcpListener { /// } /// # Ok::<_, Box>(()) /// ``` - pub fn poll_accept_std(&mut self) -> Poll<(net::TcpStream, SocketAddr), io::Error> { - try_ready!(self.io.poll_read_ready(mio::Ready::readable())); + pub fn poll_accept_std(&mut self, cx: &mut Context<'_>) -> Poll> { + ready!(self.io.poll_read_ready(cx, mio::Ready::readable()))?; match self.io.get_ref().accept_std() { - Ok(pair) => Ok(pair.into()), + Ok(pair) => Poll::Ready(Ok(pair)), Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - self.io.clear_read_ready(mio::Ready::readable())?; - Ok(Async::NotReady) + self.io.clear_read_ready(cx, mio::Ready::readable())?; + Poll::Pending } - Err(e) => Err(e), + Err(e) => Poll::Ready(Err(e)), } } @@ -279,6 +262,7 @@ impl TcpListener { /// }); /// # Ok::<_, Box>(()) /// ``` + #[cfg(feature = "incoming")] pub fn incoming(self) -> Incoming { Incoming::new(self) } diff --git a/tokio-tcp/src/stream.rs b/tokio-tcp/src/stream.rs index 1a00679de..46f17837f 100644 --- a/tokio-tcp/src/stream.rs +++ b/tokio-tcp/src/stream.rs @@ -1,11 +1,13 @@ use bytes::{Buf, BufMut}; -use futures::{try_ready, Async, Future, Poll}; use iovec::IoVec; use mio; use std::fmt; -use std::io::{self, Read, Write}; +use std::future::Future; +use std::io; use std::mem; use std::net::{self, Shutdown, SocketAddr}; +use std::pin::Pin; +use std::task::{Context, Poll}; use std::time::Duration; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_reactor::{Handle, PollEvented}; @@ -42,13 +44,10 @@ pub struct TcpStream { /// Future returned by `TcpStream::connect` which will resolve to a `TcpStream` /// when the stream is connected. #[must_use = "futures do nothing unless polled"] -#[derive(Debug)] -pub struct ConnectFuture { +struct ConnectFuture { inner: ConnectFutureState, } -#[must_use = "futures do nothing unless polled"] -#[derive(Debug)] enum ConnectFutureState { Waiting(TcpStream), Error(io::Error), @@ -76,7 +75,7 @@ impl TcpStream { /// println!("successfully connected to {}", stream.local_addr().unwrap())); /// # Ok::<_, Box>(()) /// ``` - pub fn connect(addr: &SocketAddr) -> ConnectFuture { + pub fn connect(addr: &SocketAddr) -> impl Future> { use self::ConnectFutureState::*; let inner = match mio::net::TcpStream::connect(addr) { @@ -138,7 +137,7 @@ impl TcpStream { stream: net::TcpStream, addr: &SocketAddr, handle: &Handle, - ) -> ConnectFuture { + ) -> impl Future> { use self::ConnectFutureState::*; let io = mio::net::TcpStream::connect_stream(stream, addr) @@ -193,8 +192,8 @@ impl TcpStream { /// }); /// # Ok::<_, Box>(()) /// ``` - pub fn poll_read_ready(&self, mask: mio::Ready) -> Poll { - self.io.poll_read_ready(mask) + pub fn poll_read_ready(&self, cx: &mut Context<'_>, mask: mio::Ready) -> Poll> { + self.io.poll_read_ready(cx, mask) } /// Check the TCP stream's write readiness state. @@ -232,8 +231,8 @@ impl TcpStream { /// }); /// # Ok::<_, Box>(()) /// ``` - pub fn poll_write_ready(&self) -> Poll { - self.io.poll_write_ready() + pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> { + self.io.poll_write_ready(cx) } /// Returns the local address that this stream is bound to. @@ -279,15 +278,6 @@ impl TcpStream { self.io.get_ref().peer_addr() } - #[deprecated(since = "0.1.2", note = "use poll_peek instead")] - #[doc(hidden)] - pub fn peek(&mut self, buf: &mut [u8]) -> io::Result { - match self.poll_peek(buf)? { - Async::Ready(n) => Ok(n), - Async::NotReady => Err(io::ErrorKind::WouldBlock.into()), - } - } - /// Receives data on the socket from the remote address to which it is /// connected, without removing that data from the queue. On success, /// returns the number of bytes peeked. @@ -328,16 +318,16 @@ impl TcpStream { /// }); /// # Ok::<_, Box>(()) /// ``` - pub fn poll_peek(&mut self, buf: &mut [u8]) -> Poll { - try_ready!(self.io.poll_read_ready(mio::Ready::readable())); + pub fn poll_peek(&mut self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll> { + ready!(self.io.poll_read_ready(cx, mio::Ready::readable()))?; match self.io.get_ref().peek(buf) { - Ok(ret) => Ok(ret.into()), + Ok(ret) => Poll::Ready(Ok(ret)), Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - self.io.clear_read_ready(mio::Ready::readable())?; - Ok(Async::NotReady) + self.io.clear_read_ready(cx, mio::Ready::readable())?; + Poll::Pending } - Err(e) => Err(e), + Err(e) => Poll::Ready(Err(e)), } } @@ -721,68 +711,17 @@ impl TcpStream { // ===== impl Read / Write ===== -impl Read for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.io.read(buf) - } -} - -impl Write for TcpStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.io.write(buf) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - impl AsyncRead for TcpStream { unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { false } - fn read_buf(&mut self, buf: &mut B) -> Poll { - <&TcpStream>::read_buf(&mut &*self, buf) - } -} - -impl AsyncWrite for TcpStream { - fn shutdown(&mut self) -> Poll<(), io::Error> { - <&TcpStream>::shutdown(&mut &*self) + fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll> { + Pin::new(&mut self.io).poll_read(cx, buf) } - fn write_buf(&mut self, buf: &mut B) -> Poll { - <&TcpStream>::write_buf(&mut &*self, buf) - } -} - -// ===== impl Read / Write for &'a ===== - -impl<'a> Read for &'a TcpStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (&self.io).read(buf) - } -} - -impl<'a> Write for &'a TcpStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&self.io).write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - (&self.io).flush() - } -} - -impl<'a> AsyncRead for &'a TcpStream { - unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { - false - } - - fn read_buf(&mut self, buf: &mut B) -> Poll { - if let Async::NotReady = self.io.poll_read_ready(mio::Ready::readable())? { - return Ok(Async::NotReady); - } + fn poll_read_buf(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll> { + ready!(self.io.poll_read_ready(cx, mio::Ready::readable()))?; let r = unsafe { // The `IoVec` type can't have a 0-length size, so we create a bunch @@ -831,26 +770,34 @@ impl<'a> AsyncRead for &'a TcpStream { unsafe { buf.advance_mut(n); } - Ok(Async::Ready(n)) + Poll::Ready(Ok(n)) } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - self.io.clear_read_ready(mio::Ready::readable())?; - Ok(Async::NotReady) + self.io.clear_read_ready(cx, mio::Ready::readable())?; + Poll::Pending } - Err(e) => Err(e), + Err(e) => Poll::Ready(Err(e)), } } } -impl<'a> AsyncWrite for &'a TcpStream { - fn shutdown(&mut self) -> Poll<(), io::Error> { - Ok(().into()) +impl AsyncWrite for TcpStream { + fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { + Pin::new(&mut self.io).poll_write(cx, buf) } - fn write_buf(&mut self, buf: &mut B) -> Poll { - if let Async::NotReady = self.io.poll_write_ready()? { - return Ok(Async::NotReady); - } + #[inline] + fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + // tcp flush is a no-op + Poll::Ready(Ok(())) + } + + fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_write_buf(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B) -> Poll> { + ready!(self.io.poll_write_ready(cx))?; let r = { // The `IoVec` type can't have a zero-length size, so create a dummy @@ -865,13 +812,13 @@ impl<'a> AsyncWrite for &'a TcpStream { match r { Ok(n) => { buf.advance(n); - Ok(Async::Ready(n)) + Poll::Ready(Ok(n)) } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - self.io.clear_write_ready()?; - Ok(Async::NotReady) + self.io.clear_write_ready(cx)?; + Poll::Pending } - Err(e) => Err(e), + Err(e) => Poll::Ready(Err(e)), } } } @@ -883,18 +830,17 @@ impl fmt::Debug for TcpStream { } impl Future for ConnectFuture { - type Item = TcpStream; - type Error = io::Error; + type Output = io::Result; - fn poll(&mut self) -> Poll { - self.inner.poll() + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_inner(|io| io.poll_write_ready(cx)) } } impl ConnectFutureState { - fn poll_inner(&mut self, f: F) -> Poll + fn poll_inner(&mut self, f: F) -> Poll> where - F: FnOnce(&mut PollEvented) -> Poll, + F: FnOnce(&mut PollEvented) -> Poll>, { { let stream = match *self { @@ -902,9 +848,9 @@ impl ConnectFutureState { ConnectFutureState::Error(_) => { let e = match mem::replace(self, ConnectFutureState::Empty) { ConnectFutureState::Error(e) => e, - _ => panic!(), + _ => unreachable!(), }; - return Err(e); + return Poll::Ready(Err(e)); } ConnectFutureState::Empty => panic!("can't poll TCP stream twice"), }; @@ -915,31 +861,20 @@ impl ConnectFutureState { // actually hit an error or not. // // If all that succeeded then we ship everything on up. - if let Async::NotReady = f(&mut stream.io)? { - return Ok(Async::NotReady); - } + ready!(f(&mut stream.io))?; if let Some(e) = stream.io.get_ref().take_error()? { - return Err(e); + return Poll::Ready(Err(e)); } } match mem::replace(self, ConnectFutureState::Empty) { - ConnectFutureState::Waiting(stream) => Ok(Async::Ready(stream)), - _ => panic!(), + ConnectFutureState::Waiting(stream) => Poll::Ready(Ok(stream)), + _ => unreachable!(), } } } -impl Future for ConnectFutureState { - type Item = TcpStream; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - self.poll_inner(|io| io.poll_write_ready()) - } -} - #[cfg(unix)] mod sys { use super::TcpStream; diff --git a/tokio-test/Cargo.toml b/tokio-test/Cargo.toml index 52b0113e8..3b090a28b 100644 --- a/tokio-test/Cargo.toml +++ b/tokio-test/Cargo.toml @@ -22,6 +22,7 @@ categories = ["asynchronous", "testing"] publish = false [dependencies] -futures = "0.1" -tokio-timer = { version = "0.3.0", path = "../tokio-timer" } +assertive = { git = "http://github.com/carllerche/assertive" } +pin-convert = "0.1.0" +# tokio-timer = { version = "0.3.0", path = "../tokio-timer" } tokio-executor = { version = "0.2.0", path = "../tokio-executor" } diff --git a/tokio-test/src/lib.rs b/tokio-test/src/lib.rs index 256759eaa..eca6762a4 100644 --- a/tokio-test/src/lib.rs +++ b/tokio-test/src/lib.rs @@ -20,13 +20,17 @@ //! assert_ready!(fut.poll()); //! ``` -pub mod clock; +// pub mod clock; mod macros; pub mod task; +pub use assertive::{assert_err, assert_ok}; + +/* #[doc(hidden)] pub mod codegen { pub mod futures { pub use futures::*; } } +*/ diff --git a/tokio-test/src/macros.rs b/tokio-test/src/macros.rs index 4dbabd296..722bbd681 100644 --- a/tokio-test/src/macros.rs +++ b/tokio-test/src/macros.rs @@ -1,59 +1,80 @@ //! A collection of useful macros for testing futures and tokio based code -/// Assert if a poll is ready +/// Assert a `Poll` is ready, returning the value. #[macro_export] macro_rules! assert_ready { ($e:expr) => {{ - use $crate::codegen::futures::Async::Ready; + use core::task::Poll::*; match $e { - Ok(Ready(v)) => v, - Ok(_) => panic!("not ready"), - Err(e) => panic!("error = {:?}", e), + Ready(v) => v, + Pending => panic!("pending"), } }}; ($e:expr, $($msg:tt),+) => {{ - use $crate::codegen::futures::Async::Ready; + use core::task::Poll::*; match $e { - Ok(Ready(v)) => v, - Ok(_) => { + Ready(v) => v, + Pending => { let msg = format_args!($($msg),+); - panic!("not ready; {}", msg) - } - Err(e) => { - let msg = format!($($msg),+); - panic!("error = {:?}; {}", e, msg) + panic!("pending; {}", msg) } } }}; } -/// Asset if the poll is not ready +/// Assert a `Poll>` is ready and `Ok`, returning the value. #[macro_export] -macro_rules! assert_not_ready { +macro_rules! assert_ready_ok { ($e:expr) => {{ - use $crate::codegen::futures::Async::{Ready, NotReady}; + use tokio_test::{assert_ready, assert_ok}; + let val = assert_ready!($e); + assert_ok!(val) + }}; + ($e:expr, $($msg:tt),+) => {{ + use tokio_test::{assert_ready, assert_ok}; + let val = assert_ready!($e, $($msg),*); + assert_ok!(val, $($msg),*) + }}; +} + +/// Assert a `Poll>` is ready and `Err`, returning the error. +#[macro_export] +macro_rules! assert_ready_err { + ($e:expr) => {{ + use tokio_test::{assert_ready, assert_err}; + let val = assert_ready!($e); + assert_err!(val) + }}; + ($e:expr, $($msg:tt),+) => {{ + use tokio_test::{assert_ready, assert_err}; + let val = assert_ready!($e, $($msg),*); + assert_err!(val, $($msg),*) + }}; +} + +/// Asset a `Poll` is pending. +#[macro_export] +macro_rules! assert_pending { + ($e:expr) => {{ + use core::task::Poll::*; match $e { - Ok(NotReady) => {} - Ok(Ready(v)) => panic!("ready; value = {:?}", v), - Err(e) => panic!("error = {:?}", e), + Pending => {} + Ready(v) => panic!("ready; value = {:?}", v), } }}; ($e:expr, $($msg:tt),+) => {{ - use $crate::codegen::futures::Async::{Ready, NotReady}; + use core::task::Poll::*; match $e { - Ok(NotReady) => {} - Ok(Ready(v)) => { + Pending => {} + Ready(v) => { let msg = format_args!($($msg),+); panic!("ready; value = {:?}; {}", v, msg) } - Err(e) => { - let msg = format_args!($($msg),+); - panic!("error = {:?}; {}", e, msg) - } } }}; } +/* /// Assert if a poll is ready and check for equality on the value #[macro_export] macro_rules! assert_ready_eq { @@ -76,7 +97,9 @@ macro_rules! assert_ready_eq { } }; } +*/ +/* /// Assert if the deadline has passed #[macro_export] macro_rules! assert_elapsed { @@ -88,6 +111,7 @@ macro_rules! assert_elapsed { assert!($e.unwrap_err().is_elapsed(), $msg); }; } +*/ #[cfg(test)] mod tests { diff --git a/tokio-test/src/task.rs b/tokio-test/src/task.rs index 328d2064c..f8944a74e 100644 --- a/tokio-test/src/task.rs +++ b/tokio-test/src/task.rs @@ -17,115 +17,164 @@ //! assert_ready_eq!(task.enter(|| rx.poll()), Some(())); //! ``` -use futures::executor::{spawn, Notify}; -use futures::{future, Async}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use tokio_executor::enter; + +use pin_convert::AsPinMut; +use std::future::Future; +use std::mem; use std::sync::{Arc, Condvar, Mutex}; +use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; /// Mock task /// -/// A mock task is able to intercept and track notifications. +/// A mock task is able to intercept and track wake notifications. #[derive(Debug)] pub struct MockTask { - notify: Arc, + waker: Arc, } #[derive(Debug)] -struct ThreadNotify { - state: AtomicUsize, - mutex: Mutex<()>, +struct ThreadWaker { + state: Mutex, condvar: Condvar, } const IDLE: usize = 0; -const NOTIFY: usize = 1; +const WAKE: usize = 1; const SLEEP: usize = 2; impl MockTask { /// Create a new mock task pub fn new() -> Self { MockTask { - notify: Arc::new(ThreadNotify::new()), + waker: Arc::new(ThreadWaker::new()), } } + /// Poll a future + pub fn poll(&mut self, mut fut: T) -> Poll + where + T: AsPinMut, + F: Future, + { + self.enter(|cx| fut.as_pin_mut().poll(cx)) + } + /// Run a closure from the context of the task. /// - /// Any notifications resulting from the execution of the closure are + /// Any wake notifications resulting from the execution of the closure are /// tracked. pub fn enter(&mut self, f: F) -> R where - F: FnOnce() -> R, + F: FnOnce(&mut Context<'_>) -> R, { - self.notify.clear(); + let _enter = enter().unwrap(); - let res = spawn(future::lazy(|| Ok::<_, ()>(f()))).poll_future_notify(&self.notify, 0); + self.waker.clear(); + let waker = self.waker(); + let mut cx = Context::from_waker(&waker); - match res.unwrap() { - Async::Ready(v) => v, - _ => unreachable!(), - } + f(&mut cx) } - /// Returns `true` if the inner future has received a readiness notification + /// Returns `true` if the inner future has received a wake notification /// since the last call to `enter`. - pub fn is_notified(&self) -> bool { - self.notify.is_notified() + pub fn is_woken(&self) -> bool { + self.waker.is_woken() } - /// Returns the number of references to the task notifier + /// Returns the number of references to the task waker /// /// The task itself holds a reference. The return value will never be zero. - pub fn notifier_ref_count(&self) -> usize { - Arc::strong_count(&self.notify) + pub fn waker_ref_count(&self) -> usize { + Arc::strong_count(&self.waker) + } + + fn waker(&self) -> Waker { + unsafe { + let raw = to_raw(self.waker.clone()); + Waker::from_raw(raw) + } } } -impl ThreadNotify { +impl ThreadWaker { fn new() -> Self { - ThreadNotify { - state: AtomicUsize::new(IDLE), - mutex: Mutex::new(()), + ThreadWaker { + state: Mutex::new(IDLE), condvar: Condvar::new(), } } - /// Clears any previously received notify, avoiding potential spurrious - /// notifications. This should only be called immediately before running the + /// Clears any previously received wakes, avoiding potential spurrious + /// wake notifications. This should only be called immediately before running the /// task. fn clear(&self) { - self.state.store(IDLE, Ordering::SeqCst); + *self.state.lock().unwrap() = IDLE; } - fn is_notified(&self) -> bool { - match self.state.load(Ordering::SeqCst) { + fn is_woken(&self) -> bool { + match *self.state.lock().unwrap() { IDLE => false, - NOTIFY => true, + WAKE => true, _ => unreachable!(), } } -} -impl Notify for ThreadNotify { - fn notify(&self, _unpark_id: usize) { + fn wake(&self) { // First, try transitioning from IDLE -> NOTIFY, this does not require a // lock. - match self.state.compare_and_swap(IDLE, NOTIFY, Ordering::SeqCst) { - IDLE | NOTIFY => return, - SLEEP => {} - _ => unreachable!(), + let mut state = self.state.lock().unwrap(); + let prev = *state; + + if prev == WAKE { + return; } - // The other half is sleeping, this requires a lock - let _m = self.mutex.lock().unwrap(); + *state = WAKE; - // Transition from SLEEP -> NOTIFY - match self.state.compare_and_swap(SLEEP, NOTIFY, Ordering::SeqCst) { - SLEEP => {} - _ => return, + if prev == IDLE { + return; } - // Wakeup the sleeper + // The other half is sleeping, so we wake it up. + assert_eq!(prev, SLEEP); self.condvar.notify_one(); } } + +static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); + +unsafe fn to_raw(waker: Arc) -> RawWaker { + RawWaker::new(Arc::into_raw(waker) as *const (), &VTABLE) +} + +unsafe fn from_raw(raw: *const ()) -> Arc { + Arc::from_raw(raw as *const ThreadWaker) +} + +unsafe fn clone(raw: *const ()) -> RawWaker { + let waker = from_raw(raw); + + // Increment the ref count + mem::forget(waker.clone()); + + to_raw(waker) +} + +unsafe fn wake(raw: *const ()) { + let waker = from_raw(raw); + waker.wake(); +} + +unsafe fn wake_by_ref(raw: *const ()) { + let waker = from_raw(raw); + waker.wake(); + + // We don't actually own a reference to the unparker + mem::forget(waker); +} + +unsafe fn drop(raw: *const ()) { + let _ = from_raw(raw); +} diff --git a/tokio-timer/Cargo.toml b/tokio-timer/Cargo.toml index a91043f92..20fac3b37 100644 --- a/tokio-timer/Cargo.toml +++ b/tokio-timer/Cargo.toml @@ -21,14 +21,32 @@ Timer facilities for Tokio """ publish = false +[features] +# individual `Stream` impls if you so desire +delay-queue = ["futures-core-preview"] +interval = ["futures-core-preview"] +timeout-stream = ["futures-core-preview"] +throttle = ["futures-core-preview"] + +# easily enable all `Stream` impls +streams = [ + "delay-queue", + "interval", + "timeout-stream", + "throttle", +] + [dependencies] -futures = "0.1.19" tokio-executor = { version = "0.2.0", path = "../tokio-executor" } +tokio-sync = { version = "0.2.0", path = "../tokio-sync" } crossbeam-utils = "0.6.0" # Backs `DelayQueue` slab = "0.4.1" +# optionals +futures-core-preview = { version = "0.3.0-alpha.16", optional = true } + [dev-dependencies] rand = "0.6" tokio-mock-task = "0.1.0" diff --git a/tokio-timer/src/delay.rs b/tokio-timer/src/delay.rs index 941dde7a4..47c4fab37 100644 --- a/tokio-timer/src/delay.rs +++ b/tokio-timer/src/delay.rs @@ -1,7 +1,8 @@ use crate::timer::{HandlePriv, Registration}; -use crate::Error; -use futures::{Future, Poll}; +use std::future::Future; +use std::pin::Pin; use std::time::{Duration, Instant}; +use std::task::{self, Poll}; /// A future that completes at a specified instant in time. /// @@ -72,6 +73,8 @@ impl Delay { self.registration.reset(deadline); } + // Used by `Timeout` + #[cfg(feature = "timeout-stream")] pub(crate) fn reset_timeout(&mut self) { self.registration.reset_timeout(); } @@ -84,13 +87,24 @@ impl Delay { } impl Future for Delay { - type Item = (); - type Error = Error; + type Output = (); - fn poll(&mut self) -> Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { // Ensure the `Delay` instance is associated with a timer. self.register(); - self.registration.poll_elapsed() + // `poll_elapsed` can return an error in two cases: + // + // - AtCapacity: this is a pathlogical case where far too many + // delays have been scheduled. + // - Shutdown: No timer has been setup, which is a mis-use error. + // + // Both cases are extremely rare, and pretty accurately fit into + // "logic errors", so we just panic in this case. A user couldn't + // really do much better if we passed the error onwards. + match ready!(self.registration.poll_elapsed(cx)) { + Ok(()) => Poll::Ready(()), + Err(e) => panic!("timer error: {}", e), + } } } diff --git a/tokio-timer/src/delay_queue.rs b/tokio-timer/src/delay_queue.rs index 56ff9e5bb..77b7b4091 100644 --- a/tokio-timer/src/delay_queue.rs +++ b/tokio-timer/src/delay_queue.rs @@ -8,10 +8,13 @@ use crate::clock::now; use crate::timer::Handle; use crate::wheel::{self, Wheel}; use crate::{Delay, Error}; -use futures::{try_ready, Future, Poll, Stream}; +use futures_core::Stream; use slab::Slab; use std::cmp; +use std::future::Future; use std::marker::PhantomData; +use std::pin::Pin; +use std::task::{self, Poll}; use std::time::{Duration, Instant}; /// A queue of delayed elements. @@ -177,7 +180,7 @@ pub struct Key { struct Stack { /// Head of the stack head: Option, - _p: PhantomData, + _p: PhantomData T>, } #[derive(Debug)] @@ -645,19 +648,19 @@ impl DelayQueue { /// should be returned. /// /// A slot should be returned when the associated deadline has been reached. - fn poll_idx(&mut self) -> Poll, Error> { + fn poll_idx(&mut self, cx: &mut task::Context<'_>) -> Poll>> { use self::wheel::Stack; let expired = self.expired.pop(&mut self.slab); if expired.is_some() { - return Ok(expired.into()); + return Poll::Ready(expired.map(Ok)); } loop { if let Some(ref mut delay) = self.delay { if !delay.is_elapsed() { - try_ready!(delay.poll()); + ready!(Pin::new(&mut *delay).poll(cx)); } let now = crate::ms(delay.deadline() - self.start, crate::Round::Down); @@ -668,13 +671,13 @@ impl DelayQueue { self.delay = None; if let Some(idx) = self.wheel.poll(&mut self.poll, &mut self.slab) { - return Ok(Some(idx).into()); + return Poll::Ready(Some(Ok(idx))); } if let Some(deadline) = self.next_deadline() { self.delay = Some(self.handle.delay(deadline)); } else { - return Ok(None.into()); + return Poll::Ready(None); } } } @@ -690,24 +693,29 @@ impl DelayQueue { } } +// We never put `T` in a `Pin`... +impl Unpin for DelayQueue {} + impl Stream for DelayQueue { - type Item = Expired; - type Error = Error; + // DelayQueue seems much more specific, where a user may care that it + // has reached capacity, so return those errors instead of panicking. + type Item = Result, Error>; - fn poll(&mut self) -> Poll, Error> { - let item = try_ready!(self.poll_idx()).map(|idx| { - let data = self.slab.remove(idx); - debug_assert!(data.next.is_none()); - debug_assert!(data.prev.is_none()); + fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll> { + let item = ready!(self.poll_idx(cx)); + Poll::Ready(item.map(|result| { + result.map(|idx| { + let data = self.slab.remove(idx); + debug_assert!(data.next.is_none()); + debug_assert!(data.prev.is_none()); - Expired { - key: Key::new(idx), - data: data.inner, - deadline: self.start + Duration::from_millis(data.when), - } - }); - - Ok(item.into()) + Expired { + key: Key::new(idx), + data: data.inner, + deadline: self.start + Duration::from_millis(data.when), + } + }) + })) } } diff --git a/tokio-timer/src/interval.rs b/tokio-timer/src/interval.rs index e065bf127..8b18e33d2 100644 --- a/tokio-timer/src/interval.rs +++ b/tokio-timer/src/interval.rs @@ -1,6 +1,9 @@ use crate::clock; use crate::Delay; -use futures::{try_ready, Future, Poll, Stream}; +use futures_core::Stream; +use std::future::Future; +use std::pin::Pin; +use std::task::{self, Poll}; use std::time::{Duration, Instant}; /// A stream representing notifications at fixed interval @@ -53,20 +56,20 @@ impl Interval { impl Stream for Interval { type Item = Instant; - type Error = crate::Error; - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll> { // Wait for the delay to be done - let _ = try_ready!(self.delay.poll()); + ready!(Pin::new(&mut self.delay).poll(cx)); // Get the `now` by looking at the `delay` deadline let now = self.delay.deadline(); // The next interval value is `duration` after the one that just // yielded. - self.delay.reset(now + self.duration); + let next = now + self.duration; + self.delay.reset(next); // Return the current instant - Ok(Some(now).into()) + Poll::Ready(Some(now)) } } diff --git a/tokio-timer/src/lib.rs b/tokio-timer/src/lib.rs index 3a960240c..083d8d878 100644 --- a/tokio-timer/src/lib.rs +++ b/tokio-timer/src/lib.rs @@ -31,27 +31,36 @@ //! [`Interval`]: struct.Interval.html //! [`Timer`]: timer/struct.Timer.html +macro_rules! ready { + ($e:expr) => ( + match $e { + ::std::task::Poll::Ready(v) => v, + ::std::task::Poll::Pending => return ::std::task::Poll::Pending, + } + ) +} + pub mod clock; +#[cfg(feature = "delay-queue")] pub mod delay_queue; +#[cfg(feature = "throttle")] pub mod throttle; pub mod timeout; pub mod timer; mod atomic; -mod deadline; mod delay; mod error; +#[cfg(feature = "interval")] mod interval; mod wheel; -#[deprecated(since = "0.2.6", note = "use Timeout instead")] -#[doc(hidden)] -#[allow(deprecated)] -pub use deadline::{Deadline, DeadlineError}; pub use delay::Delay; +#[cfg(feature = "delay-queue")] #[doc(inline)] pub use delay_queue::DelayQueue; pub use error::Error; +#[cfg(feature = "interval")] pub use interval::Interval; #[doc(inline)] pub use timeout::Timeout; diff --git a/tokio-timer/src/throttle.rs b/tokio-timer/src/throttle.rs index de71bf7fb..ab8733fd5 100644 --- a/tokio-timer/src/throttle.rs +++ b/tokio-timer/src/throttle.rs @@ -1,11 +1,12 @@ //! Slow down a stream by enforcing a delay between items. -use crate::{clock, Delay, Error}; -use futures::future::Either; -use futures::{try_ready, Async, Future, Poll, Stream}; +use crate::{clock, Delay}; +use futures_core::Stream; use std::{ - error::Error as StdError, - fmt::{Display, Formatter, Result as FmtResult}, + future::Future, + marker::Unpin, + pin::Pin, + task::{self, Poll}, time::Duration, }; @@ -13,26 +14,25 @@ use std::{ #[derive(Debug)] #[must_use = "streams do nothing unless polled"] pub struct Throttle { - delay: Option, - duration: Duration, + delay: Delay, + /// Set to true when `delay` has returned ready, but `stream` hasn't. + has_delayed: bool, stream: T, } -/// Either the error of the underlying stream, or an error within -/// tokio's timing machinery. -#[derive(Debug)] -pub struct ThrottleError(Either); - impl Throttle { /// Slow down a stream by enforcing a delay between items. pub fn new(stream: T, duration: Duration) -> Self { Self { - delay: None, - duration: duration, + delay: Delay::new_timeout(clock::now() + duration, duration), + has_delayed: false, stream: stream, } } +} +// XXX: are these safe if `T: !Unpin`? +impl Throttle { /// Acquires a reference to the underlying stream that this combinator is /// pulling from. pub fn get_ref(&self) -> &T { @@ -59,107 +59,22 @@ impl Throttle { impl Stream for Throttle { type Item = T::Item; - type Error = ThrottleError; - fn poll(&mut self) -> Poll, Self::Error> { - if let Some(ref mut delay) = self.delay { - try_ready!({ delay.poll().map_err(ThrottleError::from_timer_err) }); - } + fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll> { + unsafe { + if !self.has_delayed { + ready!(self.as_mut().map_unchecked_mut(|me| &mut me.delay).poll(cx)); + self.as_mut().get_unchecked_mut().has_delayed = true; + } - self.delay = None; - let value = try_ready!({ self.stream.poll().map_err(ThrottleError::from_stream_err) }); + let value = ready!(self.as_mut().map_unchecked_mut(|me| &mut me.stream).poll_next(cx)); - if value.is_some() { - self.delay = Some(Delay::new(clock::now() + self.duration)); - } + if value.is_some() { + self.as_mut().get_unchecked_mut().delay.reset_timeout(); + self.as_mut().get_unchecked_mut().has_delayed = false; + } - Ok(Async::Ready(value)) - } -} - -impl ThrottleError { - /// Creates a new `ThrottleError` from the given stream error. - pub fn from_stream_err(err: T) -> Self { - ThrottleError(Either::A(err)) - } - - /// Creates a new `ThrottleError` from the given tokio timer error. - pub fn from_timer_err(err: Error) -> Self { - ThrottleError(Either::B(err)) - } - - /// Attempts to get the underlying stream error, if it is present. - pub fn get_stream_error(&self) -> Option<&T> { - match self.0 { - Either::A(ref x) => Some(x), - _ => None, - } - } - - /// Attempts to get the underlying timer error, if it is present. - pub fn get_timer_error(&self) -> Option<&Error> { - match self.0 { - Either::B(ref x) => Some(x), - _ => None, - } - } - - /// Attempts to extract the underlying stream error, if it is present. - pub fn into_stream_error(self) -> Option { - match self.0 { - Either::A(x) => Some(x), - _ => None, - } - } - - /// Attempts to extract the underlying timer error, if it is present. - pub fn into_timer_error(self) -> Option { - match self.0 { - Either::B(x) => Some(x), - _ => None, - } - } - - /// Returns whether the throttle error has occured because of an error - /// in the underlying stream. - pub fn is_stream_error(&self) -> bool { - !self.is_timer_error() - } - - /// Returns whether the throttle error has occured because of an error - /// in tokio's timer system. - pub fn is_timer_error(&self) -> bool { - match self.0 { - Either::A(_) => false, - Either::B(_) => true, - } - } -} - -impl Display for ThrottleError { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self.0 { - Either::A(ref err) => write!(f, "stream error: {}", err), - Either::B(ref err) => write!(f, "timer error: {}", err), - } - } -} - -impl StdError for ThrottleError { - fn description(&self) -> &str { - match self.0 { - Either::A(_) => "stream error", - Either::B(_) => "timer error", - } - } - - // FIXME(taiki-e): When the minimum support version of tokio reaches Rust 1.30, - // replace this with Error::source. - #[allow(deprecated)] - fn cause(&self) -> Option<&dyn StdError> { - match self.0 { - Either::A(ref err) => Some(err), - Either::B(ref err) => Some(err), + Poll::Ready(value) } } } diff --git a/tokio-timer/src/timeout.rs b/tokio-timer/src/timeout.rs index e860d3f02..42c0d9b13 100644 --- a/tokio-timer/src/timeout.rs +++ b/tokio-timer/src/timeout.rs @@ -6,9 +6,12 @@ use crate::clock::now; use crate::Delay; -use futures::{Async, Future, Poll, Stream}; -use std::error; +#[cfg(feature = "timeout-stream")] +use futures_core::Stream; use std::fmt; +use std::future::Future; +use std::pin::Pin; +use std::task::{self, Poll}; use std::time::{Duration, Instant}; /// Allows a `Future` or `Stream` to execute for a limited amount of time. @@ -69,22 +72,10 @@ pub struct Timeout { delay: Delay, } + /// Error returned by `Timeout`. #[derive(Debug)] -pub struct Error(Kind); - -/// Timeout error variants -#[derive(Debug)] -enum Kind { - /// Inner value returned an error - Inner(T), - - /// The timeout elapsed. - Elapsed, - - /// Timer returned an error. - Timer(crate::Error), -} +pub struct Elapsed(()); impl Timeout { /// Create a new `Timeout` that allows `value` to execute for a duration of @@ -161,141 +152,70 @@ impl Future for Timeout where T: Future, { - type Item = T::Item; - type Error = Error; + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { // First, try polling the future - match self.value.poll() { - Ok(Async::Ready(v)) => return Ok(Async::Ready(v)), - Ok(Async::NotReady) => {} - Err(e) => return Err(Error::inner(e)), + + // Safety: we never move `self.value` + unsafe { + let p = self.as_mut().map_unchecked_mut(|me| &mut me.value); + if let Poll::Ready(v) = p.poll(cx) { + return Poll::Ready(Ok(v)); + } } // Now check the timer - match self.delay.poll() { - Ok(Async::NotReady) => Ok(Async::NotReady), - Ok(Async::Ready(_)) => Err(Error::elapsed()), - Err(e) => Err(Error::timer(e)), + // Safety: X_X! + unsafe { + match self.map_unchecked_mut(|me| &mut me.delay).poll(cx) { + Poll::Ready(()) => Poll::Ready(Err(Elapsed(()))), + Poll::Pending => Poll::Pending + } } } } +#[cfg(feature = "timeout-stream")] impl Stream for Timeout where T: Stream, { - type Item = T::Item; - type Error = Error; + type Item = Result; - fn poll(&mut self) -> Poll, Self::Error> { - // First, try polling the future - match self.value.poll() { - Ok(Async::Ready(v)) => { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll> { + // Safety: T might be !Unpin, but we never move neither `value` + // nor `delay`. + // + // ... X_X + unsafe { + // First, try polling the future + let v = self + .as_mut() + .map_unchecked_mut(|me| &mut me.value) + .poll_next(cx); + + if let Poll::Ready(v) = v { if v.is_some() { - self.delay.reset_timeout(); + self.as_mut().get_unchecked_mut().delay.reset_timeout(); } - return Ok(Async::Ready(v)); + return Poll::Ready(v.map(Ok)); } - Ok(Async::NotReady) => {} - Err(e) => return Err(Error::inner(e)), - } - // Now check the timer - match self.delay.poll() { - Ok(Async::NotReady) => Ok(Async::NotReady), - Ok(Async::Ready(_)) => { - self.delay.reset_timeout(); - Err(Error::elapsed()) - } - Err(e) => Err(Error::timer(e)), + // Now check the timer + ready!(self.map_unchecked_mut(|me| &mut me.delay).poll(cx)); + // if delay was ready, timeout elapsed! + Poll::Ready(Some(Err(Elapsed(())))) } } } -// ===== impl Error ===== +// ===== impl Elapsed ===== -impl Error { - /// Create a new `Error` representing the inner value completing with `Err`. - pub fn inner(err: T) -> Error { - Error(Kind::Inner(err)) - } - - /// Returns `true` if the error was caused by the inner value completing - /// with `Err`. - pub fn is_inner(&self) -> bool { - match self.0 { - Kind::Inner(_) => true, - _ => false, - } - } - - /// Consumes `self`, returning the inner future error. - pub fn into_inner(self) -> Option { - match self.0 { - Kind::Inner(err) => Some(err), - _ => None, - } - } - - /// Create a new `Error` representing the inner value not completing before - /// the deadline is reached. - pub fn elapsed() -> Error { - Error(Kind::Elapsed) - } - - /// Returns `true` if the error was caused by the inner value not completing - /// before the deadline is reached. - pub fn is_elapsed(&self) -> bool { - match self.0 { - Kind::Elapsed => true, - _ => false, - } - } - - /// Creates a new `Error` representing an error encountered by the timer - /// implementation - pub fn timer(err: crate::Error) -> Error { - Error(Kind::Timer(err)) - } - - /// Returns `true` if the error was caused by the timer. - pub fn is_timer(&self) -> bool { - match self.0 { - Kind::Timer(_) => true, - _ => false, - } - } - - /// Consumes `self`, returning the error raised by the timer implementation. - pub fn into_timer(self) -> Option { - match self.0 { - Kind::Timer(err) => Some(err), - _ => None, - } - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - use self::Kind::*; - - match self.0 { - Inner(ref e) => e.description(), - Elapsed => "deadline has elapsed", - Timer(ref e) => e.description(), - } - } -} - -impl fmt::Display for Error { +impl fmt::Display for Elapsed { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::Kind::*; - - match self.0 { - Inner(ref e) => e.fmt(fmt), - Elapsed => "deadline has elapsed".fmt(fmt), - Timer(ref e) => e.fmt(fmt), - } + "deadline has elapsed".fmt(fmt) } } + +impl std::error::Error for Elapsed {} diff --git a/tokio-timer/src/timer/entry.rs b/tokio-timer/src/timer/entry.rs index 3ce969a17..c1676e97e 100644 --- a/tokio-timer/src/timer/entry.rs +++ b/tokio-timer/src/timer/entry.rs @@ -2,15 +2,15 @@ use crate::atomic::AtomicU64; use crate::timer::{HandlePriv, Inner}; use crate::Error; use crossbeam_utils::CachePadded; -use futures::task::AtomicTask; -use futures::Poll; use std::cell::UnsafeCell; use std::ptr; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::{Relaxed, SeqCst}; use std::sync::{Arc, Weak}; +use std::task::{self, Poll}; use std::time::{Duration, Instant}; use std::u64; +use tokio_sync::task::AtomicWaker; /// Internal state shared between a `Delay` instance and the timer. /// @@ -46,7 +46,7 @@ pub(crate) struct Entry { state: AtomicU64, /// Task to notify once the deadline is reached. - task: AtomicTask, + waker: AtomicWaker, /// True when the entry is queued in the "process" stack. This value /// is set before pushing the value and unset after popping the value. @@ -109,7 +109,7 @@ impl Entry { Entry { time: CachePadded::new(UnsafeCell::new(Time { deadline, duration })), inner: None, - task: AtomicTask::new(), + waker: AtomicWaker::new(), state: AtomicU64::new(0), queued: AtomicBool::new(false), next_atomic: UnsafeCell::new(ptr::null_mut()), @@ -246,7 +246,7 @@ impl Entry { curr = actual; } - self.task.notify(); + self.waker.wake(); } pub fn error(&self) { @@ -269,7 +269,7 @@ impl Entry { curr = actual; } - self.task.notify(); + self.waker.wake(); } pub fn cancel(entry: &Arc) { @@ -289,32 +289,31 @@ impl Entry { let _ = inner.queue(entry); } - pub fn poll_elapsed(&self) -> Poll<(), Error> { - use futures::Async::NotReady; + pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll> { let mut curr = self.state.load(SeqCst); if is_elapsed(curr) { - if curr == ERROR { - return Err(Error::shutdown()); + return Poll::Ready(if curr == ERROR { + Err(Error::shutdown()) } else { - return Ok(().into()); - } + Ok(()) + }); } - self.task.register(); + self.waker.register_by_ref(cx.waker()); curr = self.state.load(SeqCst).into(); if is_elapsed(curr) { - if curr == ERROR { - return Err(Error::shutdown()); + return Poll::Ready(if curr == ERROR { + Err(Error::shutdown()) } else { - return Ok(().into()); - } + Ok(()) + }); } - Ok(NotReady) + Poll::Pending } /// Only called by `Registration` diff --git a/tokio-timer/src/timer/handle.rs b/tokio-timer/src/timer/handle.rs index 7e8b95c7f..128723f3a 100644 --- a/tokio-timer/src/timer/handle.rs +++ b/tokio-timer/src/timer/handle.rs @@ -1,9 +1,9 @@ use crate::timer::Inner; -use crate::{Deadline, Delay, Error, Interval, Timeout}; +use crate::{Delay, Error, /*Interval,*/ Timeout}; use std::cell::RefCell; use std::fmt; use std::sync::{Arc, Weak}; -use std::time::{Duration, Instant}; +use std::time::{/*Duration,*/ Instant}; use tokio_executor::Enter; /// Handle to timer instance. @@ -137,22 +137,18 @@ impl Handle { } } - #[doc(hidden)] - #[deprecated(since = "0.2.11", note = "use timeout instead")] - pub fn deadline(&self, future: T, deadline: Instant) -> Deadline { - Deadline::new_with_delay(future, self.delay(deadline)) - } - /// Create a `Timeout` driven by this handle's associated `Timer`. pub fn timeout(&self, value: T, deadline: Instant) -> Timeout { Timeout::new_with_delay(value, self.delay(deadline)) } + /* /// Create a new `Interval` that starts at `at` and yields every `duration` /// interval after that. pub fn interval(&self, at: Instant, duration: Duration) -> Interval { Interval::new_with_delay(self.delay(at), duration) } + */ fn as_priv(&self) -> Option<&HandlePriv> { self.inner.as_ref() diff --git a/tokio-timer/src/timer/registration.rs b/tokio-timer/src/timer/registration.rs index ee7e3feb8..74a32d903 100644 --- a/tokio-timer/src/timer/registration.rs +++ b/tokio-timer/src/timer/registration.rs @@ -1,8 +1,7 @@ -use crate::clock::now; use crate::timer::{Entry, HandlePriv}; use crate::Error; -use futures::Poll; use std::sync::Arc; +use std::task::{self, Poll}; use std::time::{Duration, Instant}; /// Registration with a timer. @@ -43,8 +42,10 @@ impl Registration { Entry::reset(&mut self.entry); } + // Used by `Timeout` + #[cfg(feature = "timeout-stream")] pub fn reset_timeout(&mut self) { - let deadline = now() + self.entry.time_ref().duration; + let deadline = crate::clock::now() + self.entry.time_ref().duration; self.entry.time_mut().deadline = deadline; Entry::reset(&mut self.entry); } @@ -53,8 +54,8 @@ impl Registration { self.entry.is_elapsed() } - pub fn poll_elapsed(&self) -> Poll<(), Error> { - self.entry.poll_elapsed() + pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll> { + self.entry.poll_elapsed(cx) } } diff --git a/tokio/Cargo.toml b/tokio/Cargo.toml index e8757947b..742e70805 100644 --- a/tokio/Cargo.toml +++ b/tokio/Cargo.toml @@ -26,63 +26,60 @@ publish = false [features] default = [ - "codec", - "fs", +# "codec", +# "fs", "io", "reactor", "rt-full", "sync", "tcp", - "timer", - "udp", - "uds", +# "timer", +# "udp", +# "uds", ] -codec = ["io", "tokio-codec"] -fs = ["tokio-fs"] +#codec = ["io", "tokio-codec"] +#fs = ["tokio-fs"] io = ["bytes", "tokio-io"] -reactor = ["io", "mio", "tokio-reactor"] +reactor = ["io", "tokio-reactor"] rt-full = [ "num_cpus", "reactor", - "timer", +# "timer", "tokio-current-thread", "tokio-executor", - "tokio-threadpool", - "tokio-trace-core", +# "tokio-threadpool", +# "tokio-trace-core", ] sync = ["tokio-sync"] tcp = ["tokio-tcp"] -timer = ["tokio-timer"] -udp = ["tokio-udp"] -uds = ["tokio-uds"] +#timer = ["tokio-timer"] +#udp = ["tokio-udp"] +#uds = ["tokio-uds"] [dependencies] # Only non-optional dependency... -futures = "0.1.20" +#futures = "0.1.20" # Everything else is optional... bytes = { version = "0.4", optional = true } num_cpus = { version = "1.8.0", optional = true } -tokio-codec = { version = "0.2.0", optional = true, path = "../tokio-codec" } +#tokio-codec = { version = "0.2.0", optional = true, path = "../tokio-codec" } tokio-current-thread = { version = "0.2.0", optional = true, path = "../tokio-current-thread" } -tokio-fs = { version = "0.2.0", optional = true, path = "../tokio-fs" } +#tokio-fs = { version = "0.2.0", optional = true, path = "../tokio-fs" } tokio-io = { version = "0.2.0", optional = true, path = "../tokio-io" } tokio-executor = { version = "0.2.0", optional = true, path = "../tokio-executor" } -tokio-macros = { version = "0.1.0", optional = true, path = "../tokio-macros" } +#tokio-macros = { version = "0.1.0", optional = true, path = "../tokio-macros" } tokio-reactor = { version = "0.2.0", optional = true, path = "../tokio-reactor" } tokio-sync = { version = "0.2.0", optional = true, path = "../tokio-sync" } -tokio-threadpool = { version = "0.2.0", optional = true, path = "../tokio-threadpool" } +#tokio-threadpool = { version = "0.2.0", optional = true, path = "../tokio-threadpool" } tokio-tcp = { version = "0.2.0", optional = true, path = "../tokio-tcp" } -tokio-udp = { version = "0.2.0", optional = true, path = "../tokio-udp" } -tokio-timer = { version = "0.3.0", optional = true, path = "../tokio-timer" } -tokio-trace-core = { version = "0.2", optional = true } - -# Needed until `reactor` is removed from `tokio`. -mio = { version = "0.6.14", optional = true } +#tokio-udp = { version = "0.2.0", optional = true, path = "../tokio-udp" } +#tokio-timer = { version = "0.3.0", optional = true, path = "../tokio-timer" } +#tokio-trace-core = { version = "0.2", optional = true } # Needed for async/await preview support -tokio-futures = { version = "0.2.0", optional = true, path = "../tokio-futures" } +#tokio-futures = { version = "0.2.0", optional = true, path = "../tokio-futures" } [target.'cfg(unix)'.dependencies] tokio-uds = { version = "0.2.1", optional = true } diff --git a/tokio/src/async_await.rs b/tokio/src/async_await.rs deleted file mode 100644 index 29ebce88e..000000000 --- a/tokio/src/async_await.rs +++ /dev/null @@ -1,17 +0,0 @@ -use tokio_futures::compat; - -/// Like `tokio::run`, but takes an `async` block -pub fn run_async(future: F) -where - F: std::future::Future + Send + 'static, -{ - crate::run(compat::infallible_into_01(future)); -} - -/// Like `tokio::spawn`, but takes an `async` block -pub fn spawn_async(future: F) -where - F: std::future::Future + Send + 'static, -{ - crate::spawn(compat::infallible_into_01(future)); -} diff --git a/tokio/src/executor/mod.rs b/tokio/src/executor.rs similarity index 80% rename from tokio/src/executor/mod.rs rename to tokio/src/executor.rs index 41fb65a7a..266da320c 100644 --- a/tokio/src/executor/mod.rs +++ b/tokio/src/executor.rs @@ -39,41 +39,15 @@ //! [`Executor`]: trait.Executor.html //! [`spawn`]: fn.spawn.html -#[deprecated( - since = "0.1.8", - note = "use tokio-current-thread crate or functions in tokio::runtime::current_thread instead", -)] -#[doc(hidden)] -pub mod current_thread; - -#[deprecated(since = "0.1.8", note = "use tokio-threadpool crate instead")] -#[doc(hidden)] -/// Re-exports of [`tokio-threadpool`], deprecated in favor of the crate. -/// -/// [`tokio-threadpool`]: https://docs.rs/tokio-threadpool/0.1 -pub mod thread_pool { - pub use tokio_threadpool::{ - Builder, - Sender, - Shutdown, - ThreadPool, - }; -} - +use std::future::Future; pub use tokio_executor::{Executor, TypedExecutor, DefaultExecutor, SpawnError}; -use futures::{Future, IntoFuture}; -use futures::future::{self, FutureResult}; - /// Return value from the `spawn` function. /// /// Currently this value doesn't actually provide any functionality. However, it /// provides a way to add functionality later without breaking backwards /// compatibility. /// -/// This also implements `IntoFuture` so that it can be used as the return value -/// in a `for_each` loop. -/// /// See [`spawn`] for more details. /// /// [`spawn`]: fn.spawn.html @@ -126,18 +100,8 @@ pub struct Spawn(()); /// /// [`DefaultExecutor`]: struct.DefaultExecutor.html pub fn spawn(f: F) -> Spawn -where F: Future + 'static + Send +where F: Future + 'static + Send { ::tokio_executor::spawn(f); Spawn(()) } - -impl IntoFuture for Spawn { - type Future = FutureResult<(), ()>; - type Item = (); - type Error = (); - - fn into_future(self) -> Self::Future { - future::ok(()) - } -} diff --git a/tokio/src/executor/current_thread/mod.rs b/tokio/src/executor/current_thread/mod.rs deleted file mode 100644 index aa5efb945..000000000 --- a/tokio/src/executor/current_thread/mod.rs +++ /dev/null @@ -1,166 +0,0 @@ -#![allow(deprecated)] - -//! Execute many tasks concurrently on the current thread. -//! -//! [`CurrentThread`] is an executor that keeps tasks on the same thread that -//! they were spawned from. This allows it to execute futures that are not -//! `Send`. -//! -//! A single [`CurrentThread`] instance is able to efficiently manage a large -//! number of tasks and will attempt to schedule all tasks fairly. -//! -//! All tasks that are being managed by a [`CurrentThread`] executor are able to -//! spawn additional tasks by calling [`spawn`]. This function only works from -//! within the context of a running [`CurrentThread`] instance. -//! -//! The easiest way to start a new [`CurrentThread`] executor is to call -//! [`block_on_all`] with an initial task to seed the executor. -//! -//! For example: -//! -//! ``` -//! # use tokio::executor::current_thread; -//! use futures::future::lazy; -//! -//! // Calling execute here results in a panic -//! // current_thread::spawn(my_future); -//! -//! # pub fn main() { -//! current_thread::block_on_all(lazy(|| { -//! // The execution context is setup, futures may be executed. -//! current_thread::spawn(lazy(|| { -//! println!("called from the current thread executor"); -//! Ok(()) -//! })); -//! -//! Ok::<_, ()>(()) -//! })); -//! # } -//! ``` -//! -//! The `block_on_all` function will block the current thread until **all** -//! tasks that have been spawned onto the [`CurrentThread`] instance have -//! completed. -//! -//! More fine-grain control can be achieved by using [`CurrentThread`] directly. -//! -//! ``` -//! # use tokio::executor::current_thread::CurrentThread; -//! use futures::future::{lazy, empty}; -//! use std::time::Duration; -//! -//! // Calling execute here results in a panic -//! // current_thread::spawn(my_future); -//! -//! # pub fn main() { -//! let mut current_thread = CurrentThread::new(); -//! -//! // Spawn a task, the task is not executed yet. -//! current_thread.spawn(lazy(|| { -//! println!("Spawning a task"); -//! Ok(()) -//! })); -//! -//! // Spawn a task that never completes -//! current_thread.spawn(empty()); -//! -//! // Run the executor, but only until the provided future completes. This -//! // provides the opportunity to start executing previously spawned tasks. -//! let res = current_thread.block_on(lazy(|| { -//! Ok::<_, ()>("Hello") -//! })).unwrap(); -//! -//! // Now, run the executor for *at most* 1 second. Since a task was spawned -//! // that never completes, this function will return with an error. -//! current_thread.run_timeout(Duration::from_secs(1)).unwrap_err(); -//! # } -//! ``` -//! -//! # Execution model -//! -//! Internally, [`CurrentThread`] maintains a queue. When one of its tasks is -//! notified, the task gets added to the queue. The executor will pop tasks from -//! the queue and call [`Future::poll`]. If the task gets notified while it is -//! being executed, it won't get re-executed until all other tasks currently in -//! the queue get polled. -//! -//! Before the task is polled, a thread-local variable referencing the current -//! [`CurrentThread`] instance is set. This enables [`spawn`] to spawn new tasks -//! onto the same executor without having to thread through a handle value. -//! -//! If the [`CurrentThread`] instance still has uncompleted tasks, but none of -//! these tasks are ready to be polled, the current thread is put to sleep. When -//! a task is notified, the thread is woken up and processing resumes. -//! -//! All tasks managed by [`CurrentThread`] remain on the current thread. When a -//! task completes, it is dropped. -//! -//! [`spawn`]: fn.spawn.html -//! [`block_on_all`]: fn.block_on_all.html -//! [`CurrentThread`]: struct.CurrentThread.html -//! [`Future::poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll - -pub use tokio_current_thread::{ - BlockError, - CurrentThread, - Entered, - Handle, - RunError, - RunTimeoutError, - TaskExecutor, - Turn, - TurnError, - block_on_all, - spawn, -}; - -use std::cell::Cell; -use std::marker::PhantomData; - -use futures::future::{self}; - -#[deprecated(since = "0.1.2", note = "use block_on_all instead")] -#[doc(hidden)] -#[derive(Debug)] -pub struct Context<'a> { - cancel: Cell, - _p: PhantomData<&'a ()>, -} - -impl<'a> Context<'a> { - /// Cancels *all* executing futures. - pub fn cancel_all_spawned(&self) { - self.cancel.set(true); - } -} - -#[deprecated(since = "0.1.2", note = "use block_on_all instead")] -#[doc(hidden)] -pub fn run(f: F) -> R - where F: FnOnce(&mut Context<'_>) -> R -{ - let mut context = Context { - cancel: Cell::new(false), - _p: PhantomData, - }; - - let mut current_thread = CurrentThread::new(); - - let ret = current_thread - .block_on(future::lazy(|| Ok::<_, ()>(f(&mut context)))) - .unwrap(); - - if context.cancel.get() { - return ret; - } - - current_thread.run().unwrap(); - ret -} - -#[deprecated(since = "0.1.2", note = "use TaskExecutor::current instead")] -#[doc(hidden)] -pub fn task_executor() -> TaskExecutor { - TaskExecutor::current() -} - diff --git a/tokio/src/io.rs b/tokio/src/io.rs index feb1f6b26..4d2b5e35c 100644 --- a/tokio/src/io.rs +++ b/tokio/src/io.rs @@ -25,22 +25,13 @@ //! [output]: fn.stdout.html //! [error]: fn.stderr.html //! -//! # Utility functions -//! -//! Utilities functions are provided for working with [`AsyncRead`] / -//! [`AsyncWrite`] types. For example, [`copy`] asynchronously copies all -//! data from a source to a destination. -//! //! # `std` re-exports //! -//! Additionally, [`Read`], [`Write`], [`Error`], [`ErrorKind`], and -//! [`Result`] are re-exported from `std::io` for ease of use. +//! Additionally, [`Error`], [`ErrorKind`], and [`Result`] are re-exported +//! from `std::io` for ease of use. //! //! [`AsyncRead`]: trait.AsyncRead.html //! [`AsyncWrite`]: trait.AsyncWrite.html -//! [`copy`]: fn.copy.html -//! [`Read`]: trait.Read.html -//! [`Write`]: trait.Write.html //! [`Error`]: struct.Error.html //! [`ErrorKind`]: enum.ErrorKind.html //! [`Result`]: type.Result.html @@ -51,12 +42,6 @@ pub use tokio_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "fs")] pub use tokio_fs::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; -// Utils -pub use tokio_io::io::{ - copy, flush, lines, read, read_exact, read_to_end, read_until, shutdown, write_all, Copy, - Flush, Lines, ReadExact, ReadHalf, ReadToEnd, ReadUntil, Shutdown, WriteAll, WriteHalf, -}; - // Re-export io::Error so that users don't have to deal // with conflicts when `use`ing `futures::io` and `std::io`. -pub use std::io::{Error, ErrorKind, Read, Result, Write}; +pub use std::io::{Error, ErrorKind, Result}; diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index 99fdae859..080e04639 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://docs.rs/tokio/0.1.20")] #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] #![cfg_attr(test, deny(warnings))] -#![cfg_attr(feature = "async-await-preview", feature(async_await, await_macro))] #![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))] //! A runtime for writing reliable, asynchronous, and slim applications. @@ -92,7 +91,7 @@ pub mod reactor; pub mod sync; #[cfg(feature = "timer")] pub mod timer; -pub mod util; +//pub mod util; if_runtime! { pub mod executor; @@ -101,17 +100,3 @@ if_runtime! { pub use crate::executor::spawn; pub use crate::runtime::run; } - -// ===== Experimental async/await support ===== - -#[cfg(feature = "async-await-preview")] -mod async_await; - -#[cfg(feature = "async-await-preview")] -pub use async_await::{run_async, spawn_async}; - -#[cfg(feature = "async-await-preview")] -pub use tokio_futures::async_wait; - -#[cfg(feature = "async-await-preview")] -pub use tokio_macros::{main, test}; diff --git a/tokio/src/net.rs b/tokio/src/net.rs index a6b425da6..6e7efb37e 100644 --- a/tokio/src/net.rs +++ b/tokio/src/net.rs @@ -41,20 +41,11 @@ pub mod tcp { //! [`TcpListener`]: struct.TcpListener.html //! [incoming_method]: struct.TcpListener.html#method.incoming //! [`Incoming`]: struct.Incoming.html - pub use tokio_tcp::{ConnectFuture, Incoming, TcpListener, TcpStream}; + pub use tokio_tcp::{TcpListener, TcpStream}; } #[cfg(feature = "tcp")] pub use self::tcp::{TcpListener, TcpStream}; -#[cfg(feature = "tcp")] -#[deprecated(note = "use `tokio::net::tcp::ConnectFuture` instead")] -#[doc(hidden)] -pub type ConnectFuture = self::tcp::ConnectFuture; -#[cfg(feature = "tcp")] -#[deprecated(note = "use `tokio::net::tcp::Incoming` instead")] -#[doc(hidden)] -pub type Incoming = self::tcp::Incoming; - #[cfg(feature = "udp")] pub mod udp { //! UDP bindings for `tokio`. @@ -76,15 +67,6 @@ pub mod udp { #[cfg(feature = "udp")] pub use self::udp::{UdpFramed, UdpSocket}; -#[cfg(feature = "udp")] -#[deprecated(note = "use `tokio::net::udp::RecvDgram` instead")] -#[doc(hidden)] -pub type RecvDgram = self::udp::RecvDgram; -#[cfg(feature = "udp")] -#[deprecated(note = "use `tokio::net::udp::SendDgram` instead")] -#[doc(hidden)] -pub type SendDgram = self::udp::SendDgram; - #[cfg(all(unix, feature = "uds"))] pub mod unix { //! Unix domain socket bindings for `tokio` (only available on unix systems). diff --git a/tokio/src/prelude.rs b/tokio/src/prelude.rs index e364e8bf1..000a680c9 100644 --- a/tokio/src/prelude.rs +++ b/tokio/src/prelude.rs @@ -10,15 +10,8 @@ //! //! The prelude may grow over time as additional items see ubiquitous use. -pub use crate::util::{FutureExt, StreamExt}; -pub use futures::{future, stream, task, Async, AsyncSink, Future, IntoFuture, Poll, Sink, Stream}; -pub use std::io::{Read, Write}; -#[cfg(feature = "async-await-preview")] -#[doc(inline)] -pub use tokio_futures::{ - io::{AsyncReadExt, AsyncWriteExt}, - sink::SinkExt, - stream::StreamExt as StreamAsyncExt, -}; +pub use std::future::Future; +pub use std::task::{self, Poll}; +//pub use crate::util::{FutureExt, StreamExt}; #[cfg(feature = "io")] pub use tokio_io::{AsyncRead, AsyncWrite}; diff --git a/tokio/src/reactor/mod.rs b/tokio/src/reactor.rs similarity index 97% rename from tokio/src/reactor/mod.rs rename to tokio/src/reactor.rs index eccb341f2..e343bcf4e 100644 --- a/tokio/src/reactor/mod.rs +++ b/tokio/src/reactor.rs @@ -134,10 +134,6 @@ //! [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html //! [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -mod poll_evented; - -#[allow(deprecated)] -pub use self::poll_evented::PollEvented; pub use tokio_reactor::{ - Background, Handle, PollEvented as PollEvented2, Reactor, Registration, Turn, + Handle, PollEvented, Reactor, Registration, Turn, }; diff --git a/tokio/src/reactor/poll_evented.rs b/tokio/src/reactor/poll_evented.rs deleted file mode 100644 index 2b0551160..000000000 --- a/tokio/src/reactor/poll_evented.rs +++ /dev/null @@ -1,545 +0,0 @@ -//! Readiness tracking streams, backing I/O objects. -//! -//! This module contains the core type which is used to back all I/O on object -//! in `tokio-core`. The `PollEvented` type is the implementation detail of -//! all I/O. Each `PollEvented` manages registration with a reactor, -//! acquisition of a token, and tracking of the readiness state on the -//! underlying I/O primitive. - -#![allow(deprecated, warnings)] - -use crate::reactor::{Handle, Registration}; -use futures::{task, Async, Poll}; -use mio::event::Evented; -use mio::Ready; -use std::fmt; -use std::io::{self, Read, Write}; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::Relaxed; -use std::sync::Mutex; -use tokio_io::{AsyncRead, AsyncWrite}; - -#[deprecated(since = "0.1.2", note = "PollEvented2 instead")] -#[doc(hidden)] -pub struct PollEvented { - io: E, - inner: Inner, - handle: Handle, -} - -struct Inner { - registration: Mutex, - - /// Currently visible read readiness - read_readiness: AtomicUsize, - - /// Currently visible write readiness - write_readiness: AtomicUsize, -} - -impl fmt::Debug for PollEvented { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PollEvented").field("io", &self.io).finish() - } -} - -impl PollEvented { - /// Creates a new readiness stream associated with the provided - /// `loop_handle` and for the given `source`. - pub fn new(io: E, handle: &Handle) -> io::Result> - where - E: Evented, - { - let registration = Registration::new(); - registration.register(&io)?; - - Ok(PollEvented { - io: io, - inner: Inner { - registration: Mutex::new(registration), - read_readiness: AtomicUsize::new(0), - write_readiness: AtomicUsize::new(0), - }, - handle: handle.clone(), - }) - } - - /// Tests to see if this source is ready to be read from or not. - /// - /// If this stream is not ready for a read then `Async::NotReady` will be - /// returned and the current task will be scheduled to receive a - /// notification when the stream is readable again. In other words, this - /// method is only safe to call from within the context of a future's task, - /// typically done in a `Future::poll` method. - /// - /// This is mostly equivalent to `self.poll_ready(Ready::readable())`. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn poll_read(&mut self) -> Async<()> { - if self.poll_read2().is_ready() { - return ().into(); - } - - Async::NotReady - } - - fn poll_read2(&self) -> Async { - let r = self.inner.registration.lock().unwrap(); - - // Load the cached readiness - match self.inner.read_readiness.load(Relaxed) { - 0 => {} - mut n => { - // Check what's new with the reactor. - if let Some(ready) = r.take_read_ready().unwrap() { - n |= ready2usize(ready); - self.inner.read_readiness.store(n, Relaxed); - } - - return usize2ready(n).into(); - } - } - - let ready = match r.poll_read_ready().unwrap() { - Async::Ready(r) => r, - _ => return Async::NotReady, - }; - - // Cache the value - self.inner.read_readiness.store(ready2usize(ready), Relaxed); - - ready.into() - } - - /// Tests to see if this source is ready to be written to or not. - /// - /// If this stream is not ready for a write then `Async::NotReady` will be returned - /// and the current task will be scheduled to receive a notification when - /// the stream is writable again. In other words, this method is only safe - /// to call from within the context of a future's task, typically done in a - /// `Future::poll` method. - /// - /// This is mostly equivalent to `self.poll_ready(Ready::writable())`. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn poll_write(&mut self) -> Async<()> { - let r = self.inner.registration.lock().unwrap(); - - match self.inner.write_readiness.load(Relaxed) { - 0 => {} - mut n => { - // Check what's new with the reactor. - if let Some(ready) = r.take_write_ready().unwrap() { - n |= ready2usize(ready); - self.inner.write_readiness.store(n, Relaxed); - } - - return ().into(); - } - } - - let ready = match r.poll_write_ready().unwrap() { - Async::Ready(r) => r, - _ => return Async::NotReady, - }; - - // Cache the value - self.inner - .write_readiness - .store(ready2usize(ready), Relaxed); - - ().into() - } - - /// Test to see whether this source fulfills any condition listed in `mask` - /// provided. - /// - /// The `mask` given here is a mio `Ready` set of possible events. This can - /// contain any events like read/write but also platform-specific events - /// such as hup and error. The `mask` indicates events that are interested - /// in being ready. - /// - /// If any event in `mask` is ready then it is returned through - /// `Async::Ready`. The `Ready` set returned is guaranteed to not be empty - /// and contains all events that are currently ready in the `mask` provided. - /// - /// If no events are ready in the `mask` provided then the current task is - /// scheduled to receive a notification when any of them become ready. If - /// the `writable` event is contained within `mask` then this - /// `PollEvented`'s `write` task will be blocked and otherwise the `read` - /// task will be blocked. This is generally only relevant if you're working - /// with this `PollEvented` object on multiple tasks. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn poll_ready(&mut self, mask: Ready) -> Async { - let mut ret = Ready::empty(); - - if mask.is_empty() { - return ret.into(); - } - - if mask.is_writable() { - if self.poll_write().is_ready() { - ret = Ready::writable(); - } - } - - let mask = mask - Ready::writable(); - - if !mask.is_empty() { - if let Async::Ready(v) = self.poll_read2() { - ret |= v & mask; - } - } - - if ret.is_empty() { - if mask.is_writable() { - let _ = self.need_write(); - } - - if mask.is_readable() { - let _ = self.need_read(); - } - - Async::NotReady - } else { - ret.into() - } - } - - /// Indicates to this source of events that the corresponding I/O object is - /// no longer readable, but it needs to be. - /// - /// This function, like `poll_read`, is only safe to call from the context - /// of a future's task (typically in a `Future::poll` implementation). It - /// informs this readiness stream that the underlying object is no longer - /// readable, typically because a "would block" error was seen. - /// - /// *All* readiness bits associated with this stream except the writable bit - /// will be reset when this method is called. The current task is then - /// scheduled to receive a notification whenever anything changes other than - /// the writable bit. Note that this typically just means the readable bit - /// is used here, but if you're using a custom I/O object for events like - /// hup/error this may also be relevant. - /// - /// Note that it is also only valid to call this method if `poll_read` - /// previously indicated that the object is readable. That is, this function - /// must always be paired with calls to `poll_read` previously. - /// - /// # Errors - /// - /// This function will return an error if the `Reactor` that this `PollEvented` - /// is associated with has gone away (been destroyed). The error means that - /// the ambient futures task could not be scheduled to receive a - /// notification and typically means that the error should be propagated - /// outwards. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn need_read(&mut self) -> io::Result<()> { - self.inner.read_readiness.store(0, Relaxed); - - if self.poll_read().is_ready() { - // Notify the current task - task::current().notify(); - } - - Ok(()) - } - - /// Indicates to this source of events that the corresponding I/O object is - /// no longer writable, but it needs to be. - /// - /// This function, like `poll_write`, is only safe to call from the context - /// of a future's task (typically in a `Future::poll` implementation). It - /// informs this readiness stream that the underlying object is no longer - /// writable, typically because a "would block" error was seen. - /// - /// The flag indicating that this stream is writable is unset and the - /// current task is scheduled to receive a notification when the stream is - /// then again writable. - /// - /// Note that it is also only valid to call this method if `poll_write` - /// previously indicated that the object is writable. That is, this function - /// must always be paired with calls to `poll_write` previously. - /// - /// # Errors - /// - /// This function will return an error if the `Reactor` that this `PollEvented` - /// is associated with has gone away (been destroyed). The error means that - /// the ambient futures task could not be scheduled to receive a - /// notification and typically means that the error should be propagated - /// outwards. - /// - /// # Panics - /// - /// This function will panic if called outside the context of a future's - /// task. - pub fn need_write(&mut self) -> io::Result<()> { - self.inner.write_readiness.store(0, Relaxed); - - if self.poll_write().is_ready() { - // Notify the current task - task::current().notify(); - } - - Ok(()) - } - - /// Returns a reference to the event loop handle that this readiness stream - /// is associated with. - pub fn handle(&self) -> &Handle { - &self.handle - } - - /// Returns a shared reference to the underlying I/O object this readiness - /// stream is wrapping. - pub fn get_ref(&self) -> &E { - &self.io - } - - /// Returns a mutable reference to the underlying I/O object this readiness - /// stream is wrapping. - pub fn get_mut(&mut self) -> &mut E { - &mut self.io - } - - /// Consumes the `PollEvented` and returns the underlying I/O object - pub fn into_inner(self) -> E { - self.io - } - - /// Deregisters this source of events from the reactor core specified. - /// - /// This method can optionally be called to unregister the underlying I/O - /// object with the event loop that the `handle` provided points to. - /// Typically this method is not required as this automatically happens when - /// `E` is dropped, but for some use cases the `E` object doesn't represent - /// an owned reference, so dropping it won't automatically unregister with - /// the event loop. - /// - /// This consumes `self` as it will no longer provide events after the - /// method is called, and will likely return an error if this `PollEvented` - /// was created on a separate event loop from the `handle` specified. - pub fn deregister(&self) -> io::Result<()> - where - E: Evented, - { - self.inner.registration.lock().unwrap().deregister(&self.io) - } -} - -impl Read for PollEvented { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if let Async::NotReady = self.poll_read() { - return Err(io::ErrorKind::WouldBlock.into()); - } - - let r = self.get_mut().read(buf); - - if is_wouldblock(&r) { - self.need_read()?; - } - - return r; - } -} - -impl Write for PollEvented { - fn write(&mut self, buf: &[u8]) -> io::Result { - if let Async::NotReady = self.poll_write() { - return Err(io::ErrorKind::WouldBlock.into()); - } - - let r = self.get_mut().write(buf); - - if is_wouldblock(&r) { - self.need_write()?; - } - - return r; - } - - fn flush(&mut self) -> io::Result<()> { - if let Async::NotReady = self.poll_write() { - return Err(io::ErrorKind::WouldBlock.into()); - } - - let r = self.get_mut().flush(); - - if is_wouldblock(&r) { - self.need_write()?; - } - - return r; - } -} - -impl AsyncRead for PollEvented {} - -impl AsyncWrite for PollEvented { - fn shutdown(&mut self) -> Poll<(), io::Error> { - Ok(().into()) - } -} - -fn is_wouldblock(r: &io::Result) -> bool { - match *r { - Ok(_) => false, - Err(ref e) => e.kind() == io::ErrorKind::WouldBlock, - } -} - -const READ: usize = 1 << 0; -const WRITE: usize = 1 << 1; - -fn ready2usize(ready: Ready) -> usize { - let mut bits = 0; - if ready.is_readable() { - bits |= READ; - } - if ready.is_writable() { - bits |= WRITE; - } - bits | platform::ready2usize(ready) -} - -fn usize2ready(bits: usize) -> Ready { - let mut ready = Ready::empty(); - if bits & READ != 0 { - ready.insert(Ready::readable()); - } - if bits & WRITE != 0 { - ready.insert(Ready::writable()); - } - ready | platform::usize2ready(bits) -} - -#[cfg(unix)] -mod platform { - use mio::unix::UnixReady; - use mio::Ready; - - const HUP: usize = 1 << 2; - const ERROR: usize = 1 << 3; - const AIO: usize = 1 << 4; - const LIO: usize = 1 << 5; - - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - fn is_aio(ready: &Ready) -> bool { - UnixReady::from(*ready).is_aio() - } - - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] - fn is_aio(_ready: &Ready) -> bool { - false - } - - #[cfg(target_os = "freebsd")] - fn is_lio(ready: &Ready) -> bool { - UnixReady::from(*ready).is_lio() - } - - #[cfg(not(target_os = "freebsd"))] - fn is_lio(_ready: &Ready) -> bool { - false - } - - pub fn ready2usize(ready: Ready) -> usize { - let ready = UnixReady::from(ready); - let mut bits = 0; - if is_aio(&ready) { - bits |= AIO; - } - if is_lio(&ready) { - bits |= LIO; - } - if ready.is_error() { - bits |= ERROR; - } - if ready.is_hup() { - bits |= HUP; - } - bits - } - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos" - ))] - fn usize2ready_aio(ready: &mut UnixReady) { - ready.insert(UnixReady::aio()); - } - - #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos" - )))] - fn usize2ready_aio(_ready: &mut UnixReady) { - // aio not available here → empty - } - - #[cfg(target_os = "freebsd")] - fn usize2ready_lio(ready: &mut UnixReady) { - ready.insert(UnixReady::lio()); - } - - #[cfg(not(target_os = "freebsd"))] - fn usize2ready_lio(_ready: &mut UnixReady) { - // lio not available here → empty - } - - pub fn usize2ready(bits: usize) -> Ready { - let mut ready = UnixReady::from(Ready::empty()); - if bits & AIO != 0 { - usize2ready_aio(&mut ready); - } - if bits & LIO != 0 { - usize2ready_lio(&mut ready); - } - if bits & HUP != 0 { - ready.insert(UnixReady::hup()); - } - if bits & ERROR != 0 { - ready.insert(UnixReady::error()); - } - ready.into() - } -} - -#[cfg(windows)] -mod platform { - use mio::Ready; - - pub fn all() -> Ready { - // No platform-specific Readinesses for Windows - Ready::empty() - } - - pub fn hup() -> Ready { - Ready::empty() - } - - pub fn ready2usize(_r: Ready) -> usize { - 0 - } - - pub fn usize2ready(_r: usize) -> Ready { - Ready::empty() - } -} diff --git a/tokio/src/runtime/current_thread/async_await.rs b/tokio/src/runtime/current_thread/async_await.rs deleted file mode 100644 index 1dc2356f5..000000000 --- a/tokio/src/runtime/current_thread/async_await.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::future::Future; -use super::Runtime; - -impl Runtime { - /// Like `block_on`, but takes an `async` block - pub fn block_on_async(&mut self, future: F) -> F::Output - where - F: Future, - { - use tokio_futures::compat; - - match self.block_on(compat::infallible_into_01(future)) { - Ok(v) => v, - Err(_) => unreachable!(), - } - } -} diff --git a/tokio/src/runtime/current_thread/builder.rs b/tokio/src/runtime/current_thread/builder.rs index dbc19fc15..d7e5323c1 100644 --- a/tokio/src/runtime/current_thread/builder.rs +++ b/tokio/src/runtime/current_thread/builder.rs @@ -1,8 +1,8 @@ -use crate::executor::current_thread::CurrentThread; use crate::runtime::current_thread::Runtime; +use tokio_current_thread::CurrentThread; use tokio_reactor::Reactor; -use tokio_timer::clock::Clock; -use tokio_timer::timer::Timer; +//use tokio_timer::clock::Clock; +//use tokio_timer::timer::Timer; use std::io; /// Builds a Single-threaded runtime with custom configuration values. @@ -35,8 +35,8 @@ use std::io; /// ``` #[derive(Debug)] pub struct Builder { - /// The clock to use - clock: Clock, + // /// The clock to use + //clock: Clock, } impl Builder { @@ -46,15 +46,17 @@ impl Builder { /// Configuration methods can be chained on the return value. pub fn new() -> Builder { Builder { - clock: Clock::new(), + //clock: Clock::new(), } } + /* /// Set the `Clock` instance that will be used by the runtime. pub fn clock(&mut self, clock: Clock) -> &mut Self { self.clock = clock; self } + */ /// Create the configured `Runtime`. pub fn build(&mut self) -> io::Result { @@ -64,18 +66,18 @@ impl Builder { // Place a timer wheel on top of the reactor. If there are no timeouts to fire, it'll let the // reactor pick up some new external events. - let timer = Timer::new_with_now(reactor, self.clock.clone()); - let timer_handle = timer.handle(); + //let timer = Timer::new_with_now(reactor, self.clock.clone()); + //let timer_handle = timer.handle(); // And now put a single-threaded executor on top of the timer. When there are no futures ready // to do something, it'll let the timer or the reactor to generate some new stimuli for the // futures to continue in their life. - let executor = CurrentThread::new_with_park(timer); + let executor = CurrentThread::new_with_park(reactor /*timer*/); let runtime = Runtime::new2( reactor_handle, - timer_handle, - self.clock.clone(), + //timer_handle, + //self.clock.clone(), executor); Ok(runtime) diff --git a/tokio/src/runtime/current_thread/mod.rs b/tokio/src/runtime/current_thread/mod.rs index 3a434bae5..5ebeea875 100644 --- a/tokio/src/runtime/current_thread/mod.rs +++ b/tokio/src/runtime/current_thread/mod.rs @@ -67,29 +67,26 @@ mod builder; mod runtime; -#[cfg(feature = "async-await-preview")] -mod async_await; - pub use self::builder::Builder; pub use self::runtime::{Runtime, Handle}; pub use tokio_current_thread::spawn; pub use tokio_current_thread::TaskExecutor; -use futures::Future; +use std::future::Future; /// Run the provided future to completion using a runtime running on the current thread. /// /// This first creates a new [`Runtime`], and calls [`Runtime::block_on`] with the provided future, /// which blocks the current thread until the provided future completes. It then calls /// [`Runtime::run`] to wait for any other spawned futures to resolve. -pub fn block_on_all(future: F) -> Result +pub fn block_on_all(future: F) -> F::Output where F: Future, { let mut r = Runtime::new().expect("failed to start runtime on current thread"); - let v = r.block_on(future)?; + let v = r.block_on(future); r.run().expect("failed to resolve remaining futures"); - Ok(v) + v } /// Start a current-thread runtime using the supplied future to bootstrap execution. @@ -99,7 +96,7 @@ where /// This function panics if called from the context of an executor. pub fn run(future: F) where - F: Future + 'static, + F: Future + 'static, { let mut r = Runtime::new().expect("failed to start runtime on current thread"); diff --git a/tokio/src/runtime/current_thread/runtime.rs b/tokio/src/runtime/current_thread/runtime.rs index 92c5390b6..85aff37a0 100644 --- a/tokio/src/runtime/current_thread/runtime.rs +++ b/tokio/src/runtime/current_thread/runtime.rs @@ -1,12 +1,12 @@ use crate::runtime::current_thread::Builder; -use futures::{future, Future}; use tokio_current_thread::{self as current_thread, CurrentThread}; use tokio_current_thread::Handle as ExecutorHandle; use tokio_executor; use tokio_reactor::{self, Reactor}; -use tokio_timer::clock::{self, Clock}; -use tokio_timer::timer::{self, Timer}; +//use tokio_timer::clock::{self, Clock}; +//use tokio_timer::timer::{self, Timer}; use std::fmt; +use std::future::Future; use std::error::Error; use std::io; @@ -19,11 +19,14 @@ use std::io; #[derive(Debug)] pub struct Runtime { reactor_handle: tokio_reactor::Handle, - timer_handle: timer::Handle, - clock: Clock, - executor: CurrentThread>, + //timer_handle: timer::Handle, + //clock: Clock, + executor: CurrentThread, } +//pub(super) type Parker = Timer; +pub(super) type Parker = Reactor; + /// Handle to spawn a future on the corresponding `CurrentThread` runtime instance #[derive(Debug, Clone)] pub struct Handle(ExecutorHandle); @@ -36,7 +39,7 @@ impl Handle { /// This function panics if the spawn fails. Failure occurs if the `CurrentThread` /// instance of the `Handle` does not exist anymore. pub fn spawn(&self, future: F) -> Result<(), tokio_executor::SpawnError> - where F: Future + Send + 'static { + where F: Future + Send + 'static { self.0.spawn(future) } @@ -54,28 +57,9 @@ impl Handle { } } -impl future::Executor for Handle -where T: Future + Send + 'static, -{ - fn execute(&self, future: T) -> Result<(), future::ExecuteError> { - if let Err(e) = self.status() { - let kind = if e.is_at_capacity() { - future::ExecuteErrorKind::NoCapacity - } else { - future::ExecuteErrorKind::Shutdown - }; - - return Err(future::ExecuteError::new(kind, future)); - } - - let _ = self.spawn(future); - Ok(()) - } -} - impl crate::executor::TypedExecutor for Handle where - T: Future + Send + 'static, + T: Future + Send + 'static, { fn spawn(&mut self, future: T) -> Result<(), crate::executor::SpawnError> { Handle::spawn(self, future) @@ -115,14 +99,14 @@ impl Runtime { pub(super) fn new2( reactor_handle: tokio_reactor::Handle, - timer_handle: timer::Handle, - clock: Clock, - executor: CurrentThread>) -> Runtime + //timer_handle: timer::Handle, + //clock: Clock, + executor: CurrentThread) -> Runtime { Runtime { reactor_handle, - timer_handle, - clock, + //timer_handle, + //clock, executor, } } @@ -165,7 +149,7 @@ impl Runtime { /// This function panics if the spawn fails. Failure occurs if the executor /// is currently at capacity and is unable to spawn a new future. pub fn spawn(&mut self, future: F) -> &mut Self - where F: Future + 'static, + where F: Future + 'static, { self.executor.spawn(future); self @@ -187,13 +171,12 @@ impl Runtime { /// /// The caller is responsible for ensuring that other spawned futures /// complete execution by calling `block_on` or `run`. - pub fn block_on(&mut self, f: F) -> Result + pub fn block_on(&mut self, f: F) -> F::Output where F: Future { self.enter(|executor| { // Run the provided future - let ret = executor.block_on(f); - ret.map_err(|e| e.into_inner().expect("unexpected execution error")) + executor.block_on(f) }) } @@ -207,12 +190,12 @@ impl Runtime { } fn enter(&mut self, f: F) -> R - where F: FnOnce(&mut current_thread::Entered<'_, Timer>) -> R + where F: FnOnce(&mut current_thread::Entered<'_, Parker>) -> R { let Runtime { ref reactor_handle, - ref timer_handle, - ref clock, + //ref timer_handle, + //ref clock, ref mut executor, .. } = *self; @@ -223,8 +206,8 @@ impl Runtime { // This will set the default handle and timer to use inside the closure // and run the future. tokio_reactor::with_default(&reactor_handle, &mut enter, |enter| { - clock::with_default(clock, enter, |enter| { - timer::with_default(&timer_handle, enter, |enter| { + //clock::with_default(clock, enter, |enter| { + // timer::with_default(&timer_handle, enter, |enter| { // The TaskExecutor is a fake executor that looks into the // current single-threaded executor when used. This is a trick, // because we need two mutable references to the executor (one @@ -235,8 +218,8 @@ impl Runtime { let mut executor = executor.enter(enter); f(&mut executor) }) - }) - }) + // }) + //}) }) } } diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index b0a441384..84a7f390b 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -109,8 +109,14 @@ //! [`Timer`]: https://docs.rs/tokio-timer/0.2/tokio_timer/timer/struct.Timer.html pub mod current_thread; -mod threadpool; +//mod threadpool; +pub use self::current_thread::{ + Builder, + Runtime, + run, +}; +/* pub use self::threadpool::{ Builder, Runtime, @@ -118,3 +124,4 @@ pub use self::threadpool::{ TaskExecutor, run, }; +*/ diff --git a/tokio/src/runtime/threadpool/async_await.rs b/tokio/src/runtime/threadpool/async_await.rs deleted file mode 100644 index fc0d9af22..000000000 --- a/tokio/src/runtime/threadpool/async_await.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::future::Future; -use super::Runtime; - -impl Runtime { - /// Like `block_on`, but takes an `async` block - pub fn block_on_async(&mut self, future: F) -> F::Output - where - F: Future + Send + 'static, - F::Output: Send + 'static, - { - use tokio_futures::compat; - - match self.block_on(compat::infallible_into_01(future)) { - Ok(v) => v, - Err(_) => unreachable!(), - } - } -} diff --git a/tokio/src/runtime/threadpool/mod.rs b/tokio/src/runtime/threadpool/mod.rs index ddb4c49fc..9761c1163 100644 --- a/tokio/src/runtime/threadpool/mod.rs +++ b/tokio/src/runtime/threadpool/mod.rs @@ -2,9 +2,6 @@ mod builder; mod shutdown; mod task_executor; -#[cfg(feature = "async-await-preview")] -mod async_await; - pub use self::builder::Builder; pub use self::shutdown::Shutdown; pub use self::task_executor::TaskExecutor; diff --git a/tokio/src/sync.rs b/tokio/src/sync.rs index c8fb75241..ab708fb51 100644 --- a/tokio/src/sync.rs +++ b/tokio/src/sync.rs @@ -13,4 +13,4 @@ //! - [watch](watch/index.html), a single-producer, multi-consumer channel that //! only stores the **most recently** sent value. -pub use tokio_sync::{lock, mpsc, oneshot, watch}; +pub use tokio_sync::{/*lock, mpsc,*/ oneshot, watch};