Compare commits

...
Author SHA1 Message Date
Carl Lerche 01052f930a Bump tokio version to v0.1.21. (#1113) 2019-05-30 14:39:30 -07:00
Lucio Franco 940f2c3431 Update tokio-trace-core to 0.2 (#1111)
Also includes 1b498e8aa2
2019-05-30 11:33:55 -07:00
Carl Lerche 475dabe96d Release tokio v0.1.20, tokio-timer v0.2.21, and remove async-await-preview feature. (#1089)
The `async-await-preview` feature is removed as 0.1 will no longer track
Rust nightly.

This also bumps:
- tokio-timer (0.2.11).
2019-05-14 11:21:24 -07:00
Carl Lerche 951f2fd910 test: re-export macro dependencies (#1077)
Callers may not always have `futures` available at the root of the
crate. Re-exporting dependencies makes them available to the macro at a
deterministic location.
2019-05-03 20:43:40 -07:00
Carl Lerche 4ef736b9d5 async-await: add current_thread::Runtime::block_on_async (#1072)
This function is used by the Tokio macros introduced by #1058  but was
omitted from the PR.
2019-04-30 19:55:22 -07:00
Steven Fackler 219f24cbf1 timer: Replace Handle::deadline with Handle::timeout (#1074)
Deadline was deprecated a while ago and replaced with Timeout, but the
methods on Handle got missed.

Fixes #1071
2019-04-30 10:29:54 -07:00
Carl Lerche ea282efb2e ci: fix isRelease condition (#1066) 2019-04-29 10:37:00 -07:00
Michal 'vorner' Vaner 042224d33c signal: Smaller dependency (#1069)
The signal-hook library got split into lower-level and higher-level
parts. The tokio-signal uses only API from the lower-level one, so it
can depend on it directly.

The only effect of this change is smaller amount of compiled (and
unused) code during compilation. There's no change in the code actually
used.
2019-04-28 19:12:40 -07:00
Ian Hamlin 927eb80ad4 Fix an error in the mit-url in the README.md (#1068) 2019-04-27 12:56:40 -07:00
Carl Lerche 6a8934e897 Fix threadpool dependency (#1061) 2019-04-25 22:23:24 -04:00
Carl Lerche 0e400af78c Async/await polish (#1058)
A general refresh of Tokio's experimental async / await support.
2019-04-25 22:22:32 -04:00
Carl Lerche df702130d6 tcp: fix some tests that spuriously fail (#1060)
This does not remove all cases of using a fixed port in doc tests, but
removing some should reduce the likelihood of spurious failures.
2019-04-25 12:01:39 -07:00
Carl Lerche 949adbb887 chore: remember to remove path deps on release (#1057) 2019-04-24 10:42:39 -07:00
Ryan Dahl b2b796a228 rt: forward panic_handler to tokio::runtime::Builder (#1055) 2019-04-24 10:41:42 -07:00
Igor Gnatenko abb014efc2 tokio: Bump min version of tokio-sync (#1054)
It is needed for lock functionality which tokio now uses.
2019-04-24 08:24:59 -07:00
Lucio Franco e5cf0cc717 Introduce tokio-test crate (#1030) 2019-04-23 20:17:57 -07:00
Carl Lerche 62f34e15ce Bump tokio to 0.1.19. (#1053)
This also bumps:

- tokio-async-await (0.1.7)
- tokio-buf (0.1.1)
- tokio-sync (0.1.5)
- tokio-threadpool (0.1.14)
2019-04-22 15:12:25 -07:00
Eliza Weisman 3ebca76a9a trace: prepare tokio-trace for release (#1051) 2019-04-22 14:15:07 -07:00
Ryan Dahl fea1f780bc threadpool: add panic_handler (#1052) 2019-04-21 16:26:09 -07:00
Eliza Weisman 712ca84033 trace-core: prepare for 0.2 release (#1047) 2019-04-21 10:20:28 -07:00
Jon Gjengset cf06621998 tokio-sync: Add async mutual exclusion primitive (#964)
This PR introduces `Lock`: A concurrency primitive built on top of `Semaphore` that provides a `Mutex`-like primitive that interacts nicely with futures. Specifically, `LockGuard` (in contrast to `MutexGuard`) does _not_ borrow the `Lock`, and can thus be passed into a future where it will later be unlocked.

This replaces #958, which attempted to introduce a less generic version. The primitive proposed there will instead live in [`async-lease`](https://github.com/jonhoo/async-lease).
2019-04-18 13:16:26 -04:00
Lucio Franco 7e51ab05e9 buf: Add IntoStream (#1048)
* buf: Add IntoStream

* Add debug implementation for IntoStream

* Add get_ref, get_mut and into_inner
2019-04-18 11:42:34 -04:00
Eliza Weisman 4bfa4ffcdf trace-core: Dispatchers unset themselves (#1033)
This branch changes `dispatcher::get_default` to unset the thread's
current dispatcher while the reference to it is held by the closure.
This prevents infinite loops if the subscriber calls code paths which
emit events or construct spans. 

Note that this also means that nested calls to `get_default` inside of a
`get_default` closure will receive a `None` dispatcher rather than the
"actual" dispatcher. However, it was necessary to unset the default in
`get_default` rather than in dispatch methods such as `Dispatch::enter`,
as when those functions are called, the current state has already been
borrowed.

Before:
```
test enter_span              ... bench:           3 ns/iter (+/- 0)
test span_no_fields          ... bench:          51 ns/iter (+/- 12)
test span_repeatedly         ... bench:       5,073 ns/iter (+/- 1,528)
test span_with_fields        ... bench:          56 ns/iter (+/- 49)
test span_with_fields_record ... bench:         363 ns/iter (+/- 61)
```

After:
```
test enter_span              ... bench:           3 ns/iter (+/- 0)
test span_no_fields          ... bench:          35 ns/iter (+/- 12)
test span_repeatedly         ... bench:       4,165 ns/iter (+/- 298)
test span_with_fields        ... bench:          48 ns/iter (+/- 12)
test span_with_fields_record ... bench:         363 ns/iter (+/- 91)
```

Closes #1032 

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-16 15:51:45 -07:00
Taiki Endo 88b942652c async-await: fix examples (#1050)
* Fix crate path in `Cargo.toml` of examples
* Add `edition2018` to examples in the documentation to make it compiled
  on Rust 2018
* Fix an example in the documentation
2019-04-16 14:19:38 -04:00
Taiki Endo 5029e80a89 async-await: update to new futures_api (#1049) 2019-04-16 14:07:03 -04:00
Eliza Weismanandcsmoe 847fb59b17 trace-core: Introduce callsite classification in metadata (#1046)
## Motivation

To ease the implementation of `Subscriber::register_callsite`, a field
should be added to `Metadata` to indicate if this callsite is an event or
a span.

## Solution

A new struct, `Kind`, is added to the `metadata` module in
`tokio-trace-core`, and a `Kind` field is added to the `Metadata`
struct. Macros which construct `metadata` now require a `Kind`.

`Kind` is represented as a struct with a private inner enum to allow new
`Kind`s to be added without breaking changes. However, the _addition_ of
the kind field _is_ a breaking change. While this could be done in a
backward-compatible way, it would permit the construction of metadata
with unknown kinds, and since the next `tokio-trace-core` release will
be a breaking change, I opted to make the breaking change instead.

New API tests for the `callsite!` and `metadata!` macros have been added
to guard against future API breakage.

Fixes: #986
Closes: #1008

Co-Authored-By: csmoe <[email protected]>
2019-04-11 11:56:42 -07:00
Jane Lusby b4fe517a16 trace-core: add a function to rebuild cached interest (#1039)
## Motivation

Currently, `tokio-trace-core` permits `Subscriber`s to indicate that
they are "always", "sometimes", or "never" interested in a particular
callsite. When "always" or "never" is returned, then the interest is
cached and the subscriber will not be asked again about that callsite.
This is much more efficient than requiring the filter to be re-evaluated
every time the callsite is hit.

However, if a subscriber wishes to change its filter configuration
dynamically at runtime, it cannot benefit from this caching. Instead, it
must always return `Interest::sometimes`.  Even when filters change very
infrequently, they must still always be re-evaluated every time.

In order to support a use-case where subscribers may change their filter
configuration at runtime (e.g. tokio-rs/tokio-trace-nursery#42),
but do so infrequently, we should introducing a new function to
invalidate the cached interest.

## Solution

This branch adds a new function in the `callsite` module, called
`rebuild_interest_cache`, that will invalidate and rebuild all cached
interest.

## Breaking Change

In order to fix a race condition that could occur when rebuilding
interest caches using `clear_interest` and `add_interest`, these methods
have been replaced by a new `set_interest` method. `set_interest` should
have the semantics of atomically replacing the previous cached interest,
so that the callsite does not enter a temporary state where it has no
interest.

Closes #1038

Co-Authored-By: yaahallo <[email protected]>
2019-04-10 13:51:05 -07:00
Simon Wollwage 7ae010f0f3 async-await: Use Context instead of Waker in poll (#1041)
Rust nightly std::future::Future recently changed Waker
to Context.

Change to use Context

Co-Authored-By: Kintaro <[email protected]>
2019-04-10 09:14:31 -07:00
Carl Lerche 9144b2ff53 sync: remove unnecessary imports (#1043) 2019-04-09 12:26:11 -07:00
Lev Eniseev 2c4549a18a Add example of blocking environment (#1036) 2019-04-09 12:10:15 -07:00
João Oliveira 4f819b7cd1 trace: fix counters example, Span IDs must be greater than zero (#1037)
## Motivation
tokio-trace counter example was panicking due to returning 0 as the first Span Id

## Solution
start ID's with 1 instead
2019-04-05 13:51:20 -07:00
Eliza Weisman 197f88f3bc trace: Change Span::enter and record to take &self (#1029)
## Motivation

The `Span::enter` function previously required an `&mut` reference to
enter a span. This is a relic of an earlier design where span closure
logic was determined by dropping an inner span component, and is no
longer strictly necessary.

Requiring `&mut self` to enter a span leads to awkward patterns in cases
when a user wishes to enter a span and then call methods on the span
(such as recording field values). For example, we cannot say
```rust
let mut span = span!("foo", bar);
span.enter(|| {
    span.record("bar" &false);
});
```
since the span is mutably borrowed by `enter`. Instead, we must clone
the span, like so:
```rust
let mut span = span!("foo", bar);
span.clone().enter(|| {
    span.record("bar" &false);
});
```

Having to clone the span is somewhat less ergonomic, and it has
performance disadvantages as well: cloning a `Span` will clone the
span's `Dispatch` handle, requiring an `Arc` bump, as well as calling
the `Subscriber`'s `clone_span` and `drop_span` functions. If we can
enter spans without a mutable borrow, we don't have to update any of
these ref counts.

The other reason we may wish to require mutable borrows to enter a span
is if we want to disallow entering a span multiple times before exiting
it. However, it is trivially possible to re-enter a span on the same
thread regardless, by cloning the span and entering it twice. Besides,
there may be a valuable semantic meaning in entering a span from inside
itself, such as when a function is called recursively, so disallowing
this is not a goal.

## Solution

This branch rewrites the `Span::enter`, `Span::record`, and
`Span::record_all` functions to no longer require mutable borrows. 

In the case of `record` and `record_all`, this was trivial, as borrowing
mutably was not actually *necessary* for those functions. For `enter`,
the `Entered` guard type was reworked to consist of an `&'a Inner`
rather than an `Inner`, so it is no longer necessary to `take` the
span's `Inner`. 

## Notes

In addition to allowing spans to be entered without mutable borrows,
`Entered` was changed to exit the span automatically when the guard is
dropped, so we may now observe correct span exits even when unwinding.

Furthermore, this allows us to simplify the `enter` function a bit,
leading to a minor performance improvement when entering spans.

Before:
```
test enter_span              ... bench:          13 ns/iter (+/- 1)
```

...and after:
```
test enter_span              ... bench:           3 ns/iter (+/- 1)
```

Note that this branch also contains a change to make the
`subscriber::enter_span` benchmark more accurate. Previously, this
benchmark constructed a new span inside of `b.iter(|| {...})`. This
means that the benchmark was measuring not only the time taken to enter
a span, but the time taken to construct a `Span` handle as well.
However, we already have benchmarks for span construction, and the
intention of this particular benchmark was to measure the overhead of
constructing a span.

I've updated the benchmark by moving the span construction out of the
`iter` closure. Now, the span is constructed a single time and entered
on every iteration. This allows us to measure only the overhead of
actually entering a span. The "before" benchmark numbers above were
recorded after backporting this change to master, so they are "fair" to
the previous implementation. Prior to this change the benchmark took
approximately 53 ns.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-03 15:06:47 -07:00
Eliza Weisman 44f65afcc6 trace: Allow field names to be separated by .s (#1027)
## Motivation

In order to support conventions that add namespacing to `tokio-trace`
field names, it's necessary to accept at least one type of separator
character. Currently, the `tokio-trace` macros only accept valid Rust
identifiers, so there is no clear separator character for namespaced
conventions. See also #1018.

## Solution

This branch changes the single `ident` fragment matcher for field names
to match *one or more* `ident` fragments separated by `.` characters.

## Notes

The resulting key is still exposed to `tokio-trace-core` as a string
constant created by stringifying the dotted expression. However, if
`tokio-trace-core` were later to adopt a first class notion of
hierarchical field keys, we would be able to track that change in
`tokio-trace` as an implementation detail.

Closes #1018.
Closes #1022.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-03 14:44:11 -07:00
Eliza Weisman 4271a9cd8d trace: Fix subscriber benchmarks panicking (#1028)
This branch fixes the `tokio-trace` Subscriber benchmarks panicking due
to constructing spans with ID 0. They will now use an arbitrary constant
instead.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-02 13:42:31 -07:00
Matthias Prechtl 9d8096b911 Improve documentation of Subscriber::record and Subscriber::event (#1026) 2019-04-02 12:44:01 -07:00
João Oliveira 597f271c08 trace: Remove default trace level and make levels mandatory on span! macro (#1025)
## Motivation 

Was determined that having the span! macro default to the TRACE level is
probably not ideal (see discussion on #952). 

Closes #1013

## Solution 

Remove default trace level and make log lvl mandatory on span! macro,
and add the respective `trace_span!`, `debug_span!`, `info_span!`,
`warn_span!` and `error_span!` macros that behave as span! macro, but
with defined log levels

## Notes 

I think this is it, also removed some captures that were repeated, and
some testcases that also seemed repeated after adding the mandatory log
level, but please review it, if more tests or examples are needed happy
to provide (tried to find a way to get the generated macros log level,
but didn't find one, if there is a way i can add tests to assert that
the generated macro has the matching log level ). thanks
2019-04-02 11:29:23 -07:00
Taiki Endo 599955f716 Replace try! macro with ? operator (#1024) 2019-04-01 13:45:59 -07:00
Ivan Petkov 91bb0f73f5 signal: refactor Windows registrations to be lazy (#1001)
- Use `Handle::default` over `Handle::current` for consistent semantics
- Make all `windows::Event` constructors lazily invoke `global_init`
  so they can be safely constructed off-task
- Don't assume the reactor is alive and event registration will be done
  when calling `global_init`

Add windows regression tests. Unfortunately, Windows doesn't have a
reliable way of programmatically sending CTRL_C or CTRL_BREAK events
to a progress, so the tests can only exercise our internal machinery by
invoking the handler that we register with the OS

Fixes #999
2019-04-01 12:46:22 -07:00
Eliza Weisman 6c9d8abba9 trace: Make Span API functions taking IDs a little more flexible (#1021)
This branch modifies the `tokio_trace::Span` API functions that take
span IDs (the `Span::child_of` constructor, and the `Span::follows_from`
method) so that more types bearing a span ID can be passed as an
argument. Span IDs may now be passed directly without requiring them to
be passed as `Some(id)`. This should make the API slightly more
ergonomic.

Also, it changes the `Span::field` method to take an `AsField` rather
than a `Borrow<str>`.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-01 11:42:29 -07:00
Carl Lerche 824b7b6759 buf: stream and iter helpers (#1011) 2019-03-29 12:26:13 -07:00
Carl Lerche cb91dd274a buf: impl Error for CollectVecError (#1010) 2019-03-29 08:49:08 -07:00
Eliza Weisman ea7178b8c6 trace-core: Add slightly more useful debug impls (#1014)
This branch improves the `fmt::Debug` implementation for `Metadata`,
and adds `fmt::Display` implementations for `FieldSet` and `ValueSet`.

When formatting a `Metadata`, only present fields are formatted --- if
optional fields, such as the file, line number, and module path are
`None`, they will be excluded. In addition, `Metadata` now formats its
`FieldSet` using `FieldSet`'s `fmt::Display` implementation, which is a
bit less noisy. Finally, the `Debug` output for `Metadata` now includes
the callsite that the metadata originates from.

The intention behind these changes is to make the output from failed
tests somewhat easier to interpret.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-28 14:47:06 -07:00
Carl Lerche a99b8e2e0b buf: impl size_hint for str types + reorg tests (#1012) 2019-03-28 14:02:45 -07:00
Carl Lerche 03859a7dcd buf: implement FromBufStream for Bytes (#1009) 2019-03-27 19:22:06 -07:00
Eliza Weisman d8177f81ac trace: Allow trace instrumentation to emit log records (#992)
## Motivation

`tokio-trace` currently offers a strategy for compatibility with the
`log` crate: its macros can be dropped in as a replacement for `log`'s
macros, and a subscriber can be used that translates trace events to log
records. However, this requires the application to be aware of
`tokio-trace` and manually set up this subscriber.

Many libraries currently emit `log` records, and would like to be able
to emit `tokio-trace` instrumentation instead. The `tokio` runtimes are
one such example. However, with the current log compatibility strategy,
replacing existing logging with trace instrumentation would break
`tokio`'s logs for any downstream user which is using only `log` and not
`tokio-trace`. It is desirable for libraries to have the option to emit
both `log` _and_ `tokio-trace` diagnostics from the same instrumentation
points.

## Solution

This branch adds a `log` feature flag to the `tokio-trace` crate, which
when set, causes `tokio-trace` instrumentation to emit log records as well
as `tokio-trace` instrumentation. 

## Notes

In order to allow spans to log their names when they are entered and 
exited even when the span is disabled, this branch adds an 
`&'static Metadata` to the `Span` type. This was previously stored in
the `Inner` type and was thus only present when the span was enabled.
This makes disabled spans one word longer, but enabled spans remain
the same size.

Fixes: #949

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-26 16:43:05 -07:00
Son ceca2a3cd6 chore: add license to tokio (#1006) 2019-03-26 08:41:41 -07:00
Son 1524ee4b60 trace: Add static level filtering (#987)
## Motivation

`tokio-trace` should have static verbosity level filtering, like the
`log` crate. The static max verbosity level should be controlled at
compile time with a set of features. It should be possible to set a
separate max level for release and debug mode builds.

## Solution

We can do this fairly similarly to how the `log` crate does it:
`tokio-trace` should export a constant whose value is set based on the
static max level feature flags. Then, we add an if statement to the
`span!` and `event!` macros which tests if that event or span's level
is enabled.

Closes #959
2019-03-25 15:19:20 -07:00
MOZGIII 7793d63739 Corrected doc for tokio_buf SizeHint (#1003) 2019-03-25 16:54:49 -04:00
Red Hara e0e26bc223 Fix typo in README.md in examples (#1002) 2019-03-24 13:02:11 -04:00
Eliza Weisman 9c5cad037f trace-core: Add overrideable downcasting to Subscribers (#974)
## Motivation

In order to implement "out of band" `Subscriber` APIs in third-party
subscriber implementations (see [this comment]) users may want to 
downcast the current `Dispatch` to a concrete subscriber type.

For example, in a library for integrating `tokio-trace` with a fancy new
(hypothetical) distributed tracing technology "ElizaTracing", which uses
256-bit span IDs, we might expect to see a function like this:
```rust

pub fn correlate(tt: tokio_trace::span::Id, et: elizatracing::SpanId) {
    tokio_trace::dispatcher::with(|c| {
        if let Some(s) = c.downcast_ref::<elizatracing::Subscriber>() {
            s.do_elizatracing_correlation_magic(tt, et);
        }
    }); 
}
```

This allows users to correlate `tokio-trace` IDs with IDs in the
distributed tracing system without having to pass a special handle to
the subscriber through application code (as one is already present in
thread-local storage, but with its type erased).

## Solution

This branch makes the following changes:
 * Add an object-safe `downcast_raw` method to the `Subscriber` trait,
   taking a `TypeId` and returning an `*const ()` if the type ID 
   matches the subscriber's type ID, or `None` if it does not, and
 * Add `is<T>` and `downcast_ref<T>` functions to `Subscriber` 
   and `Dispatch`, using `downcast_raw`.

Unlike the approach implemented in #950, the `downcast_raw` method is
object-safe, since it takes a `TypeId` rather than a type _parameter_ 
and returns a void pointer rather than an `&T`. This means that
`Subscriber` implementations can override this method if necessary. For
example, a `Subscriber` that fans out to multiple component subscribers
can downcast to their component parts, and "chained" or "middleware"
subscribers, which wrap an inner `Subscriber` and modify its behaviour 
somehow, can downcast to the inner type if they choose to.

[this comment]: https://github.com/tokio-rs/tokio/issues/932#issuecomment-469473501
[`std::error::Error`'s]: https://doc.rust-lang.org/1.33.0/src/std/error.rs.html#204

Refs: #950, #953, https://github.com/tokio-rs/tokio/issues/948#issuecomment-469444293

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-22 16:21:46 -07:00
Eliza Weisman 30330da11a chore: Fix examples not working with cargo run (#998)
* chore: Fix examples not working with `cargo run`

## Motivation

PR #991 moved the `tokio` crate to its own subdirectory, but did not
move the `examples` directory into `tokio/examples`. While attempting to
use the examples for testing another change, I noticed that #991 had
broken the ability to use `cargo run`, as the examples were no longer
considered part of a crate that cargo was aware of:

```
tokio on master [$] via 🦀v1.33.0 at ☸️ aks-eliza-dev
➜  cargo run --example chat
error: no example target named `chat`

Did you mean `echo`?
```

## Solution

This branch moves the examples into the `tokio` directory, so cargo is
now once again aware of them:

```
tokio on eliza/fix-examples [$] via 🦀v1.33.0 at ☸️ aks-eliza-dev
➜  cargo run --example chat
   Compiling tokio-executor v0.1.7 (/Users/eliza/Code/tokio/tokio-executor)
   Compiling tokio-reactor v0.1.9
   Compiling tokio-threadpool v0.1.13
   Compiling tokio-current-thread v0.1.6
   Compiling tokio-timer v0.2.10
   Compiling tokio-uds v0.2.5
   Compiling tokio-udp v0.1.3
   Compiling tokio-tcp v0.1.3
   Compiling tokio-fs v0.1.6
   Compiling tokio v0.1.18 (/Users/eliza/Code/tokio/tokio)
    Finished dev [unoptimized + debuginfo] target(s) in 7.04s
     Running `target/debug/examples/chat`
server running on localhost:6142
```

Signed-off-by: Eliza Weisman <[email protected]>

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-22 15:25:42 -07:00
Carl Lerche 6e4945025c chore: fix Cargo.toml files 2019-03-22 14:10:06 -07:00
Carl Lerche 3c8f110730 Bump Tokio version to v0.1.18 (#997)
Also bumps:

- tokio-signal (0.2.8)
- tokio-current-thread (0.1.6)
- tokio-executor (0.1.7)
- tokio-threadpool (0.1.13)

[ci-release]
2019-03-22 13:55:48 -07:00
Carl Lerche 678f15bd48 ci: skip crates.io dep run when releasing (#995)
#993 introduces changes in a sub crate that other Tokio crates depend
on. To make CI pass, a `[patch]` statement and `path` dependencies are
used.

When releasing, these must be removed. However, the commit that
removes them and prepares the crates for release will not be able to
pass CI.

This commit adds a conditional on a special `[ci-release]` snippet in
the commit message. If this exists, CI is only run with the full "patched"
dependencies.
2019-03-22 11:58:00 -07:00
Carl Lerche b1172f8074 executor: add TypedExecutor (#993)
Adds a `TypedExecutor` trait that describes how to spawn futures of a specific
type. This is useful for implementing functions that are generic over an executor
and wish to support both `Send` and `!Send` cases.
2019-03-21 14:30:18 -07:00
Carl Lerche cdde2e7a27 chore: repo maintenance + no path dependencies (#991)
- Move `tokio` into its own directory.
- Remove `path` dependencies.
- Run tests with once with crates.io dep and once with patched dep.
2019-03-19 14:58:59 -07:00
Eliza Weisman 85487727d4 trace: Span API polish (#988)
This branch makes the following changes to `tokio-trace`'s `Span` type:

* **Remove manual close API from spans**
  In practice, there wasn't really a use-case for this, and it 
  complicates the implementation a bit. We can always add it back later.

* **Remove generic lifetime from `Span`**
  Again, there wasn't actually a use-case for spans with metadata that
  doesn't live for the static lifetime, and it made using `Span`s in 
  other types somewhat inconvenient. It's also possible to implement an
  alternative API for non-static spans on top of the `tokio-trace-core`
  primitives.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-18 12:44:46 -07:00
Lucio Franco 92d51202ef trace: Remove git dep on trace core for crates version (#984) 2019-03-13 15:07:47 -04:00
Lucio Franco cb55bf4012 signal: Fix deprecated use of Handle::current (#981) 2019-03-13 11:56:25 -07:00
Carl Lerche 987ccfc8ac Bump Tokio to v0.1.17 (#983)
Also bumps:
- tokio-sync (v0.1.4)
2019-03-13 11:19:22 -07:00
Sean McArthur 1bc6d75543 sync: add mpsc benchmarks of small, medium, and large message types (#982) 2019-03-13 11:00:42 -07:00
Sean McArthur 27148d6110 sync: free chan Blocks when Chan is dropped (#978) 2019-03-13 10:38:14 -07:00
Carl Lerche a1871b1480 Prepare tokio-trace-core for initial release. (#979) 2019-03-13 10:29:27 -07:00
Eliza Weisman acd08eb23d tokio: Enable trace subscriber propagation in the runtime (#966)
Signed-off-by: Eliza Weisman <[email protected]>
2019-03-13 10:28:45 -07:00
南浦月 90b1a01010 tokio: fix dependency versions (#944)
#943
2019-03-13 07:47:05 -07:00
Thomas Lacroix 676824988e sync: impl Error for oneshot and watch error types (#967)
Refs: #937
2019-03-12 08:51:23 -07:00
Eliza Weisman 46149f031e trace-core: Fix NoSubscriber causing panics (#975)
PR #973 changed the `tokio_trace_core::span::Id::from_u64` function to
require that the provided `u64` be greater than zero. However, I had
forgotten that the implementation of `Subscriber` for the `NoSubscriber`
type (which is used when no default subscriber is set) always returned
`span::Id::from_u64(0)` from its `new_span` method. In combination with
the assert added in #973, this means that every time a span is hit when
no subscriber is set, `tokio-trace-core` will panic.

This branch fixes the panics by having `NoSubscriber` construct span IDs
using a different (arbitrarily chosen) non-zero constant.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 17:08:04 -07:00
Eliza Weisman 5510ba6dba trace-core: Require span IDs to be > 0 (#973)
This branch changes `tokio_trace_core::span::Id::from_u64` to assert
that the integer from which the span ID is constructed is greater than
zero. This is to enable future use of non-zero optimization.

Unfortunately, we can't actually use a `NonZeroU64` _now_, as that type
was only stabilized in Rust 1.28.0, and `tokio`'s current minimum
supported Rust version is 1.26.0.

Adding and documenting the assertion now allows us to change the
internal representation to `NonZeroU64` later (when 1.28.0 is the
minimum supported Rust version), without causing a breaking change.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 16:18:40 -07:00
Eliza Weisman b8f63308d7 trace-core: Pass dispatcher by ref to dispatcher::with_default (#971)
* trace-core: Pass dispatcher by ref to `dispatcher::with_default`

As requested by @carllerche in https://github.com/tokio-rs/tokio/pull/966#discussion_r264380005, this branch changes the
`dispatcher::with_default` function in `tokio-trace-core` to take the
dispatcher by ref and perform the clone internally. This makes this
function more consistant with other `with_default` functions in other
crates.

Signed-off-by: Eliza Weisman <[email protected]>

* trace: Don't set the default dispatcher on entering a span

Setting the default dispatcher on span entry is a relic of when spans
tracked their parent's ID. At that time, it was necessary to ensure that
any spans created inside a span were observed by the same subscriber
that originally provided the entered span with an ID, as otherwise, new
spans would be created with parent IDs that did not originate from that
subscriber.

Now that spans don't track their parent ID, this is no longer necessary.
However, removing this behavior does mean that if a span is entered
outside of the subscriber context it was created in, any subsequent
spans will be observed by the current default subscriber and thus will
not be part of the original span's trace tree. Since subscribers are not
expected to change frequently, and spans are not expected to move
between them, this is likely acceptable.

I've removed the tests for the old behavior.

Note that this change improves the performance of span entry/exit fairly
significantly. Here are the results of running a benchmark that enters
a span, does nothing, and immediately exits it, before this change:

```
test enter_span              ... bench:          93 ns/iter (+/- 14)
```

...and after:

```
test enter_span              ... bench:          51 ns/iter (+/- 9)
```

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 15:29:00 -07:00
Eliza Weisman 4313d65b38 trace: Switch to using local_inner_macros for instrumentation API (#969)
## Motivation

Currently, it isn't possible to import individual macros from
`tokio-trace` using the macros 1.2 syntax:

```rust
use tokio_trace::{debug, info, span};
```

This is because these macros require that `callsite` and `enabled` are
imported as well.

## Solution

This branch resolves the problem by adding the [`local_inner_macros`]
attribute to the instrumentation API's macros. This allows other macros
from within the crate to be used without requiring them to be explicitly
imported. 

However, this also requires duplicating any macros from other sources
(such as std and `tokio-trace-core`) with wrappers due to the behaviour
of `local_inner_macros`. I've added these wrapper macros as well.

Since the macros got even longer as a result of this, I've moved them
to a separate file to make `lib.rs` easier to read. I've also wrapped
some very long lines in the macros, and removed the explicit drop of
the result of evaluating some event macros (it's no longer necessary
as all event macros now evaluate to `()`).

[`local_inner_macros`]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/macros/macro-changes.html#local-helper-macros

Fixes #968

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 14:48:23 -07:00
Eliza Weisman e780fccce4 trace: Minor documentation improvements (#963) 2019-03-07 21:36:15 -08:00
Eliza Weisman b01e71b3d8 trace-core: API polish (#962)
This branch makes a handful of `tokio-trace-core` API improvements, mostly
around naming. In particular:

 * Rename `dispatcher::with` to `dispatcher::get_default`
 * Rename `Event::observe` to `Event::dispatch`
 * Make `field::ValidLen` trait private

Closes #948
Closes #960

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-07 15:19:26 -08:00
Eliza Weisman 7f911b6b70 trace-core: Debreak RustDoc links (#961)
This commit fixes a bunch of broken links in the `tokio-trace-core` API
docs.

Refs: #957
2019-03-07 14:42:08 -08:00
Eliza Weisman d88aba8d1c trace: Add arguments struct to subscriber::Record (#955)
This branch changes the `Subscriber::record` method to take a new
arguments struct, `span::Record`. The `field::Record` trait was renamed
to `field::Visit` to prevent name conflicts.

In addition, the `ValueSet::is_empty`, `ValueSet::contains`, and
`ValueSet::record` methods were made crate-private, as they are exposed
on the `Attributes` and `Record` types. 

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-07 12:41:10 -08:00
Eliza Weisman 6fbef0a528 trace-core: Add 'static bound to Subscriber (#953) 2019-03-07 11:54:21 -08:00
Blake Smith 9be5f3f9ff Fix TcpStream::try_clone error message (#946) 2019-03-04 14:17:08 -08:00
251 changed files with 7640 additions and 2962 deletions
+17 -2
View File
@@ -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
View File
@@ -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"
+14 -11
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
[build]
target-dir = "../target"
+49
View File
@@ -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);
}
}
+29
View File
@@ -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());
}
}
+22
View File
@@ -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
View File
@@ -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
View File
@@ -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 }}
+2
View File
@@ -8,5 +8,7 @@ jobs:
parameters:
rust_version: ${{ parameters.rust_version }}
- template: azure-patch-crates.yml
- script: cargo check --all
displayName: cargo check --all
+6
View File
@@ -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
+9
View File
@@ -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
+16
View File
@@ -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
+19
View File
@@ -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
View File
@@ -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 }}
+2
View File
@@ -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"
+22
View File
@@ -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" }
-48
View File
@@ -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);
}
-2
View File
@@ -1,2 +0,0 @@
[build]
target-dir = "../../target"
-49
View File
@@ -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" }
-33
View File
@@ -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());
}
});
}
-4
View File
@@ -1,4 +0,0 @@
#![doc(hidden)]
pub mod backward;
pub mod forward;
+11
View File
@@ -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
+6 -3
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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))]
+1 -1
View File
@@ -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;
+16
View File
@@ -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
}
+53 -3
View File
@@ -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"
}
}
+54
View File
@@ -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!();
}
}
+15 -1
View File
@@ -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)
}
}
+76
View File
@@ -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),
}
}
}
+4 -63
View File
@@ -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 = ()>) {}
-145
View File
@@ -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());
}
+43
View File
@@ -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());
}
+68
View File
@@ -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);
}
+33
View File
@@ -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)
}
+65
View File
@@ -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());
}
+42
View File
@@ -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);
}
+49
View File
@@ -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)
}
+38
View File
@@ -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");
}
+1
View File
@@ -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());
+5 -3
View File
@@ -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"
+5
View File
@@ -1,3 +1,8 @@
# 0.1.6 (March 22, 2019)
### Added
- implement `TypedExecutor` (#993).
# 0.1.5 (March 1, 2019)
### Fixed
+4 -4
View File
@@ -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"
+1 -1
View File
@@ -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
+20 -1
View File
@@ -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,
+5
View File
@@ -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).
+8 -5
View File
@@ -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"
+5 -5
View File
@@ -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
+50
View File
@@ -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"
}
}
+151
View File
@@ -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()
}
}
+13
View File
@@ -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
View File
@@ -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;
+181
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
+42
View File
@@ -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
View File
@@ -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"
+2 -2
View File
@@ -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)));
}
+4 -4
View File
@@ -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()?)
}
}
+1 -1
View File
@@ -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() {
+2 -2
View File
@@ -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)));
}
+4 -4
View File
@@ -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()?)
}
}
+4 -4
View File
@@ -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)
}
+27
View File
@@ -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"] }
+47
View File
@@ -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.
+13
View File
@@ -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.
+81
View File
@@ -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()
}
+7 -7
View File
@@ -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"
+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -1
View File
@@ -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(())
+4 -4
View File
@@ -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.
+7 -6
View File
@@ -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
View File
@@ -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");
}
}
+13
View File
@@ -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
+4 -3
View File
@@ -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