mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-09 00:00:08 +02:00
Compare commits
76
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01052f930a | ||
|
|
940f2c3431 | ||
|
|
475dabe96d | ||
|
|
951f2fd910 | ||
|
|
4ef736b9d5 | ||
|
|
219f24cbf1 | ||
|
|
ea282efb2e | ||
|
|
042224d33c | ||
|
|
927eb80ad4 | ||
|
|
6a8934e897 | ||
|
|
0e400af78c | ||
|
|
df702130d6 | ||
|
|
949adbb887 | ||
|
|
b2b796a228 | ||
|
|
abb014efc2 | ||
|
|
e5cf0cc717 | ||
|
|
62f34e15ce | ||
|
|
3ebca76a9a | ||
|
|
fea1f780bc | ||
|
|
712ca84033 | ||
|
|
cf06621998 | ||
|
|
7e51ab05e9 | ||
|
|
4bfa4ffcdf | ||
|
|
88b942652c | ||
|
|
5029e80a89 | ||
|
|
847fb59b17 | ||
|
|
b4fe517a16 | ||
|
|
7ae010f0f3 | ||
|
|
9144b2ff53 | ||
|
|
2c4549a18a | ||
|
|
4f819b7cd1 | ||
|
|
197f88f3bc | ||
|
|
44f65afcc6 | ||
|
|
4271a9cd8d | ||
|
|
9d8096b911 | ||
|
|
597f271c08 | ||
|
|
599955f716 | ||
|
|
91bb0f73f5 | ||
|
|
6c9d8abba9 | ||
|
|
824b7b6759 | ||
|
|
cb91dd274a | ||
|
|
ea7178b8c6 | ||
|
|
a99b8e2e0b | ||
|
|
03859a7dcd | ||
|
|
d8177f81ac | ||
|
|
ceca2a3cd6 | ||
|
|
1524ee4b60 | ||
|
|
7793d63739 | ||
|
|
e0e26bc223 | ||
|
|
9c5cad037f | ||
|
|
30330da11a | ||
|
|
6e4945025c | ||
|
|
3c8f110730 | ||
|
|
678f15bd48 | ||
|
|
b1172f8074 | ||
|
|
cdde2e7a27 | ||
|
|
85487727d4 | ||
|
|
92d51202ef | ||
|
|
cb55bf4012 | ||
|
|
987ccfc8ac | ||
|
|
1bc6d75543 | ||
|
|
27148d6110 | ||
|
|
a1871b1480 | ||
|
|
acd08eb23d | ||
|
|
90b1a01010 | ||
|
|
676824988e | ||
|
|
46149f031e | ||
|
|
5510ba6dba | ||
|
|
b8f63308d7 | ||
|
|
4313d65b38 | ||
|
|
e780fccce4 | ||
|
|
b01e71b3d8 | ||
|
|
7f911b6b70 | ||
|
|
d88aba8d1c | ||
|
|
6fbef0a528 | ||
|
|
9be5f3f9ff |
+17
-2
@@ -15,14 +15,29 @@ task:
|
||||
- sh rustup.sh -y
|
||||
- . $HOME/.cargo/env
|
||||
- rustup target add i686-unknown-freebsd
|
||||
- |
|
||||
# Remove any existing patch statements
|
||||
mv Cargo.toml Cargo.toml.bck
|
||||
sed -n '/\[patch.crates-io\]/q;p' Cargo.toml.bck > Cargo.toml
|
||||
|
||||
# Patch all crates
|
||||
cat ci/patch.toml >> Cargo.toml
|
||||
|
||||
# Print `Cargo.toml` for debugging
|
||||
echo "~~~~ Cargo.toml ~~~~"
|
||||
cat Cargo.toml
|
||||
echo "~~~~~~~~~~~~~~~~~~~~"
|
||||
cargo_cache:
|
||||
folder: $HOME/.cargo/registry
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo test --all --no-fail-fast
|
||||
- cargo test --all
|
||||
- (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 --no-fail-fast --target i686-unknown-freebsd
|
||||
- |
|
||||
cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd
|
||||
before_cache_script:
|
||||
- rm -rf $HOME/.cargo/registry/index
|
||||
|
||||
+4
-108
@@ -1,40 +1,19 @@
|
||||
[package]
|
||||
name = "tokio"
|
||||
# When releasing to crates.io:
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.16"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
documentation = "https://docs.rs/tokio/0.1.16/tokio/"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
description = """
|
||||
An event-driven, non-blocking I/O platform for writing asynchronous I/O
|
||||
backed applications.
|
||||
"""
|
||||
categories = ["asynchronous", "network-programming"]
|
||||
keywords = ["io", "async", "non-blocking", "futures"]
|
||||
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"./",
|
||||
"tokio-async-await",
|
||||
"tokio",
|
||||
"tokio-buf",
|
||||
"tokio-codec",
|
||||
"tokio-current-thread",
|
||||
"tokio-executor",
|
||||
"tokio-fs",
|
||||
"tokio-futures",
|
||||
"tokio-io",
|
||||
"tokio-macros",
|
||||
"tokio-reactor",
|
||||
"tokio-signal",
|
||||
"tokio-sync",
|
||||
"tokio-test",
|
||||
"tokio-threadpool",
|
||||
"tokio-timer",
|
||||
"tokio-tcp",
|
||||
@@ -44,86 +23,3 @@ members = [
|
||||
"tokio-udp",
|
||||
"tokio-uds",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"codec",
|
||||
"fs",
|
||||
"io",
|
||||
"reactor",
|
||||
"rt-full",
|
||||
"sync",
|
||||
"tcp",
|
||||
"timer",
|
||||
"udp",
|
||||
"uds",
|
||||
]
|
||||
|
||||
codec = ["io", "tokio-codec"]
|
||||
fs = ["tokio-fs"]
|
||||
io = ["bytes", "tokio-io"]
|
||||
reactor = ["io", "mio", "tokio-reactor"]
|
||||
rt-full = [
|
||||
"num_cpus",
|
||||
"reactor",
|
||||
"timer",
|
||||
"tokio-current-thread",
|
||||
"tokio-executor",
|
||||
"tokio-threadpool",
|
||||
]
|
||||
sync = ["tokio-sync"]
|
||||
tcp = ["tokio-tcp"]
|
||||
timer = ["tokio-timer"]
|
||||
udp = ["tokio-udp"]
|
||||
uds = ["tokio-uds"]
|
||||
|
||||
# This feature comes with no promise of stability. Things will
|
||||
# break with each patch release. Use at your own risk.
|
||||
async-await-preview = [
|
||||
"tokio-async-await/async-await-preview",
|
||||
]
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "tokio-rs/tokio" }
|
||||
appveyor = { repository = "carllerche/tokio", id = "s83yxhy9qeb58va7" }
|
||||
|
||||
[dependencies]
|
||||
# Only non-optional dependency...
|
||||
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.1.0", path = "tokio-codec", optional = true }
|
||||
tokio-current-thread = { version = "0.1.3", path = "tokio-current-thread", optional = true }
|
||||
tokio-fs = { version = "0.1.3", path = "tokio-fs", optional = true }
|
||||
tokio-io = { version = "0.1.6", path = "tokio-io", optional = true }
|
||||
tokio-executor = { version = "0.1.5", path = "tokio-executor", optional = true }
|
||||
tokio-reactor = { version = "0.1.1", path = "tokio-reactor", optional = true }
|
||||
tokio-sync = { version = "0.1.0", path = "tokio-sync", optional = true }
|
||||
tokio-threadpool = { version = "0.1.8", path = "tokio-threadpool", optional = true }
|
||||
tokio-tcp = { version = "0.1.0", path = "tokio-tcp", optional = true }
|
||||
tokio-udp = { version = "0.1.0", path = "tokio-udp", optional = true }
|
||||
tokio-timer = { version = "0.2.8", path = "tokio-timer", optional = true }
|
||||
|
||||
# Needed until `reactor` is removed from `tokio`.
|
||||
mio = { version = "0.6.14", optional = true }
|
||||
|
||||
# Needed for async/await preview support
|
||||
tokio-async-await = { version = "0.1.0", path = "tokio-async-await", optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
tokio-uds = { version = "0.2.1", path = "tokio-uds", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { version = "0.5", default-features = false }
|
||||
flate2 = { version = "1", features = ["tokio"] }
|
||||
futures-cpupool = "0.1"
|
||||
http = "0.1"
|
||||
httparse = "1.0"
|
||||
libc = "0.2"
|
||||
num_cpus = "1.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
time = "0.1"
|
||||
|
||||
@@ -20,7 +20,7 @@ the Rust programming language. It is:
|
||||
[crates-badge]: https://img.shields.io/crates/v/tokio.svg
|
||||
[crates-url]: https://crates.io/crates/tokio
|
||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[mit-url]: LICENSE-MIT
|
||||
[mit-url]: LICENSE
|
||||
[azure-badge]: https://dev.azure.com/tokio-rs/Tokio/_apis/build/status/tokio-rs.tokio?branchName=master
|
||||
[azure-url]: https://dev.azure.com/tokio-rs/Tokio/_build/latest?definitionId=1&branchName=master
|
||||
[gitter-badge]: https://img.shields.io/gitter/room/tokio-rs/tokio.svg
|
||||
@@ -28,7 +28,7 @@ the Rust programming language. It is:
|
||||
|
||||
[Website](https://tokio.rs) |
|
||||
[Guides](https://tokio.rs/docs/getting-started/hello-world/) |
|
||||
[API Docs](https://docs.rs/tokio/0.1.16/tokio) |
|
||||
[API Docs](https://docs.rs/tokio/0.1.20/tokio) |
|
||||
[Chat](https://gitter.im/tokio-rs/tokio)
|
||||
|
||||
The API docs for the master branch are published [here][master-dox].
|
||||
@@ -49,9 +49,9 @@ level, it provides a few major components:
|
||||
These components provide the runtime components necessary for building
|
||||
an asynchronous application.
|
||||
|
||||
[net]: https://docs.rs/tokio/0.1/tokio/net/index.html
|
||||
[reactor]: https://docs.rs/tokio/0.1/tokio/reactor/index.html
|
||||
[scheduler]: https://tokio-rs.github.io/tokio/tokio/runtime/index.html
|
||||
[net]: https://docs.rs/tokio/0.1.20/tokio/net/index.html
|
||||
[reactor]: https://docs.rs/tokio/0.1.20/tokio/reactor/index.html
|
||||
[scheduler]: https://docs.rs/tokio/0.1.20/tokio/runtime/index.html
|
||||
|
||||
## Example
|
||||
|
||||
@@ -98,7 +98,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
More examples can be found [here](examples).
|
||||
More examples can be found [here](tokio/examples).
|
||||
|
||||
## Getting Help
|
||||
|
||||
@@ -126,10 +126,6 @@ have greater guarantees of stability.
|
||||
|
||||
The crates included as part of Tokio are:
|
||||
|
||||
* [`tokio-async-await`]: Experimental `async` / `await` support.
|
||||
|
||||
* [`tokio-codec`]: Utilities for encoding and decoding protocol frames.
|
||||
|
||||
* [`tokio-current-thread`]: Schedule the execution of futures on the current
|
||||
thread.
|
||||
|
||||
@@ -137,8 +133,14 @@ The crates included as part of Tokio are:
|
||||
|
||||
* [`tokio-fs`]: Filesystem (and standard in / out) APIs.
|
||||
|
||||
* [`tokio-futures`]: Experimental `std::future::Future` and `async` / `await` support.
|
||||
|
||||
* [`tokio-codec`]: Utilities for encoding and decoding protocol frames.
|
||||
|
||||
* [`tokio-io`]: Asynchronous I/O related traits and utilities.
|
||||
|
||||
* [`tokio-macros`]: Macros for usage with Tokio.
|
||||
|
||||
* [`tokio-reactor`]: Event loop that drives I/O resources (like TCP and UDP
|
||||
sockets).
|
||||
|
||||
@@ -154,12 +156,13 @@ The crates included as part of Tokio are:
|
||||
* [`tokio-uds`]: Unix Domain Socket bindings for use with `tokio-io` and
|
||||
`tokio-reactor`.
|
||||
|
||||
[`tokio-async-await`]: tokio-async-await
|
||||
[`tokio-codec`]: tokio-codec
|
||||
[`tokio-current-thread`]: tokio-current-thread
|
||||
[`tokio-executor`]: tokio-executor
|
||||
[`tokio-fs`]: tokio-fs
|
||||
[`tokio-futures`]: tokio-futures
|
||||
[`tokio-io`]: tokio-io
|
||||
[`tokio-macros`]: tokio-macros
|
||||
[`tokio-reactor`]: tokio-reactor
|
||||
[`tokio-tcp`]: tokio-tcp
|
||||
[`tokio-threadpool`]: tokio-threadpool
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[build]
|
||||
target-dir = "../target"
|
||||
@@ -0,0 +1,49 @@
|
||||
[package]
|
||||
name = "examples"
|
||||
edition = "2018"
|
||||
version = "0.1.0"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
|
||||
# Break out of the parent workspace
|
||||
[workspace]
|
||||
|
||||
[[bin]]
|
||||
name = "chat"
|
||||
path = "src/chat.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "echo_client"
|
||||
path = "src/echo_client.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "echo_server"
|
||||
path = "src/echo_server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hyper"
|
||||
path = "src/hyper.rs"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.1.18", features = ["async-await-preview"] }
|
||||
futures = "0.1.23"
|
||||
bytes = "0.4.9"
|
||||
hyper = "0.12.8"
|
||||
|
||||
# Avoid using crates.io for Tokio dependencies
|
||||
[patch.crates-io]
|
||||
tokio = { path = "../tokio" }
|
||||
tokio-codec = { path = "../tokio-codec" }
|
||||
tokio-current-thread = { path = "../tokio-current-thread" }
|
||||
tokio-executor = { path = "../tokio-executor" }
|
||||
tokio-fs = { path = "../tokio-fs" }
|
||||
tokio-futures = { path = "../tokio-futures" }
|
||||
tokio-io = { path = "../tokio-io" }
|
||||
tokio-reactor = { path = "../tokio-reactor" }
|
||||
tokio-signal = { path = "../tokio-signal" }
|
||||
tokio-tcp = { path = "../tokio-tcp" }
|
||||
tokio-threadpool = { path = "../tokio-threadpool" }
|
||||
tokio-timer = { path = "../tokio-timer" }
|
||||
tokio-tls = { path = "../tokio-tls" }
|
||||
tokio-udp = { path = "../tokio-udp" }
|
||||
tokio-uds = { path = "../tokio-uds" }
|
||||
@@ -1,9 +1,6 @@
|
||||
#![feature(await_macro, async_await, futures_api)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tokio;
|
||||
extern crate futures; // v0.1
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
use tokio::await;
|
||||
use tokio::codec::{LinesCodec, Decoder};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::prelude::*;
|
||||
@@ -95,7 +92,8 @@ async fn process(stream: TcpStream, state: Arc<Mutex<Shared>>) -> io::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[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
|
||||
@@ -113,23 +111,21 @@ fn main() {
|
||||
println!("server running on localhost:6142");
|
||||
|
||||
// Start the Tokio runtime.
|
||||
tokio::run_async(async move {
|
||||
let mut incoming = listener.incoming();
|
||||
let mut incoming = listener.incoming();
|
||||
|
||||
while let Some(stream) = await!(incoming.next()) {
|
||||
let stream = match stream {
|
||||
Ok(stream) => stream,
|
||||
Err(_) => continue,
|
||||
};
|
||||
while let Some(stream) = await!(incoming.next()) {
|
||||
let stream = match stream {
|
||||
Ok(stream) => stream,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let state = state.clone();
|
||||
let state = state.clone();
|
||||
|
||||
tokio::spawn_async(async move {
|
||||
if let Err(_) = await!(process(stream, state)) {
|
||||
eprintln!("failed to process connection");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
tokio::spawn_async(async move {
|
||||
if let Err(_) = await!(process(stream, state)) {
|
||||
eprintln!("failed to process connection");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#![feature(await_macro, async_await, futures_api)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tokio;
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
use tokio::await;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::prelude::*;
|
||||
|
||||
@@ -36,7 +34,8 @@ async fn run_client(addr: &SocketAddr) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
use std::env;
|
||||
|
||||
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
|
||||
@@ -44,10 +43,8 @@ fn main() {
|
||||
|
||||
// Connect to the echo serveer
|
||||
|
||||
tokio::run_async(async move {
|
||||
match await!(run_client(&addr)) {
|
||||
Ok(_) => println!("done."),
|
||||
Err(e) => eprintln!("echo client failed; error = {:?}", e),
|
||||
}
|
||||
});
|
||||
match await!(run_client(&addr)) {
|
||||
Ok(_) => println!("done."),
|
||||
Err(e) => eprintln!("echo client failed; error = {:?}", e),
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
#![feature(await_macro, async_await, futures_api)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tokio;
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
use tokio::await;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::prelude::*;
|
||||
|
||||
@@ -24,7 +22,8 @@ fn handle(mut stream: TcpStream) {
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
use std::env;
|
||||
|
||||
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
|
||||
@@ -34,12 +33,10 @@ fn main() {
|
||||
let listener = TcpListener::bind(&addr).unwrap();
|
||||
println!("Listening on: {}", addr);
|
||||
|
||||
tokio::run_async(async {
|
||||
let mut incoming = listener.incoming();
|
||||
let mut incoming = listener.incoming();
|
||||
|
||||
while let Some(stream) = await!(incoming.next()) {
|
||||
let stream = stream.unwrap();
|
||||
handle(stream);
|
||||
}
|
||||
});
|
||||
while let Some(stream) = await!(incoming.next()) {
|
||||
let stream = stream.unwrap();
|
||||
handle(stream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
use tokio::await;
|
||||
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 = await!({
|
||||
client.get(uri)
|
||||
.timeout(Duration::from_secs(10))
|
||||
}).unwrap();
|
||||
|
||||
println!("Response: {}", response.status());
|
||||
|
||||
let mut body = response.into_body();
|
||||
|
||||
while let Some(chunk) = await!(body.next()) {
|
||||
let chunk = chunk.unwrap();
|
||||
println!("chunk = {}", str::from_utf8(&chunk[..]).unwrap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
use tokio::await;
|
||||
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);
|
||||
await!(Delay::new(when));
|
||||
}
|
||||
+13
-14
@@ -1,5 +1,5 @@
|
||||
trigger: ["master"]
|
||||
pr: ["master"]
|
||||
trigger: ["master", "v0.1.x"]
|
||||
pr: ["master", "v0.1.x"]
|
||||
|
||||
jobs:
|
||||
# Check formatting
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- template: ci/azure-test-stable.yml
|
||||
parameters:
|
||||
name: test_linux
|
||||
displayName: Test sub crates - Any
|
||||
displayName: Test sub crates -
|
||||
crates:
|
||||
- tokio-buf
|
||||
- tokio-codec
|
||||
@@ -45,8 +45,11 @@ jobs:
|
||||
- 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
|
||||
|
||||
- template: ci/azure-cargo-check.yml
|
||||
parameters:
|
||||
@@ -64,20 +67,16 @@ jobs:
|
||||
- timer
|
||||
- udp
|
||||
- uds
|
||||
- sync
|
||||
tokio-buf:
|
||||
- util
|
||||
|
||||
# Check async / await
|
||||
- template: ci/azure-cargo-check.yml
|
||||
# Run async-await tests
|
||||
- template: ci/azure-test-nightly.yml
|
||||
parameters:
|
||||
name: async_await
|
||||
displayName: Async / Await
|
||||
rust: nightly-2019-02-28
|
||||
noDefaultFeatures: ''
|
||||
benches: true
|
||||
crates:
|
||||
tokio:
|
||||
- async-await-preview
|
||||
name: test_nightly
|
||||
displayName: Test Async / Await
|
||||
rust: nightly-2019-04-25
|
||||
|
||||
# Try cross compiling
|
||||
- template: ci/azure-cross-compile.yml
|
||||
@@ -109,7 +108,7 @@ jobs:
|
||||
- test_sub_cross
|
||||
- test_linux
|
||||
- features
|
||||
- async_await
|
||||
- test_nightly
|
||||
- cross_32bit_linux
|
||||
- minrust
|
||||
- tsan
|
||||
|
||||
+12
-10
@@ -11,17 +11,19 @@ jobs:
|
||||
parameters:
|
||||
rust_version: ${{ parameters.rust }}
|
||||
|
||||
- template: azure-is-release.yml
|
||||
|
||||
- ${{ each crate in parameters.crates }}:
|
||||
- ${{ each feature in crate.value }}:
|
||||
- ${{ if eq(crate.key, 'tokio') }}:
|
||||
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
|
||||
displayName: Check features = ${{ feature }}
|
||||
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
|
||||
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
|
||||
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
|
||||
condition: and(succeeded(), not(variables['isRelease']))
|
||||
|
||||
- ${{ if not(eq(crate.key, 'tokio')) }}:
|
||||
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
|
||||
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
|
||||
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
|
||||
- template: azure-patch-crates.yml
|
||||
|
||||
- ${{ if parameters.benches }}:
|
||||
- script: cargo check --benches --all
|
||||
displayName: Check benchmarks
|
||||
- ${{ each crate in parameters.crates }}:
|
||||
- ${{ each feature in crate.value }}:
|
||||
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
|
||||
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
|
||||
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
|
||||
|
||||
@@ -8,5 +8,7 @@ jobs:
|
||||
parameters:
|
||||
rust_version: ${{ parameters.rust_version }}
|
||||
|
||||
- template: azure-patch-crates.yml
|
||||
|
||||
- script: cargo check --all
|
||||
displayName: cargo check --all
|
||||
|
||||
@@ -8,12 +8,18 @@ jobs:
|
||||
parameters:
|
||||
rust_version: stable
|
||||
|
||||
- script: sudo apt-get update
|
||||
displayName: "apt-get update"
|
||||
|
||||
- script: sudo apt-get install gcc-multilib
|
||||
displayName: "Install gcc-multilib"
|
||||
|
||||
- script: rustup target add ${{ parameters.target }}
|
||||
displayName: "Add target"
|
||||
|
||||
# Always patch
|
||||
- template: azure-patch-crates.yml
|
||||
|
||||
- script: cargo check --all --exclude tokio-tls --target ${{ parameters.target }}
|
||||
displayName: Check source
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
steps:
|
||||
- bash: |
|
||||
set -e
|
||||
|
||||
if git log --no-merges -1 --format='%B' | grep -qF '[ci-release]'; then
|
||||
echo "##vso[task.setvariable variable=isRelease]true"
|
||||
fi
|
||||
failOnStderr: true
|
||||
displayName: Check if release commit
|
||||
@@ -0,0 +1,16 @@
|
||||
steps:
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
# Remove any existing patch statements
|
||||
mv Cargo.toml Cargo.toml.bck
|
||||
sed -n '/\[patch.crates-io\]/q;p' Cargo.toml.bck > Cargo.toml
|
||||
|
||||
# Patch all crates
|
||||
cat ci/patch.toml >> Cargo.toml
|
||||
|
||||
# Print `Cargo.toml` for debugging
|
||||
echo "~~~~ Cargo.toml ~~~~"
|
||||
cat Cargo.toml
|
||||
echo "~~~~~~~~~~~~~~~~~~~~"
|
||||
displayName: Patch Cargo.toml
|
||||
@@ -0,0 +1,19 @@
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
displayName: ${{ parameters.displayName }}
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
|
||||
steps:
|
||||
- template: azure-install-rust.yml
|
||||
parameters:
|
||||
rust_version: ${{ parameters.rust }}
|
||||
|
||||
- template: azure-patch-crates.yml
|
||||
|
||||
- script: cargo check --all
|
||||
displayName: cargo +nightly check --all
|
||||
|
||||
# Check benches
|
||||
- script: cargo check --benches --all
|
||||
displayName: Check benchmarks
|
||||
+19
-14
@@ -19,18 +19,23 @@ jobs:
|
||||
parameters:
|
||||
rust_version: stable
|
||||
|
||||
- ${{ each crate in parameters.crates }}:
|
||||
- ${{ if eq(crate, 'tokio') }}:
|
||||
- script: cargo test
|
||||
env:
|
||||
LOOM_MAX_DURATION: 10
|
||||
CI: 'True'
|
||||
displayName: cargo test
|
||||
- template: azure-is-release.yml
|
||||
|
||||
- ${{ if not(eq(crate, 'tokio')) }}:
|
||||
- script: cargo test
|
||||
env:
|
||||
LOOM_MAX_DURATION: 10
|
||||
CI: 'True'
|
||||
displayName: cargo test -p ${{ crate }}
|
||||
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
|
||||
- ${{ 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
|
||||
env:
|
||||
LOOM_MAX_DURATION: 10
|
||||
CI: 'True'
|
||||
displayName: cargo test -p ${{ crate }} (PATCHED)
|
||||
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
|
||||
|
||||
@@ -14,8 +14,10 @@ jobs:
|
||||
parameters:
|
||||
rust_version: nightly-2018-11-18
|
||||
|
||||
- template: azure-patch-crates.yml
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
# Make sure the benchmarks compile
|
||||
export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
|
||||
export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Patch dependencies to run all tests against versions of the crate in the
|
||||
# repository.
|
||||
[patch.crates-io]
|
||||
tokio = { path = "tokio" }
|
||||
tokio-buf = { path = "tokio-buf" }
|
||||
tokio-codec = { path = "tokio-codec" }
|
||||
tokio-current-thread = { path = "tokio-current-thread" }
|
||||
tokio-executor = { path = "tokio-executor" }
|
||||
tokio-fs = { path = "tokio-fs" }
|
||||
tokio-futures = { path = "tokio-futures" }
|
||||
tokio-io = { path = "tokio-io" }
|
||||
tokio-reactor = { path = "tokio-reactor" }
|
||||
tokio-signal = { path = "tokio-signal" }
|
||||
tokio-sync = { path = "tokio-sync" }
|
||||
tokio-threadpool = { path = "tokio-threadpool" }
|
||||
tokio-timer = { path = "tokio-timer" }
|
||||
tokio-tcp = { path = "tokio-tcp" }
|
||||
tokio-tls = { path = "tokio-tls" }
|
||||
tokio-trace = { path = "tokio-trace" }
|
||||
tokio-trace-core = { path = "tokio-trace/tokio-trace-core" }
|
||||
tokio-udp = { path = "tokio-udp" }
|
||||
tokio-uds = { path = "tokio-uds" }
|
||||
@@ -1,48 +0,0 @@
|
||||
use std::future::Future as StdFuture;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Poll, Waker};
|
||||
|
||||
fn map_ok<T: StdFuture>(future: T) -> impl StdFuture<Output = Result<(), ()>> {
|
||||
MapOk(future)
|
||||
}
|
||||
|
||||
struct MapOk<T>(T);
|
||||
|
||||
impl<T> MapOk<T> {
|
||||
fn future<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
|
||||
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StdFuture> StdFuture for MapOk<T> {
|
||||
type Output = Result<(), ()>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> {
|
||||
match self.future().poll(waker) {
|
||||
Poll::Ready(_) => Poll::Ready(Ok(())),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `tokio::run`, but takes an `async` block
|
||||
pub fn run_async<F>(future: F)
|
||||
where
|
||||
F: StdFuture<Output = ()> + Send + 'static,
|
||||
{
|
||||
use tokio_async_await::compat::backward;
|
||||
let future = backward::Compat::new(map_ok(future));
|
||||
|
||||
::run(future);
|
||||
}
|
||||
|
||||
/// Like `tokio::spawn`, but takes an `async` block
|
||||
pub fn spawn_async<F>(future: F)
|
||||
where
|
||||
F: StdFuture<Output = ()> + Send + 'static,
|
||||
{
|
||||
use tokio_async_await::compat::backward;
|
||||
let future = backward::Compat::new(map_ok(future));
|
||||
|
||||
::spawn(future);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
[build]
|
||||
target-dir = "../../target"
|
||||
@@ -1,49 +0,0 @@
|
||||
[package]
|
||||
name = "examples"
|
||||
edition = "2018"
|
||||
version = "0.1.0"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
|
||||
# Break out of the parent workspace
|
||||
[workspace]
|
||||
|
||||
[[bin]]
|
||||
name = "chat"
|
||||
path = "src/chat.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "echo_client"
|
||||
path = "src/echo_client.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "echo_server"
|
||||
path = "src/echo_server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hyper"
|
||||
path = "src/hyper.rs"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.1.0", path = "../..", features = ["async-await-preview"] }
|
||||
futures = "0.1.23"
|
||||
bytes = "0.4.9"
|
||||
hyper = "0.12.8"
|
||||
|
||||
# Avoid using crates.io for Tokio dependencies
|
||||
[patch.crates-io]
|
||||
tokio = { path = "../.." }
|
||||
tokio-async-await = { path = "../" }
|
||||
tokio-codec = { path = "../../tokio-codec" }
|
||||
tokio-current-thread = { path = "../../tokio-current-thread" }
|
||||
tokio-executor = { path = "../../tokio-executor" }
|
||||
tokio-fs = { path = "../../tokio-fs" }
|
||||
tokio-io = { path = "../../tokio-io" }
|
||||
tokio-reactor = { path = "../../tokio-reactor" }
|
||||
tokio-signal = { path = "../../tokio-signal" }
|
||||
tokio-tcp = { path = "../../tokio-tcp" }
|
||||
tokio-threadpool = { path = "../../tokio-threadpool" }
|
||||
tokio-timer = { path = "../../tokio-timer" }
|
||||
tokio-tls = { path = "../../tokio-tls" }
|
||||
tokio-udp = { path = "../../tokio-udp" }
|
||||
tokio-uds = { path = "../../tokio-uds" }
|
||||
@@ -1,33 +0,0 @@
|
||||
#![feature(await_macro, async_await, futures_api)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tokio;
|
||||
extern crate hyper;
|
||||
|
||||
use tokio::prelude::*;
|
||||
use hyper::Client;
|
||||
|
||||
use std::time::Duration;
|
||||
use std::str;
|
||||
|
||||
pub fn main() {
|
||||
tokio::run_async(async {
|
||||
let client = Client::new();
|
||||
|
||||
let uri = "http://httpbin.org/ip".parse().unwrap();
|
||||
|
||||
let response = await!({
|
||||
client.get(uri)
|
||||
.timeout(Duration::from_secs(10))
|
||||
}).unwrap();
|
||||
|
||||
println!("Response: {}", response.status());
|
||||
|
||||
let mut body = response.into_body();
|
||||
|
||||
while let Some(chunk) = await!(body.next()) {
|
||||
let chunk = chunk.unwrap();
|
||||
println!("chunk = {}", str::from_utf8(&chunk[..]).unwrap());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#![doc(hidden)]
|
||||
|
||||
pub mod backward;
|
||||
pub mod forward;
|
||||
@@ -1,3 +1,14 @@
|
||||
# 0.1.1 (April 22, 2019)
|
||||
|
||||
### Added
|
||||
- Utilities for creating a `BufStream` from iterators and streams (#1011).
|
||||
- Add `BufStream::into_stream` (#1048).
|
||||
- Implement `FromBufStream` for `Bytes` (#1009).
|
||||
- Implement `Error` for `CollectVecError` (#1010).
|
||||
|
||||
### Fixed
|
||||
- Implement `size_hint` for string types (#1012).
|
||||
|
||||
# 0.1.0 (February 23, 2019)
|
||||
|
||||
* Initial release
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
[package]
|
||||
name = "tokio-buf"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
documentation = "https://docs.rs/tokio-buf/0.1.0/tokio_buf"
|
||||
documentation = "https://docs.rs/tokio-buf/0.1.1/tokio_buf"
|
||||
description = """
|
||||
Asynchronous stream of byte buffers
|
||||
"""
|
||||
@@ -27,3 +27,6 @@ futures = "0.1.23"
|
||||
[features]
|
||||
default = ["util"]
|
||||
util = ["bytes/either", "either"]
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-mock-task = "0.1.1"
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ First, add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tokio-buf = "0.1.0"
|
||||
tokio-buf = "0.1.1"
|
||||
```
|
||||
|
||||
Next, add this to your crate:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-buf/0.1.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-buf/0.1.1")]
|
||||
#![deny(missing_docs, missing_debug_implementations, unreachable_pub)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ impl SizeHint {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `value` is less than `upper`.
|
||||
/// The function panics if `value` is greater than `upper`.
|
||||
pub fn set_lower(&mut self, value: u64) {
|
||||
assert!(value <= self.upper.unwrap_or(u64::MAX));
|
||||
self.lower = value;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use never::Never;
|
||||
use BufStream;
|
||||
use SizeHint;
|
||||
|
||||
use futures::Poll;
|
||||
|
||||
@@ -20,6 +21,10 @@ impl BufStream for String {
|
||||
|
||||
Ok(Some(buf).into())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> SizeHint {
|
||||
size_hint(&self[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl BufStream for &'static str {
|
||||
@@ -36,4 +41,15 @@ impl BufStream for &'static str {
|
||||
|
||||
Ok(Some(buf).into())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> SizeHint {
|
||||
size_hint(&self[..])
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(s: &str) -> SizeHint {
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(s.len() as u64);
|
||||
hint.set_upper(s.len() as u64);
|
||||
hint
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use SizeHint;
|
||||
|
||||
use bytes::{Buf, BufMut};
|
||||
use bytes::{Buf, BufMut, Bytes};
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::usize;
|
||||
|
||||
/// Conversion from a `BufStream`.
|
||||
@@ -47,12 +49,18 @@ pub struct CollectVecError {
|
||||
_p: (),
|
||||
}
|
||||
|
||||
/// Error returned from collecting into a `Bytes`
|
||||
#[derive(Debug)]
|
||||
pub struct CollectBytesError {
|
||||
_p: (),
|
||||
}
|
||||
|
||||
impl<T: Buf> FromBufStream<T> for Vec<u8> {
|
||||
type Builder = Vec<u8>;
|
||||
type Error = CollectVecError;
|
||||
|
||||
fn builder(_hint: &SizeHint) -> Vec<u8> {
|
||||
Vec::new()
|
||||
fn builder(hint: &SizeHint) -> Vec<u8> {
|
||||
Vec::with_capacity(hint.lower() as usize)
|
||||
}
|
||||
|
||||
fn extend(builder: &mut Self, buf: &mut T, hint: &SizeHint) -> Result<(), Self::Error> {
|
||||
@@ -110,3 +118,45 @@ impl<T: Buf> FromBufStream<T> for Vec<u8> {
|
||||
Ok(builder)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> FromBufStream<T> for Bytes {
|
||||
type Builder = Vec<u8>;
|
||||
type Error = CollectBytesError;
|
||||
|
||||
fn builder(hint: &SizeHint) -> Vec<u8> {
|
||||
<Vec<u8> as FromBufStream<T>>::builder(hint)
|
||||
}
|
||||
|
||||
fn extend(builder: &mut Vec<u8>, buf: &mut T, hint: &SizeHint) -> Result<(), Self::Error> {
|
||||
<Vec<u8> as FromBufStream<T>>::extend(builder, buf, hint)
|
||||
.map_err(|_| CollectBytesError { _p: () })
|
||||
}
|
||||
|
||||
fn build(builder: Vec<u8>) -> Result<Self, Self::Error> {
|
||||
Ok(builder.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CollectVecError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "BufStream is too big")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CollectVecError {
|
||||
fn description(&self) -> &str {
|
||||
"BufStream too big"
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CollectBytesError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "BufStream too big")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CollectBytesError {
|
||||
fn description(&self) -> &str {
|
||||
"BufStream too big"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use bytes::Buf;
|
||||
use futures::Poll;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use BufStream;
|
||||
|
||||
/// Converts an `Iterator` into a `BufStream` which is always ready to yield the
|
||||
/// next value.
|
||||
///
|
||||
/// Iterators in Rust don't express the ability to block, so this adapter
|
||||
/// simply always calls `iter.next()` and returns that.
|
||||
pub fn iter<I>(i: I) -> Iter<I::IntoIter>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Buf,
|
||||
{
|
||||
Iter {
|
||||
iter: i.into_iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// `BufStream` returned by the [`iter`] function.
|
||||
#[derive(Debug)]
|
||||
pub struct Iter<I> {
|
||||
iter: I,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Never {}
|
||||
|
||||
impl<I> BufStream for Iter<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Buf,
|
||||
{
|
||||
type Item = I::Item;
|
||||
type Error = Never;
|
||||
|
||||
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
Ok(self.iter.next().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Never {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for Never {
|
||||
fn description(&self) -> &str {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,22 @@
|
||||
mod chain;
|
||||
mod collect;
|
||||
mod from;
|
||||
mod iter;
|
||||
mod limit;
|
||||
mod stream;
|
||||
|
||||
pub use self::chain::Chain;
|
||||
pub use self::collect::Collect;
|
||||
pub use self::from::FromBufStream;
|
||||
pub use self::iter::iter;
|
||||
pub use self::limit::Limit;
|
||||
pub use self::stream::{stream, IntoStream};
|
||||
|
||||
pub mod error {
|
||||
//! Error types
|
||||
|
||||
pub use super::collect::CollectError;
|
||||
pub use super::from::CollectVecError;
|
||||
pub use super::from::{CollectBytesError, CollectVecError};
|
||||
pub use super::limit::LimitError;
|
||||
}
|
||||
|
||||
@@ -70,4 +74,14 @@ pub trait BufStreamExt: BufStream {
|
||||
{
|
||||
Limit::new(self, amount)
|
||||
}
|
||||
|
||||
/// Creates a `Stream` from a `BufStream`.
|
||||
///
|
||||
/// This produces a `Stream` of `BufStream::Items`.
|
||||
fn into_stream(self) -> IntoStream<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
IntoStream::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
use bytes::Buf;
|
||||
use futures::{Async, Poll, Stream};
|
||||
use BufStream;
|
||||
|
||||
/// Converts a `Stream` of `Buf` types into a `BufStream`.
|
||||
///
|
||||
/// While `Stream` and `BufStream` are very similar, they are not identical. The
|
||||
/// `stream` function returns a `BufStream` that is backed by the provided
|
||||
/// `Stream` type.
|
||||
pub fn stream<T>(stream: T) -> FromStream<T>
|
||||
where
|
||||
T: Stream,
|
||||
T::Item: Buf,
|
||||
{
|
||||
FromStream { stream }
|
||||
}
|
||||
|
||||
/// `BufStream` returned by the [`stream`] function.
|
||||
#[derive(Debug)]
|
||||
pub struct FromStream<T> {
|
||||
stream: T,
|
||||
}
|
||||
|
||||
impl<T> BufStream for FromStream<T>
|
||||
where
|
||||
T: Stream,
|
||||
T::Item: Buf,
|
||||
{
|
||||
type Item = T::Item;
|
||||
type Error = T::Error;
|
||||
|
||||
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
self.stream.poll()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `BufStream` into a `Stream`.
|
||||
#[derive(Debug)]
|
||||
pub struct IntoStream<T> {
|
||||
buf: T,
|
||||
}
|
||||
|
||||
impl<T> IntoStream<T> {
|
||||
/// Create a new `Stream` from the provided `BufStream`.
|
||||
pub fn new(buf: T) -> Self {
|
||||
IntoStream { buf }
|
||||
}
|
||||
|
||||
/// Get a reference to the inner `BufStream`.
|
||||
pub fn get_ref(&self) -> &T {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the inner `BufStream`
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.buf
|
||||
}
|
||||
|
||||
/// Get the inner `BufStream`.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.buf
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BufStream> Stream for IntoStream<T> {
|
||||
type Item = T::Item;
|
||||
type Error = T::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
match self.buf.poll_buf()? {
|
||||
Async::Ready(Some(buf)) => Ok(Async::Ready(Some(buf))),
|
||||
Async::Ready(None) => Ok(Async::Ready(None)),
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +1,7 @@
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use bytes::Buf;
|
||||
use futures::Async::*;
|
||||
use tokio_buf::{BufStream, SizeHint};
|
||||
use tokio_buf::BufStream;
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
// ===== test `SizeHint` =====
|
||||
|
||||
#[test]
|
||||
fn size_hint() {
|
||||
let hint = SizeHint::new();
|
||||
assert_eq!(hint.lower(), 0);
|
||||
assert!(hint.upper().is_none());
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(100);
|
||||
assert_eq!(hint.lower(), 100);
|
||||
assert!(hint.upper().is_none());
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_upper(200);
|
||||
assert_eq!(hint.lower(), 0);
|
||||
assert_eq!(hint.upper(), Some(200));
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(100);
|
||||
hint.set_upper(100);
|
||||
assert_eq!(hint.lower(), 100);
|
||||
assert_eq!(hint.upper(), Some(100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn size_hint_lower_bigger_than_upper() {
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_upper(100);
|
||||
hint.set_lower(200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn size_hint_upper_less_than_lower() {
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(200);
|
||||
hint.set_upper(100);
|
||||
}
|
||||
|
||||
// ===== BufStream impelmentations for misc types =====
|
||||
|
||||
#[test]
|
||||
fn str_buf_stream() {
|
||||
let mut bs = "hello world".to_string();
|
||||
assert_buf_eq!(bs.poll_buf(), "hello world");
|
||||
assert!(bs.is_empty());
|
||||
assert_none!(bs.poll_buf());
|
||||
|
||||
let mut bs = "hello world";
|
||||
assert_buf_eq!(bs.poll_buf(), "hello world");
|
||||
assert!(bs.is_empty());
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
// Ensures that `BufStream` can be a trait object
|
||||
#[allow(dead_code)]
|
||||
fn obj(_: &mut BufStream<Item = u32, Error = ()>) {}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
#![cfg(feature = "ext")]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use bytes::Buf;
|
||||
use futures::Async::*;
|
||||
use futures::Future;
|
||||
use tokio_buf::{BufStream, BufStreamExt};
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
use support::*;
|
||||
|
||||
// ===== test `chain()` =====
|
||||
|
||||
#[test]
|
||||
fn chain() {
|
||||
// Chain one with one
|
||||
//
|
||||
let mut bs = one("hello").chain(one("world"));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "hello");
|
||||
assert_buf_eq!(bs.poll_buf(), "world");
|
||||
assert_none!(bs.poll_buf());
|
||||
|
||||
// Chain multi with multi
|
||||
let mut bs = list(&["foo", "bar"]).chain(list(&["baz", "bok"]));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "foo");
|
||||
assert_buf_eq!(bs.poll_buf(), "bar");
|
||||
assert_buf_eq!(bs.poll_buf(), "baz");
|
||||
assert_buf_eq!(bs.poll_buf(), "bok");
|
||||
assert_none!(bs.poll_buf());
|
||||
|
||||
// Chain includes a not ready call
|
||||
//
|
||||
let mut bs = new_mock(&[Ok(Ready("foo")), Ok(NotReady), Ok(Ready("bar"))]).chain(one("baz"));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "foo");
|
||||
assert_not_ready!(bs.poll_buf());
|
||||
assert_buf_eq!(bs.poll_buf(), "bar");
|
||||
assert_buf_eq!(bs.poll_buf(), "baz");
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
// ===== Test `collect()` =====
|
||||
|
||||
#[test]
|
||||
fn collect_vec() {
|
||||
// While unfortunate, this test makes some assumptions on vec's resizing
|
||||
// behavior.
|
||||
//
|
||||
// Collect one
|
||||
//
|
||||
let bs = one("hello world");
|
||||
|
||||
let vec: Vec<u8> = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, b"hello world");
|
||||
assert_eq!(vec.capacity(), 64);
|
||||
|
||||
// Collect one, with size hint
|
||||
//
|
||||
let mut bs = one("hello world");
|
||||
bs.size_hint.set_lower(11);
|
||||
|
||||
let vec: Vec<u8> = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, b"hello world");
|
||||
assert_eq!(vec.capacity(), 64);
|
||||
|
||||
// Collect one, with size hint
|
||||
//
|
||||
let mut bs = one("hello world");
|
||||
bs.size_hint.set_lower(10);
|
||||
|
||||
let vec: Vec<u8> = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, b"hello world");
|
||||
assert_eq!(vec.capacity(), 64);
|
||||
|
||||
// Collect many
|
||||
//
|
||||
let bs = list(&["hello", " ", "world", ", one two three"]);
|
||||
|
||||
let vec: Vec<u8> = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, b"hello world, one two three");
|
||||
}
|
||||
|
||||
// ===== Test limit() =====
|
||||
|
||||
#[test]
|
||||
fn limit() {
|
||||
// Not limited
|
||||
|
||||
let res = one("hello world")
|
||||
.limit(100)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
let res = list(&["hello", " ", "world"])
|
||||
.limit(100)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
let res = list(&["hello", " ", "world"])
|
||||
.limit(11)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
// Limited
|
||||
|
||||
let res = one("hello world").limit(5).collect::<Vec<_>>().wait();
|
||||
|
||||
assert!(res.is_err());
|
||||
|
||||
let res = one("hello world").limit(10).collect::<Vec<_>>().wait();
|
||||
|
||||
assert!(res.is_err());
|
||||
|
||||
let mut bs = list(&["hello", " ", "world"]).limit(9);
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "hello");
|
||||
assert_buf_eq!(bs.poll_buf(), " ");
|
||||
assert!(bs.poll_buf().is_err());
|
||||
|
||||
let mut bs = list(&["hello", " ", "world"]);
|
||||
bs.size_hint.set_lower(11);
|
||||
let mut bs = bs.limit(9);
|
||||
|
||||
assert!(bs.poll_buf().is_err());
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#![cfg(feature = "util")]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use futures::Async::*;
|
||||
use tokio_buf::{BufStream, BufStreamExt};
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
use support::*;
|
||||
|
||||
#[test]
|
||||
fn chain() {
|
||||
// Chain one with one
|
||||
//
|
||||
let mut bs = one("hello").chain(one("world"));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "hello");
|
||||
assert_buf_eq!(bs.poll_buf(), "world");
|
||||
assert_none!(bs.poll_buf());
|
||||
|
||||
// Chain multi with multi
|
||||
let mut bs = list(&["foo", "bar"]).chain(list(&["baz", "bok"]));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "foo");
|
||||
assert_buf_eq!(bs.poll_buf(), "bar");
|
||||
assert_buf_eq!(bs.poll_buf(), "baz");
|
||||
assert_buf_eq!(bs.poll_buf(), "bok");
|
||||
assert_none!(bs.poll_buf());
|
||||
|
||||
// Chain includes a not ready call
|
||||
//
|
||||
let mut bs = new_mock(&[Ok(Ready("foo")), Ok(NotReady), Ok(Ready("bar"))]).chain(one("baz"));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "foo");
|
||||
assert_not_ready!(bs.poll_buf());
|
||||
assert_buf_eq!(bs.poll_buf(), "bar");
|
||||
assert_buf_eq!(bs.poll_buf(), "baz");
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#![cfg(feature = "util")]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures::Future;
|
||||
use tokio_buf::BufStreamExt;
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
use support::*;
|
||||
|
||||
macro_rules! test_collect_impl {
|
||||
($t:ty $(, $capacity:ident)*) => {
|
||||
// While unfortunate, this test makes some assumptions on vec's resizing
|
||||
// behavior.
|
||||
//
|
||||
// Collect one
|
||||
//
|
||||
let bs = one("hello world");
|
||||
|
||||
let vec: $t = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, &b"hello world"[..]);
|
||||
$( assert_eq!(vec.$capacity(), 64); )*
|
||||
|
||||
// Collect one, with size hint
|
||||
//
|
||||
let mut bs = one("hello world");
|
||||
bs.size_hint.set_lower(11);
|
||||
|
||||
let vec: $t = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, &b"hello world"[..]);
|
||||
$( assert_eq!(vec.$capacity(), 64); )*
|
||||
|
||||
// Collect one, with size hint
|
||||
//
|
||||
let mut bs = one("hello world");
|
||||
bs.size_hint.set_lower(10);
|
||||
|
||||
let vec: $t = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, &b"hello world"[..]);
|
||||
$( assert_eq!(vec.$capacity(), 64); )*
|
||||
|
||||
// Collect many
|
||||
//
|
||||
let bs = list(&["hello", " ", "world", ", one two three"]);
|
||||
|
||||
let vec: $t = bs.collect().wait().unwrap();
|
||||
|
||||
assert_eq!(vec, &b"hello world, one two three"[..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_vec() {
|
||||
test_collect_impl!(Vec<u8>, capacity);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_bytes() {
|
||||
test_collect_impl!(Bytes);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use futures::Async::*;
|
||||
use std::io::Cursor;
|
||||
use tokio_buf::{util, BufStream};
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
type Buf = Cursor<&'static [u8]>;
|
||||
|
||||
#[test]
|
||||
fn empty_iter() {
|
||||
let mut bs = util::iter(Vec::<Buf>::new());
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_iter() {
|
||||
let bufs = vec![buf(b"one"), buf(b"two"), buf(b"three")];
|
||||
|
||||
let mut bs = util::iter(bufs);
|
||||
assert_buf_eq!(bs.poll_buf(), "one");
|
||||
assert_buf_eq!(bs.poll_buf(), "two");
|
||||
assert_buf_eq!(bs.poll_buf(), "three");
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
fn buf(data: &'static [u8]) -> Buf {
|
||||
Cursor::new(data)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#![cfg(feature = "util")]
|
||||
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use futures::Async::*;
|
||||
use futures::Future;
|
||||
use tokio_buf::{BufStream, BufStreamExt};
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
use support::*;
|
||||
|
||||
#[test]
|
||||
fn limit() {
|
||||
// Not limited
|
||||
|
||||
let res = one("hello world")
|
||||
.limit(100)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
let res = list(&["hello", " ", "world"])
|
||||
.limit(100)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
let res = list(&["hello", " ", "world"])
|
||||
.limit(11)
|
||||
.collect::<Vec<_>>()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, b"hello world");
|
||||
|
||||
// Limited
|
||||
|
||||
let res = one("hello world").limit(5).collect::<Vec<_>>().wait();
|
||||
|
||||
assert!(res.is_err());
|
||||
|
||||
let res = one("hello world").limit(10).collect::<Vec<_>>().wait();
|
||||
|
||||
assert!(res.is_err());
|
||||
|
||||
let mut bs = list(&["hello", " ", "world"]).limit(9);
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "hello");
|
||||
assert_buf_eq!(bs.poll_buf(), " ");
|
||||
assert!(bs.poll_buf().is_err());
|
||||
|
||||
let mut bs = list(&["hello", " ", "world"]);
|
||||
bs.size_hint.set_lower(11);
|
||||
let mut bs = bs.limit(9);
|
||||
|
||||
assert!(bs.poll_buf().is_err());
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
extern crate tokio_buf;
|
||||
|
||||
use tokio_buf::SizeHint;
|
||||
|
||||
#[test]
|
||||
fn size_hint() {
|
||||
let hint = SizeHint::new();
|
||||
assert_eq!(hint.lower(), 0);
|
||||
assert!(hint.upper().is_none());
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(100);
|
||||
assert_eq!(hint.lower(), 100);
|
||||
assert!(hint.upper().is_none());
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_upper(200);
|
||||
assert_eq!(hint.lower(), 0);
|
||||
assert_eq!(hint.upper(), Some(200));
|
||||
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(100);
|
||||
hint.set_upper(100);
|
||||
assert_eq!(hint.lower(), 100);
|
||||
assert_eq!(hint.upper(), Some(100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn size_hint_lower_bigger_than_upper() {
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_upper(100);
|
||||
hint.set_lower(200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn size_hint_upper_less_than_lower() {
|
||||
let mut hint = SizeHint::new();
|
||||
hint.set_lower(200);
|
||||
hint.set_upper(100);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
extern crate tokio_mock_task;
|
||||
|
||||
use futures::sync::mpsc;
|
||||
use futures::Async::*;
|
||||
use std::io::Cursor;
|
||||
use tokio_buf::{util, BufStream};
|
||||
use tokio_mock_task::MockTask;
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
type Buf = Cursor<&'static [u8]>;
|
||||
|
||||
#[test]
|
||||
fn empty_stream() {
|
||||
let (_, rx) = mpsc::unbounded::<Buf>();
|
||||
let mut bs = util::stream(rx);
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_stream() {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
let mut bs = util::stream(rx);
|
||||
let mut task = MockTask::new();
|
||||
|
||||
tx.unbounded_send(buf(b"one")).unwrap();
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "one");
|
||||
task.enter(|| assert_not_ready!(bs.poll_buf()));
|
||||
|
||||
tx.unbounded_send(buf(b"two")).unwrap();
|
||||
|
||||
assert!(task.is_notified());
|
||||
assert_buf_eq!(bs.poll_buf(), "two");
|
||||
task.enter(|| assert_not_ready!(bs.poll_buf()));
|
||||
|
||||
drop(tx);
|
||||
|
||||
assert!(task.is_notified());
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
fn buf(data: &'static [u8]) -> Buf {
|
||||
Cursor::new(data)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate tokio_buf;
|
||||
|
||||
use futures::Async::*;
|
||||
use std::fmt;
|
||||
use tokio_buf::BufStream;
|
||||
|
||||
#[macro_use]
|
||||
mod support;
|
||||
|
||||
fn test_hello_world<B>(mut bs: B)
|
||||
where
|
||||
B: BufStream + fmt::Debug,
|
||||
B::Item: fmt::Debug,
|
||||
B::Error: fmt::Debug,
|
||||
{
|
||||
let hint = bs.size_hint();
|
||||
assert_eq!(hint.lower(), 11);
|
||||
assert_eq!(hint.upper(), Some(11));
|
||||
|
||||
assert_buf_eq!(bs.poll_buf(), "hello world");
|
||||
|
||||
let hint = bs.size_hint();
|
||||
assert_eq!(hint.lower(), 0);
|
||||
assert_eq!(hint.upper(), Some(0));
|
||||
assert_none!(bs.poll_buf());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string() {
|
||||
test_hello_world("hello world".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str() {
|
||||
test_hello_world("hello world");
|
||||
}
|
||||
@@ -14,6 +14,7 @@ use std::io::Cursor;
|
||||
|
||||
macro_rules! assert_buf_eq {
|
||||
($actual:expr, $expect:expr) => {{
|
||||
use bytes::Buf;
|
||||
match $actual {
|
||||
Ok(Ready(Some(val))) => {
|
||||
assert_eq!(val.remaining(), val.bytes().len());
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
[package]
|
||||
name = "tokio-codec"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc URL.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.1"
|
||||
@@ -18,6 +20,6 @@ Utilities for encoding and decoding frames.
|
||||
categories = ["asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
tokio-io = { version = "0.1.7", path = "../tokio-io" }
|
||||
tokio-io = "0.1.7"
|
||||
bytes = "0.4.7"
|
||||
futures = "0.1.18"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# 0.1.6 (March 22, 2019)
|
||||
|
||||
### Added
|
||||
- implement `TypedExecutor` (#993).
|
||||
|
||||
# 0.1.5 (March 1, 2019)
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[package]
|
||||
name = "tokio-current-thread"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.5"
|
||||
documentation = "https://docs.rs/tokio-current-thread/0.1.5/tokio_current_thread"
|
||||
version = "0.1.6"
|
||||
documentation = "https://docs.rs/tokio-current-thread/0.1.6/tokio_current_thread"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://github.com/tokio-rs/tokio"
|
||||
license = "MIT"
|
||||
@@ -21,5 +21,5 @@ keywords = ["futures", "tokio"]
|
||||
categories = ["concurrency", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
tokio-executor = { version = "0.1.5", path = "../tokio-executor" }
|
||||
tokio-executor = "0.1.7"
|
||||
futures = "0.1.19"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Single threaded executor for Tokio.
|
||||
|
||||
[Documentation](https://docs.rs/tokio-current-thread/0.1.5/tokio_current_thread/)
|
||||
[Documentation](https://docs.rs/tokio-current-thread/0.1.6/tokio_current_thread/)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-current-thread/0.1.5")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-current-thread/0.1.6")]
|
||||
#![deny(warnings, missing_docs, missing_debug_implementations)]
|
||||
|
||||
//! A single-threaded executor which executes tasks on the same thread from which
|
||||
@@ -431,6 +431,16 @@ impl tokio_executor::Executor for CurrentThread {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> tokio_executor::TypedExecutor<T> for CurrentThread
|
||||
where
|
||||
T: Future<Item = (), Error = ()> + 'static,
|
||||
{
|
||||
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
|
||||
self.borrow().spawn_local(Box::new(future), false);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Park> fmt::Debug for CurrentThread<P> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("CurrentThread")
|
||||
@@ -742,6 +752,15 @@ impl tokio_executor::Executor for TaskExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> tokio_executor::TypedExecutor<F> for TaskExecutor
|
||||
where
|
||||
F: Future<Item = (), Error = ()> + 'static,
|
||||
{
|
||||
fn spawn(&mut self, future: F) -> Result<(), SpawnError> {
|
||||
self.spawn_local(Box::new(future))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Executor<F> for TaskExecutor
|
||||
where
|
||||
F: Future<Item = (), Error = ()> + 'static,
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# 0.1.7 (March 22, 2019)
|
||||
|
||||
### Added
|
||||
- `TypedExecutor` for spawning futures of a specific type (#993).
|
||||
|
||||
# 0.1.6 (January 6, 2019)
|
||||
|
||||
* Implement `Unpark` for `Arc<Unpark>` (#802).
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[package]
|
||||
name = "tokio-executor"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.6"
|
||||
documentation = "https://docs.rs/tokio-executor/0.1.6/tokio_executor"
|
||||
version = "0.1.7"
|
||||
documentation = "https://docs.rs/tokio-executor/0.1.7/tokio_executor"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://github.com/tokio-rs/tokio"
|
||||
license = "MIT"
|
||||
@@ -23,3 +23,6 @@ categories = ["concurrency", "asynchronous"]
|
||||
[dependencies]
|
||||
crossbeam-utils = "0.6.2"
|
||||
futures = "0.1.19"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = "0.1.18"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Task execution related traits and utilities.
|
||||
|
||||
[Documentation](https://docs.rs/tokio-executor/0.1.6/tokio_executor)
|
||||
[Documentation](https://docs.rs/tokio-executor/0.1.7/tokio_executor)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -31,10 +31,10 @@ executor, including:
|
||||
|
||||
* [`Park`] abstracts over blocking and unblocking the current thread.
|
||||
|
||||
[`Executor`]: https://docs.rs/tokio-executor/0.1.6/tokio_executor/trait.Executor.html
|
||||
[`enter`]: https://docs.rs/tokio-executor/0.1.6/tokio_executor/fn.enter.html
|
||||
[`DefaultExecutor`]: https://docs.rs/tokio-executor/0.1.6/tokio_executor/struct.DefaultExecutor.html
|
||||
[`Park`]: https://docs.rs/tokio-executor/0.1.6/tokio_executor/park/trait.Park.html
|
||||
[`Executor`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/trait.Executor.html
|
||||
[`enter`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/fn.enter.html
|
||||
[`DefaultExecutor`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/struct.DefaultExecutor.html
|
||||
[`Park`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/park/trait.Park.html
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
/// Errors returned by `Executor::spawn`.
|
||||
///
|
||||
/// Spawn errors should represent relatively rare scenarios. Currently, the two
|
||||
/// scenarios represented by `SpawnError` are:
|
||||
///
|
||||
/// * An executor being at capacity or full. As such, the executor is not able
|
||||
/// to accept a new future. This error state is expected to be transient.
|
||||
/// * An executor has been shutdown and can no longer accept new futures. This
|
||||
/// error state is expected to be permanent.
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnError {
|
||||
is_shutdown: bool,
|
||||
}
|
||||
|
||||
impl SpawnError {
|
||||
/// Return a new `SpawnError` reflecting a shutdown executor failure.
|
||||
pub fn shutdown() -> Self {
|
||||
SpawnError { is_shutdown: true }
|
||||
}
|
||||
|
||||
/// Return a new `SpawnError` reflecting an executor at capacity failure.
|
||||
pub fn at_capacity() -> Self {
|
||||
SpawnError { is_shutdown: false }
|
||||
}
|
||||
|
||||
/// Returns `true` if the error reflects a shutdown executor failure.
|
||||
pub fn is_shutdown(&self) -> bool {
|
||||
self.is_shutdown
|
||||
}
|
||||
|
||||
/// Returns `true` if the error reflects an executor at capacity failure.
|
||||
pub fn is_at_capacity(&self) -> bool {
|
||||
!self.is_shutdown
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SpawnError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for SpawnError {
|
||||
fn description(&self) -> &str {
|
||||
"attempted to spawn task while the executor is at capacity or shut down"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
use futures::Future;
|
||||
use SpawnError;
|
||||
|
||||
/// A value that executes futures.
|
||||
///
|
||||
/// The [`spawn`] function is used to submit a future to an executor. Once
|
||||
/// submitted, the executor takes ownership of the future and becomes
|
||||
/// responsible for driving the future to completion.
|
||||
///
|
||||
/// The strategy employed by the executor to handle the future is less defined
|
||||
/// and is left up to the `Executor` implementation. The `Executor` instance is
|
||||
/// expected to call [`poll`] on the future once it has been notified, however
|
||||
/// the "when" and "how" can vary greatly.
|
||||
///
|
||||
/// For example, the executor might be a thread pool, in which case a set of
|
||||
/// threads have already been spawned up and the future is inserted into a
|
||||
/// queue. A thread will acquire the future and poll it.
|
||||
///
|
||||
/// The `Executor` trait is only for futures that **are** `Send`. These are most
|
||||
/// common. There currently is no trait that describes executors that operate
|
||||
/// entirely on the current thread (i.e., are able to spawn futures that are not
|
||||
/// `Send`). Note that single threaded executors can still implement `Executor`,
|
||||
/// but only futures that are `Send` can be spawned via the trait.
|
||||
///
|
||||
/// This trait is primarily intended to implemented by executors and used to
|
||||
/// back `tokio::spawn`. Libraries and applications **may** use this trait to
|
||||
/// bound generics, but doing so will limit usage to futures that implement
|
||||
/// `Send`. Instead, libraries and applications are recommended to use
|
||||
/// [`TypedExecutor`] as a bound.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The [`spawn`] function returns `Result` with an error type of `SpawnError`.
|
||||
/// This error type represents the reason that the executor was unable to spawn
|
||||
/// the future. The two current represented scenarios are:
|
||||
///
|
||||
/// * An executor being at capacity or full. As such, the executor is not able
|
||||
/// to accept a new future. This error state is expected to be transient.
|
||||
/// * An executor has been shutdown and can no longer accept new futures. This
|
||||
/// error state is expected to be permanent.
|
||||
///
|
||||
/// If a caller encounters an at capacity error, the caller should try to shed
|
||||
/// load. This can be as simple as dropping the future that was spawned.
|
||||
///
|
||||
/// If the caller encounters a shutdown error, the caller should attempt to
|
||||
/// gracefully shutdown.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`spawn`]: #tymethod.spawn
|
||||
/// [`poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll
|
||||
/// [`TypedExecutor`]: ../trait.TypedExecutor.html
|
||||
pub trait Executor {
|
||||
/// Spawns a future object to run on this executor.
|
||||
///
|
||||
/// `future` is passed to the executor, which will begin running it. The
|
||||
/// future may run on the current thread or another thread at the discretion
|
||||
/// of the `Executor` implementation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Implementations are encouraged to avoid panics. However, panics are
|
||||
/// permitted and the caller should check the implementation specific
|
||||
/// documentation for more details on possible panics.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn spawn(
|
||||
&mut self,
|
||||
future: Box<Future<Item = (), Error = ()> + Send>,
|
||||
) -> Result<(), SpawnError>;
|
||||
|
||||
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
|
||||
///
|
||||
/// This function may return both false positives **and** false negatives.
|
||||
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
|
||||
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
|
||||
/// *probably* fail, but may succeed.
|
||||
///
|
||||
/// This allows a caller to avoid creating the task if the call to `spawn`
|
||||
/// has a high likelihood of failing.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function must not panic. Implementers must ensure that panics do
|
||||
/// not happen.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
///
|
||||
/// if my_executor.status().is_ok() {
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// } else {
|
||||
/// println!("the executor is not in a good state");
|
||||
/// }
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Executor + ?Sized> Executor for Box<E> {
|
||||
fn spawn(
|
||||
&mut self,
|
||||
future: Box<Future<Item = (), Error = ()> + Send>,
|
||||
) -> Result<(), SpawnError> {
|
||||
(**self).spawn(future)
|
||||
}
|
||||
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
(**self).status()
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,19 @@ impl super::Executor for DefaultExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> super::TypedExecutor<T> for DefaultExecutor
|
||||
where
|
||||
T: Future<Item = (), Error = ()> + Send + 'static,
|
||||
{
|
||||
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
|
||||
super::Executor::spawn(self, Box::new(future))
|
||||
}
|
||||
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
super::Executor::status(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> future::Executor<T> for DefaultExecutor
|
||||
where
|
||||
T: Future<Item = (), Error = ()> + Send + 'static,
|
||||
|
||||
+25
-198
@@ -1,5 +1,5 @@
|
||||
#![deny(missing_docs, missing_debug_implementations, warnings)]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.6")]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.7")]
|
||||
|
||||
//! Task execution related traits and utilities.
|
||||
//!
|
||||
@@ -17,8 +17,12 @@
|
||||
//! This crate provides traits and utilities that are necessary for building an
|
||||
//! executor, including:
|
||||
//!
|
||||
//! * The [`Executor`] trait describes the API for spawning a future onto an
|
||||
//! executor.
|
||||
//! * The [`Executor`] trait spawns future object onto an executor.
|
||||
//!
|
||||
//! * The [`TypedExecutor`] trait spawns futures of a specific type onto an
|
||||
//! executor. This is used to be generic over executors that spawn futures
|
||||
//! that are either `Send` or `!Send` or implement executors that apply to
|
||||
//! specific futures.
|
||||
//!
|
||||
//! * [`enter`] marks that the current thread is entering an execution
|
||||
//! context. This prevents a second executor from accidentally starting from
|
||||
@@ -29,7 +33,19 @@
|
||||
//!
|
||||
//! * [`Park`] abstracts over blocking and unblocking the current thread.
|
||||
//!
|
||||
//! # Implementing an executor
|
||||
//!
|
||||
//! Executors should always implement `TypedExecutor`. This usually is the bound
|
||||
//! that applications and libraries will use when generic over an executor. See
|
||||
//! the [trait documentation][`TypedExecutor`] for more details.
|
||||
//!
|
||||
//! If the executor is able to spawn all futures that are `Send`, then the
|
||||
//! executor should also implement the `Executor` trait. This trait is rarely
|
||||
//! used directly by applications and libraries. Instead, `tokio::spawn` is
|
||||
//! configured to dispatch to type that implements `Executor`.
|
||||
//!
|
||||
//! [`Executor`]: trait.Executor.html
|
||||
//! [`TypedExecutor`]: trait.TypedExecutor.html
|
||||
//! [`enter`]: fn.enter.html
|
||||
//! [`DefaultExecutor`]: struct.DefaultExecutor.html
|
||||
//! [`Park`]: park/index.html
|
||||
@@ -39,203 +55,14 @@ extern crate crossbeam_utils;
|
||||
extern crate futures;
|
||||
|
||||
mod enter;
|
||||
mod error;
|
||||
mod executor;
|
||||
mod global;
|
||||
pub mod park;
|
||||
mod typed;
|
||||
|
||||
pub use enter::{enter, Enter, EnterError};
|
||||
pub use error::SpawnError;
|
||||
pub use executor::Executor;
|
||||
pub use global::{spawn, with_default, DefaultExecutor};
|
||||
|
||||
use futures::Future;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
/// A value that executes futures.
|
||||
///
|
||||
/// The [`spawn`] function is used to submit a future to an executor. Once
|
||||
/// submitted, the executor takes ownership of the future and becomes
|
||||
/// responsible for driving the future to completion.
|
||||
///
|
||||
/// The strategy employed by the executor to handle the future is less defined
|
||||
/// and is left up to the `Executor` implementation. The `Executor` instance is
|
||||
/// expected to call [`poll`] on the future once it has been notified, however
|
||||
/// the "when" and "how" can vary greatly.
|
||||
///
|
||||
/// For example, the executor might be a thread pool, in which case a set of
|
||||
/// threads have already been spawned up and the future is inserted into a
|
||||
/// queue. A thread will acquire the future and poll it.
|
||||
///
|
||||
/// The `Executor` trait is only for futures that **are** `Send`. These are most
|
||||
/// common. There currently is no trait that describes executors that operate
|
||||
/// entirely on the current thread (i.e., are able to spawn futures that are not
|
||||
/// `Send`). Note that single threaded executors can still implement `Executor`,
|
||||
/// but only futures that are `Send` can be spawned via the trait.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The [`spawn`] function returns `Result` with an error type of `SpawnError`.
|
||||
/// This error type represents the reason that the executor was unable to spawn
|
||||
/// the future. The two current represented scenarios are:
|
||||
///
|
||||
/// * An executor being at capacity or full. As such, the executor is not able
|
||||
/// to accept a new future. This error state is expected to be transient.
|
||||
/// * An executor has been shutdown and can no longer accept new futures. This
|
||||
/// error state is expected to be permanent.
|
||||
///
|
||||
/// If a caller encounters an at capacity error, the caller should try to shed
|
||||
/// load. This can be as simple as dropping the future that was spawned.
|
||||
///
|
||||
/// If the caller encounters a shutdown error, the caller should attempt to
|
||||
/// gracefully shutdown.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`spawn`]: #tymethod.spawn
|
||||
/// [`poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll
|
||||
pub trait Executor {
|
||||
/// Spawns a future object to run on this executor.
|
||||
///
|
||||
/// `future` is passed to the executor, which will begin running it. The
|
||||
/// future may run on the current thread or another thread at the discretion
|
||||
/// of the `Executor` implementation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Implementers are encouraged to avoid panics. However, a panic is
|
||||
/// permitted and the caller should check the implementation specific
|
||||
/// documentation for more details on possible panics.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn spawn(
|
||||
&mut self,
|
||||
future: Box<Future<Item = (), Error = ()> + Send>,
|
||||
) -> Result<(), SpawnError>;
|
||||
|
||||
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
|
||||
///
|
||||
/// This function may return both false positives **and** false negatives.
|
||||
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
|
||||
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
|
||||
/// *probably* fail, but may succeed.
|
||||
///
|
||||
/// This allows a caller to avoid creating the task if the call to `spawn`
|
||||
/// has a high likelihood of failing.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function must not panic. Implementers must ensure that panics do
|
||||
/// not happen.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::Executor;
|
||||
/// # fn docs(my_executor: &mut Executor) {
|
||||
/// use futures::future::lazy;
|
||||
///
|
||||
/// if my_executor.status().is_ok() {
|
||||
/// my_executor.spawn(Box::new(lazy(|| {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(())
|
||||
/// }))).unwrap();
|
||||
/// } else {
|
||||
/// println!("the executor is not in a good state");
|
||||
/// }
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Executor + ?Sized> Executor for Box<E> {
|
||||
fn spawn(
|
||||
&mut self,
|
||||
future: Box<Future<Item = (), Error = ()> + Send>,
|
||||
) -> Result<(), SpawnError> {
|
||||
(**self).spawn(future)
|
||||
}
|
||||
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
(**self).status()
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors returned by `Executor::spawn`.
|
||||
///
|
||||
/// Spawn errors should represent relatively rare scenarios. Currently, the two
|
||||
/// scenarios represented by `SpawnError` are:
|
||||
///
|
||||
/// * An executor being at capacity or full. As such, the executor is not able
|
||||
/// to accept a new future. This error state is expected to be transient.
|
||||
/// * An executor has been shutdown and can no longer accept new futures. This
|
||||
/// error state is expected to be permanent.
|
||||
#[derive(Debug)]
|
||||
pub struct SpawnError {
|
||||
is_shutdown: bool,
|
||||
}
|
||||
|
||||
impl SpawnError {
|
||||
/// Return a new `SpawnError` reflecting a shutdown executor failure.
|
||||
pub fn shutdown() -> Self {
|
||||
SpawnError { is_shutdown: true }
|
||||
}
|
||||
|
||||
/// Return a new `SpawnError` reflecting an executor at capacity failure.
|
||||
pub fn at_capacity() -> Self {
|
||||
SpawnError { is_shutdown: false }
|
||||
}
|
||||
|
||||
/// Returns `true` if the error reflects a shutdown executor failure.
|
||||
pub fn is_shutdown(&self) -> bool {
|
||||
self.is_shutdown
|
||||
}
|
||||
|
||||
/// Returns `true` if the error reflects an executor at capacity failure.
|
||||
pub fn is_at_capacity(&self) -> bool {
|
||||
!self.is_shutdown
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SpawnError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for SpawnError {
|
||||
fn description(&self) -> &str {
|
||||
"attempted to spawn task while the executor is at capacity or shut down"
|
||||
}
|
||||
}
|
||||
pub use typed::TypedExecutor;
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
use SpawnError;
|
||||
|
||||
/// A value that spawns futures of a specific type.
|
||||
///
|
||||
/// The trait is generic over `T`: the type of future that can be spawened. This
|
||||
/// is useful for implementing an executor that is only able to spawn a specific
|
||||
/// type of future.
|
||||
///
|
||||
/// The [`spawn`] function is used to submit the future to the executor. Once
|
||||
/// submitted, the executor takes ownership of the future and becomes
|
||||
/// responsible for driving the future to completion.
|
||||
///
|
||||
/// This trait is useful as a bound for applications and libraries in order to
|
||||
/// be generic over futures that are `Send` vs. `!Send`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Consider a function that provides an API for draining a `Stream` in the
|
||||
/// background. To do this, a task must be spawned to perform the draining. As
|
||||
/// such, the function takes a stream and an executor on which the background
|
||||
/// task is spawned.
|
||||
///
|
||||
/// ```rust
|
||||
/// #[macro_use]
|
||||
/// extern crate futures;
|
||||
/// extern crate tokio;
|
||||
///
|
||||
/// use futures::{Future, Stream, Poll};
|
||||
/// use tokio::executor::TypedExecutor;
|
||||
/// use tokio::sync::oneshot;
|
||||
///
|
||||
/// pub fn drain<T, E>(stream: T, executor: &mut E)
|
||||
/// -> impl Future<Item = (), Error = ()>
|
||||
/// where
|
||||
/// T: Stream,
|
||||
/// E: TypedExecutor<Drain<T>>
|
||||
/// {
|
||||
/// let (tx, rx) = oneshot::channel();
|
||||
///
|
||||
/// executor.spawn(Drain {
|
||||
/// stream,
|
||||
/// tx: Some(tx),
|
||||
/// }).unwrap();
|
||||
///
|
||||
/// rx.map_err(|_| ())
|
||||
/// }
|
||||
///
|
||||
/// // The background task
|
||||
/// pub struct Drain<T: Stream> {
|
||||
/// stream: T,
|
||||
/// tx: Option<oneshot::Sender<()>>,
|
||||
/// }
|
||||
///
|
||||
/// impl<T: Stream> Future for Drain<T> {
|
||||
/// type Item = ();
|
||||
/// type Error = ();
|
||||
///
|
||||
/// fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
/// loop {
|
||||
/// let item = try_ready!(
|
||||
/// self.stream.poll()
|
||||
/// .map_err(|_| ())
|
||||
/// );
|
||||
///
|
||||
/// if item.is_none() { break; }
|
||||
/// }
|
||||
///
|
||||
/// self.tx.take().unwrap().send(()).map_err(|_| ());
|
||||
/// Ok(().into())
|
||||
/// }
|
||||
/// }
|
||||
/// # pub fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// By doing this, the `drain` fn can accept a stream that is `!Send` as long as
|
||||
/// the supplied executor is able to spawn `!Send` types.
|
||||
pub trait TypedExecutor<T> {
|
||||
/// Spawns a future to run on this executor.
|
||||
///
|
||||
/// `future` is passed to the executor, which will begin running it. The
|
||||
/// executor takes ownership of the future and becomes responsible for
|
||||
/// driving the future to completion.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Implementations are encouraged to avoid panics. However, panics are
|
||||
/// permitted and the caller should check the implementation specific
|
||||
/// documentation for more details on possible panics.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::TypedExecutor;
|
||||
/// # use futures::{Future, Poll};
|
||||
/// fn example<T>(my_executor: &mut T)
|
||||
/// where
|
||||
/// T: TypedExecutor<MyFuture>,
|
||||
/// {
|
||||
/// my_executor.spawn(MyFuture).unwrap();
|
||||
/// }
|
||||
///
|
||||
/// struct MyFuture;
|
||||
///
|
||||
/// impl Future for MyFuture {
|
||||
/// type Item = ();
|
||||
/// type Error = ();
|
||||
///
|
||||
/// fn poll(&mut self) -> Poll<(), ()> {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(().into())
|
||||
/// }
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn spawn(&mut self, future: T) -> Result<(), SpawnError>;
|
||||
|
||||
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
|
||||
///
|
||||
/// This function may return both false positives **and** false negatives.
|
||||
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
|
||||
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
|
||||
/// *probably* fail, but may succeed.
|
||||
///
|
||||
/// This allows a caller to avoid creating the task if the call to `spawn`
|
||||
/// has a high likelihood of failing.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function must not panic. Implementers must ensure that panics do
|
||||
/// not happen.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate futures;
|
||||
/// # extern crate tokio_executor;
|
||||
/// # use tokio_executor::TypedExecutor;
|
||||
/// # use futures::{Future, Poll};
|
||||
/// fn example<T>(my_executor: &mut T)
|
||||
/// where
|
||||
/// T: TypedExecutor<MyFuture>,
|
||||
/// {
|
||||
/// if my_executor.status().is_ok() {
|
||||
/// my_executor.spawn(MyFuture).unwrap();
|
||||
/// } else {
|
||||
/// println!("the executor is not in a good state");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// struct MyFuture;
|
||||
///
|
||||
/// impl Future for MyFuture {
|
||||
/// type Item = ();
|
||||
/// type Error = ();
|
||||
///
|
||||
/// fn poll(&mut self) -> Poll<(), ()> {
|
||||
/// println!("running on the executor");
|
||||
/// Ok(().into())
|
||||
/// }
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, T> TypedExecutor<T> for Box<E>
|
||||
where
|
||||
E: TypedExecutor<T>,
|
||||
{
|
||||
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
|
||||
(**self).spawn(future)
|
||||
}
|
||||
|
||||
fn status(&self) -> Result<(), SpawnError> {
|
||||
(**self).status()
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,11 @@ extern crate futures;
|
||||
extern crate tokio_executor;
|
||||
|
||||
use futures::{future::lazy, Future};
|
||||
use tokio_executor::*;
|
||||
use tokio_executor::DefaultExecutor;
|
||||
|
||||
mod out_of_executor_context {
|
||||
use super::*;
|
||||
use tokio_executor::Executor;
|
||||
|
||||
fn test<F, E>(spawn: F)
|
||||
where
|
||||
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "tokio-fs"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.6"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
@@ -23,13 +23,13 @@ categories = ["asynchronous", "network-programming", "filesystem"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.21"
|
||||
tokio-threadpool = { version = "0.1.3", path = "../tokio-threadpool" }
|
||||
tokio-io = { version = "0.1.6", path = "../tokio-io" }
|
||||
tokio-threadpool = "0.1.3"
|
||||
tokio-io = "0.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.6"
|
||||
tempfile = "3"
|
||||
tempdir = "0.3"
|
||||
tokio-io = { version = "0.1.6", path = "../tokio-io" }
|
||||
tokio-codec = { version = "0.1.0", path = "../tokio-codec" }
|
||||
tokio = { version = "0.1.7", path = ".." }
|
||||
tokio-io = "0.1.6"
|
||||
tokio-codec = "0.1.0"
|
||||
tokio = "0.1.7"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
[package]
|
||||
name = "tokio-async-await"
|
||||
name = "tokio-futures"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Update html_root_url.
|
||||
version = "0.1.6"
|
||||
version = "0.1.0"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
documentation = "https://docs.rs/tokio-async-await/0.1.6"
|
||||
documentation = "https://docs.rs/tokio-futures/0.1.0"
|
||||
description = """
|
||||
Experimental async/await support for Tokio
|
||||
Experimental std::future::Future and async/await support for Tokio
|
||||
"""
|
||||
categories = ["asynchronous"]
|
||||
|
||||
@@ -21,9 +21,9 @@ async-await-preview = ["futures/nightly"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.23"
|
||||
tokio-io = { version = "0.1.7", path = "../tokio-io" }
|
||||
tokio-io = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
bytes = "0.4.9"
|
||||
tokio = { version = "0.1.8", path = ".." }
|
||||
hyper = "0.12.8"
|
||||
tokio = { version = "0.1.8", path = "../tokio" }
|
||||
@@ -9,7 +9,7 @@ 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.34.0-nightly or later.
|
||||
1.35.0-nightly or later.
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
@@ -25,9 +25,9 @@ Then, get started. In your application, add:
|
||||
|
||||
```rust
|
||||
// The nightly features that are commonly needed with async / await
|
||||
#![feature(await_macro, async_await, futures_api)]
|
||||
#![feature(await_macro, async_await)]
|
||||
|
||||
// This pulls in the `tokio-async-await` crate. While Rust 2018 doesn't require
|
||||
// This pulls in the `tokio-futures` crate. While Rust 2018 doesn't require
|
||||
// `extern crate`, we need to pull in the macros.
|
||||
#[macro_use]
|
||||
extern crate tokio;
|
||||
@@ -1,22 +1,24 @@
|
||||
//! 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::{Poll as StdPoll, RawWaker, RawWakerVTable, Waker};
|
||||
use std::task::{Context, Poll as StdPoll, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
/// Convert an 0.3 `Future` to an 0.1 `Future`.
|
||||
/// Converts a `std::future::Future` into an 0.1 `Future.
|
||||
#[derive(Debug)]
|
||||
pub struct Compat<T>(Pin<Box<T>>);
|
||||
|
||||
impl<T> Compat<T> {
|
||||
/// Create a new `Compat` backed by `future`.
|
||||
pub fn new(future: T) -> Compat<T> {
|
||||
pub(crate) fn new(future: T) -> Compat<T> {
|
||||
Compat(Box::pin(future))
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a value into one that can be used with `await!`.
|
||||
#[doc(hidden)]
|
||||
pub trait IntoAwaitable {
|
||||
type Awaitable;
|
||||
|
||||
@@ -45,8 +47,9 @@ where
|
||||
use futures::Async::*;
|
||||
|
||||
let waker = noop_waker();
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
let res = self.0.as_mut().poll(&waker);
|
||||
let res = self.0.as_mut().poll(&mut context);
|
||||
|
||||
match res {
|
||||
StdPoll::Ready(Ok(val)) => Ok(Ready(val)),
|
||||
@@ -63,7 +66,7 @@ fn noop_raw_waker() -> RawWaker {
|
||||
}
|
||||
|
||||
fn noop_waker() -> Waker {
|
||||
unsafe { Waker::new_unchecked(noop_raw_waker()) }
|
||||
unsafe { Waker::from_raw(noop_raw_waker()) }
|
||||
}
|
||||
|
||||
unsafe fn clone_raw(_data: *const ()) -> RawWaker {
|
||||
@@ -73,11 +76,11 @@ unsafe fn clone_raw(_data: *const ()) -> RawWaker {
|
||||
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.");
|
||||
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 {
|
||||
clone: clone_raw,
|
||||
drop: drop_raw,
|
||||
wake,
|
||||
};
|
||||
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake, wake, drop_raw);
|
||||
@@ -1,10 +1,12 @@
|
||||
//! 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::{Poll as StdPoll, Waker};
|
||||
use std::task::{Context, Poll as StdPoll};
|
||||
|
||||
/// Converts an 0.1 `Future` into an 0.3 `Future`.
|
||||
/// Converts an 0.1 `Future` into a `std::future::Future`.
|
||||
#[derive(Debug)]
|
||||
pub struct Compat<T>(T);
|
||||
|
||||
@@ -31,7 +33,7 @@ pub(crate) fn convert_poll_stream<T, E>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a value into one that can be used with `await!`.
|
||||
#[doc(hidden)]
|
||||
pub trait IntoAwaitable {
|
||||
type Awaitable;
|
||||
|
||||
@@ -53,7 +55,7 @@ where
|
||||
{
|
||||
type Output = Result<T::Item, T::Error>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &Waker) -> StdPoll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut Context) -> StdPoll<Self::Output> {
|
||||
use futures::Async::{NotReady, Ready};
|
||||
|
||||
// TODO: wire in cx
|
||||
@@ -0,0 +1,42 @@
|
||||
//! Compatibility layer between futures 0.1 and `std`.
|
||||
|
||||
pub mod backward;
|
||||
pub mod forward;
|
||||
|
||||
/// Convert a `std::future::Future` yielding `Result` into an 0.1 `Future`.
|
||||
pub fn into_01<T, Item, Error>(future: T) -> backward::Compat<T>
|
||||
where
|
||||
T: std::future::Future<Output = Result<Item, Error>>,
|
||||
{
|
||||
backward::Compat::new(future)
|
||||
}
|
||||
|
||||
/// Convert a `std::future::Future` into an 0.1 `Future` with unit error.
|
||||
pub fn infallible_into_01<T>(future: T) -> impl futures::Future<Item = T::Output, Error = ()>
|
||||
where
|
||||
T: std::future::Future,
|
||||
{
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub struct Map<T>(T);
|
||||
|
||||
impl<T> Map<T> {
|
||||
fn future<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
|
||||
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::future::Future> std::future::Future for Map<T> {
|
||||
type Output = Result<T::Output, ()>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
match self.future().poll(cx) {
|
||||
Poll::Ready(v) => Poll::Ready(Ok(v)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
into_01(Map(future))
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use tokio_io::AsyncWrite;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Poll, Waker};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// A future used to fully flush an I/O object.
|
||||
#[derive(Debug)]
|
||||
@@ -23,7 +23,7 @@ impl<'a, T: AsyncWrite + ?Sized> Flush<'a, T> {
|
||||
impl<'a, T: AsyncWrite + ?Sized> Future for Flush<'a, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _wx: &Waker) -> Poll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut Context) -> Poll<Self::Output> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
convert_poll(self.writer.poll_flush())
|
||||
}
|
||||
@@ -24,8 +24,8 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -58,8 +58,8 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -77,8 +77,8 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
///
|
||||
/// ## EOF is hit before `buf` is filled
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -109,8 +109,8 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -138,8 +138,8 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -162,8 +162,8 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(async_await, await_macro, futures_api)]
|
||||
/// ```edition2018
|
||||
/// #![feature(async_await, await_macro)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
@@ -25,7 +25,7 @@ impl<'a, T: AsyncRead + ?Sized> Read<'a, T> {
|
||||
impl<'a, T: AsyncRead + ?Sized> Future for Read<'a, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &task::Waker) -> Poll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context) -> Poll<Self::Output> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
|
||||
let this = &mut *self;
|
||||
@@ -30,7 +30,7 @@ fn eof() -> io::Error {
|
||||
impl<'a, T: AsyncRead + ?Sized> Future for ReadExact<'a, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &task::Waker) -> Poll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context) -> Poll<Self::Output> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
|
||||
let this = &mut *self;
|
||||
@@ -25,7 +25,7 @@ impl<'a, T: AsyncWrite + ?Sized> Write<'a, T> {
|
||||
impl<'a, T: AsyncWrite + ?Sized> Future for Write<'a, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &task::Waker) -> Poll<io::Result<usize>> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context) -> Poll<io::Result<usize>> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
|
||||
let this = &mut *self;
|
||||
@@ -30,7 +30,7 @@ fn zero_write() -> io::Error {
|
||||
impl<'a, T: AsyncWrite + ?Sized> Future for WriteAll<'a, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &task::Waker) -> Poll<io::Result<()>> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context) -> Poll<io::Result<()>> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
|
||||
let this = &mut *self;
|
||||
@@ -1,6 +1,6 @@
|
||||
#![cfg(feature = "async-await-preview")]
|
||||
#![feature(rust_2018_preview, async_await, await_macro, futures_api)]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-async-await/0.1.6")]
|
||||
#![feature(await_macro)]
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-futures/0.1.0")]
|
||||
#![deny(missing_docs, missing_debug_implementations)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
|
||||
@@ -27,7 +27,7 @@ impl<'a, T: Sink + Unpin + ?Sized> Send<'a, T> {
|
||||
impl<T: Sink + Unpin + ?Sized> Future for Send<'_, T> {
|
||||
type Output = Result<(), T::SinkError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &task::Waker) -> Poll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut task::Context) -> Poll<Self::Output> {
|
||||
use crate::compat::forward::convert_poll;
|
||||
use futures::AsyncSink::{NotReady, Ready};
|
||||
|
||||
@@ -12,12 +12,12 @@ pub trait StreamExt: Stream {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```edition2018
|
||||
/// #![feature(await_macro, async_await)]
|
||||
/// tokio::run_async(async {
|
||||
/// // The extension trait can also be imported with
|
||||
/// // `use tokio::prelude::*`.
|
||||
/// use tokio::prelude::{stream, StreamExt};
|
||||
/// use tokio::prelude::{stream, StreamAsyncExt};
|
||||
///
|
||||
/// let mut stream = stream::iter_ok::<_, ()>(1..3);
|
||||
///
|
||||
@@ -2,7 +2,7 @@ use futures::Stream;
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Poll, Waker};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// A future of the next element of a stream.
|
||||
#[derive(Debug)]
|
||||
@@ -21,7 +21,7 @@ impl<'a, T: Stream + Unpin> Next<'a, T> {
|
||||
impl<'a, T: Stream + Unpin> Future for Next<'a, T> {
|
||||
type Output = Option<Result<T::Item, T::Error>>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _waker: &Waker) -> Poll<Self::Output> {
|
||||
fn poll(mut self: Pin<&mut Self>, _context: &mut Context) -> Poll<Self::Output> {
|
||||
use crate::compat::forward::convert_poll_stream;
|
||||
|
||||
convert_poll_stream(self.stream.poll())
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "tokio-io"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - Readme.md
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.12"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
@@ -25,4 +25,4 @@ futures = "0.1.18"
|
||||
log = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-current-thread = { version = "0.1.1", path = "../tokio-current-thread" }
|
||||
tokio-current-thread = "0.1.1"
|
||||
|
||||
@@ -186,13 +186,13 @@ where
|
||||
// readable again, at which point the stream is terminated.
|
||||
if self.is_readable {
|
||||
if self.eof {
|
||||
let frame = try!(self.inner.decode_eof(&mut self.buffer));
|
||||
let frame = self.inner.decode_eof(&mut self.buffer)?;
|
||||
return Ok(Async::Ready(frame));
|
||||
}
|
||||
|
||||
trace!("attempting to decode a frame");
|
||||
|
||||
if let Some(frame) = try!(self.inner.decode(&mut self.buffer)) {
|
||||
if let Some(frame) = self.inner.decode(&mut self.buffer)? {
|
||||
trace!("frame decoded from buffer");
|
||||
return Ok(Async::Ready(Some(frame)));
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ where
|
||||
}
|
||||
|
||||
fn close(&mut self) -> Poll<(), Self::SinkError> {
|
||||
Ok(try!(self.inner.close()))
|
||||
Ok(self.inner.close()?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,14 +173,14 @@ where
|
||||
// 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 {
|
||||
try!(self.poll_complete());
|
||||
self.poll_complete()?;
|
||||
|
||||
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
|
||||
return Ok(AsyncSink::NotReady(item));
|
||||
}
|
||||
}
|
||||
|
||||
try!(self.inner.encode(item, &mut self.buffer));
|
||||
self.inner.encode(item, &mut self.buffer)?;
|
||||
|
||||
Ok(AsyncSink::Ready)
|
||||
}
|
||||
@@ -216,7 +216,7 @@ where
|
||||
|
||||
fn close(&mut self) -> Poll<(), Self::SinkError> {
|
||||
try_ready!(self.poll_complete());
|
||||
Ok(try!(self.inner.shutdown()))
|
||||
Ok(self.inner.shutdown()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ pub trait Decoder {
|
||||
/// frames to yield. This behavior enables returning finalization frames
|
||||
/// that may not be based on inbound data.
|
||||
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
match try!(self.decode(buf)) {
|
||||
match self.decode(buf)? {
|
||||
Some(frame) => Ok(Some(frame)),
|
||||
None => {
|
||||
if buf.is_empty() {
|
||||
|
||||
@@ -190,13 +190,13 @@ where
|
||||
// readable again, at which point the stream is terminated.
|
||||
if self.is_readable {
|
||||
if self.eof {
|
||||
let frame = try!(self.inner.decode_eof(&mut self.buffer));
|
||||
let frame = self.inner.decode_eof(&mut self.buffer)?;
|
||||
return Ok(Async::Ready(frame));
|
||||
}
|
||||
|
||||
trace!("attempting to decode a frame");
|
||||
|
||||
if let Some(frame) = try!(self.inner.decode(&mut self.buffer)) {
|
||||
if let Some(frame) = self.inner.decode(&mut self.buffer)? {
|
||||
trace!("frame decoded from buffer");
|
||||
return Ok(Async::Ready(Some(frame)));
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ where
|
||||
}
|
||||
|
||||
fn close(&mut self) -> Poll<(), Self::SinkError> {
|
||||
Ok(try!(self.inner.close()))
|
||||
Ok(self.inner.close()?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,14 +177,14 @@ where
|
||||
// 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 {
|
||||
try!(self.poll_complete());
|
||||
self.poll_complete()?;
|
||||
|
||||
if self.buffer.len() >= BACKPRESSURE_BOUNDARY {
|
||||
return Ok(AsyncSink::NotReady(item));
|
||||
}
|
||||
}
|
||||
|
||||
try!(self.inner.encode(item, &mut self.buffer));
|
||||
self.inner.encode(item, &mut self.buffer)?;
|
||||
|
||||
Ok(AsyncSink::Ready)
|
||||
}
|
||||
@@ -220,7 +220,7 @@ where
|
||||
|
||||
fn close(&mut self) -> Poll<(), Self::SinkError> {
|
||||
try_ready!(self.poll_complete());
|
||||
Ok(try!(self.inner.shutdown()))
|
||||
Ok(self.inner.shutdown()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ impl codec::Decoder for Decoder {
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
|
||||
let n = match self.state {
|
||||
DecodeState::Head => match try!(self.decode_head(src)) {
|
||||
DecodeState::Head => match self.decode_head(src)? {
|
||||
Some(n) => {
|
||||
self.state = DecodeState::Data(n);
|
||||
n
|
||||
@@ -378,7 +378,7 @@ impl codec::Decoder for Decoder {
|
||||
DecodeState::Data(n) => n,
|
||||
};
|
||||
|
||||
match try!(self.decode_data(n, src)) {
|
||||
match self.decode_data(n, src)? {
|
||||
Some(data) => {
|
||||
// Update the decode state
|
||||
self.state = DecodeState::Head;
|
||||
@@ -525,11 +525,11 @@ impl<T: AsyncWrite, B: IntoBuf> Sink for FramedWrite<T, B> {
|
||||
type SinkError = io::Error;
|
||||
|
||||
fn start_send(&mut self, item: B) -> StartSend<B, io::Error> {
|
||||
if !try!(self.do_write()).is_ready() {
|
||||
if !self.do_write()?.is_ready() {
|
||||
return Ok(AsyncSink::NotReady(item));
|
||||
}
|
||||
|
||||
try!(self.set_frame(item.into_buf()));
|
||||
self.set_frame(item.into_buf())?;
|
||||
|
||||
Ok(AsyncSink::Ready)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "tokio-macros"
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.0"
|
||||
authors = ["Tokio Contributors <[email protected]>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
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"
|
||||
quote = "0.6.11"
|
||||
syn = { version = "0.15.27", features = ["full", "extra-traits", "visit-mut"] }
|
||||
@@ -0,0 +1,47 @@
|
||||
Copyright (c) 2019 Tokio Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Yoshua Wuyts
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Tokio Macros
|
||||
|
||||
Procedural macros for use with Tokio
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
|
||||
terms or conditions.
|
||||
@@ -0,0 +1,81 @@
|
||||
#![cfg(feature = "async-await-preview")]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Define the program entry point
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// println!("Hello world");
|
||||
/// }
|
||||
#[proc_macro_attribute]
|
||||
pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
|
||||
let ret = &input.decl.output;
|
||||
let name = &input.ident;
|
||||
let body = &input.block;
|
||||
|
||||
if input.asyncness.is_none() {
|
||||
let tokens = quote_spanned! { input.span() =>
|
||||
compile_error!("the async keyword is missing from the function declaration");
|
||||
};
|
||||
|
||||
return TokenStream::from(tokens);
|
||||
}
|
||||
|
||||
let result = quote! {
|
||||
fn #name() #ret {
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on_async(async { #body })
|
||||
}
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
/// Define a Tokio aware unit test
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #[tokio::test]
|
||||
/// async fn my_test() {
|
||||
/// assert!(true);
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
|
||||
let ret = &input.decl.output;
|
||||
let name = &input.ident;
|
||||
let body = &input.block;
|
||||
let attrs = &input.attrs;
|
||||
|
||||
if input.asyncness.is_none() {
|
||||
let tokens = quote_spanned! { input.span() =>
|
||||
compile_error!("the async keyword is missing from the function declaration");
|
||||
};
|
||||
|
||||
return TokenStream::from(tokens);
|
||||
}
|
||||
|
||||
let result = quote! {
|
||||
#[test]
|
||||
#(#attrs)*
|
||||
fn #name() #ret {
|
||||
let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap();
|
||||
rt.block_on_async(async { #body })
|
||||
}
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "tokio-reactor"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.9"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
@@ -29,11 +29,11 @@ mio = "0.6.14"
|
||||
num_cpus = "1.8.0"
|
||||
parking_lot = "0.7.0"
|
||||
slab = "0.4.0"
|
||||
tokio-executor = { version = "0.1.1", path = "../tokio-executor" }
|
||||
tokio-io = { version = "0.1.6", path = "../tokio-io" }
|
||||
tokio-sync = { version = "0.1.1", path = "../tokio-sync" }
|
||||
tokio-executor = "0.1.1"
|
||||
tokio-io = "0.1.6"
|
||||
tokio-sync = "0.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
num_cpus = "1.8.0"
|
||||
tokio = { version = "0.1.7", path = ".." }
|
||||
tokio = "0.1.7"
|
||||
tokio-io-pool = "0.1.4"
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
# 0.2.9
|
||||
|
||||
### Fixed
|
||||
- `windows::Event` performs internal registrations lazily, so now it can be
|
||||
constructed outside of a running task
|
||||
- remove usage of deprecated `Handle::current` in default `windows::Event`
|
||||
constructors
|
||||
|
||||
# 0.2.8 (March 22, 2019)
|
||||
|
||||
### Fixed
|
||||
- remove usage of deprecated `Handle::current` (#981).
|
||||
|
||||
## 0.2.7 - (November 21, 2018)
|
||||
### Changed
|
||||
* `unix::Signal` now implements `Sync`
|
||||
|
||||
+13
-11
@@ -1,17 +1,19 @@
|
||||
[package]
|
||||
name = "tokio-signal"
|
||||
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Update doc URL.
|
||||
# - Create "v0.2.x" git tag.
|
||||
version = "0.2.7"
|
||||
authors = ["Alex Crichton <[email protected]>"]
|
||||
version = "0.2.8"
|
||||
authors = ["Tokio Contributors <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://github.com/tokio-rs/tokio"
|
||||
documentation = "https://docs.rs/tokio-signal/0.2.7/tokio_signal"
|
||||
documentation = "https://docs.rs/tokio-signal/0.2.8/tokio_signal"
|
||||
description = """
|
||||
An implementation of an asynchronous Unix signal handling backed futures.
|
||||
"""
|
||||
@@ -24,18 +26,18 @@ appveyor = { repository = "carllerche/tokio", id = "s83yxhy9qeb58va7" }
|
||||
[dependencies]
|
||||
futures = "0.1.11"
|
||||
mio = "0.6.14"
|
||||
tokio-reactor = { version = "0.1.0", path = "../tokio-reactor" }
|
||||
tokio-executor = { version = "0.1.0", path = "../tokio-executor" }
|
||||
tokio-io = { version = "0.1", path = "../tokio-io" }
|
||||
tokio-reactor = "0.1.0"
|
||||
tokio-executor = "0.1.0"
|
||||
tokio-io = "0.1"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
mio-uds = "0.6"
|
||||
signal-hook = "0.1"
|
||||
signal-hook-registry = "~1"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "0.1.8", path = ".." }
|
||||
tokio = "0.1.8"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["minwindef", "wincon"]
|
||||
features = ["consoleapi", "minwindef", "wincon"]
|
||||
|
||||
+5
-14
@@ -1,16 +1,8 @@
|
||||
# tokio-signal
|
||||
|
||||
An implementation of Unix signal handling for Tokio
|
||||
Unix signal handling for Tokio.
|
||||
|
||||
[![Travis Build Status][travis-badge]][travis-url]
|
||||
[![Appveyor Build Status][appveyor-badge]][appveyor-url]
|
||||
|
||||
[travis-badge]: https://travis-ci.org/tokio-rs/tokio.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/tokio-rs/tokio
|
||||
[appveyor-badge]: https://ci.appveyor.com/api/projects/status/s83yxhy9qeb58va7/branch/master?svg=true
|
||||
[appveyor-url]: https://ci.appveyor.com/project/carllerche/tokio/branch/master
|
||||
|
||||
[Documentation](https://docs.rs/tokio-signal)
|
||||
[Documentation](https://docs.rs/tokio-signal/0.2.8/tokio_signal)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -18,7 +10,7 @@ First, add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tokio-signal = "0.2"
|
||||
tokio-signal = "0.2.8"
|
||||
```
|
||||
|
||||
Next you can use this in conjunction with the `tokio` and `futures` crates:
|
||||
@@ -46,10 +38,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
# License
|
||||
## License
|
||||
|
||||
This project is licensed the MIT license ([LICENSE](LICENSE) or
|
||||
http://opensource.org/licenses/MIT).
|
||||
This project is licensed under the [MIT license](./LICENSE).
|
||||
|
||||
### Contribution
|
||||
|
||||
|
||||
@@ -53,7 +53,12 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
||||
// Up until now, we haven't really DONE anything, just prepared
|
||||
// now it's time to actually schedule, and thus execute, the stream
|
||||
// on our event loop
|
||||
tokio::runtime::current_thread::block_on_all(future)?;
|
||||
// FIXME(1000): windows uses a global driver task which doesn't terminate
|
||||
// on its own, so if we use block_on_all our application will never exit
|
||||
//tokio::runtime::current_thread::block_on_all(future)?;
|
||||
tokio::runtime::current_thread::Runtime::new()
|
||||
.expect("failed to start runtime on current thread")
|
||||
.block_on(future)?;
|
||||
|
||||
println!("Stream ended, quiting the program.");
|
||||
Ok(())
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-signal/0.2.8")]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! Asynchronous signal handling for Tokio
|
||||
//!
|
||||
//! This crate implements asynchronous signal handling for Tokio, an
|
||||
@@ -67,9 +70,6 @@
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/tokio-signal/0.2.7")]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate mio;
|
||||
extern crate tokio_executor;
|
||||
@@ -102,7 +102,7 @@ pub type IoStream<T> = Box<Stream<Item = T, Error = io::Error> + Send>;
|
||||
/// read up on the documentation in the `unix` or `windows` module to take a
|
||||
/// peek.
|
||||
pub fn ctrl_c() -> IoFuture<IoStream<()>> {
|
||||
ctrl_c_handle(&Handle::current())
|
||||
ctrl_c_handle(&Handle::default())
|
||||
}
|
||||
|
||||
/// Creates a stream which receives "ctrl-c" notifications sent to a process.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
pub extern crate libc;
|
||||
extern crate mio;
|
||||
extern crate mio_uds;
|
||||
extern crate signal_hook;
|
||||
extern crate signal_hook_registry;
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, Error, ErrorKind};
|
||||
@@ -153,7 +153,7 @@ fn action(slot: &SignalInfo, mut sender: &UnixStream) {
|
||||
/// This will register the signal handler if it hasn't already been registered,
|
||||
/// returning any error along the way if that fails.
|
||||
fn signal_enable(signal: c_int) -> io::Result<()> {
|
||||
if signal_hook::FORBIDDEN.contains(&signal) {
|
||||
if signal_hook_registry::FORBIDDEN.contains(&signal) {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Refusing to register signal {}", signal),
|
||||
@@ -168,7 +168,8 @@ fn signal_enable(signal: c_int) -> io::Result<()> {
|
||||
let mut registered = Ok(());
|
||||
siginfo.init.call_once(|| {
|
||||
registered = unsafe {
|
||||
signal_hook::register(signal, move || action(siginfo, &globals.sender)).map(|_| ())
|
||||
signal_hook_registry::register(signal, move || action(siginfo, &globals.sender))
|
||||
.map(|_| ())
|
||||
};
|
||||
if registered.is_ok() {
|
||||
siginfo.initialized.store(true, Ordering::Relaxed);
|
||||
@@ -351,7 +352,7 @@ impl Signal {
|
||||
/// * If the signal is one of
|
||||
/// [`signal_hook::FORBIDDEN`](https://docs.rs/signal-hook/*/signal_hook/fn.register.html#panics)
|
||||
pub fn new(signal: c_int) -> IoFuture<Signal> {
|
||||
Signal::with_handle(signal, &Handle::current())
|
||||
Signal::with_handle(signal, &Handle::default())
|
||||
}
|
||||
|
||||
/// Creates a new stream which will receive notifications when the current
|
||||
@@ -377,11 +378,11 @@ impl Signal {
|
||||
Box::new(future::lazy(move || {
|
||||
let result = (|| {
|
||||
// Turn the signal delivery on once we are ready for it
|
||||
try!(signal_enable(signal));
|
||||
signal_enable(signal)?;
|
||||
|
||||
// Ensure there's a driver for our associated event loop processing
|
||||
// signals.
|
||||
let driver = try!(Driver::new(&handle));
|
||||
let driver = Driver::new(&handle)?;
|
||||
|
||||
// One wakeup in a queue is enough, no need for us to buffer up any
|
||||
// more. NB: channels always guarantee at least one slot per sender,
|
||||
|
||||
+106
-51
@@ -16,21 +16,18 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
use self::winapi::shared::minwindef::*;
|
||||
use self::winapi::um::consoleapi::SetConsoleCtrlHandler;
|
||||
use self::winapi::um::wincon::*;
|
||||
use futures::future;
|
||||
use futures::stream::Fuse;
|
||||
use futures::sync::mpsc;
|
||||
use futures::sync::oneshot;
|
||||
use futures::{Async, Future, IntoFuture, Poll, Stream};
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
use mio::Ready;
|
||||
use tokio_reactor::{Handle, PollEvented};
|
||||
|
||||
use IoFuture;
|
||||
|
||||
extern "system" {
|
||||
fn SetConsoleCtrlHandler(HandlerRoutine: usize, Add: BOOL) -> BOOL;
|
||||
}
|
||||
|
||||
static INIT: Once = ONCE_INIT;
|
||||
static mut GLOBAL_STATE: *mut GlobalState = 0 as *mut _;
|
||||
|
||||
@@ -85,7 +82,7 @@ impl Event {
|
||||
/// This function will register a handler via `SetConsoleCtrlHandler` and
|
||||
/// deliver notifications to the returned stream.
|
||||
pub fn ctrl_c() -> IoFuture<Event> {
|
||||
Event::ctrl_c_handle(&Handle::current())
|
||||
Event::ctrl_c_handle(&Handle::default())
|
||||
}
|
||||
|
||||
/// Creates a new stream listening for the `CTRL_C_EVENT` events.
|
||||
@@ -101,7 +98,7 @@ impl Event {
|
||||
/// This function will register a handler via `SetConsoleCtrlHandler` and
|
||||
/// deliver notifications to the returned stream.
|
||||
pub fn ctrl_break() -> IoFuture<Event> {
|
||||
Event::ctrl_break_handle(&Handle::current())
|
||||
Event::ctrl_break_handle(&Handle::default())
|
||||
}
|
||||
|
||||
/// Creates a new stream listening for the `CTRL_BREAK_EVENT` events.
|
||||
@@ -113,11 +110,17 @@ impl Event {
|
||||
}
|
||||
|
||||
fn new(signum: DWORD, handle: &Handle) -> IoFuture<Event> {
|
||||
let mut init = None;
|
||||
INIT.call_once(|| {
|
||||
init = Some(global_init(handle));
|
||||
});
|
||||
let new_signal = future::lazy(move || {
|
||||
let handle = handle.clone();
|
||||
let new_signal = future::poll_fn(move || {
|
||||
let mut init = None;
|
||||
INIT.call_once(|| {
|
||||
init = Some(global_init(&handle));
|
||||
});
|
||||
|
||||
if let Some(Err(e)) = init {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let msg = Message::NewEvent(signum, tx);
|
||||
let res = unsafe { (*GLOBAL_STATE).tx.clone().unbounded_send(msg) };
|
||||
@@ -125,12 +128,10 @@ impl Event {
|
||||
"failed to request a new signal stream, did the \
|
||||
first event loop go away?",
|
||||
);
|
||||
rx.then(|r| r.unwrap())
|
||||
Ok(Async::Ready(rx.then(|r| r.unwrap())))
|
||||
});
|
||||
match init {
|
||||
Some(init) => Box::new(init.into_future().and_then(|()| new_signal)),
|
||||
None => Box::new(new_signal),
|
||||
}
|
||||
|
||||
Box::new(new_signal.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +146,7 @@ impl Stream for Event {
|
||||
self.reg.clear_read_ready(Ready::readable())?;
|
||||
self.reg
|
||||
.get_ref()
|
||||
.inner
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.1
|
||||
.readiness
|
||||
.set_readiness(mio::Ready::empty())
|
||||
.expect("failed to set readiness");
|
||||
Ok(Async::Ready(Some(())))
|
||||
@@ -157,12 +154,12 @@ impl Stream for Event {
|
||||
}
|
||||
|
||||
fn global_init(handle: &Handle) -> io::Result<()> {
|
||||
let reg = MyRegistration::new();
|
||||
let ready = reg.readiness.clone();
|
||||
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
let reg = MyRegistration {
|
||||
inner: RefCell::new(None),
|
||||
};
|
||||
let reg = try!(PollEvented::new_with_handle(reg, handle));
|
||||
let ready = reg.get_ref().inner.borrow().as_ref().unwrap().1.clone();
|
||||
|
||||
unsafe {
|
||||
let state = Box::new(GlobalState {
|
||||
ready: ready,
|
||||
@@ -176,7 +173,7 @@ fn global_init(handle: &Handle) -> io::Result<()> {
|
||||
});
|
||||
GLOBAL_STATE = Box::into_raw(state);
|
||||
|
||||
let rc = SetConsoleCtrlHandler(handler as usize, TRUE);
|
||||
let rc = SetConsoleCtrlHandler(Some(handler), TRUE);
|
||||
if rc == 0 {
|
||||
Box::from_raw(GLOBAL_STATE);
|
||||
GLOBAL_STATE = 0 as *mut _;
|
||||
@@ -238,9 +235,9 @@ impl DriverTask {
|
||||
|
||||
// Acquire the (registration, set_readiness) pair by... assuming
|
||||
// we're on the event loop (true because of the spawn above).
|
||||
let reg = MyRegistration {
|
||||
inner: RefCell::new(None),
|
||||
};
|
||||
let reg = MyRegistration::new();
|
||||
let ready = reg.readiness.clone();
|
||||
|
||||
let reg = match PollEvented::new_with_handle(reg, &self.handle) {
|
||||
Ok(reg) => reg,
|
||||
Err(e) => {
|
||||
@@ -252,7 +249,6 @@ impl DriverTask {
|
||||
// Create the `Event` to pass back and then also keep a handle to
|
||||
// the `SetReadiness` for ourselves internally.
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let ready = reg.get_ref().inner.borrow_mut().as_mut().unwrap().1.clone();
|
||||
drop(complete.send(Ok(Event {
|
||||
reg: reg,
|
||||
_finished: tx,
|
||||
@@ -268,13 +264,9 @@ impl DriverTask {
|
||||
self.reg.clear_read_ready(Ready::readable())?;
|
||||
self.reg
|
||||
.get_ref()
|
||||
.inner
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.1
|
||||
.readiness
|
||||
.set_readiness(mio::Ready::empty())
|
||||
.unwrap();
|
||||
.expect("failed to set readiness");
|
||||
|
||||
if unsafe { (*GLOBAL_STATE).ctrl_c.ready.swap(false, Ordering::SeqCst) } {
|
||||
for task in self.ctrl_c.tasks.iter() {
|
||||
@@ -305,15 +297,27 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
|
||||
FALSE
|
||||
} else {
|
||||
drop((*GLOBAL_STATE).ready.set_readiness(mio::Ready::readable()));
|
||||
// TODO: this will report that we handled a CTRL_BREAK_EVENT when in
|
||||
// fact we may not have any streams actually created for that
|
||||
// TODO(1000): this will report that we handled a CTRL_BREAK_EVENT when
|
||||
// in fact we may not have any streams actually created for that
|
||||
// event.
|
||||
TRUE
|
||||
}
|
||||
}
|
||||
|
||||
struct MyRegistration {
|
||||
inner: RefCell<Option<(mio::Registration, mio::SetReadiness)>>,
|
||||
registration: mio::Registration,
|
||||
readiness: mio::SetReadiness,
|
||||
}
|
||||
|
||||
impl MyRegistration {
|
||||
fn new() -> Self {
|
||||
let (registration, readiness) = mio::Registration::new2();
|
||||
|
||||
Self {
|
||||
registration,
|
||||
readiness,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mio::Evented for MyRegistration {
|
||||
@@ -324,23 +328,74 @@ impl mio::Evented for MyRegistration {
|
||||
events: mio::Ready,
|
||||
opts: mio::PollOpt,
|
||||
) -> io::Result<()> {
|
||||
let reg = mio::Registration::new2();
|
||||
reg.0.register(poll, token, events, opts)?;
|
||||
*self.inner.borrow_mut() = Some(reg);
|
||||
Ok(())
|
||||
self.registration.register(poll, token, events, opts)
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
_poll: &mio::Poll,
|
||||
_token: mio::Token,
|
||||
_events: mio::Ready,
|
||||
_opts: mio::PollOpt,
|
||||
poll: &mio::Poll,
|
||||
token: mio::Token,
|
||||
events: mio::Ready,
|
||||
opts: mio::PollOpt,
|
||||
) -> io::Result<()> {
|
||||
Ok(())
|
||||
self.registration.reregister(poll, token, events, opts)
|
||||
}
|
||||
|
||||
fn deregister(&self, _poll: &mio::Poll) -> io::Result<()> {
|
||||
Ok(())
|
||||
fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
|
||||
mio::Evented::deregister(&self.registration, poll)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tokio;
|
||||
|
||||
use self::tokio::runtime::current_thread;
|
||||
use self::tokio::timer::Timeout;
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
fn with_timeout<F: Future>(future: F) -> impl Future<Item = F::Item, Error = F::Error> {
|
||||
Timeout::new(future, Duration::from_secs(1)).map_err(|e| {
|
||||
if e.is_timer() {
|
||||
panic!("failed to register timer");
|
||||
} else if e.is_elapsed() {
|
||||
panic!("timed out")
|
||||
} else {
|
||||
e.into_inner().expect("missing inner error")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ctrl_c_and_ctrl_break() {
|
||||
// FIXME(1000): combining into one test due to a restriction where the
|
||||
// first event loop cannot go away
|
||||
let mut rt = current_thread::Runtime::new().unwrap();
|
||||
let event_ctrl_c = rt
|
||||
.block_on(with_timeout(Event::ctrl_c()))
|
||||
.expect("failed to run future");
|
||||
|
||||
// Windows doesn't have a good programmatic way of sending events
|
||||
// like sending signals on Unix, so we'll stub out the actual OS
|
||||
// integration and test that our handling works.
|
||||
unsafe {
|
||||
super::handler(CTRL_C_EVENT);
|
||||
}
|
||||
|
||||
rt.block_on(with_timeout(event_ctrl_c.into_future()))
|
||||
.ok()
|
||||
.expect("failed to run event");
|
||||
|
||||
let event_ctrl_break = rt
|
||||
.block_on(with_timeout(Event::ctrl_break()))
|
||||
.expect("failed to run future");
|
||||
unsafe {
|
||||
super::handler(CTRL_BREAK_EVENT);
|
||||
}
|
||||
|
||||
rt.block_on(with_timeout(event_ctrl_break.into_future()))
|
||||
.ok()
|
||||
.expect("failed to run event");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
# 0.1.5 (April 22, 2019)
|
||||
|
||||
### Added
|
||||
- Add asynchronous mutual exclusion primitive (#964).
|
||||
|
||||
# 0.1.4 (March 13, 2019)
|
||||
|
||||
### Fixed
|
||||
- Fix memory leak on channel drop (#917).
|
||||
|
||||
### Added
|
||||
- `std::error::Error` implementation for `oneshot`, `watch` error types (#967).
|
||||
|
||||
# 0.1.3 (March 1, 2019)
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
[package]
|
||||
name = "tokio-sync"
|
||||
# When releasing to crates.io:
|
||||
# - Remove path dependencies
|
||||
# - Update html_root_url.
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
authors = ["Carl Lerche <[email protected]>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tokio"
|
||||
homepage = "https://tokio.rs"
|
||||
documentation = "https://docs.rs/tokio-sync/0.1.3/tokio_sync"
|
||||
documentation = "https://docs.rs/tokio-sync/0.1.5/tokio_sync"
|
||||
description = """
|
||||
Synchronization utilities.
|
||||
"""
|
||||
@@ -24,6 +25,6 @@ futures = "0.1.19"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { version = "0.5", default-features = false }
|
||||
tokio = { version = "0.1.15", path = ".." }
|
||||
tokio = { version = "0.1.15", path = "../tokio" }
|
||||
tokio-mock-task = "0.1.1"
|
||||
loom = { version = "0.1.1", features = ["futures"] }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user