Compare commits

...
546 Commits
Author SHA1 Message Date
Alice Ryhl 148bea82ee tokio: prepare Tokio v1.18.1 (#4650) 2022-05-02 17:07:27 +02:00
Alice Ryhl dc54aec1c7 metrics: use mocked AtomicU64 in IO metrics driver (#4649) 2022-05-02 13:32:59 +02:00
Taiki Endo fa665b91a8 macros: always emit return statement (#4636)
Fixes #4635
2022-04-28 07:53:40 +09:00
Eliza Weisman 48183430fb tokio: prepare to release v1.18.0 (#4641)
# 1.18.0 (April 27, 2022)

This release adds a number of new APIs in `tokio::net`, `tokio::signal`, and
`tokio::sync`. In addition, it adds new unstable APIs to `tokio::task` (`Id`s
for uniquely identifying a task, and `AbortHandle` for remotely cancelling a
task), as well as a number of bugfixes.

### Fixed

- blocking: add missing `#[track_caller]` for `spawn_blocking` ([#4616])
- macros: fix `select` macro to process 64 branches ([#4519])
- net: fix `try_io` methods not calling Mio's `try_io` internally ([#4582])
- runtime: recover when OS fails to spawn a new thread ([#4485])

### Added

- macros: support setting a custom crate name for `#[tokio::main]` and
  `#[tokio::test]` ([#4613])
- net: add `UdpSocket::peer_addr` ([#4611])
- net: add `try_read_buf` method for named pipes ([#4626])
- signal: add `SignalKind` `Hash`/`Eq` impls and `c_int` conversion ([#4540])
- signal: add support for signals up to `SIGRTMAX` ([#4555])
- sync: add `watch::Sender::send_modify` method ([#4310])
- sync: add `broadcast::Receiver::len` method ([#4542])
- sync: add `watch::Receiver::same_channel` method ([#4581])
- sync: implement `Clone` for `RecvError` types ([#4560])

### Changed

- update `nix` to 0.24, limit features ([#4631])
- update `mio` to 0.8.1 ([#4582])
- macros: rename `tokio::select!`'s internal `util` module ([#4543])
- runtime: use `Vec::with_capacity` when building runtime ([#4553])

### Documented

- improve docs for `tokio_unstable` ([#4524])
- runtime: include more documentation for thread_pool/worker ([#4511])
- runtime: update `Handle::current`'s docs to mention `EnterGuard` ([#4567])
- time: clarify platform specific timer resolution ([#4474])
- signal: document that `Signal::recv` is cancel-safe ([#4634])
- sync: `UnboundedReceiver` close docs ([#4548])

### Unstable

The following changes only apply when building with `--cfg tokio_unstable`:

- task: add `task::Id` type ([#4630])
- task: add `AbortHandle` type for cancelling tasks in a `JoinSet` ([#4530],
  [#4640])
- task: fix missing `doc(cfg(...))` attributes for `JoinSet` ([#4531])
- task: fix broken link in `AbortHandle` RustDoc ([#4545])
- metrics: add initial IO driver metrics ([#4507])

[#4616]: https://github.com/tokio-rs/tokio/pull/4616
[#4519]: https://github.com/tokio-rs/tokio/pull/4519
[#4582]: https://github.com/tokio-rs/tokio/pull/4582
[#4485]: https://github.com/tokio-rs/tokio/pull/4485
[#4613]: https://github.com/tokio-rs/tokio/pull/4613
[#4611]: https://github.com/tokio-rs/tokio/pull/4611
[#4626]: https://github.com/tokio-rs/tokio/pull/4626
[#4540]: https://github.com/tokio-rs/tokio/pull/4540
[#4555]: https://github.com/tokio-rs/tokio/pull/4555
[#4310]: https://github.com/tokio-rs/tokio/pull/4310
[#4542]: https://github.com/tokio-rs/tokio/pull/4542
[#4581]: https://github.com/tokio-rs/tokio/pull/4581
[#4560]: https://github.com/tokio-rs/tokio/pull/4560
[#4631]: https://github.com/tokio-rs/tokio/pull/4631
[#4582]: https://github.com/tokio-rs/tokio/pull/4582
[#4543]: https://github.com/tokio-rs/tokio/pull/4543
[#4553]: https://github.com/tokio-rs/tokio/pull/4553
[#4524]: https://github.com/tokio-rs/tokio/pull/4524
[#4511]: https://github.com/tokio-rs/tokio/pull/4511
[#4567]: https://github.com/tokio-rs/tokio/pull/4567
[#4474]: https://github.com/tokio-rs/tokio/pull/4474
[#4634]: https://github.com/tokio-rs/tokio/pull/4634
[#4548]: https://github.com/tokio-rs/tokio/pull/4548
[#4630]: https://github.com/tokio-rs/tokio/pull/4630
[#4530]: https://github.com/tokio-rs/tokio/pull/4530
[#4640]: https://github.com/tokio-rs/tokio/pull/4640
[#4531]: https://github.com/tokio-rs/tokio/pull/4531
[#4545]: https://github.com/tokio-rs/tokio/pull/4545
[#4507]: https://github.com/tokio-rs/tokio/pull/4507

Signed-off-by: Eliza Weisman <[email protected]>
2022-04-27 17:08:07 +00:00
Eliza Weisman d456706528 util: implement JoinMap (#4640)
## Motivation

In many cases, it is desirable to spawn a set of tasks associated with
keys, with the ability to cancel them by key. As an example use case for
this sort of thing, see Tower's [`ReadyCache` type][1].

Now that PR #4530 adds a way of cancelling tasks in a
`tokio::task::JoinSet`, we can implement a map-like API based on the
same `IdleNotifiedSet` primitive.

## Solution

This PR adds an implementation of a `JoinMap` type to
`tokio_util::task`, using the `JoinSet` type from `tokio::task`, the
`AbortHandle` type added in #4530, and the new task IDs added in #4630.

Individual tasks can be aborted by key using the `JoinMap::abort`
method, and a set of tasks whose key match a given predicate can be
aborted using `JoinMap::abort_matching`.

When tasks complete, `JoinMap::join_one` returns their associated key
alongside the output from the spawned future, or the key and the
`JoinError` if the task did not complete successfully.

Overall, I think the way this works is pretty straightforward; much of
this PR is just API boilerplate to implement the union of applicable
APIs from `JoinSet` and `HashMap`. Unlike previous iterations on the
`JoinMap` API (e.g. #4538), this version is implemented entirely in
`tokio_util`, using only public APIs from the `tokio` crate. Currently,
the required `tokio` APIs are unstable, but implementing `JoinMap` in
`tokio-util` means we will never have to make stability commitments for
the `JoinMap` API itself.

[1]: https://github.com/tower-rs/tower/blob/master/tower/src/ready_cache/cache.rs

Signed-off-by: Eliza Weisman <[email protected]>
2022-04-26 17:25:48 +00:00
Eliza Weisman 1d3f12304e task: add task IDs (#4630)
## Motivation

PR #4538 adds a prototype implementation of a `JoinMap` API in
`tokio::task`. In [this comment][1] on that PR, @carllerche pointed out
that a much simpler `JoinMap` type could be implemented outside of
`tokio` (either in `tokio-util` or in user code) if we just modified
`JoinSet` to return a task ID type when spawning new tasks, and when
tasks complete. This seems like a better approach for the following
reasons:

* A `JoinMap`-like type need not become a permanent part of `tokio`'s
  stable API
* Task IDs seem like something that could be generally useful outside of
  a `JoinMap` implementation

## Solution

This branch adds a `tokio::task::Id` type that uniquely identifies a
task relative to all other spawned tasks. Task IDs are assigned
sequentially based on an atomic `usize` counter of spawned tasks.

In addition, I modified `JoinSet` to add a `join_with_id` method that
behaves identically to `join_one` but also returns an ID. This can be
used to implement a `JoinMap` type.

Note that because `join_with_id` must return a task ID regardless of
whether the task completes successfully or returns a `JoinError`, I've
also changed `JoinError` to carry the ID of the task that errored, and 
added a `JoinError::id` method for accessing it. Alternatively, we could
have done one of the following:

* have `join_with_id` return `Option<(Id, Result<T, JoinError>)>`, which
  would be inconsistent with the return type of `join_one` (which we've
  [already bikeshedded over once][2]...)
* have `join_with_id` return `Result<Option<(Id, T)>, (Id, JoinError)>>`,
  which just feels gross.

I thought adding the task ID to `JoinError` was the nicest option, and
is potentially useful for other stuff as well, so it's probably a good API to
have anyway.

[1]: https://github.com/tokio-rs/tokio/pull/4538#issuecomment-1065614755
[2]: https://github.com/tokio-rs/tokio/pull/4335#discussion_r773377901

Closes #4538

Signed-off-by: Eliza Weisman <[email protected]>
2022-04-25 17:31:19 +00:00
Aleksey Kladov b4d82c3e70 docs: Signal::recv is cancel-safe (#4634) 2022-04-23 09:12:24 +00:00
cui fliter 1472af5bd4 docs: fix some typos (#4632)
Signed-off-by: cuishuang <[email protected]>
2022-04-21 10:16:19 +00:00
Piepmatz d397e77c90 net: add try_read_buf for named pipes (#4626) 2022-04-21 09:50:12 +02:00
Ryan Zoeller 711d9d0156 chore: upgrade nix to 0.24, limit features (#4631)
This reduces tokio's test compile time by a few seconds.
2022-04-21 04:31:15 +00:00
Carl Lerche 911a0efa87 rt: internally split Handle into two structs (#4629)
Previously, `runtime::Handle` was a single struct composed of the
internal handles for each runtime component. This patch splits the
`Handle` struct into a `HandleInner` which contains everything
**except** the task scheduler handle. Now, `HandleInner` is passed to
the task scheduler during creation and the task scheduler is responsible
for storing it. `Handle` only  needs to hold the scheduler handle and
can access the rest of the component handles by querying the task
scheduler.

The motivation for this change is it now enables the multi-threaded
scheduler to have direct access to the blocking spawner handle.
Previously, when spawning a new thread, the multi-threaded scheduler had
to access the blocking spawner by accessing a thread-local variable.
Now, in theory, the multi-threaded scheduler can use `HandleInner`
directly. However, this change hasn't been done in this PR yet.

Also, now the `Handle` struct is much smaller.

This change is intended to make it easier for the multi-threaded
scheduler to shutdown idle threads and respawn them on demand.
2022-04-20 12:56:55 -07:00
Kezhu Wang d590a369d5 macros: custom crate name for #[tokio::main] and #[tokio::test] (#4613)
This also enables `#[crate::test(crate = "crate")]` in unit tests.

See: rust-lang/cargo#5653
Fixes: #2312
2022-04-18 11:24:27 +02:00
Name1e5s 2fe49a68a4 sync: add panic docs for tokio::sync::broadcast::channel (#4622) 2022-04-17 13:34:51 +02:00
Alan Somers c43832a7b1 ci: update FreeBSD CI image to 12.3 (#4620) 2022-04-15 11:50:40 +02:00
Dom 221bb94b9c blocking: #[track_caller] for spawn_blocking (#4616)
Annotates spawn_blocking() with #[track_caller] in order to produce the
correct tracing span spawn locations that show the caller as the spawn
point.
2022-04-13 15:27:58 +00:00
Bruno 252b0fa9d5 net: add peer_addr to UdpSocket (#4611)
The std UdpSocket has the peer_addr method which can be used to get the address of the remote peer the socket is connected to.

Fixes: #4609
2022-04-10 01:52:45 +00:00
Jedidiah Buck McCready 83477c725a time: clarify platform specific resolution in sleep function docs (#4474) 2022-04-06 15:29:44 +02:00
Stepan Koltsov 3652f71ade sync: add Clone to RecvError types (#4560) 2022-04-06 15:26:45 +02:00
ObsidianMinor b98a7e4d07 runtime: update Handle::current to mention EnterGuard (#4567)
Handle::current docs say it's not possible to call it on any non-runtime thread, but you can call it from a runtime context created by an EnterGuard. This updates the docs to mention EnterGuard as a way to avoid this panic.
2022-04-06 15:23:49 +02:00
Adam Cigánek 7d3b9d73ff stream: expose Timout (#4601) 2022-04-06 15:17:58 +02:00
Paolo Barbolini f8a6cf49cd tracing: don't require default tracing features (#4592) 2022-04-03 11:30:07 +02:00
Arash Sal Moslehian 702d6dccc9 tests: complete TODOs in uds_stream (#4587) 2022-03-28 19:58:06 +00:00
Dirkjan Ochtman a05135a4f8 chore: prepare tokio-util 0.7.1 release (#4521) 2022-03-28 14:34:11 +02:00
masa.koz 2bb97db5e1 net: make try_io methods call mio's try_io internally (#4582) 2022-03-28 09:06:47 +00:00
Matthew Ahrens a8b75dbdf4 sync: add watch::Receiver::same_channel (#4581) 2022-03-25 19:16:47 +00:00
b-naber f84c4d596a io: add StreamReader::into_inner_with_chunk (#4559) 2022-03-23 20:41:09 +01:00
Taiki Endo 121769c762 ci: run reusable_box tests with Miri (#4578) 2022-03-21 23:57:47 +09:00
Jedidiah Buck McCready 0abe825b72 time: clarify platform specific timer resolution (#4474) 2022-03-16 15:49:16 +00:00
Eliza Weisman 61e37c6c8d ci: run doctests for unstable APIs (#4562)
It turns out that the CI job for testing `tokio_unstable` features isn't
actually running doctests for `tokio_unstable`, just lib and integration
tests. This is because RustDoc is responsible for running doctests, and
it needs the unstable cfg passed to it separately from `RUSTFLAGS`.

This means that if the examples for unstable APIs are broken, CI won't
catch this, which is not great!

This commit changes the `test-unstable` CI job to pass `--cfg
tokio_unstable` in `RUSTDOCFLAGS` as well as `RUSTFLAGS`. This way,
doctests for unstable APIs should actually run.

I also fixed a typo in one of the runtime metrics doctests that was
causing a compilation error, which was caught as a result of actually
testing the unstable API docs on CI. :)

Signed-off-by: Eliza Weisman <[email protected]>
2022-03-11 20:13:51 +00:00
Eliza Weisman dee26c92dd chore: fix a bunch of annoying clippy lints (#4558)
## Motivation

Recent Clippy releases have added some new lints that trigger on some
code in Tokio. These aren't a big deal, but seeing them in my editor is
mildly annoying.

## Solution

This branch fixes the following issues flagged by Clippy:

* manual `Option::map` implementation
* use of `.map(...).flatten(...)` that could be replaced with
  `.and_then(...)`
* manual implementation of saturating arithmetic on `Duration`s
* simplify some boolean expressions in assertions (`!res.is_ok()` can be
`res.is_err()`)
* fix redundant field names in initializers
* replace an unnecessary cast to `usize` with an explicitly typed
  integer literal

Signed-off-by: Eliza Weisman <[email protected]>
2022-03-08 12:24:19 -08:00
b-naber 2f944dfa1b sync: add broadcast::Receiver::len (#4542) 2022-03-07 13:47:26 +01:00
weisbrja e8ae65a697 tokio: add support for signals up to SIGRTMAX (#4555)
The POSIX standard not only supports "reliable signals", but also
"real-time signals". This commit adds support for the latter.
2022-03-05 06:33:32 +00:00
Rafael Camargo LeiteandRafael 5b947ca2c7 runtime: include more documentation for thread_pool/worker (#4511)
Co-authored-by: Rafael <[email protected]>
2022-03-02 13:55:15 +01:00
Alisue 014be71cca stream: expose Elapsed error (#4502) 2022-03-02 13:53:21 +01:00
William ba49294bae macros: rename tokio::select!'s internal util module (#4543)
This internal module's identifier can clash with existing identifiers in library users' code and produce confusing error messages.
2022-03-02 13:37:37 +01:00
Alex Saveau fb9a01b362 runtime: use Vec::with_capacity when building runtime (#4553) 2022-03-02 12:41:43 +01:00
Quinn 6f9a586214 sync: unbounded receiver close docs (#4548) 2022-02-27 22:12:29 +01:00
Andy Barron 3dd5a0d3bb signal: add SignalKind Hash/Eq impls and c_int conversion (#4540) 2022-02-26 13:23:28 +01:00
Gus Wynn 413c812ac8 util: switch tokio-util from log to tracing (#4539) 2022-02-26 12:47:04 +01:00
Eliza Weisman ac69d37302 task: fix broken link in AbortHandle RustDoc (#4545)
## Motivation

There's a broken docs link in the docs for `AbortHandle`. Somehow this
managed to slip past CI yesterday when #4530 was merged
(https://github.com/tokio-rs/tokio/runs/5325278596?check_suite_focus=true)
but it's breaking the build now
(https://github.com/tokio-rs/tokio/runs/5337182732?check_suite_focus=true)
which seems really weird to me, but...whatever...

## Solution

This branch fixes the broken link lol.

Signed-off-by: Eliza Weisman <[email protected]>
2022-02-25 19:07:59 +00:00
Cody Casterline 4485921ba7 Improve docs for tokio_unstable. (#4524) 2022-02-25 12:36:37 -05:00
Antonin Amand 70c10bae60 runtime: recover when OS fails to spawn a new thread (#4485) 2022-02-25 12:28:56 +01:00
Eliza Weisman 8e0e56fdf2 task: add AbortHandle type for cancelling tasks in a JoinSet (#4530)
## Motivation

Before we stabilize the `JoinSet` API, we intend to add a method for
individual tasks in the `JoinSet` to be aborted. Because the
`JoinHandle`s for the tasks spawned on a `JoinSet` are owned by the
`JoinSet`, the user can no longer use them to abort tasks on the
`JoinSet`. Therefore, we need another way to cause a remote abort of a
task on a `JoinSet` without holding its `JoinHandle`.

## Solution

This branch adds a new `AbortHandle` type in `tokio::task`, which
represents the owned permission to remotely cancel a task, but _not_ to
await its output. The `AbortHandle` type holds an additional reference
to the task cell.

A crate-private method is added to `JoinHandle` that returns an
`AbortHandle` for the same task, incrementing its ref count.
`AbortHandle` provides a single method, `AbortHandle::abort(self)`, that
remotely cancels the task. Dropping an `AbortHandle` decrements the
task's ref count but does not cancel it. The `AbortHandle` type is
currently marked as unstable.

The spawning methods on `JoinSet` are modified to return an
`AbortHandle` that can be used to cancel the spawned task.

## Future Work

- Currently, the `AbortHandle` type is _only_ available in the public
API through a `JoinSet`. We could also make the
`JoinHandle::abort_handle` method public, to allow users to use the
`AbortHandle` type in other contexts. I didn't do that in this PR,
because I wanted to make the API addition as minimal as possible, but we
could make this method public later.

- Currently, `AbortHandle` is not `Clone`. We could easily make it
`Clone` by incrementing the task's ref count. Since this adds more trait
impls to the API, we may want to be cautious about this, but I see no
obvious reason we would need to remove a `Clone` implementation if one
was added...

- There's been some discussion of adding a `JoinMap` type that allows
aborting tasks by key, and manages a hash map of keys to `AbortHandle`s,
and removes the tasks from the map when they complete. This would make
aborting by key much easier, since the user wouldn't have to worry about
keeping the state of the map of abort handles and the tasks actually
active on the `JoinSet` in sync. After thinking about it a bit, I
thought this is probably best as a `tokio-util` API --- it can currently
be implemented in `tokio-util` with the APIs added in `tokio` in this
PR.

- I noticed while working on this that `JoinSet::join_one` and
`JoinSet::poll_join_one` return a cancelled `JoinError` when a task is
cancelled. I'm not sure if I love this behavior --- it seems like it
would be nicer to just skip cancelled tasks and continue polling. But,
there are currently tests that expect a cancelled `JoinError` to be
returned for each cancelled task, so I didn't want to change it in
_this_ PR. I think this is worth revisiting before stabilizing the API,
though?

Signed-off-by: Eliza Weisman <[email protected]>
2022-02-24 13:08:23 -08:00
Eliza Weisman dfac73d580 macros: update trybuild output for Rust 1.59.0 (#4536)
## Motivation

Rust error messages seem to have changed a bit in 1.59.0

## Solution

Update the `trybuild` stderr output.

This should unbreak the tests on the latest Rust (and fix CI).
2022-02-24 11:52:47 -08:00
Lucio Franco 769fb1547f tokio: Add initial io driver metrics (#4507) 2022-02-24 13:39:37 -05:00
Eliza Weisman 0b97567b49 task: fix missing doc(cfg(...)) attributes for JoinSet (#4531)
## Motivation

The `JoinSet` type is currently missing the `tokio_unstable` and
`feature = "rt"` `doc(cfg(...))` attributes, making it erroneously
appear to be available without the required feature and without unstable
features enabled. This is incorrect.

I believe this is because `doc(cfg(...))` on a re-export doesn't
actually add the required cfgs to the type itself, and the
`cfg_unstable!` is currently only guarding a re-export and module.

## Solution

This PR fixes the missing attributes.
2022-02-23 13:03:41 -08:00
Nikolai Vazquez 3f508d1622 codec: add length_field_type to LengthDelimitedCodec builder (#4508) 2022-02-23 11:46:52 +01:00
Takuya Kajiwara 503ae34cd3 util: fix import path of CancellationToken in example code (#4520) 2022-02-23 11:46:35 +01:00
Alice Ryhl ff8befbc54 ci: fix test not working on wasm (#4527) 2022-02-23 11:46:17 +01:00
Nylonicious 067ddff063 sync: add watch::Sender::send_modify method (#4310) 2022-02-22 21:19:21 +01:00
DevSabbandDevSabb e8f19e771f macros: fix select macro to process 64 branches (#4519)
Co-authored-by: DevSabb <devsabb@local>
2022-02-21 08:41:52 +01:00
Eliza Weisman 43c224ff47 chore: prepare Tokio v1.17.0 release (#4504)
# 1.17.0 (February 16, 2022)

This release updates the minimum supported Rust version (MSRV) to 1.49,
the `mio` dependency to v0.8, and the (optional) `parking_lot`
dependency to v0.12. Additionally, it contains several bug fixes, as
well as internal refactoring and performance improvements.

### Fixed

- time: prevent panicking in `sleep` with large durations ([#4495])
- time: eliminate potential panics in `Instant` arithmetic on platforms
  where `Instant::now` is not monotonic ([#4461])
- io: fix `DuplexStream` not participating in cooperative yielding
  ([#4478])
- rt: fix potential double panic when dropping a `JoinHandle` ([#4430])

### Changed

- update minimum supported Rust version to 1.49 ([#4457])
- update `parking_lot` dependency to v0.12.0 ([#4459])
- update `mio` dependency to v0.8 ([#4449])
- rt: remove an unnecessary lock in the blocking pool ([#4436])
- rt: remove an unnecessary enum in the basic scheduler ([#4462])
- time: use bit manipulation instead of modulo to improve performance
  ([#4480])
- net: use `std::future::Ready` instead of our own `Ready` future
  ([#4271])
- replace deprecated `atomic::spin_loop_hint` with `hint::spin_loop`
  ([#4491])
- fix miri failures in intrusive linked lists ([#4397])

### Documented

- io: add an example for `tokio::process::ChildStdin` ([#4479])

### Unstable

The following changes only apply when building with `--cfg
tokio_unstable`:

- task: fix missing location information in `tracing` spans generated by
  `spawn_local` ([#4483])
- task: add `JoinSet` for managing sets of tasks ([#4335])
- metrics: fix compilation error on MIPS ([#4475])
- metrics: fix compilation error on arm32v7 ([#4453])

[#4495]: https://github.com/tokio-rs/tokio/pull/4495
[#4461]: https://github.com/tokio-rs/tokio/pull/4461
[#4478]: https://github.com/tokio-rs/tokio/pull/4478
[#4430]: https://github.com/tokio-rs/tokio/pull/4430
[#4457]: https://github.com/tokio-rs/tokio/pull/4457
[#4459]: https://github.com/tokio-rs/tokio/pull/4459
[#4449]: https://github.com/tokio-rs/tokio/pull/4449
[#4462]: https://github.com/tokio-rs/tokio/pull/4462
[#4436]: https://github.com/tokio-rs/tokio/pull/4436
[#4480]: https://github.com/tokio-rs/tokio/pull/4480
[#4271]: https://github.com/tokio-rs/tokio/pull/4271
[#4491]: https://github.com/tokio-rs/tokio/pull/4491
[#4397]: https://github.com/tokio-rs/tokio/pull/4397
[#4479]: https://github.com/tokio-rs/tokio/pull/4479
[#4483]: https://github.com/tokio-rs/tokio/pull/4483
[#4335]: https://github.com/tokio-rs/tokio/pull/4335
[#4475]: https://github.com/tokio-rs/tokio/pull/4475
[#4453]: https://github.com/tokio-rs/tokio/pull/4453
2022-02-16 10:50:22 -08:00
Eliza Weisman 8758965206 task: fix unstable API documentation notes (#4503)
## Motivation

PR #4499 made the `JoinSet` API unstable, but did not add a
documentation note explaining unstable features. In general, since the
docs.rs build includes unstable APIs, it's probably worth including
these notes so that users understand what it means for an API to be
unstable.

## Solution

This branch adds a note on unstable APIs to the `JoinSet` type-level
documentation, similar to the notes for `task::Builder` and the runtime
metrics APIs.

Also, I noticed that there was a broken link to the top-level
documentation on unstable APIs in the docs for `task::Builder`, so I
fixed that as well.
2022-02-15 09:57:06 -08:00
Samuel Tardieu 28b983c4bc time: use bit manipulation instead of modulo (#4480)
time: resolve TODO

## Motivation

Existing `TODO` comment in `src/time/driver/wheel/level.rs`.

## Solution

`level_range()` always return a strictly positive power of 2. If `b` is a
strictly positive power of 2, `a - (a % b)` is equal to `a & !(b - 1)`.
2022-02-15 09:26:07 -08:00
Jonathan Johnson 0826f763e0 time: prevent panicking in sleep() with large durations (#4495) 2022-02-15 10:49:41 +01:00
Carl Lerche 37917b821d rt: make JoinSet unstable (#4499) 2022-02-15 10:37:40 +01:00
b-naber 9a3ce91ef5 util: fix waker update condition in CancellationToken (#4497)
There was a missing exclamation mark in the condition we used to test
whether we need a waker update in `check_for_cancellation`.
2022-02-14 13:18:10 -08:00
Thomas de Zeeuw 8fb15da8f8 Update to Mio v0.8
The major breaking change in Mio v0.8 is TcpSocket type being removed.

Replacing Mio's TcpSocket we switch to the socket2 library which
provides a similar type Socket, as well as SockRef, which provide all
options TcpSocket provided (and more!).

Tokio's TcpSocket type is now backed by Socket2 instead of Mio's
TcpSocket. The main pitfall here is that socket2 isn't non-blocking by
default, which Mio obviously is. As a result we have to do potentially
blocking calls more carefully, specifically we need to handle
would-block-like errors when connecting the TcpSocket ourselves.

One benefit for this change is that adding more socket options to
TcpSocket is now merely a single function call away (in most cases
anyway).
2022-02-13 16:56:18 +01:00
Taiki Endo ac0f894dd9 net: use std::future::ready instead of own Ready future (#4271) 2022-02-13 04:54:45 +09:00
Name1e5s 02141db1e1 replace spin_loop_hint with hint::spin_loop (#4491) 2022-02-12 11:47:04 -08:00
Taiki Endo 62274b0710 chore: update minimal mio requirement to 0.7.11 (#4492) 2022-02-12 10:02:46 +01:00
Dirkjan Ochtman 69f135ed60 util: bump tokio dependency to 1.6 to satisfy minimal versions (#4490) 2022-02-12 10:02:07 +01:00
coral ed187ddfb8 doc: Created a simple example for tokio::process::ChildStdin (#4479) 2022-02-11 19:38:12 -08:00
Toby Lawrence e7a0da60cd chore: prepare tokio-util 0.7.0 (#4486) 2022-02-10 12:23:58 -05:00
KestrerandToby Lawrence 9c688ecdc3 util: add lifetime parameter to ReusableBoxFuture (#3762)
Co-authored-by: Toby Lawrence <[email protected]>
2022-02-09 14:29:21 -05:00
Toby Lawrence 52fb93dce9 sync: refactored PollSender<T> to fix a subtly broken Sink<T> implementation (#4214)
Signed-off-by: Toby Lawrence <[email protected]>
2022-02-09 12:09:04 -05:00
Taiki Endo 1be8e9dfb7 miri: make miri accept our intrusive linked lists (#4397) 2022-02-09 11:11:17 +01:00
Eliza Weisman ca51f6a980 task: fix missing #[track_caller] in spawn_local (#4483)
PR #3881 factored out the spawning of local tasks on a `LocalSet` into a
function `spawn_local_inner`, so that the implementation could be shared
with the `task::Builder` API. But, that PR neglected to add a
`#[track_caller]` attribute to `spawn_local_inner`, so the `tracing`
spans for local tasks are all generated with `spawn_local_inner` as
their spawn location, rather than forwarding the actual spawn location
from the calling function.

This causes pretty useless results when using `tokio-console` with code
that spawns a number of local tasks, such as Actix
(https://reddit.com/r/rust/comments/snt5fq/can_tokioconsole_profile_actixrt/)

This commit fixes the issue by adding the missing `#[track_caller]`
attribute.
2022-02-09 10:12:06 +01:00
GongLG fd4d2b0a99 io: make duplex stream cooperative (#4470) (#4478) 2022-02-09 09:59:01 +01:00
Benjamin Saunders cf38ba627a util: remove error case from the infallible DelayQueue::poll_elapsed (#4241) 2022-02-08 21:07:33 -05:00
Sunyeop Lee 0b05ef638d codec: implement Encoder<BytesMut> for BytesCodec (#4465) 2022-02-08 09:11:24 -05:00
Alice Ryhl d6143c9566 io: improve safety comment on FillBuf (#4476) 2022-02-07 10:07:58 +01:00
Name1e5s 5690f0c32e metrics: fix build on mips (#4475) 2022-02-07 10:06:03 +01:00
Oliver Gould fc4deaa1d0 time: eliminate panics from Instant arithmetic (#4461)
`Instant::duration_since`, `Instant::elapsed`, and `Instant::sub` may
panic. This is especially dangerous when `Instant::now` travels back in
time. While this isn't supposed to happen, this behavior is highly
platform-dependent (e.g., rust-lang/rust#86470).

This change modifies the behavior of `tokio::time::Instant` to prevent
this class of panic, as proposed for `std::time::Instant` in
rust-lang/rust#89926.
2022-02-06 16:20:03 +01:00
Carl Lerche bc474f1d81 rt: remove unnecessary enum in basic_scheduler (#4462)
The enum is no longer needed. It was used previously to support multiple
kinds of control messages to the scheduler but that has been refactored
out.
2022-02-03 09:14:22 -08:00
Alice Ryhl 59579465be io: add test for take bug (#4443) 2022-02-02 16:39:16 +01:00
Alice Ryhl 1bb4d23162 task: add JoinSet for managing sets of tasks(#4335)
Adds `JoinSet` for managing multiple spawned tasks and joining them
in completion order.

Closes: #3903
2022-02-01 14:17:09 -08:00
Oliver Gould f602410227 chore: update parking_lot to v0.12.0 (#4459) 2022-01-31 14:55:40 -08:00
Carl Lerche 49fff47111 chore: increase MSRV to 1.49. (#4457)
Rust 1.49 was released on December 31, 2020, which meets our MSRV policy
of a minimum of 6 months.
2022-01-31 13:26:12 -08:00
Riley 77468ae3b0 metrics: add fetch_add for AtomicU64 (#4453) 2022-01-31 10:06:02 +01:00
Carl Lerche 2cee1db20c chore: make it easier to pin Rust versions in CI (#4448)
When backporting patches to LTS branches, we often run into CI failures due to
changes in rust. Newer rust versions add more lints, which break CI. We really
don't want to also have to backport patches that fix CI, so instead, LTS branches
should pin the stable rust version in CI (e.g. #4434).

This PR restructures the CI config files to make it a bit easier to set a specific rust
version in CI.
2022-01-30 10:07:31 -08:00
wspsxing db18e0d39d rt: reduce an unnecessary lock operation (#4436) 2022-01-28 14:01:37 -08:00
Gabriel Grubba b09899832c stream: fix disabled tests (#4441) 2022-01-28 17:30:07 +01:00
Braulio Valdivielso Martínez 111dd66f3e runtime: swallow panics in drop(JoinHandle) (#4430) 2022-01-28 17:21:03 +01:00
Alice Ryhl 91b9850505 chore: prepare Tokio v1.16.1 release (#4438) 2022-01-28 10:30:23 +01:00
Alice Ryhl 3c467056e9 io: fix take pointer check (#4437) 2022-01-28 10:04:13 +01:00
Carl Lerche afd2189eec chore: prepare Tokio v1.16 release (#4431) 2022-01-27 15:16:08 -08:00
Carl Lerche 986b88b3f1 chore: update year in LICENSE files (#4429) 2022-01-27 13:36:21 -08:00
Mark Drobnak 257053e40b util: add spawn_pinned (#3370) 2022-01-27 15:26:09 +01:00
Daniel Henry-Mantilla 5af9e0db2b sync: add blocking lock methods to RwLock (#4425) 2022-01-27 15:15:18 +01:00
Cecile Tonglet 8f77ee8609 net: add generic trait to combine UnixListener and TcpListener (#4385) 2022-01-27 15:13:37 +01:00
Ivan Petkov 2747043f6f tests: enable running wasm32-unknown-unknown tests (#4421)
* Several of tokio's features (e.g. the channel implementation) do not
  need a runtime to work, and can be compiled and used for
  wasm32-unknown-unknown targets
* This change enables running tests for the `sync` and `macros` features
  so that we can note any regressions there
2022-01-27 15:07:52 +01:00
Luiz Carlos 2a5071fc2d feat: implement Framed::map_codec (#4427) 2022-01-27 12:37:30 +01:00
Alice Ryhl 621790e165 io: fix take when using evil reader (#4428) 2022-01-27 11:45:04 +01:00
Braulio Valdivielso Martínez 7aad428994 fs: guarantee that File::write will attempt the write even if the runtime shuts down (#4316) 2022-01-25 19:46:06 +01:00
Jamie 9e38ebcaa9 task: mark JoinHandle as UnwindSafe (#4418) 2022-01-24 11:07:37 +01:00
Carl Lerche 9a57a6a7c4 chore: setup ARM CI with CircleCI (#4417) 2022-01-22 13:49:07 -08:00
Carl Lerche 24f4ee31f0 runtime: expand on runtime metrics (#4373)
This patch adds more runtime metrics. The API is still unstable.
2022-01-21 22:17:38 -08:00
Carl Lerche 4eed411519 rt: reduce no-op wakeups in the multi-threaded scheduler (#4383)
This patch reduces the number of times worker threads wake up without having
work to do in the multi-threaded scheduler. Unnecessary wake-ups are expensive
and slow down the scheduler. I have observed this change reduce no-op wakes
by up to 50%.

The multi-threaded scheduler is work-stealing. When a worker has tasks to process,
and other workers are idle (parked), these idle workers must be unparked so that
they can steal work from the busy worker. However, unparking threads is expensive,
so there is an optimization that avoids unparking a worker if there already exists
workers in a "searching" state (the worker is unparked and looking for work). This
works pretty well, but transitioning from 1 "searching" worker to 0 searching workers
introduces a race condition where a thread unpark can be lost:

* thread 1: last searching worker about to exit searching state
* thread 2: needs to unpark a thread, but skip because there is a searching worker.
* thread 1: exits searching state w/o seeing thread 2's work.

Because this should be a rare condition, Tokio solves this by always unparking a
new worker when the current worker:

* is the last searching worker
* is transitioning out of searching
* has work to process.

When the newly unparked worker wakes, if the race condition described above
happened, "thread 2"'s work will be found. Otherwise, it will just go back to sleep.

Now we come to the issue at hand. A bug incorrectly set a worker to "searching"
when the I/O driver unparked the thread. In a situation where the scheduler was
only partially under load and is able to operate with 1 active worker, the I/O driver
would unpark the thread when new I/O events are received, incorrectly transition
it to "searching", find new work generated by inbound I/O events, incorrectly
transition itself from the last searcher -> no searchers, and unpark a new thread.
This new thread would wake, find no work and go back to sleep.

Note that, when the scheduler is fully saturated, this change will make no impact
as most workers are always unparked and the optimization to avoid unparking
threads described at the top apply.
2022-01-13 15:18:32 -08:00
Carl Lerche 16a8404967 chore: fix ci to track Rust 1.58 (#4401) 2022-01-13 20:49:13 +01:00
Matthew Pomes 089eeae24b runtime: add better error message when spawning blocking threads (#4398) 2022-01-12 19:49:57 +01:00
Taiki Endo e255a265d3 ci: upgrade to new nightly (#4396) 2022-01-13 00:27:05 +09:00
Carl Lerche e951d55720 rt: refactor current-thread scheduler (take 2) (#4395)
Re-applies #4377 and fixes the bug resulting in Hyper's double panic.

Revert: #4394

Original PR:

This PR does some refactoring to the current-thread scheduler bringing it closer to the structure of the
multi-threaded scheduler. More specifically, the core scheduler data is stored in a Core struct and that
struct is passed around as a "token" indicating permission to do work. The Core structure is also stored
in the thread-local context.

This refactor is intended to support #4373, making it easier to track counters in more locations in the
current-thread scheduler.

I tried to keep commits small, but the "set Core in thread-local context" is both the biggest commit and
the key one.
2022-01-11 18:39:56 -08:00
Taiki Endo 1d698b5a90 chore: test hyper on CI (#4393) 2022-01-11 13:38:18 -08:00
Carl Lerche 867f137dc9 Revert "rt: refactor current-thread scheduler (#4377)" (#4394)
This reverts commit cc8ad367a0.
2022-01-11 11:57:14 -08:00
Carl Lerche aea26b322c Revert "Update mio to 0.8 (#4270)" and dependent changes (#4392)
This reverts commits:
 * ee0e811a36
 * 49a9dc6743
 * 0190831ec1
 * 43cdb2cb50
 * 96370ba4ce
 * a9d9bde068
2022-01-11 10:53:45 -08:00
0xd34d10cc bcb968af84 sync: add blocking_recv to oneshot::Receiver (#4334) 2022-01-10 14:42:16 +01:00
Matt Schulte cec1bc151e watch: document recursive borrow deadlock (#4360)
Under the hood, the watch channel uses a RwLock to implement reading
(borrow) and writing (send). This may cause a deadlock if a user has
concurrent borrows on the same thread. This is most likely to occur  due
to a recursive borrow.

This PR adds documentation to describe the deadlock so that future users
of the watch channel will be aware.
2022-01-10 11:41:01 +01:00
Alice Ryhl 1601de1196 process: drop pipe after child exits in wait_with_output (#4315) 2022-01-10 11:40:28 +01:00
b-naber c800deaacc util: add shrink_to_fit and compact methods to DelayQueue (#4170) 2022-01-09 12:41:30 +01:00
Jamie ac2343d984 net: add UnwindSafe impl to PollEvented (#4384) 2022-01-08 13:58:26 +01:00
Trey Smith 553cc3b194 net: document that port 0 picks a random port (#4386) 2022-01-08 13:21:11 +01:00
Eliza Weisman cb9a68eb1a examples: update tracing-subscriber to 0.3 (#4227) 2022-01-08 13:13:28 +09:00
Carl Lerche cc8ad367a0 rt: refactor current-thread scheduler (#4377)
This patch does some refactoring to the current-thread scheduler bringing it closer to the
structure of the multi-threaded scheduler. More specifically, the core scheduler data is stored
in a Core struct and that struct is passed around as a "token" indicating permission to do
work. The Core structure is also stored in the thread-local context.

This refactor is intended to support #4373, making it easier to track counters in more locations
in the current-thread scheduler.
2022-01-06 17:19:26 -08:00
Rob Ede 25e5141c36 test: fix version requirement of tokio-stream (#4376) 2022-01-04 22:01:12 +01:00
Tom Dohrmann 4a12163d7c util: add mutable reference getters for codecs to pinned Framed (#4372) 2022-01-03 22:21:43 +01:00
Elichai Turkel 12dd06336d sync: add a has_changed method to watch::Receiver (#4342) 2021-12-31 16:23:29 +01:00
Alice Ryhl c301f6d83a sync: don't inherit Send from parking_lot::*Guard (#4359) 2021-12-31 15:57:56 +01:00
Braulio Valdivielso Martínez fb35c83944 tokio-stream: add StreamExt::map_while (#4351)
Fixes #4337

Rust 1.57 stabilized the `Iterator::map_while` API. This PR adds the
same functionality to the `StreamExt` trait, to keep parity.
2021-12-31 22:53:09 +09:00
Taiki Endo 43cdb2cb50 net: add tos and set_tos methods to TCP and UDP sockets (#4366) 2021-12-31 21:19:14 +09:00
Taiki Endo 49a9dc6743 net: add buffer size methods to UdpSocket (#4363)
This adds the following methods:

- UdpSocket::set_send_buffer_size
- UdpSocket::send_buffer_size
- UdpSocket::set_recv_buffer_size
- UdpSocket::recv_buffer_size
2021-12-31 20:47:34 +09:00
Taiki Endo 96370ba4ce net: add TcpSocket::take_error (#4364) 2021-12-31 11:25:50 +01:00
Taiki Endo a9d9bde068 net: add UdpSocket::peer_addr (#4362) 2021-12-31 11:23:04 +01:00
Taiki Endo 0190831ec1 net: fix build error on master (#4361) 2021-12-31 11:21:23 +01:00
Taiki Endo ee0e811a36 Update mio to 0.8 (#4270) 2021-12-31 12:28:14 +09:00
Alice Ryhl 47feaa7a89 io: fix clippy lint in write_all (#4358) 2021-12-30 15:31:11 +01:00
Alice Ryhl dda8da75d0 stream: add StreamExt::then (#4355) 2021-12-30 15:28:13 +01:00
David Kleingeld dc1894105b codec: improve Builder::max_frame_length docs (#4352) 2021-12-28 15:08:37 +01:00
Eliza Weisman 78e0f0b42a docs: improve RustDoc for unstable features (#4331)
Currently, the docs.rs documentation for tokio is built without
--cfg tokio_unstable set. This means that unstable features are not shown in
the API docs, making them difficutl to discover. Clearly, we do want to
document the existence of unstable APIs, given that there's a section in
the lib.rs documentation listing them, so it would be better if it was
also possible to determine what APIs an unstable feature enables when
reading the RustDoc documentation.

This branch changes the docs.rs metadata to also pass --cfg tokio_unstable
when building the documentation. It turns out that it's
necessary to separately pass the cfg flag to both RustDoc and rustc,
or else the tracing dependency, which is only enabled in
target.cfg(tokio_unstable).dependencies, will be missing and the build
will fail.

In addition, I made some minor improvements to the docs for unstable
features. Some links in the task::Builder docs were broken, and the
required tokio_unstable cfg was missing from the doc(cfg(...))
attributes. Furthermore, I added a note in the top-level docs for
unstable APIs, stating that they are unstable and linking back to the
section in the crate-level docs that explains how to enable unstable
features.

Fixes #4328
2021-12-21 11:11:48 -08:00
Jinhua Tan e55f3d4398 examples: make the introduction in examples/Cargo.toml more clear (#4333) 2021-12-21 14:02:18 +01:00
Alice Ryhl 8582363b4e stats: mark stats feature unstable in lib.rs (#4327) 2021-12-18 13:40:24 +01:00
Cyborus04 c3fbaba1f9 io: replace use of transmute with pointer manipulations (#4307) 2021-12-17 20:00:24 +01:00
Fabien GaudandFabien Gaud 22e6aef6e7 net: allow to set linger on TcpSocket (#4324)
For now, this is only allowed on TcpStream. This is a problem when one
want to disable lingering (i.e. set it to Duration(0, 0)). Without being
able to set it prior to the connect call, if the connect future is
dropped it would leave sockets in a TIME_WAIT state.

Co-authored-by: Fabien Gaud <[email protected]>
2021-12-16 20:34:00 +01:00
Carl Lerche f64673580d chore: prepare Tokio v1.15.0 release (#4320)
Includes `tokio-macros` v1.7.0
2021-12-15 10:36:09 -08:00
Braulio Valdivielso Martínez 54e6693dff time: make timeout robust against budget-depleting tasks (#4314) 2021-12-15 11:59:21 +01:00
Zahari Dichev 4e3268d222 tracing: instrument more resources (#4302)
This PR adds instrumentation to more resources from the sync package. The new
instrumentation requires the `tokio_unstable` feature flag to enable.
2021-12-14 14:04:19 -08:00
Toby Lawrence 4b6bb1d9a7 chore(util): start v0.7 release cycle (#4313)
* chore(util): start v0.7 release cycle

Signed-off-by: Toby Lawrence <[email protected]>
2021-12-10 13:16:17 -05:00
Braulio Valdivielso Martínez eb1af7f29c io: make tokio::io::empty cooperative (#4300)
Reads and buffered reads from a `tokio::io::empty` were always marked
as ready. That makes sense, given that there is nothing to wait for.
However, doing repeated reads on the `empty` could stall the event
loop and prevent other tasks from making progress.

This change uses tokio's coop system to yield control back to the
executor when appropriate.

Note that the issue that originally triggered this PR is not fixed
yet, because the `timeout` function will not poll the timer after
empty::read runs out of budget. A different change will be needed to
address that.

Refs: #4291
2021-12-10 11:08:49 +01:00
Toby Lawrence 0bc9160e25 chore: update labeler.yml to drop filepath prefixes (#4308)
- update labeler.yml to drop filepath prefixes
- make sure labeler enforces labels over lifetime of PR
2021-12-09 10:40:27 -05:00
Shin Seunghun 4c571b55b1 runtime: fix typo in the task modules (#4306) 2021-12-08 13:30:52 +01:00
Naruto210 60ba634d60 time: fix typo in tokio-time document (#4304) 2021-12-07 15:49:45 +01:00
Shin Seunghun f73ed1fdba runtime: fix typo (#4303) 2021-12-07 11:07:00 +01:00
Ivan Petkov ee4b2ede83 process: add as_std() method to Command (#4295) 2021-12-03 08:51:27 +01:00
Shin Seunghun 64da914d17 time: add doc links in entry doc (#4293) 2021-12-02 15:27:46 +01:00
kenmasu d764ba5816 io: call tcp.set_nonblocking(true) in AsyncFd example. (#4292) 2021-12-02 11:01:23 +01:00
Alice Ryhl 65fb0210d5 tokio: add 1.14.x to LTS releases (#4273) 2021-11-24 09:18:50 +01:00
Axel Forsman a77b2fbab2 io: extend AsyncFdReadyGuard method lifetimes (#4267)
The implicit elided lifetimes of the `AsyncFd` references in return
types of methods on `AsyncFdReadyGuard` resolved to that of `&self`.
However that lifetime is smaller than `'a` since `self` contains an `&'a
AsyncFd` reference. This will not change so the change also does not
lessen future proofing.
2021-11-23 13:56:31 +01:00
oblique 347c0cdaba time: add Interval::reset method (#4248) 2021-11-23 13:51:07 +01:00
Shin Seunghun 2c0e5c9704 time: document missing timer panics (#4247) 2021-11-23 12:14:08 +01:00
omjadas 2a614fba0d docs: document that parking_lot is enabled by full (#4269) 2021-11-23 12:11:42 +01:00
David Pedersen 3b339024f0 stream: impl Extend for StreamMap (#4272)
## Motivation

This allows `StreamMap` to be used with [`futures::stream::StreamExt::collect`][collect].

My use case is something like this:

```rust
let stream_map: StreamMap<_, _> = things
    .into_iter()
    .map(|thing| make_stream(thing)) // iterator of futures
    .collect::<FuturesUnordered<_>>() // stream of streams
    .collect::<StreamMap<_, _>>() // combine all the inner streams into one
    .await;

async fn make_stream(thing: Thing) -> impl Stream { ... }
```

[collect]: https://docs.rs/futures/0.3.17/futures/stream/trait.StreamExt.html#method.collect

## Solution

Add `Extend` impl that delegates to the inner `Vec`.
2021-11-23 11:54:06 +01:00
Taiki Endo 1a423b3322 chore: remove doc URL from Cargo.toml (#4251)
https://doc.rust-lang.org/cargo/reference/manifest.html#the-documentation-field

> If no URL is specified in the manifest file, crates.io will
> automatically link your crate to the corresponding docs.rs page.
2021-11-23 11:53:32 +01:00
Taiki Endo a8b662f643 ci: upgrade to new nightly (#4268) 2021-11-23 19:29:57 +09:00
Taiki Endo cf3206842c chore: bump MSRV to 1.46 (#4254) 2021-11-23 12:09:24 +09:00
Taiki Endo 8943e8aeef macros: address remainging clippy::semicolon_if_nothing_returned warning (#4252) 2021-11-22 18:41:17 +09:00
Taiki Endo fe770dc509 chore: fix newly added warnings (#4253) 2021-11-22 18:40:57 +09:00
Taiki Endo 8b6542fc3e chore: update nix to 0.23 (#4255) 2021-11-22 06:13:14 +09:00
Alice Ryhl b1afd95994 sync: elaborate on cross-runtime message passing (#4240) 2021-11-17 16:02:07 +01:00
Alice Ryhl 095b5dcf93 net: add connect_std -> TcpSocket doc alias (#4219) 2021-11-16 22:22:47 +01:00
Alice Ryhl 623c09c52c chore: prepare tokio-macros 1.6.0 (#4239) 2021-11-16 09:54:07 +01:00
Eliza Weisman 884a9a4b18 chore: prepare Tokio v1.14.0 (#4234)
# 1.14.0 (November 15, 2021)

### Fixed

- macros: fix compiler errors when using `mut` patterns in `select!`
  ([#4211])
- sync: fix a data race between `oneshot::Sender::send` and awaiting a
  `oneshot::Receiver` when the oneshot has been closed ([#4226])
- sync: make `AtomicWaker` panic safe ([#3689])
- runtime: fix basic scheduler dropping tasks outside a runtime context
  ([#4213])

### Added

- stats: add `RuntimeStats::busy_duration_total` ([#4179], [#4223])

### Changed

- io: updated `copy` buffer size to match `std::io::copy` ([#4209])

### Documented

- io: rename buffer to file in doc-test ([#4230])
- sync: fix Notify example ([#4212])

[#4211]: https://github.com/tokio-rs/tokio/pull/4211
[#4226]: https://github.com/tokio-rs/tokio/pull/4226
[#3689]: https://github.com/tokio-rs/tokio/pull/3689
[#4213]: https://github.com/tokio-rs/tokio/pull/4213
[#4179]: https://github.com/tokio-rs/tokio/pull/4179
[#4223]: https://github.com/tokio-rs/tokio/pull/4223
[#4209]: https://github.com/tokio-rs/tokio/pull/4209
[#4230]: https://github.com/tokio-rs/tokio/pull/4230
[#4212]: https://github.com/tokio-rs/tokio/pull/4212
2021-11-15 16:39:09 -08:00
Eliza Weisman e0be45e49b Merge v1.13.1 (#4236)
Refs: #4235
2021-11-15 16:09:33 -08:00
Eliza Weisman 26f0938bf3 oneshot: document UnsafeCell invariants (#4229)
Depends on #4226

## Motivation

Currently, the safety invariants and synchronization strategy used in
`tokio::sync::oneshot` are not particularly obvious, especially to a new
reader. It would be nice to better document this code to make these
invariants clearer.

## Solution

This branch adds `SAFETY:` comments to the `oneshot` channel
implementation. In particular, I've focused on documenting the
invariants around when the inner `UnsafeCell` that stores the value can
be accessed by the sender and receiver sides of the channel.

I still want to take a closer look at when the waker cells can be set,
and I'd like to add more documentation there in a follow-up branch.

Signed-off-by: Eliza Weisman <[email protected]>
2021-11-15 12:46:12 -08:00
Eliza Weisman 4b78ed4d68 sync: fix racy UnsafeCell access on a closed oneshot (#4226) 2021-11-14 18:03:41 +01:00
Shin Seunghun 79d7a625d0 io: rename buffer to file in doc-test (#4230) 2021-11-13 11:31:42 +01:00
Alice Ryhl ccf855ec24 stats: only expose busy_duration_total (#4223) 2021-11-11 21:53:29 +01:00
Alice Ryhl 579f61106d ci: check for minimal versions with tokio_unstable (#4224) 2021-11-11 21:53:15 +01:00
Alice Ryhl f45320a9c0 stats: add busy_duration stats (#4179) 2021-11-08 14:59:36 -05:00
Alice Ryhl 1f8105588c runtime: drop basic scheduler tasks inside context (#4213) 2021-11-02 23:25:34 +01:00
Alice Ryhl 94ee305741 macros: fix mut patterns in select! macro (#4211) 2021-11-02 18:05:24 +01:00
Alice Ryhl 669bc4476e io: update copy buffer size (#4209) 2021-11-02 16:22:45 +01:00
Alice Ryhl 1265d0c5dc sync: fix Notify example (#4212) 2021-11-02 16:22:30 +01:00
John-John Tedro 09b770c5db sync: make AtomicWaker panic safe (#3689) 2021-11-02 13:41:36 +01:00
Alice Ryhl d1a400912e chore: prepare tokio-stream 0.1.8 (#4198) 2021-10-29 18:34:43 +02:00
Alice Ryhl aa03622cf3 chore: prepare tokio-util 0.6.9 (#4199) 2021-10-29 18:34:23 +02:00
Alice Ryhl ac89d8926d chore: prepare Tokio v1.13.0 (#4196) 2021-10-29 18:34:13 +02:00
Alice Ryhl e184205421 chore: prepare tokio-macros 1.6.0 (#4197) 2021-10-29 18:33:40 +02:00
sander2 44a1aad8df task: allocate callback on heap immediately in debug mode (#4203) 2021-10-29 17:34:25 +02:00
Alice Ryhl 75c07770bf sync: make watch::send_replace infallible (#4195) 2021-10-27 14:05:25 +02:00
Colin Walters 268ed5e73e task: add more tips + links to spawn_blocking docs (#4150) 2021-10-26 20:57:57 +02:00
Bhargav 0c68b89452 codec: update stream impl for Framed to return None after Err (#4166) 2021-10-26 16:56:15 +02:00
Alice Ryhl 827694a9e3 ci: fix nightly version for cirrus ci (#4200) 2021-10-26 16:53:05 +02:00
Alice Ryhl d15e5fad16 ci: split FreeBSD into two jobs (#4194) 2021-10-26 15:44:00 +02:00
Alice Ryhl 9cb495cdb8 tokio: upgrade to new nightly for CI (#4193) 2021-10-26 14:08:11 +02:00
Ibraheem Ahmed e7d3e0c93c macros: use qualified syntax when polling in select! (#4192) 2021-10-25 23:54:34 +09:00
Alice Ryhl e04b5be1f5 time: update deadline on removal in DelayQueue (#4178) 2021-10-22 20:34:36 +02:00
Colin Walters 2734fa9a85 util/io: add SyncIoBridge (#4146) 2021-10-22 18:46:29 +02:00
Alice Ryhl 83aeae8610 chore: fix output of macro after new rustc release (#4189) 2021-10-22 09:36:12 +02:00
Taiki Endo cf550b2183 ci: ignore RUSTSEC-2020-0159 in audit (#4186) 2021-10-21 10:27:26 +02:00
Colin Walters e1c8b5a159 tests: add #[cfg(sync)] to watch test (#4183) 2021-10-21 09:11:14 +02:00
Jared Stanbrough eb7a615c96 tokio: add riscv32 to non atomic64 architectures (#4185) 2021-10-21 04:25:00 +09:00
John-John Tedro 44e9013f64 tokio: assert platform-minimum requirements at build time (#3797) 2021-10-19 15:16:45 +02:00
antogilbertandAntonello Palazzi 03969cdae7 doc: conversion of doc comments to indicative mood (#4174)
Co-authored-by: Antonello Palazzi <[email protected]>
2021-10-19 10:54:16 +02:00
Taiki Endo 095012b03b macros: fix type resolution error in #[tokio::main] (#4176) 2021-10-19 12:49:57 +09:00
Jonathan b5c1fb4012 signal: add example with background listener (#4171) 2021-10-17 20:37:15 +02:00
Philip Dubé d4848a9e2e examples: replace time crate with httpdate (#4169) 2021-10-15 15:21:08 +02:00
Alice Ryhl bb6a292d0a chore: prepare tokio-macros v1.5.0 (#4167) 2021-10-13 15:51:09 +02:00
Suika eb2106f87e runtime: reset woken of outer future after polled (#4157) 2021-10-12 13:35:14 +02:00
Lukas Wirth fadd0190da macros: make tokio-macros attributes more IDE friendly (#4162) 2021-10-11 22:04:47 +02:00
Alice Ryhl f0cb360d70 sync: add more oneshot examples (#4153) 2021-10-08 08:52:50 +02:00
Alice Ryhl d047584e86 time: document Interval::tick cancel safety (#4152) 2021-10-05 15:55:15 +02:00
Alice Ryhl c5d37204dc chore: fix unused field warnings (#4151) 2021-10-05 13:21:38 +02:00
我就像屎的倒影 7f26ad85c2 fmt: ignore the target dir when formatting (#4145)
Signed-off-by: hi-rustin <[email protected]>
2021-10-04 08:36:17 +02:00
Alice Ryhl d39c9ed9dc chore: prepare tokio-macros 1.4.1 (#4142)
This reverts commit 33f0a1fd2e.
2021-09-30 10:38:52 +02:00
Noah Kennedy 44cfe10ee5 chore: prepare tokio-macros 1.4.0 (#4139) 2021-09-29 23:30:47 +02:00
Frank Steffahn 1073f6e8be sync: expand Debug for Mutex<T> impl to unsized T (#4134) 2021-09-26 12:29:08 +02:00
Kai Jewson dee3236c97 sync: add watch::Sender::send_replace (#3962) 2021-09-25 22:06:40 +02:00
Noah Kennedy d9ca1517c6 net: add try_*, readable, writable, ready, and peer_addr methods to split halves (#4120) 2021-09-25 20:19:29 +02:00
你好-肚财 6c1a1d9b07 docs: add returning on the first error example for try_join! (#4133) 2021-09-25 16:04:38 +02:00
Arthur Gautier d32acd97eb net: add poll_{recv,send}_ready methods to udp and uds_datagram (#4131) 2021-09-24 20:28:18 +02:00
João Marcos Bezerra 7875f26586 docs: fixing broken links in tokio/src/lib.rs (#4132) 2021-09-24 11:16:30 +02:00
我就像屎的倒影 7ce8f05cff sync: add blocking_lock to Mutex (#4130) 2021-09-23 11:46:14 +02:00
Sean McArthur ea19606bc4 sync: fix Notify to clone the waker before locking its waiter list (#4129)
Since a waker can trigger arbitrary code, such as with a custom waker,
and even more so now that it can emit a tracing event that could do
respond, we must be careful about the internal state when that code is
triggered. The clone method of a waker is one of those instances.

This changes the internals of `Notify` so that the waker is cloned
*before* locking the waiter list. While this does mean that in some
contended cases, we'll have made an optimistic clone, it makes `Notify`
more robust and correct.

Note that the included test case is built from an instance that did
happen naturally in another project, see
https://github.com/tokio-rs/console/issues/133.
2021-09-23 08:33:14 +02:00
Zahari Dichev b9b59e4f15 tracing: use structured location fields for spawned tasks (#4128)
This change enables `tokio-console` to parse the location information
for a spawned task into a structured object rather than simply displaying
this info as a field on the task.

Signed-off-by: Zahari Dichev <[email protected]>
2021-09-22 23:17:41 +03:00
Suika cdc46a9ded io: add assert in copy_bidirectional that poll_write is sensible (#4125) 2021-09-22 10:06:51 +02:00
Zahari Dichev b9834f6d8b tracing: instrument time::Sleep (#4072)
This branch instruments the `Sleep` resource to allow the tokio-console
to consume data about resources usage. The corresponding console branch
is here: https://github.com/tokio-rs/console/pull/77

Signed-off-by: Zahari Dichev <[email protected]>
2021-09-22 08:34:41 +03:00
Alice Ryhl 1ed89aa5cf chore: prepare Tokio v1.12.0 (#4123) 2021-09-21 17:15:22 +02:00
Andrew Hlynskyi d9b2dc81ca task: improve JoinHandle::abort cancellation doc (#4121) 2021-09-21 10:20:03 +02:00
Alice Ryhl 8e54145c8b ci: make loom tests optional (#4112) 2021-09-20 21:52:35 +02:00
Alice Ryhl 279e8b001a sync: document spurious failures on poll_recv (#4117) 2021-09-19 09:52:40 +02:00
Alan Briolat e9f6faee67 mpsc: ensure try_reserve error is consistent with try_send (#4119) 2021-09-19 09:52:28 +02:00
Alice Ryhl f1b89675eb mpsc: use spin_loop_hint instead of yield_now (#4115) 2021-09-18 09:27:25 +02:00
Alice Ryhl ddd33f2b05 sync: implement try_recv for mpsc channels (#4113) 2021-09-18 09:27:16 +02:00
Alan Somers 8e92f05795 io: update the mio-aio dev-dependency (#4116) 2021-09-18 09:25:52 +02:00
Simon Farnsworth 957ed3eac0 runtime: callback when a worker parks and unparks (#4070) 2021-09-16 11:44:30 +02:00
Alice Ryhl ab34805849 time: more docs on advance (#4103) 2021-09-15 19:22:24 +02:00
Alan Somers 8b298d9ed4 io: add POSIX AIO on FreeBSD (#4054) 2021-09-15 18:55:50 +02:00
Andrew Lamb 57563e218b docs: clarify CPU-bound tasks on Tokio (#4105) 2021-09-15 14:07:52 +02:00
Ben Noordhuis 33f0a1fd2e macros: run runtime inside LocalSet when using macro (#4027) 2021-09-15 11:25:02 +02:00
Alice Ryhl 4c9b469562 sync: PollSender impls Sink (#4110) 2021-09-14 22:39:52 +02:00
Thibeau Vercruyssen 7af0f32751 io: add convenience method AsyncSeekExt::rewind. (#4107) 2021-09-14 16:05:01 +02:00
Milo 3fe1662e4b ci: caching for CI (#4108) 2021-09-14 09:40:04 +02:00
Nylonicious a73428252b util: update README (#4099) 2021-09-10 08:55:03 +02:00
Alice Ryhl b99eedc2ea sync: make SendError field public (#4097) 2021-09-09 19:13:26 +02:00
Sean McArthur 6ebd0575e4 runtime: add tracing span for block_on futures (#4094) 2021-09-09 08:58:21 -07:00
Alice Ryhl 7e51b44a20 task: document non-guarantees of yield_now (#4091) 2021-09-08 12:02:25 +02:00
Alice Ryhl bd1e4aaea6 chore: add Debug to NotDefinedHere (#4092) 2021-09-08 12:02:07 +02:00
Alice Ryhl fd22164f5d ci: disable benchmarks in CI (#4090) 2021-09-08 10:52:40 +02:00
Pablo Sichert 98e78a6f7b codec: implement Clone for LengthDelimitedCodec (#4089) 2021-09-07 13:51:35 +02:00
Toby Lawrence 01a6feb0dc chore: prepare tokio-util v0.6.8 (#4087)
Signed-off-by: Toby Lawrence <[email protected]>
2021-09-03 10:57:27 -04:00
Jorge Leitao e31e06c5c2 compat: added AsyncSeek compat (#4078) 2021-09-03 08:54:40 +02:00
ttys3 d0dd74a058 io: add with_capacity for ReaderStream (#4086) 2021-09-02 09:53:23 +02:00
Alice Ryhl 6778a7def6 time: document paused time details better (#4061) 2021-09-01 18:49:50 +02:00
Alice Ryhl 9a97eb36bc chore: prepare Tokio v1.11.0 (#4083) 2021-08-31 23:26:42 +02:00
Alice Ryhl 1409041525 io: fix fill_buf by not calling poll_fill_buf twice (#4084) 2021-08-31 23:25:52 +02:00
Toby Lawrence 23b0aee5dd tokio-util: expose key used in DelayQueue's Expired (#4081)
Signed-off-by: Toby Lawrence <[email protected]>
2021-08-31 17:09:10 -04:00
Francis Murillo 909d3ec0ff stream: add From<Receiver<T>> impl for receiver streams (#4080) 2021-08-29 16:30:13 +02:00
Alan Somers b67d46403f process: skip the process_kill_on_drop test if bash is not installed. (#4079) 2021-08-29 10:59:58 +02:00
Alice Ryhl 98578a6f4a stats: initial work on runtime stats (#4043) 2021-08-27 11:40:41 +02:00
Alice Ryhl 8a097d27b5 util: add safety comment to assume_init (#4075) 2021-08-26 23:06:58 +02:00
Eliza Weisman 1e2e38b7cd sync: use WakeList in Notify and batch_semaphore (#4071)
## Motivation

PR #4055 added a new `WakeList` type, to manage a potentially
uninitialized array when waking batches of wakers. This has the
advantage of not initializing a bunch of empty `Option`s when only a
small number of tasks are being woken, potentially improving performance
in these cases.

Currently, `WakeList` is used only in the IO driver. However,
`tokio::sync` contains some code that's almost identical to the code in
the IO driver that was replaced with `WakeList`, so we can apply the
same optimizations there.

## Solution

This branch changes `tokio::sync::Notify` and
`tokio::sync::batch_semaphore::Semaphore` to use `WakeList` when waking
batches of wakers. This was a pretty straightforward drop-in
replacement.

Signed-off-by: Eliza Weisman <[email protected]>
2021-08-26 11:33:22 -07:00
Fedorenko Dmitrij 80bda3bf5f macros: fix wrong error messages (#4067) 2021-08-25 19:59:41 +02:00
Gleb Pomykalov 51f4f0594c io: speed-up waking by using uninitialized array (#4055) 2021-08-25 16:18:19 +02:00
Alice Ryhl 897fed1609 ci: fail if valgrind complains (#4066) 2021-08-24 23:35:37 +02:00
Alice Ryhl fd52f9f66b Merge branch 'merge-1.10.1' into master 2021-08-24 20:50:43 +02:00
Alice Ryhl dd060b16f5 chore: prepare Tokio v1.10.1 2021-08-24 17:48:25 +02:00
Alice Ryhl 4152918a39 runtime: fix leak in UnownedTask 2021-08-24 17:48:25 +02:00
Alice Ryhl 7e474640dd chore: fix chores (#4060) 2021-08-24 14:57:23 +02:00
Nylonicious 84f6845bf2 stream: impl FromIterator for StreamMap (#4052) 2021-08-24 13:21:02 +02:00
Alice Ryhl 2bc9a42d2b process: add from_std to ChildStd* (#4045) 2021-08-19 09:46:05 +02:00
Christoph HerzogandAlice Ryhl 8aa2bfe23e watch: make watch::Sender::subscribe public (#3800)
Co-authored-by: Alice Ryhl <[email protected]>
2021-08-19 09:43:59 +02:00
Alice Ryhl 5ac32934b4 time: don't panic when Instant is not monotonic (#4044) 2021-08-19 09:41:35 +02:00
Eliza Weisman d0305d57e5 tracing: change span naming to new console convention (#4042)
Currently, the per-task spans generated by Tokio's `tracing` feature
have the span name "task" and the target "tokio::task". This is because
the console subscriber identified tasks by looking specifically for the
"tokio::task" target.

In tokio-rs/console#41, it was proposed that the console change to a
more generic system for identifying the spans that correspond to tasks,
to allow recording tasks belonging to multiple runtime crates (e.g. an
application that uses Tokio for async tasks and Rayon for CPU-bound
tasks). PR tokio-rs/console#68 changed the console to track any spans
"runtime.spawn", regardless of target (so that the target can be used to
identify the runtime a task came from), with "tokio::task/task" tracked
for backwards-compatibility with the current release version of tokio.

This branch changes Tokio's span naming to the new convention. I also
rearranged a couple fields so that the task's kind field always comes
before the name and spawn location, since it's likely to be the
shortest, and renamed the `function` field on blocking tasks to `fn`,
for brevity's sake.

Signed-off-by: Eliza Weisman <[email protected]>
2021-08-16 12:43:34 -07:00
Alice Ryhl 5c19b5a162 time: make Sleep examples easier to find (#4040) 2021-08-15 19:24:04 +02:00
Alice Ryhl f478647a8e ci: add readme check to CI (#4039) 2021-08-13 15:05:09 +02:00
Alice Ryhl c0974bad94 chore: prepare Tokio v1.10.0 (#4038) 2021-08-12 21:55:48 +02:00
Alice Ryhl b67534a20b tests: fix flaky test (#4024) 2021-08-12 20:15:06 +02:00
Alice Ryhl c4e56232ff sync: use spin_loop_hint instead of yield_now in mpsc (#4037) 2021-08-12 16:03:10 +02:00
Blas Rodriguez Irizar 84c4a6d89f task: quickly send task to heap on debug mode (#4009) 2021-08-12 15:37:26 +02:00
Alice Ryhl b501f25202 runtime: give Notified a safe API (#4005) 2021-08-12 10:06:05 +02:00
Alan Somers 032c55e77f tokio: the test-util feature depends on rt, sync, and time (#4036)
Fixes #4035
2021-08-12 10:04:09 +02:00
Kateřina Churanová 1e95d6994a chore: explicitly relaxed clippy lint for runtime entry macro (#4030) 2021-08-11 18:16:00 +09:00
LinkTed 362df5a317 io: add test for write_f(32|64)[_le] (#4026) 2021-08-04 18:58:38 +02:00
LinkTed 106bb94896 io: add (read|write)_f(32|64)[_le] methods (#4022) 2021-08-04 13:45:26 +02:00
LinkTed 8198ef3881 chore: fix clippy warnings (#4017) 2021-08-03 10:50:40 +02:00
Alice Ryhl e66217575b sync: document when watch::send fails (#4021) 2021-08-03 09:38:58 +02:00
Alice Ryhl 175d84e2b1 chore: fix doc failure in CI on master (#4020) 2021-08-03 09:07:38 +02:00
Alice Ryhl 69a6585429 signal: make windows docs for signal module show up on unix builds (#3770) 2021-08-02 20:55:17 +02:00
Alan Somers cf02b3f32d fs: reorganize tokio::fs::file's mock tests (#3988) 2021-07-31 09:55:32 +02:00
Alice Ryhl d01bda86a4 tests: simplify loom tests (#3995) 2021-07-30 13:03:38 +02:00
Alice Ryhl e60d7a474b chore: fix CI on master (#4008) 2021-07-30 12:28:46 +02:00
Alice Ryhl 0d9430b99c tests: reduce sleep durations (#3994) 2021-07-30 11:27:04 +02:00
quininer f51676891f io: fix copy buffered write (#4001) 2021-07-30 11:20:16 +02:00
Alice Ryhl 3340ae6aa9 io: add fill_buf and consume (#3991) 2021-07-30 11:17:40 +02:00
Félix Saparelli f957f7f9a7 process: add Child::raw_handle() on windows (#3998)
Fixes #3987
2021-07-28 15:42:03 +00:00
Alice Ryhl 8b447649bb io: document cancellation safety of AsyncBufReadExt (#3997) 2021-07-27 17:59:38 +02:00
Erik Tews 4d8cc28b76 io: add missing Option to doc (#3999) 2021-07-27 16:06:47 +02:00
Alice Ryhl f2a06bff1b runtime: add owner id for tasks in OwnedTasks (#3979) 2021-07-27 10:41:35 +02:00
Alice Ryhl 0de05422ce Merge branch 'master' and 'merge-1.8.3' 2021-07-26 21:07:52 +02:00
Alice Ryhl afb734d189 chore: prepare Tokio v1.8.3 (#3983) 2021-07-26 17:35:40 +02:00
Alice Ryhl 2b731c0e01 task: elaborate on queue behavior of spawn_blocking (#3981) 2021-07-26 15:37:17 +02:00
Alice Ryhl 8f27c04a9e codec: remove unnecessary doc(cfg(...)) (#3989) 2021-07-26 12:32:24 +02:00
LinkTed c85a0e524e process: add arg0 method to Command (#3984) 2021-07-26 11:43:55 +02:00
Alice Ryhl 1eb468be08 task: fix leak in LocalSet (#3978) 2021-07-22 15:26:31 +02:00
Alice Ryhl 378409d15d runtime: add large test and fix leak it found (#3967) 2021-07-22 15:26:31 +02:00
Alice Ryhl 51ff95c144 chore: use the loom mutex wrapper everywhere (#3958) 2021-07-22 15:26:23 +02:00
Alice Ryhl df10b68d47 readme: add release schedule and bugfix policy (#3948) 2021-07-22 13:53:43 +02:00
Alice Ryhl b280c6dcd7 chore: prepare Tokio v1.9.0 (#3961) 2021-07-22 12:05:39 +02:00
Alice Ryhl 998dc5a2eb task: fix leak in LocalSet (#3978) 2021-07-22 12:05:02 +02:00
Alice Ryhl ced7992f65 runtime: add large test and fix leak it found (#3967) 2021-07-22 09:06:38 +02:00
Alice Ryhl 0cefa85bfa runtime: make scheduler non-optional (#3980) 2021-07-21 20:05:21 +02:00
Alice Ryhl 2087f3e0eb runtime: rework binding of new tasks (#3955) 2021-07-20 16:43:34 +02:00
Blas Rodriguez Irizar 5ae2855eaf io: fix docs referring to clear_{read,write}_ready (#3957) 2021-07-20 15:35:18 +02:00
Ian Jackson 252004811f sync: add getter for the mutex from a guard (#3928) 2021-07-20 15:28:31 +02:00
Alice Ryhl 549e89e9cd chore: use the loom mutex wrapper everywhere (#3958) 2021-07-20 12:12:30 +02:00
Carl Lerche c8fc492748 Merge remote-tracking branch 'origin/tokio-1.8.x' into merge-1.8 2021-07-19 12:13:21 -07:00
Carl Lerche 7147042534 chore: prepare Tokio v1.8.2 release 2021-07-19 11:16:26 -07:00
Diggory Blake 634fcac2d9 runtime: drop future when polling cancelled future (#3965) 2021-07-19 11:16:26 -07:00
Diggory Blake 7c4183a45d runtime: drop future when polling cancelled future (#3965) 2021-07-18 22:46:35 +02:00
Alice Ryhl aef2d64b0a task: remove mutex in JoinError (#3959) 2021-07-16 09:50:03 +02:00
Alice Ryhl 8f10d81613 net: documentation updates (#3944) 2021-07-13 14:23:25 +02:00
Alice Ryhl 7a11cfd77a chore: update async_send_sync test (#3943) 2021-07-12 07:38:19 -07:00
Alice Ryhl 6610ba9bd6 runtime: use OwnedTasks in LocalSet (#3950) 2021-07-12 14:42:00 +02:00
Alan Somers 3fd88dac64 net: fix the uds_datagram tests with the latest nightly stdlib (#3952) 2021-07-12 11:36:50 +02:00
Alice Ryhl ccd495647d chore: update nightly version (#3953) 2021-07-12 11:21:10 +02:00
Alice Ryhl 80d8d40a34 sync: clean up OnceCell (#3945) 2021-07-12 11:19:14 +02:00
Alice Ryhl 3b38ebd7f5 runtime: move inject queue to tokio::runtime::task (#3939) 2021-07-12 10:31:36 +02:00
Alan Somers 127983e5b4 tests: update Nix to 0.22.0 (#3951) 2021-07-11 09:53:04 +02:00
ty c306bf853a net: allow customized I/O operations for TcpStream (#3888) 2021-07-08 13:02:40 +02:00
Moritz Gunz c6fbb9aeb1 task: expose nameable future for TaskLocal::scope (#3273) 2021-07-08 12:54:31 +02:00
Alice Ryhl 5d61c997e9 chore: prepare tokio-stream 0.1.7 (#3923) 2021-07-07 10:58:51 +02:00
Alice Ryhl c505a2f81a chore: prepare tokio-macros 1.3.0 (#3931) 2021-07-07 10:58:02 +02:00
Alice Ryhl e2589a0e40 runtime: add OwnedTasks (#3909) 2021-07-07 10:53:57 +02:00
Alice Ryhl 51fad066e2 bench: update spawn benchmarks (#3927) 2021-07-07 10:52:53 +02:00
Alice Ryhl ae233c1e9f Merge branch 'upstream/merge-1.8.1' into 'master' 2021-07-07 10:22:13 +02:00
Alice Ryhl be26ca7625 sync: wrap state in helper struct (#3922) 2021-07-07 10:17:47 +02:00
Carl Lerche 2d41f0303e Merge branch 'tokio-1.8.x' into merge-1.8.1 2021-07-06 16:20:57 -07:00
Carl Lerche e0c527f383 chore: prepare Tokio v1.8.1 release 2021-07-06 15:37:17 -07:00
Carl Lerche 1160e8864c Merge branch 'tokio-1.7.x' into merge-1.7.2 2021-07-06 15:36:24 -07:00
Carl Lerche 998a125717 chore: prepare Tokio 1.7.2 release 2021-07-06 14:35:36 -07:00
Carl Lerche cbfdc9d69e Merge branch 'tokio-1.6.x' into merge-1.6.3 2021-07-06 14:34:34 -07:00
Carl Lerche 08337c5f79 chore: prepare Tokio v1.6.3 2021-07-06 13:45:47 -07:00
Carl Lerche 87f4969fbc Merge branch 'tokio-1.5.x' into merge-1.5.x 2021-07-06 13:44:11 -07:00
Alice Ryhl e385108920 rt: remotely abort tasks on JoinHandle::abort (#3934) 2021-07-06 13:41:25 -07:00
Blas Rodriguez Irizar 4818c2ed05 fs: document performance considerations (#3920) 2021-07-06 16:25:13 +02:00
Blas Rodriguez Irizar 80f0801e19 tokio-macros: compat with clippy::unwrap_used (#3926) 2021-07-06 15:01:13 +02:00
David CARLIER 8148b2107c net: make ucred return pid field for OpenBSD (#3919) 2021-07-06 11:15:15 +02:00
oiovoyo 2e7de1ae1d stream: modify HashMap to StreamMap in example. (#3925) 2021-07-05 16:10:55 +02:00
Alice Ryhl 37e60fc7f9 chore: fix new clippy complaint (#3915) 2021-07-05 09:58:49 +02:00
Alice Ryhl 8170e2787c sync: fix watch wrapper (#3914) 2021-07-02 23:24:02 +02:00
Alice Ryhl 677107d8d9 chore: prepare Tokio v1.8.0 (#3912) 2021-07-02 22:21:10 +02:00
Alice Ryhl c8ecfc894d sync: fix watch borrow_and_update (#3913) 2021-07-02 10:14:34 -07:00
Taiki Endo 08ed41f339 chore: fix typos (#3907) 2021-07-01 02:06:56 +09:00
Alice Ryhl 90e1935c48 test: test with tracing (#3906) 2021-06-30 09:40:10 -07:00
Alice Ryhl b877629cb1 net: handle HUP event with UnixStream (#3898)
Fixes: #3879
2021-06-30 09:39:06 -07:00
Mikhail Zabaluev 0531549b6e io: efficient implementation of vectored writes for BufWriter (#3163) 2021-06-29 20:26:47 +02:00
Alice Ryhl 38204f5fba time: fix Timeout size_hint (#3902) 2021-06-29 20:06:10 +02:00
Jacob Rothstein 8fa29cb00a rt: add tokio::task::Builder (#3881)
Adds a builder API for spawning tasks. Initially, this enables the caller to name the spawned
task in order to provide better visibility into all tasks in the system.
2021-06-29 10:47:30 -07:00
Alice Ryhl b521cc2689 doc: document cancellation safety (#3900)
This patch documents cancellation safety. It also moves the "Avoid racy if preconditions"
section in the select! documentation since otherwise the first code block on the page
shows how not to use it, which seems counterintuitive.
2021-06-29 10:35:42 -07:00
Jake Shadle 57c90c9750 net: add read/try_read etc methods to NamedPipeServer (#3899) 2021-06-29 10:05:20 +02:00
Mikail Bagishov d35ff7064f sync: add drop guard for cancellation token (#3839) 2021-06-28 12:34:58 +02:00
Milo ab0791b817 time: add wait alias to sleep (#3897) 2021-06-28 10:48:07 +02:00
Jake Shadle 959c5c997f net: add ready/try methods to NamedPipeClient (#3866) 2021-06-28 10:43:57 +02:00
sb64 845626410a sync: implement From<T> for OnceCell<T> (#3877) 2021-06-22 15:11:01 +02:00
Carl Lerche 3207479fa7 Merge branch 'tokio-1.7.x' into merge-1.7.1 2021-06-18 16:37:21 -07:00
Carl Lerche 7601dc6d2a rt: avoid early task shutdown (#3870)
Tokio 1.7.0 introduced a change intended to eagerly shutdown newly
spawned tasks if the runtime is in the process of shutting down.
However, it introduced a bug where already spawned tasks could be
shutdown too early, resulting in the potential introduction of deadlocks
if tasks acquired mutexes in drop handlers.

Fixes #3869
2021-06-18 16:32:53 -07:00
Alice Ryhl d1aa2df80e sync: add Receiver::borrow_and_update (#3813) 2021-06-16 18:42:05 +02:00
sb64 e979ad7f2d time: allow users to specify Interval behavior when delayed (#3721) 2021-06-16 13:51:27 +02:00
sb64 5ad3dd3378 time: document auto-advancing behavior of runtime (#3763) 2021-06-16 13:51:12 +02:00
teor 60bd40d529 time: fix typo in Instant::saturating_duration_since docs (#3864) 2021-06-16 12:50:30 +02:00
brain0 4a93af4d25 io: add get_{ref,mut} methods to AsyncFdReadyGuard and AsyncFdReadyMutGuard. (#3807) 2021-06-16 12:45:05 +02:00
Alice Ryhl 34c6a26c01 chore: prepare Tokio v1.7.0 (#3863) 2021-06-15 19:39:33 +02:00
John-John TedroandAlice Ryhl 97e7830364 net: provide NamedPipe{Client, Server} types and builders (#3760)
This builds on https://github.com/tokio-rs/mio/pull/1351 and introduces the
tokio::net::windows::named_pipe module which provides low level types for
building and communicating asynchronously over windows named pipes.

Named pipes require the `net` feature flag to be enabled on Windows.

Co-authored-by: Alice Ryhl <[email protected]>
2021-06-15 08:13:31 +02:00
Carl Lerche 606206ecad Merge branch 'tokio-1.6.x' into merge-1.6.x 2021-06-14 17:51:30 -07:00
Carl Lerche dfe4013ff2 chore: prepare Tokio 1.6.2 release (#3859) 2021-06-14 17:50:34 -07:00
Carl Lerche 18779aa2e2 time: fix time::advance() with sub-ms durations (#3852)
Instead of using sleep in time::advance, this fixes the root of the issue. When futures passed
to `Runtime::block_on` are woken, it bypassed all the machinery around advancing time. By
intercepting wakes in the time driver, we know when the block_on task is woken and skip
advancing time in that case.

Fixes #3837
2021-06-14 16:36:04 -07:00
Alan Somers 2c24a028f6 chore: re-enable test_socket_pair on FreeBSD (#3844)
It was disabled due to an OS bug that has been fixed on all currently
supported releases of FreeBSD
2021-06-14 13:14:35 -07:00
Sean McArthur f55b77aadd tracing: emit waker op as str instead as Debug (#3853) 2021-06-14 10:37:24 -07:00
Yotam Ofek 21de476ae7 sync: export sync::notify::Notified future publicly (#3840) 2021-06-14 10:05:34 +02:00
Alice Ryhl cb147a2b3f sync: deprecate mpsc::RecvError (#3833) 2021-06-11 11:01:34 +02:00
Bart Pelle f759240254 chore: update version in README.md (#3851) 2021-06-11 11:01:22 +02:00
AtulJatia 2e44cd29df net: TcpSocket from std::net::TcpStream (#3838) 2021-06-11 10:58:58 +02:00
Oğuz Bilgener 2ab1fb00a9 sync: add examples to Semaphore (#3808) 2021-06-11 10:46:16 +02:00
Evan Mesterhazy d16e50639a doc: clarify EOF condition for AsyncReadExt::read_buf (#3850) 2021-06-09 15:00:32 +02:00
Sean McArthur e7d74b3119 tracing: instrument task wakers (#3836)
## Motivation

In support of tokio-rs/console#37, we want to understand when a specific task's waker has been interacted with, such as when it is awoken, or if it's forgotten (not cloned), etc.

## Solution

When the tracing feature is enabled, a super trait of Future (InstrumentedFuture) is implemented for Instrumented<F> that allows grabbing the task's ID (well, its span ID), and stores that in the raw task trailer. The waker vtable then emits events and includes that ID.
2021-06-08 14:50:40 -07:00
Tony Han d101feac50 runtime: fix typo in task state doc (#3835) 2021-06-04 22:31:04 +02:00
Taiki Endo 9d8b37d51a macros: suppress clippy::default_numeric_fallback lint in generated code (#3831) 2021-06-02 18:16:23 +09:00
James Hallowell d4c89758fc sync: fix spelling mistake in mpsc::Sender docs (#3828) 2021-06-01 09:56:34 +02:00
Taiki Endo 932be12481 ci: ignore private crates in minimal-versions check (#3827) 2021-05-31 23:39:06 +09:00
Edward Shen bdd6765016 doc: clarify limits on return values of AsyncWrite::poll_write (#3820) 2021-05-31 19:55:55 +09:00
Carl Lerche 8f6d8b25bf chore: add FUNDING.yml (#3824)
Reference Tokio sponsorship
2021-05-28 13:55:16 -07:00
Carl Lerche eb7aee980c Merge branch 'tokio-1.6.x' into merge-1.6.1 2021-05-28 10:04:08 -07:00
Alice Ryhl 1baea398c4 chore: prepare Tokio v1.6.1 2021-05-28 09:59:28 -07:00
Alice Ryhl 3fbcf1ba50 Revert "fs: try doing a non-blocking read before punting to the threadpool (#3518)"
This reverts commit 39706b198c.
2021-05-28 09:59:28 -07:00
j-vanderstoep 21264f1d33 tcp: assign an unused port (#3817) 2021-05-28 09:03:27 +02:00
Rafael Bachmann 81ee3d202a doc: fix minor doc typo (stray backtick) (#3814) 2021-05-26 14:23:39 +02:00
Alice Ryhl a39e6c2439 runtime: immediately drop new task when runtime is shut down (#3752) 2021-05-26 10:24:56 +02:00
Petros Angelatos 4abeca7bc5 io: impl AsyncSeek for BufStream (#3810)
Signed-off-by: Petros Angelatos <[email protected]>
2021-05-26 07:11:47 +09:00
GITSRC 5ed84e1cd8 doc: update README.md (#3806) 2021-05-21 09:55:53 +02:00
Lucio Franco 44a070d1b4 doc: add missing backtick (#3799) 2021-05-19 10:14:08 +02:00
Aaron Taner ce9ca45c92 doc: fix invalid #[doc(inline)] warnings on latest nightly. (#3788)
This commit fixed issue #3787 by removing [doc(inline)] from
macro `cfg_macros` and added proper #[doc(inline)] attributes
to `pub use` items inside `cfg_macros` calls.

It's probably not `cfg_macros`s responsibility to inlining public
macros, though it's conveninent to do so. Notice that in lib.rs:

cfg_macros! {
    /// Implementation detail of the `select!` macro. This macro is **not**
    /// intended to be used as part of the public API and is permitted to
    /// change.
    #[doc(hidden)]
    pub use tokio_macros::select_priv_declare_output_enum;

    ...
}

`#[doc(hidden)]` and `#[doc(inline)]` are conflict with each other
in the sense of correctness.

Fixes: #3787
2021-05-18 01:28:17 +09:00
Folyd f3ed064a26 chore: update *::{max, min}_value() to const *::MAX and *::MIN respectively (#3794) 2021-05-17 12:31:58 +02:00
Sören Meier 652f0ae728 sync: add receiver_count to watch::Sender (#3729) 2021-05-15 11:56:24 +02:00
Alice Ryhl ff9b0ef7ca chore: prepare tokio-test v0.4.2 (#3786) 2021-05-14 18:24:13 +02:00
Alice Ryhl aaa150d211 chore: prepare tokio-stream v0.1.6 (#3785) 2021-05-14 18:22:44 +02:00
Alice Ryhl deb1f98125 chore: prepare tokio-util v0.6.7 (#3784) 2021-05-14 18:22:08 +02:00
Alice Ryhl 3a659c47c3 chore: prepare tokio-mcaros v1.2.0 (#3783) 2021-05-14 18:20:17 +02:00
Alice Ryhl 580dc9594c chore: prepare Tokio v1.6.0 (#3782) 2021-05-14 18:19:10 +02:00
Taiki Endo 8c395dfe61 io: impl AsyncSeek for BufReader/BufWriter/BufStream (#3491) 2021-05-14 19:32:00 +09:00
Ivan Petkov e188e99ca3 process: avoid redundant effort to reap orphan processes (#3743) 2021-05-14 10:21:21 +02:00
Kestrer 0b93bd511d net: support non-blocking vectored I/O (#3761) 2021-05-14 09:38:01 +02:00
Alice Ryhl d846bf24b1 sync: Barrier doc should use task, not thread (#3780) 2021-05-13 10:14:10 +02:00
Taiki Endo 9ff7d8c352 net: hide net::unix::datagram module from docs (#3775) 2021-05-10 04:35:09 +09:00
Taiki Endo 8324317005 doc: fix doc-cfg on io::duplex, io::copy_bidirectional, and task::unconstrained (#3773) 2021-05-10 04:03:42 +09:00
Taiki Endo 7207e3ca43 signal: use std::os::raw::c_int instead of libc::c_int on public API (#3774) 2021-05-10 02:53:57 +09:00
Taiki Endo 312321cbd3 chore: enable syntax highlighting for toml in readme 2021-05-09 16:21:36 +02:00
Taiki Endo 17c7ce616c benches: fix build error (#3769) 2021-05-09 22:26:20 +09:00
Taiki Endo f9ce18a524 macros: improve diagnostics on type mismatch (#3766) 2021-05-09 18:58:05 +09:00
Chris Moore 05c3cf3a0a util: impl AsRawFd/AsRawHandle for Compat<T> (#3765) 2021-05-08 12:55:04 +02:00
John-John Tedro 2c5dc83019 cargo: path dependencies for all tokio things (#3764) 2021-05-08 12:54:30 +02:00
sb64 6b9bdd5ca2 chore: fix CI for Rust 1.52 (#3758) 2021-05-06 22:26:27 +02:00
Stefan d4075a4457 io: wake pending writers on DuplexStream close (#3756) 2021-05-06 18:30:39 +02:00
Stefan Sydow 177522cd43 benchmark: add file reading benchmarks (#3013) 2021-05-05 21:49:00 +02:00
Alice Ryhl 7ac341b526 task: update documentation on block_in_place (#3753) 2021-05-05 21:44:02 +02:00
Taiki Endo c4b6b130f3 chore: bump nightly to nightly-2021-04-25 (#3754) 2021-05-05 17:39:17 +02:00
Simon Lindholm 6845a93cbf sync: preserve permit state in notify_waiters (#3660) 2021-05-05 15:20:24 +02:00
Russell Cohen 8ef39dfb22 tokio-test: add assert_elapsed macro (#3728) 2021-05-05 12:09:28 +02:00
MGlolenstine 541b0c3af2 process: updated example (#3748) 2021-05-05 11:51:05 +02:00
Kai Mast 55c5d12451 util: require full feature in tokio-util tests (#3636) 2021-05-05 18:21:25 +09:00
Chế Vũ Gia Hy a945ce0996 stream: implement Error and Display for BroadcastStreamRecvError (#3745) 2021-05-05 11:15:42 +02:00
Russell Cohen 14bb2f624f io: add write_all_buf to AsyncWriteExt (#3737) 2021-05-01 20:54:38 +02:00
Marco Ieni a08ce0d3e0 ci: check docs of private items (#3715) 2021-04-30 13:25:50 +02:00
Arthur Silva 078e317c0b tokio: update CHANGELOG.md (#3735) 2021-04-30 00:26:28 +02:00
kamulos ce9697f2a2 doc: fix missing backtick in select doc (#3732) 2021-04-27 22:23:03 +09:00
Alice Ryhl 73466f4b6c task: update JoinHandle panic message (#3727) 2021-04-25 09:03:14 +02:00
Sunjay Varma 0ba1e3c3e1 sync: add a MutexGuard::map method that returns a MappedMutexGuard (#2472) 2021-04-23 17:26:02 +02:00
Nylonicious 1e2f893da2 chore: fix some clippy lints (#3720) 2021-04-22 13:33:42 +02:00
Carl Lerche 2b9b558108 time: prevent time::advance from going too far (#3712)
Previously, `time::advance` would set the mocked clock forward the
requested amount, then yield. However, if there was no work ready to
perform immediately, this would result in advancing to the next expiring
sleep.

Now, `time::advance(...)` will unblock at the requested time. The
difference between `time::advance(...)` and `time::sleep(...)` is a bit
fuzzy. The main difference is `time::sleep(...)` operates on the current
task and `time::advance(...)` operates at the runtime level.

Fixes #3710
2021-04-21 15:23:35 -07:00
Eliza Weisman d6da67b2e6 sync: add mpsc::Sender::{reserve_owned, try_reserve_owned} (#3704)
* sync: add `mpsc::Sender::{reserve_owned, try_reserve_owned}`

## Motivation

The `mpsc::Sender::reserve` method currently returns a permit that borrows
from the `Sender`. It would be nice to have a version of it that returns
an owned permit.

## Solution

This branch adds an `OwnedPermit` type and `Sender::{reserve_owned,
try_reserve_owned}` methods. Unlike the comparable methods on
`Semaphore`, these methods do *not* require an `Arc<Sender>` as the
receiver; this is because the sender internally reference counts the
channel and is already cheap to clone. Requiring an `Arc` would simply
add an unnecessary second layer of reference counting, which is not
ideal; instead, the documentation encourages the user to clone the
sender prior to calling `reserve_owned` when necessary.

Since these methods take the `Sender` by value, they also have the ability
to _return_ the `Sender` from a successful `OwnedPermit::send`. This
allows them to be used without additional clones. Essentially, this is a
very simple type-level encoding of the sender's state, with the
transitions
```
      ┌──────┐
 ┌───►│Sender├───┐
 │    └──────┘   │
send          reserve
 │ ┌───────────┐ │
 └─┤OwnedPermit│◄┘
   └───────────┘
```

Additionally, I added an `OwnedPermit::release`, which returns the
`Sender` and releases the permit *without* sending a message.

Closes #3688 

Signed-off-by: Eliza Weisman <[email protected]>
2021-04-15 12:55:57 -07:00
madjack c8a6bb0b90 time: add getter for Interval's period (#3705) 2021-04-15 14:21:52 +02:00
Evan Cameron 9eeec039f2 util: make UdpFramed take Borrow<UdpSocket> (#3451) 2021-04-14 20:16:23 +02:00
William Manley 39706b198c fs: try doing a non-blocking read before punting to the threadpool (#3518) 2021-04-14 15:44:49 +02:00
baoyachi. Aka Rust Hairy crabs cab4a592ac chore: update version in README.md (#3698) 2021-04-13 16:17:14 +09:00
Alice Ryhl a5ee2f0d3d chore: prepare Tokio v1.5.0 (#3695) 2021-04-12 21:24:47 +02:00
Alice Ryhl 917aad684b chore: prepare tokio-util 0.6.6 (#3696) 2021-04-12 21:23:20 +02:00
Alice Ryhl e366cf9b3e chore: upgrade loom to 0.5.0 (#3697) 2021-04-12 20:28:48 +02:00
Alice Ryhl 3a02d34d3a sync: document that Semaphore is fair (#3693) 2021-04-12 15:46:42 +02:00
conblem adad8fc3cd io: add a copy_bidirectional utility (#3572) 2021-04-12 14:18:45 +02:00
David Pedersen 08f1b67fcb sync: add mpsc::Sender::capacity (#3690)
Simply exposes the number of available permits of the semaphore.

This makes some kinds of bookkeeping easier without having to manually keep counts using atomics.

Fixes #2642
2021-04-12 09:23:03 +02:00
David Pedersen 28d6879897 macros: forward input arguments in #[tokio::test] (#3691)
Fixes #2388

Previously `#[tokio::test]` would error on functions that took
arguments. That meant other attribute macros couldn't do further
transformations on them. This changes that so arguments are forwarded as
is.

Whatever else might be included on the function is forwarded as well.
For example return type, generics, etc.

Worth noting that this is only for compatibility with other macros.
`#[test]`s that take arguments will still fail to compile.

A bit odd that [trybuild] tests don't fail `#[test]` functions with
arguments which is why the new tests are run with `t.pass(...)`. They do
actually fail if part of a real crate.

[trybuild]: https://crates.io/crates/trybuild
2021-04-11 20:39:05 +02:00
John-John Tedro 1a72b28f53 rt: fix panic in JoinHandle::abort() when called from other thread (#3672)
When aborting a task registered with a current-thread scheduler from off runtime, the tasks may not
be immediately unlinked from the runtime. Instead, send a message to the runtime, notifying it to
remove the aborted task.

Fixes #3662
2021-04-08 13:49:39 -07:00
Geoffry Song 1d5655272b runtime: use Park::Error: Debug for better panic messages (#3641) 2021-04-08 20:30:43 +02:00
Matthias Beyer 5513b6b825 time: change 300ms to 1s in documentation (#3685) 2021-04-08 11:04:27 +02:00
ty 787aca1826 net: implement IntoRawFd for TcpSocket (#3684) 2021-04-08 09:28:44 +02:00
Zahari Dichev e89c8981f1 sync: allow configuring RwLock max reads (#3644) 2021-04-07 20:44:29 +02:00
Eliza Weisman bf8c77bea1 util: add PollSemaphore::{add_permits, available_permits} (#3683)
## Motivation

The `tokio::sync::Semaphore` type provides a
[`Semaphore::available_permits` method][1] which returns the current
number of permits available on the semaphore.
`tokio_util::sync::PollSemaphore` [does not expose such a method][2]. It
is possible to use `PollSemaphore::into_inner` or
`PollSemaphore::clone_inner` to unwrap the inner semaphore, but this may
require cloning/dropping the semaphore's `Arc` which shouldn't be
necessary to access the permits.

## Solution

This commit adds `PollSemaphore::available_permits`. It also adds
`PollSemaphore::add_permits` and an `AsRef<Semaphore>` impl while
we're here.

[1]: https://docs.rs/tokio/1.4.0/tokio/sync/struct.Semaphore.html#method.available_permits
[2]: https://docs.rs/tokio-util/0.6.5/tokio_util/sync/struct.PollSemaphore.html#implementations

Closes #3682
2021-04-07 11:40:03 -07:00
Lucas Zanela 0074b963b8 doc: add features = "full" to readme (#3680) 2021-04-06 11:03:21 +02:00
David Pedersen eabb7ce61c io: add AsyncWriteExt::write_vectored (#3678)
Fixes #3676
2021-04-06 00:02:00 +02:00
David Pedersen 618d2bfc71 macros: various error message improvements (#3677)
Improves a few of the error messages for `#[tokio::main]` and `#[tokio::test]`.

Also adds a note to the docs about `start_paused` requiring the `test-util` feature which wasn't mentioned previously.
2021-04-05 22:40:42 +02:00
b-naber f6e4e85dfb sync: add OnceCell (#3591) 2021-04-05 22:03:57 +02:00
xd009642 f93bc9bad1 sync: don't panic in oneshot::try_recv (#3674) 2021-04-04 20:03:00 +02:00
Michael P. Jung b05b9a1788 sync: add Semaphore::is_closed (#3673) 2021-04-04 19:14:41 +02:00
Donough Liu b42f21ec3e doc: fix incorrect link in doc (#3670) 2021-04-01 15:24:29 +02:00
Nylonicious 8fc49dc522 chore: update years in all licenses (#3665) 2021-03-30 21:45:13 +02:00
Amos Wenger 9ec3393650 net: typo in socket.rs (#3663) 2021-03-30 20:44:54 +02:00
Simon Lindholm f7c181c2c4 sync: fix notifications getting dropped on receiver drop (#3652) 2021-03-30 09:18:07 +02:00
Alice Ryhl fee76ea7d5 chore: try to avoid noalias attributes on intrusive linked list (#3654) 2021-03-29 22:38:29 +02:00
CorinJG 1a80d6eee5 sync: improve doc on blocking mutex (#3645) 2021-03-27 13:26:10 +01:00
Taiki Endo 7384813979 chore: update proptest to 1 (#3653) 2021-03-27 19:34:11 +09:00
Taiki Endo a257a3a2b1 io: add AsyncSeekExt::stream_position (#3650) 2021-03-27 12:28:51 +09:00
Alexandr 9a3603fa75 chore: fix several typos in docs (#3651) 2021-03-27 12:27:52 +09:00
Alice Ryhl 724ba348d1 chore: fix warning from new Rust version (#3647) 2021-03-26 19:22:43 +09:00
Kai Jewson 0dc4769708 sync: add OwnedRwLockReadGuard and OwnedRwLockWriteGuard (#3340) 2021-03-23 13:40:17 +01:00
Mihail Malo 6f896d8846 macros: add missing => in doc (#3638) 2021-03-22 21:37:29 +01:00
Daniel Franklin 10abc45da1 io: clarify requirements of AsyncFd (#3635) 2021-03-22 21:16:40 +01:00
Moritz Gunz 227b3e0d9c chore: avoid allocation if PollSemaphore is unused (#3634) 2021-03-22 17:02:30 +01:00
quininer c659e4a757 task: add sync_scope for LocalKey (#3612) 2021-03-22 17:02:10 +01:00
somethingelseentirely 8ed825fd49 util: makes Framed and FramedStream resumable after eof (#3272) 2021-03-22 09:09:01 +01:00
Ibraheem Ahmed 63395f061e macros: fix typo in select macro docs (#3629) 2021-03-21 20:10:28 +01:00
Kai Jewson 69b129b405 stream: avoid yielding in AllFuture and AnyFuture (#3625) 2021-03-21 09:34:18 +01:00
David Pedersen 0bfcbc8be5 runtime: fix unclear docs for {Handle,Runtime}::block_on (#3628) 2021-03-20 14:52:25 +01:00
David Pedersen 81f47e8866 util: fix indentation and typos in DelayQueue docs (#3626) 2021-03-20 14:31:12 +01:00
David Pedersen b4918adbd8 chore: prepare tokio-stream v0.1.5 (#3624) 2021-03-20 12:17:37 +01:00
David Pedersen b1310ad14d chore: prepare tokio-util v0.6.5 (#3622) 2021-03-20 12:16:56 +01:00
David Pedersen dcac336dc7 chore: prepare Tokio v1.4.0 (#3621) 2021-03-20 12:16:15 +01:00
David Pedersen c39d9867bb runtime: add Handle::block_on (#3569)
Add `runtime::Handle::block_on`. The function enters the runtime context and
blocks the current thread while the future executes.

Refs: #3097
Fixes #2965, #3096
2021-03-20 10:52:28 +01:00
Ivan Petkov e4f76688a0 runtime: fix memory leak/growth when creating many runtimes (#3564) 2021-03-16 19:31:46 +01:00
Zahari Dichev e6103d6661 docs: add link to PollSender (#3613)
There was no link to [`PollSender`] in [`mpsc::Sender`] docs which made it
less discoverable.

[`PollSender`]: https://docs.rs/tokio-util/0.6.4/tokio_util/sync/struct.PollSender.html
[`mpsc::Sender::send`]: https://docs.rs/tokio/1.3.0/tokio/sync/mpsc/struct.Sender.html
2021-03-16 17:55:06 +01:00
David Pedersen cc90a5c679 chore: mention fix for building docs in contributing guide (#3618)
I ran into this when writing the docs for `Handle::block_on`. Seems to
be caused by a bug in cargo. Until that is fixed I think it makes sense
to mention it in the contributing guide.
2021-03-16 21:39:28 +09:00
David Pedersen f107c4f49b timer: fix double newline in module docs (#3617) 2021-03-16 21:37:50 +09:00
Zahari Dichev e6a9167bb7 runtime: avoid unnecessary polling of block_on future (#3582) 2021-03-16 10:30:18 +01:00
setpill 345b29ca11 sync: improve Mutex FIFO explanation (#3615) 2021-03-12 21:24:05 +01:00
Nate Mara b75d02a2b6 macros: introduce biased argument for select! (#3603) 2021-03-12 21:20:20 +01:00
Faraz a1b4bdee61 runtime: mark EnterGuard with must_use (#3609) 2021-03-12 09:06:08 +01:00
Zahari Dichev edfff7551a util: anotate time module as requiring time feature (#3606)
Signed-off-by: Zahari Dichev <[email protected]>
2021-03-11 16:02:01 +01:00
Rob Ede 1cda0f16a2 doc: alias sleep to delay (#3604) 2021-03-10 23:26:11 +01:00
Lucio Franco e40ec3e424 chore: Prepare tokio-test v0.4.1 release (#3602) 2021-03-10 16:04:08 -05:00
Jake HamandJake Ham 6919f7cede test: Make Mock both Send and Sync (#3594)
Co-authored-by: Jake Ham <[email protected]>
2021-03-10 14:29:22 -05:00
cssivision bcb95db4e2 chore: fix clippy warnings in newer versions (#3588) 2021-03-10 08:42:24 +01:00
Matthew James Briggs 8c5cde9bc3 stream: documentation note for throttle Unpin (#3600) 2021-03-10 08:39:43 +01:00
Alice Ryhl b08b5edb2c chore: prepare tokio-util v0.6.4 (#3599) 2021-03-09 22:11:38 +01:00
Alice Ryhl 88863a0c5d chore: prepare tokio-stream v0.1.4 (#3598) 2021-03-09 22:10:57 +01:00
Alice Ryhl d0e4dd1d7b chore: prepare Tokio v1.3.0 (#3597) 2021-03-09 22:09:51 +01:00
Andrew Liu 872bc09e83 examples: update chat example (#3587) 2021-03-09 19:54:10 +01:00
Alice Ryhl db1d90453c util: fuse PollSemaphore (#3578) 2021-03-09 19:22:36 +01:00
Thomas Orozco 05eeea570e coop: expose an unconstrained() opt-out (#3547) 2021-03-09 19:10:15 +01:00
Henry Gomersall f70b9b84f7 sync: documenation for oneshot (#3592) 2021-03-09 18:58:45 +01:00
nickelc 704de8c01b stream: remove duplicate doc(test(..)) & cfg_attr declarations (#3571) 2021-03-06 20:54:28 +09:00
Thomas Orozco 47be928444 sync: yield initial value in WatchStream (#3576) 2021-03-05 21:35:12 +01:00
Zhang Jingqiang e06b257e09 sync: add same_channel method to mpsc Senders (#3532) 2021-03-04 17:45:40 +01:00
Alice Ryhl 0867a6fc03 util: add pollable mpsc::Sender (#3490) 2021-03-04 17:29:30 +01:00
Gus Wynn 0d838bf5ad io: fix link to std src in util (#3568)
The big move or 'src' in rust-lang caused this link to be broken
2021-03-02 02:50:13 +09:00
Max Bruckner fc23f8a1a5 sync: add {try_,}acquire_many_owned to Semaphore (#3535) 2021-03-01 14:37:00 +01:00
Pirmin Kalberer fd93ecf5e0 stream: remove duplicate doc_cfg declaration (#3561) 2021-02-27 22:47:26 +01:00
Stepan Koltsov d2ad7afd21 time: do not panic on timeout(Duration::MAX) (#3551)
It is tempting to use very large `Duration` value to get a practically
infinite timeout.

Before this commit Tokio panics on checked Instant + Duration
overflow.

This commit implements very simple fix: if Instant + Duration
overflows, we use duration = 30 years. Better fix should avoid
firing a timer on duration overflow. It requires deeper understanding
how timers work, but also it is not clear, for example, what
`Sleep::deadline` function should return.

Similar fix is done for `sleep`.
2021-02-26 10:04:08 +01:00
r-zig 5756a005a6 codec: LinesCodec should only return MaxLineLengthExceeded once per line (#3556) 2021-02-25 23:21:59 +01:00
Paho Lurie-Gregg 017a483b5e io: update AsyncRead::poll_read doc (#3557)
The trait-level documentation accurately describes this method, but the
function-level documentation imples that an implementer should overwrite
the entire buf, rather than just the unfilled portion.
2021-02-25 23:19:02 +01:00
Stepan Koltsov 112e160b62 sync: allow oneshot::Receiver::close after successful try_recv (#3552)
Before this commit `close` after successful `try_recv` panics.

My use case is this: on drop, I call `close` to prevent pushing a
message to the queue, and then fetch the message if any and process
it.

But if message is already processed, `close` panics.  And there is
no API to know if message was already fetched or not (except for
writing a wrapped which would track that info, which would be an
overkill).

But generally `close` operation should be safe to be called any
time.
2021-02-25 20:28:24 +01:00
r-zig c9d2a36c7b codec: AnyDelimiter codec (#3406) 2021-02-23 16:56:11 +01:00
Kestrer 8efed43fa7 runtime: update documentation of thread limits (#3527)
Since ed5a94eb2d, there is no longer a
limit of 32,768 threads on the worker threads and blocking thread pool,
but the documentation has not been updated. This commit removes that
part of the documentation.
2021-02-23 16:54:50 +01:00
Marko Mikulicic 7de18af82c doc: sync interval.rs and time/mod.rs docs (#3533) 2021-02-22 11:45:49 +01:00
xlUpandAaron Taner 52457dcf5b doc: fix typos (#3541)
Co-authored-by: Aaron Taner <[email protected]>
2021-02-22 17:31:45 +09:00
Adam Harvey 53558cb489 doc: note the EOF behaviour of read_until (#3536) 2021-02-20 10:22:51 +01:00
Taiki EndoandAlice Ryhl 36d7dab504 chore: remove html_root_url (#3489)
Co-authored-by: Alice Ryhl <[email protected]>
2021-02-18 14:11:39 -08:00
Kornel 6fd06aaeec doc: doc aliases for pre-1.0 function names (#3523) 2021-02-17 13:00:44 +01:00
Pen Tree 36bcfa6b9d doc: rename notify to notify_one (#3526) 2021-02-15 20:21:27 +01:00
Alice Ryhl e3f2dcf5bc sync: add back RwLockWriteGuard::map and RwLockWriteGuard::try_map (#3348) 2021-02-13 12:53:21 +01:00
Alice Ryhl 7c6a1c4637 net: update UdpSocket splitting doc (#3517) 2021-02-13 11:13:42 +01:00
Alice Ryhl 4099bfdef0 sync: do not recommend join_all for Barrier (#3514) 2021-02-12 10:43:11 +01:00
Alice Ryhl 469b43de6a time: fix typo in Sleep doc (#3515) 2021-02-11 10:30:48 +01:00
Alice Ryhl e827829402 signal: add Signal wrappers to tokio-stream (#3510) 2021-02-07 11:30:18 +01:00
Alice Ryhl 58bd242831 net: add into_std for net types without it (#3509) 2021-02-06 23:01:47 +01:00
Alice Ryhl 6fd9084d47 runtime: add link to LocalSet on new_current_thread (#3508) 2021-02-06 19:08:59 +01:00
Alice Ryhl 572a897d43 chore: prepare tokio v1.2.0 (#3506) 2021-02-05 23:27:42 +01:00
Alice Ryhl d41882e2a1 chore: prepare tokio-macros 1.1.0 (#3505) 2021-02-05 22:21:29 +01:00
Alice Ryhl 23fdc2b3c4 chore: prepare tokio-stream 0.1.3 (#3507) 2021-02-05 22:18:56 +01:00
Alice Ryhl 0a04954d5c stream: update features and doc for broadcast/watch stream (#3504) 2021-02-05 20:39:27 +01:00
Steven Fackler fcb6d041b9 time: make test-util paused time fully deterministic (#3492)
The time driver stores an Instant internally used as a "base" for future
time calculations. Since this is generated as the Runtime is being
constructed, it previously always happened before the user had a chance
to pause time. The fractional-millisecond variations in the timing
around the runtime construction and time pause cause tests running
entirely in paused time to be very slightly deterministic, with the time
driver advancing time by 1 millisecond more or less depending on how the
sub-millisecond components of the `Instant`s involved compared.

To avoid this, there is now a new option on `runtime::Builder` which
will create a `Runtime` with time "instantly" paused. This, along with a
small change to have the time driver use the provided clock as the
source for its start time allow totally deterministic tests with paused
time.
2021-02-05 20:12:25 +01:00
Fuyang Liu 1c1e0e3fc9 tokio-stream: add wrapper for broadcast and watch (#3384) 2021-02-05 19:56:24 +01:00
Fuyang Liu 77ca8a934c signal: make Signal::poll_recv method public (#3383)
Signed-off-by: Fuyang Liu <[email protected]>
2021-02-05 19:43:58 +01:00
surechen 3e5a0a7df6 runtime: fix a spelling mistake (#3503) 2021-02-04 12:30:31 +01:00
Artem VorotnikovandTaiki Endo cc97fb8a5f Suppress deprecated warnings for spin_loop_hint (#3497)
* Suppress deprecated warnings for spin_loop_hint

* Update tokio/src/loom/std/mod.rs

Co-authored-by: Taiki Endo <[email protected]>

* Update tokio/src/sync/task/atomic_waker.rs

Co-authored-by: Taiki Endo <[email protected]>

* fmt

Co-authored-by: Taiki Endo <[email protected]>
2021-02-01 15:55:21 +03:00
Alice Ryhl 60d88840f4 chore: prepare tokio-util v0.6.3 (#3488) 2021-01-31 12:39:22 +01:00
Alice Ryhl ee1f0c473f util: remove tokio-stream dependency from tokio-util (#3487) 2021-01-31 11:08:40 +01:00
Rob Ede 06d6adf4b7 util: use ReusableBoxFuture for PollSemaphore (#3463) 2021-01-30 10:57:04 +01:00
Alice Ryhl 891aba5f71 util: add ReusableBoxFuture utility (#3464) 2021-01-30 00:03:01 +01:00
Carl Lerche 10c3b2f4a3 Merge branch 'tokio-1.1.x' 2021-01-29 14:13:24 -08:00
Markus Westerlind 6f988728bb runtime: minimize the amount of duplicated code (#3416) 2021-01-29 21:45:29 +01:00
Carl Lerche 085f819f28 Merge branch 'tokio-1.0.x' into 'tokio-1.1.x' 2021-01-28 20:23:50 -08:00
Carl Lerche 5d0a81fb91 io: fix memory leak during shutdown (#3477)
In some cases, a cycle is created between I/O driver wakers and the I/O
driver resource slab. This patch clears stored wakers when an I/O
resource is dropped, breaking the cycle.

Fixes #3228
2021-01-28 17:49:10 -08:00
Ivan Petkov 1f9765fb5f process: add missing drop child stdin to wait() (#3421) 2021-01-28 23:08:44 +01:00
Jamie 225e8ea05f sync: update RwLock doc to mention possibility of deadlock (#3389) 2021-01-28 16:38:49 +01:00
Alice Ryhl cd7526873c net: improve discoverability of TcpSocket (#3471) 2021-01-28 14:09:14 +01:00
vitalyd 4968f59af6 sync: update Sender::try_reserve doc (#3476) 2021-01-28 10:31:23 +01:00
Ivan Petkov 34f1d3d040 process: allow for ergonomically piping stdio of one child into another (#3466)
* Add `TryInto<Stdio>` impls for `ChildStd{in,out,err}` for ergonomic
  conversions into `std::process::Stdio` so callers can perform the
  conversion without needing to manipulate raw fds/handles directly
2021-01-27 01:12:54 +00:00
Ontonator f13a9dd87a tokio: update dates in CHANGELOG.md to 2021 (#3469) 2021-01-25 12:04:58 +01:00
444 changed files with 38399 additions and 6431 deletions
+8
View File
@@ -0,0 +1,8 @@
# See https://github.com/rustsec/rustsec/blob/59e1d2ad0b9cbc6892c26de233d4925074b4b97b/cargo-audit/audit.toml.example for example.
[advisories]
ignore = [
# We depend on nix 0.22 only via mio-aio, a dev-dependency.
# https://github.com/tokio-rs/tokio/pull/4255#issuecomment-974786349
"RUSTSEC-2021-0119",
]
+2
View File
@@ -0,0 +1,2 @@
# [build]
# rustflags = ["--cfg", "tokio_unstable"]
+25
View File
@@ -0,0 +1,25 @@
version: 2.1
jobs:
test-arm:
machine:
image: ubuntu-2004:202101-01
resource_class: arm.medium
environment:
# Change to pin rust versino
RUST_STABLE: stable
steps:
- checkout
- run:
name: Install Rust
command: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup.sh
chmod +x rustup.sh
./rustup.sh -y --default-toolchain $RUST_STABLE
source "$HOME"/.cargo/env
# Only run Tokio tests
- run: cargo test --all-features -p tokio
workflows:
ci:
jobs:
- test-arm
+39 -12
View File
@@ -1,19 +1,51 @@
freebsd_instance:
image: freebsd-12-2-release-amd64
image: freebsd-12-3-release-amd64
env:
RUST_STABLE: stable
RUST_NIGHTLY: nightly-2022-03-21
RUSTFLAGS: -D warnings
# Test FreeBSD in a full VM on cirrus-ci.com. Test the i686 target too, in the
# same VM. The binary will be built in 32-bit mode, but will execute on a
# 64-bit kernel and in a 64-bit environment. Our tests don't execute any of
# the system's binaries, so the environment shouldn't matter.
task:
name: FreeBSD
env:
LOOM_MAX_PREEMPTIONS: 2
RUSTFLAGS: -Dwarnings
name: FreeBSD 64-bit
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain stable
- sh rustup.sh -y --profile minimal --default-toolchain $RUST_STABLE
- . $HOME/.cargo/env
- |
echo "~~~~ rustc --version ~~~~"
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo test --all --all-features
task:
name: FreeBSD docs
env:
RUSTFLAGS: --cfg docsrs --cfg tokio_unstable
RUSTDOCFLAGS: --cfg docsrs --cfg tokio_unstable -Dwarnings
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain $RUST_NIGHTLY
- . $HOME/.cargo/env
- |
echo "~~~~ rustc --version ~~~~"
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo doc --lib --no-deps --all-features --document-private-items
task:
name: FreeBSD 32-bit
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain $RUST_STABLE
- . $HOME/.cargo/env
- rustup target add i686-unknown-freebsd
- |
@@ -21,9 +53,4 @@ task:
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo test --all --all-features
- cargo doc --all --no-deps
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --all-features --target i686-unknown-freebsd
- cargo test --all --all-features --target i686-unknown-freebsd
+1
View File
@@ -0,0 +1 @@
msrv = "1.49"
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [tokio-rs]
+8
View File
@@ -0,0 +1,8 @@
R-loom:
- tokio/src/sync/*
- tokio/src/sync/**/*
- tokio-util/src/sync/*
- tokio-util/src/sync/**/*
- tokio/src/runtime/*
- tokio/src/runtime/**/*
-55
View File
@@ -1,55 +0,0 @@
name: Benchmark
on:
push:
branches:
- master
jobs:
benchmark:
name: Benchmark
runs-on: ubuntu-latest
strategy:
matrix:
bench:
- rt_multi_threaded
- sync_mpsc
- sync_rwlock
- sync_semaphore
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
# Run benchmark with `go test -bench` and stores the output to a file
- name: Run benchmark
run: cargo bench --bench ${{ matrix.bench }} | tee ../output.txt
working-directory: benches
# Download previous benchmark result from cache (if exists)
- name: Download previous benchmark data
uses: actions/cache@v1
with:
path: ./cache
key: ${{ runner.os }}-benchmark
# Run `github-action-benchmark` action
- name: Store benchmark result
uses: rhysd/github-action-benchmark@v1
with:
name: ${{ matrix.bench }}
# What benchmark tool the output.txt came from
tool: 'cargo'
# Where the output from the benchmark tool is stored
output-file-path: output.txt
# # Where the previous data file is stored
# external-data-json-path: ./cache/benchmark-data.json
# Workflow will fail when an alert happens
fail-on-alert: true
# GitHub API token to make a commit comment
github-token: ${{ secrets.GITHUB_TOKEN }}
# Enable alert commit comment
comment-on-alert: true
alert-comment-cc-users: '@tokio-rs/maintainers'
auto-push: true
# Upload the updated cache file for the next job by actions/cache
+246 -67
View File
@@ -9,8 +9,15 @@ name: CI
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2020-09-21
minrust: 1.45.2
# Change to specific Rust release to pin
rust_stable: stable
rust_nightly: nightly-2022-03-21
rust_clippy: 1.52.0
rust_min: 1.49.0
defaults:
run:
shell: bash
jobs:
# Depends on all action sthat are required for a "successful" CI run.
@@ -20,6 +27,7 @@ jobs:
needs:
- test
- test-unstable
- test-parking_lot
- miri
- cross
- features
@@ -27,7 +35,11 @@ jobs:
- fmt
- clippy
- docs
- loom
- valgrind
- loom-compile
- check-readme
- test-hyper
- wasm32-unknown-unknown
steps:
- run: exit 0
@@ -42,8 +54,14 @@ jobs:
- macos-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
@@ -67,6 +85,72 @@ jobs:
run: cargo hack test --each-feature
working-directory: tests-build
# Build benchmarks. Run of benchmarks is done by bench.yml workflow.
- name: build benches
run: cargo build --benches
working-directory: benches
# bench.yml workflow runs benchmarks only on linux.
if: startsWith(matrix.os, 'ubuntu')
test-parking_lot:
# The parking_lot crate has a feature called send_guard which changes when
# some of its types are Send. Tokio has some measures in place to prevent
# this from affecting when Tokio types are Send, and this test exists to
# ensure that those measures are working.
#
# This relies on the potentially affected Tokio type being listed in
# `tokio/tokio/tests/async_send_sync.rs`.
name: compile tests with parking lot send guards
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Enable parking_lot send_guard feature
# Inserts the line "plsend = ["parking_lot/send_guard"]" right after [features]
run: sed -i '/\[features\]/a plsend = ["parking_lot/send_guard"]' tokio/Cargo.toml
- name: Compile tests with all features enabled
run: cargo build --workspace --all-features --tests
valgrind:
name: valgrind
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install Valgrind
run: |
sudo apt-get update -y
sudo apt-get install -y valgrind
# Compile tests
- name: cargo build test-mem
run: cargo build --features rt-net --bin test-mem
working-directory: tests-integration
# Run with valgrind
- name: Run valgrind test-mem
run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/debug/test-mem
# Compile tests
- name: cargo build test-process-signal
run: cargo build --features rt-process-signal --bin test-process-signal
working-directory: tests-integration
# Run with valgrind
- name: Run valgrind test-process-signal
run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/debug/test-process-signal
test-unstable:
name: test tokio full --unstable
runs-on: ${{ matrix.os }}
@@ -78,44 +162,54 @@ jobs:
- macos-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
# Run `tokio` with "unstable" cfg flag.
- name: test tokio full --cfg unstable
run: cargo test --features full
run: cargo test --all-features
working-directory: tokio
env:
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
# in order to run doctests for unstable features, we must also pass
# the unstable cfg to RustDoc
RUSTDOCFLAGS: --cfg tokio_unstable
miri:
name: miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
toolchain: ${{ env.rust_nightly }}
components: miri
override: true
- name: Install Miri
run: |
set -e
rustup component add miri
cargo miri setup
rm -rf tokio/tests
- uses: Swatinem/rust-cache@v1
- name: miri
run: cargo miri test --features rt,rt-multi-thread,sync task
# Many of tests in tokio/tests and doctests use #[tokio::test] or
# #[tokio::main] that calls epoll_create1 that Miri does not support.
run: cargo miri test --features full --lib --no-fail-fast
working-directory: tokio
env:
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-tag-raw-pointers
PROPTEST_CASES: 10
san:
name: san
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
toolchain: ${{ env.rust_nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: asan
run: cargo test --all-features --target x86_64-unknown-linux-gnu --lib -- --test-threads 1
working-directory: tokio
@@ -134,34 +228,45 @@ jobs:
- powerpc64-unknown-linux-gnu
- mips-unknown-linux-gnu
- arm-linux-androideabi
- mipsel-unknown-linux-musl
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: stable
toolchain: ${{ env.rust_stable }}
target: ${{ matrix.target }}
override: true
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: check
args: --workspace --target ${{ matrix.target }}
args: --workspace --all-features --target ${{ matrix.target }}
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: check
args: --workspace --all-features --target ${{ matrix.target }}
env:
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
features:
name: features
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
toolchain: ${{ env.rust_nightly }}
target: ${{ matrix.target }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
- name: check --each-feature
run: cargo hack check --all --each-feature -Z avoid-dev-deps
# Try with unstable feature flags
- name: check --each-feature --unstable
run: cargo hack check --all --each-feature -Z avoid-dev-deps
@@ -173,11 +278,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_min }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.minrust }}
toolchain: ${{ env.rust_min }}
override: true
- uses: Swatinem/rust-cache@v1
- name: "test --workspace --all-features"
run: cargo check --workspace --all-features
@@ -186,10 +292,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
toolchain: ${{ env.rust_nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
- name: "check --all-features -Z minimal-versions"
@@ -199,24 +307,36 @@ jobs:
cargo hack --remove-dev-deps --workspace
# Update Cargo.lock to minimal version dependencies.
cargo update -Z minimal-versions
cargo check --all-features
cargo hack check --all-features --ignore-private
- name: "check --all-features --unstable -Z minimal-versions"
env:
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
run: |
# Remove dev-dependencies from Cargo.toml to prevent the next `cargo update`
# from determining minimal versions based on dev-dependencies.
cargo hack --remove-dev-deps --workspace
# Update Cargo.lock to minimal version dependencies.
cargo update -Z minimal-versions
cargo hack check --all-features --ignore-private
fmt:
name: fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Install rustfmt
run: rustup component add rustfmt
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
components: rustfmt
- uses: Swatinem/rust-cache@v1
# Check fmt
- name: "rustfmt --check"
# Workaround for rust-lang/cargo#7732
run: |
if ! rustfmt --check --edition 2018 $(find . -name '*.rs' -print); then
printf "Please run \`rustfmt --edition 2018 \$(find . -name '*.rs' -print)\` to fix rustfmt errors.\nSee CONTRIBUTING.md for more details.\n" >&2
if ! rustfmt --check --edition 2018 $(git ls-files '*.rs'); then
printf "Please run \`rustfmt --edition 2018 \$(git ls-files '*.rs')\` to fix rustfmt errors.\nSee CONTRIBUTING.md for more details.\n" >&2
exit 1
fi
@@ -225,11 +345,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update ${{ env.minrust }} && rustup default ${{ env.minrust }}
- name: Install clippy
run: rustup component add clippy
- name: Install Rust ${{ env.rust_clippy }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_clippy }}
override: true
components: clippy
- uses: Swatinem/rust-cache@v1
# Run clippy
- name: "clippy --all"
run: cargo clippy --all --tests --all-features
@@ -239,37 +361,94 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
toolchain: ${{ env.rust_nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: "doc --lib --all-features"
run: cargo doc --lib --no-deps --all-features
run: cargo doc --lib --no-deps --all-features --document-private-items
env:
RUSTDOCFLAGS: --cfg docsrs
RUSTFLAGS: --cfg docsrs --cfg tokio_unstable
RUSTDOCFLAGS: --cfg docsrs --cfg tokio_unstable -Dwarnings
loom:
name: loom
loom-compile:
name: build loom tests
runs-on: ubuntu-latest
strategy:
matrix:
scope:
- --skip loom_pool
- loom_pool::group_a
- loom_pool::group_b
- loom_pool::group_c
- loom_pool::group_d
- time::driver
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: loom ${{ matrix.scope }}
run: cargo test --lib --release --features full -- --nocapture $SCOPE
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: build --cfg loom
run: cargo test --no-run --lib --features full
working-directory: tokio
env:
RUSTFLAGS: --cfg loom --cfg tokio_unstable -Dwarnings
LOOM_MAX_PREEMPTIONS: 2
SCOPE: ${{ matrix.scope }}
check-readme:
name: Check README
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Verify that both READMEs are identical
run: diff README.md tokio/README.md
- name: Verify that Tokio version is up to date in README
working-directory: tokio
run: grep -q "$(sed '/^version = /!d' Cargo.toml | head -n1)" README.md
test-hyper:
name: Test hyper
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- windows-latest
- ubuntu-latest
- macos-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Test hyper
run: |
set -x
git clone https://github.com/hyperium/hyper.git
cd hyper
# checkout the latest release because HEAD maybe contains breakage.
tag=$(git describe --abbrev=0 --tags)
git checkout "${tag}"
echo '[workspace]' >>Cargo.toml
echo '[patch.crates-io]' >>Cargo.toml
echo 'tokio = { path = "../tokio" }' >>Cargo.toml
echo 'tokio-util = { path = "../tokio-util" }' >>Cargo.toml
echo 'tokio-stream = { path = "../tokio-stream" }' >>Cargo.toml
echo 'tokio-test = { path = "../tokio-test" }' >>Cargo.toml
git diff
cargo test --features full
wasm32-unknown-unknown:
name: test tokio for wasm32-unknown-unknown
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: test tokio
run: wasm-pack test --node -- --features "macros sync"
working-directory: tokio
+14
View File
@@ -0,0 +1,14 @@
name: "Pull Request Labeler"
on:
- pull_request_target
# See .github/labeler.yml file
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v3
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
sync-labels: true
+45
View File
@@ -0,0 +1,45 @@
on:
push:
branches: ["master", "tokio-*.x"]
pull_request:
types: [labeled, opened, synchronize, reopened]
branches: ["master", "tokio-*.x"]
name: Loom
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
# Change to specific Rust release to pin
rust_stable: stable
jobs:
loom:
name: loom
# base_ref is null when it's not a pull request
if: contains(github.event.pull_request.labels.*.name, 'R-loom') || (github.base_ref == null)
runs-on: ubuntu-latest
strategy:
matrix:
scope:
- --skip loom_pool
- loom_pool::group_a
- loom_pool::group_b
- loom_pool::group_c
- loom_pool::group_d
- time::driver
steps:
- uses: actions/checkout@v2
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: loom ${{ matrix.scope }}
run: cargo test --lib --release --features full -- --nocapture $SCOPE
working-directory: tokio
env:
RUSTFLAGS: --cfg loom --cfg tokio_unstable -Dwarnings
LOOM_MAX_PREEMPTIONS: 2
SCOPE: ${{ matrix.scope }}
+12 -3
View File
@@ -5,6 +5,12 @@ on:
branches:
- master
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
# Change to specific Rust release to pin
rust_stable: stable
jobs:
stess-test:
name: Stress Test
@@ -15,9 +21,12 @@ jobs:
- simple_echo_tcp
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Install Rust ${{ env.rust_stable }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.rust_stable }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install Valgrind
run: |
sudo apt-get update -y
+2
View File
@@ -1,2 +1,4 @@
target
Cargo.lock
.cargo/config.toml
+27 -4
View File
@@ -124,23 +124,41 @@ arguments to many common cargo commands. This section lists some commonly needed
commands.
Some commands just need the `--all-features` argument:
```
cargo build --all-features
cargo check --all-features
cargo test --all-features
```
When building documentation normally, the markers that list the features
required for various parts of Tokio are missing. To build the documentation
correctly, use this command:
```
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features
```
To build documentation including Tokio's unstable features, it is necessary to
pass `--cfg tokio_unstable` to both RustDoc *and* rustc. To build the
documentation for unstable features, use this command:
```
RUSTDOCFLAGS="--cfg docsrs --cfg tokio_unstable" RUSTFLAGS="--cfg tokio_unstable" cargo +nightly doc --all-features
```
There is currently a [bug in cargo] that means documentation cannot be built
from the root of the workspace. If you `cd` into the `tokio` subdirectory the
command shown above will work.
[bug in cargo]: https://github.com/rust-lang/cargo/issues/9274
The `cargo fmt` command does not work on the Tokio codebase. You can use the
command below instead:
```
# Mac or Linux
rustfmt --check --edition 2018 $(find . -name '*.rs' -print)
rustfmt --check --edition 2018 $(git ls-files '*.rs')
# Powershell
Get-ChildItem . -Filter "*.rs" -Recurse | foreach { rustfmt --check --edition 2018 $_.FullName }
@@ -155,6 +173,12 @@ LOOM_MAX_PREEMPTIONS=1 RUSTFLAGS="--cfg loom" \
cargo test --lib --release --features full -- --test-threads=1 --nocapture
```
You can run miri tests with
```
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-tag-raw-pointers" PROPTEST_CASES=10 \
cargo +nightly miri test --features full --lib
```
### Tests
If the change being proposed alters code (as opposed to only documentation for
@@ -571,9 +595,8 @@ When releasing a new version of a crate, follow these steps:
2. **Update Cargo metadata.** After releasing any path dependencies, update the
`version` field in `Cargo.toml` to the new version, and the `documentation`
field to the docs.rs URL of the new version.
3. **Update other documentation links.** Update the `#![doc(html_root_url)]`
attribute in the crate's `lib.rs` and the "Documentation" link in the crate's
`README.md` to point to the docs.rs URL of the new version.
3. **Update other documentation links.** Update the "Documentation" link in the
crate's `README.md` to point to the docs.rs URL of the new version.
4. **Update the changelog for the crate.** Each crate in the Tokio repository
has its own `CHANGELOG.md` in that crate's subdirectory. Any changes to that
crate since the last release should be added to the changelog. Change
+4
View File
@@ -0,0 +1,4 @@
[build.env]
passthrough = [
"RUSTFLAGS",
]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2019 Tokio Contributors
Copyright (c) 2022 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+41 -7
View File
@@ -50,7 +50,15 @@ an asynchronous application.
## Example
A basic TCP echo server with Tokio:
A basic TCP echo server with Tokio.
Make sure you activated the full features of the tokio crate on Cargo.toml:
```toml
[dependencies]
tokio = { version = "1.18.1", features = ["full"] }
```
Then, on your main.rs:
```rust,no_run
use tokio::net::TcpListener;
@@ -58,7 +66,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
@@ -132,8 +140,7 @@ several other libraries, including:
* [`tower`]: A library of modular and reusable components for building robust networking clients and servers.
* [`tracing`] (formerly `tokio-trace`): A framework for application-level
tracing and async-aware diagnostics.
* [`tracing`] (formerly `tokio-trace`): A framework for application-level tracing and async-aware diagnostics.
* [`rdbc`]: A Rust database connectivity library for MySQL, Postgres and SQLite.
@@ -156,9 +163,36 @@ several other libraries, including:
## Supported Rust Versions
Tokio is built against the latest stable release. The minimum supported version is 1.45.
The current Tokio version is not guaranteed to build on Rust versions earlier than the
minimum supported version.
Tokio will keep a rolling MSRV (minimum supported rust version) policy of **at
least** 6 months. When increasing the MSRV, the new Rust version must have been
released at least six months ago. The current MSRV is 1.49.0.
## Release schedule
Tokio doesn't follow a fixed release schedule, but we typically make one to two
new minor releases each month. We make patch releases for bugfixes as necessary.
## Bug patching policy
For the purposes of making patch releases with bugfixes, we have designated
certain minor releases as LTS (long term support) releases. Whenever a bug
warrants a patch release with a fix for the bug, it will be backported and
released as a new patch release for each LTS minor version. Our current LTS
releases are:
* `1.8.x` - LTS release until February 2022.
* `1.14.x` - LTS release until June 2022.
Each LTS release will continue to receive backported fixes for at least half a
year. If you wish to use a fixed minor release in your project, we recommend
that you use an LTS release.
To use a fixed minor version, you can specify the version with a tilde. For
example, to specify that you wish to use the newest `1.8.x` patch release, you
can use the following dependency specification:
```text
tokio = { version = "~1.8", features = [...] }
```
## License
+10 -1
View File
@@ -5,9 +5,13 @@ publish = false
edition = "2018"
[dependencies]
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
tokio = { version = "1.5.0", path = "../tokio", features = ["full"] }
bencher = "0.1.5"
[dev-dependencies]
tokio-util = { version = "0.7.0", path = "../tokio-util", features = ["full"] }
tokio-stream = { path = "../tokio-stream" }
[target.'cfg(unix)'.dependencies]
libc = "0.2.42"
@@ -41,3 +45,8 @@ harness = false
name = "signal"
path = "signal.rs"
harness = false
[[bench]]
name = "fs"
path = "fs.rs"
harness = false
+103
View File
@@ -0,0 +1,103 @@
#![cfg(unix)]
use tokio_stream::StreamExt;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio_util::codec::{BytesCodec, FramedRead /*FramedWrite*/};
use bencher::{benchmark_group, benchmark_main, Bencher};
use std::fs::File as StdFile;
use std::io::Read as StdRead;
fn rt() -> tokio::runtime::Runtime {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.build()
.unwrap()
}
const BLOCK_COUNT: usize = 1_000;
const BUFFER_SIZE: usize = 4096;
const DEV_ZERO: &str = "/dev/zero";
fn async_read_codec(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let task = || async {
let file = File::open(DEV_ZERO).await.unwrap();
let mut input_stream = FramedRead::with_capacity(file, BytesCodec::new(), BUFFER_SIZE);
for _i in 0..BLOCK_COUNT {
let _bytes = input_stream.next().await.unwrap();
}
};
rt.block_on(task());
});
}
fn async_read_buf(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let task = || async {
let mut file = File::open(DEV_ZERO).await.unwrap();
let mut buffer = [0u8; BUFFER_SIZE];
for _i in 0..BLOCK_COUNT {
let count = file.read(&mut buffer).await.unwrap();
if count == 0 {
break;
}
}
};
rt.block_on(task());
});
}
fn async_read_std_file(b: &mut Bencher) {
let rt = rt();
let task = || async {
let mut file = tokio::task::block_in_place(|| Box::pin(StdFile::open(DEV_ZERO).unwrap()));
for _i in 0..BLOCK_COUNT {
let mut buffer = [0u8; BUFFER_SIZE];
let mut file_ref = file.as_mut();
tokio::task::block_in_place(move || {
file_ref.read_exact(&mut buffer).unwrap();
});
}
};
b.iter(|| {
rt.block_on(task());
});
}
fn sync_read(b: &mut Bencher) {
b.iter(|| {
let mut file = StdFile::open(DEV_ZERO).unwrap();
let mut buffer = [0u8; BUFFER_SIZE];
for _i in 0..BLOCK_COUNT {
file.read_exact(&mut buffer).unwrap();
}
});
}
benchmark_group!(
file,
async_read_std_file,
async_read_buf,
async_read_codec,
sync_read
);
benchmark_main!(file);
+1 -1
View File
@@ -1,4 +1,4 @@
//! Benchmark implementation details of the theaded scheduler. These benches are
//! Benchmark implementation details of the threaded scheduler. These benches are
//! intended to be used as a form of regression testing and not as a general
//! purpose benchmark demonstrating real-world performance.
+57 -37
View File
@@ -2,63 +2,83 @@
//! This essentially measure the time to enqueue a task in the local and remote
//! case.
#[macro_use]
extern crate bencher;
use bencher::{black_box, Bencher};
async fn work() -> usize {
let val = 1 + 1;
tokio::task::yield_now().await;
black_box(val)
}
fn basic_scheduler_local_spawn(bench: &mut Bencher) {
fn basic_scheduler_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn threaded_scheduler_local_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn basic_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
bench.iter(|| {
let h = runtime.spawn(work());
black_box(h);
runtime.block_on(async {
let h = tokio::spawn(work());
assert_eq!(h.await.unwrap(), 2);
});
});
}
fn threaded_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread().build().unwrap();
fn basic_scheduler_spawn10(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
bench.iter(|| {
let h = runtime.spawn(work());
black_box(h);
runtime.block_on(async {
let mut handles = Vec::with_capacity(10);
for _ in 0..10 {
handles.push(tokio::spawn(work()));
}
for handle in handles {
assert_eq!(handle.await.unwrap(), 2);
}
});
});
}
fn threaded_scheduler_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.build()
.unwrap();
bench.iter(|| {
runtime.block_on(async {
let h = tokio::spawn(work());
assert_eq!(h.await.unwrap(), 2);
});
});
}
fn threaded_scheduler_spawn10(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.build()
.unwrap();
bench.iter(|| {
runtime.block_on(async {
let mut handles = Vec::with_capacity(10);
for _ in 0..10 {
handles.push(tokio::spawn(work()));
}
for handle in handles {
assert_eq!(handle.await.unwrap(), 2);
}
});
});
}
bencher::benchmark_group!(
spawn,
basic_scheduler_local_spawn,
threaded_scheduler_local_spawn,
basic_scheduler_remote_spawn,
threaded_scheduler_remote_spawn
basic_scheduler_spawn,
basic_scheduler_spawn10,
threaded_scheduler_spawn,
threaded_scheduler_spawn10,
);
bencher::benchmark_main!(spawn);
+21 -7
View File
@@ -5,15 +5,14 @@ publish = false
edition = "2018"
# If you copy one of the examples into a new project, you should be using
# [dependencies] instead.
# [dependencies] instead, and delete the **path**.
[dev-dependencies]
tokio = { version = "1.0.0", features = ["full", "tracing"] }
tokio-util = { version = "0.6.1", features = ["full"] }
tokio-stream = { version = "0.1" }
tokio = { version = "1.0.0", path = "../tokio", features = ["full", "tracing"] }
tokio-util = { version = "0.7.0", path = "../tokio-util", features = ["full"] }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
async-stream = "0.3"
tracing = "0.1"
tracing-subscriber = { version = "0.2.7", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log"] }
tracing-subscriber = { version = "0.3.1", default-features = false, features = ["fmt", "ansi", "env-filter", "tracing-log"] }
bytes = "1.0.0"
futures = { version = "0.3.0", features = ["thread-pool"]}
http = "0.2"
@@ -21,9 +20,12 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
httparse = "1.0"
time = "0.1"
httpdate = "1.0"
once_cell = "1.5.2"
rand = "0.8.3"
[target.'cfg(windows)'.dev-dependencies.winapi]
version = "0.3.8"
[[example]]
name = "chat"
@@ -77,3 +79,15 @@ path = "custom-executor.rs"
[[example]]
name = "custom-executor-tokio-context"
path = "custom-executor-tokio-context.rs"
[[example]]
name = "named-pipe"
path = "named-pipe.rs"
[[example]]
name = "named-pipe-ready"
path = "named-pipe-ready.rs"
[[example]]
name = "named-pipe-multi-client"
path = "named-pipe-multi-client.rs"
+31 -69
View File
@@ -28,8 +28,8 @@
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::{mpsc, Mutex};
use tokio_stream::{Stream, StreamExt};
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
use tokio_stream::StreamExt;
use tokio_util::codec::{Framed, LinesCodec};
use futures::SinkExt;
use std::collections::HashMap;
@@ -37,9 +37,7 @@ use std::env;
use std::error::Error;
use std::io;
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
@@ -101,6 +99,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
/// Shorthand for the transmit half of the message channel.
type Tx = mpsc::UnboundedSender<String>;
/// Shorthand for the receive half of the message channel.
type Rx = mpsc::UnboundedReceiver<String>;
/// Data that is shared between all peers in the chat server.
///
/// This is the set of `Tx` handles for all connected clients. Whenever a
@@ -124,7 +125,7 @@ struct Peer {
///
/// This is used to receive messages from peers. When a message is received
/// off of this `Rx`, it will be written to the socket.
rx: Pin<Box<dyn Stream<Item = String> + Send>>,
rx: Rx,
}
impl Shared {
@@ -156,58 +157,15 @@ impl Peer {
let addr = lines.get_ref().peer_addr()?;
// Create a channel for this peer
let (tx, mut rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel();
// Add an entry for this `Peer` in the shared state map.
state.lock().await.peers.insert(addr, tx);
let rx = Box::pin(async_stream::stream! {
while let Some(item) = rx.recv().await {
yield item;
}
});
Ok(Peer { lines, rx })
}
}
#[derive(Debug)]
enum Message {
/// A message that should be broadcasted to others.
Broadcast(String),
/// A message that should be received by a client
Received(String),
}
// Peer implements `Stream` in a way that polls both the `Rx`, and `Framed` types.
// A message is produced whenever an event is ready until the `Framed` stream returns `None`.
impl Stream for Peer {
type Item = Result<Message, LinesCodecError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
// First poll the `UnboundedReceiver`.
if let Poll::Ready(Some(v)) = Pin::new(&mut self.rx).poll_next(cx) {
return Poll::Ready(Some(Ok(Message::Received(v))));
}
// Secondly poll the `Framed` stream.
let result: Option<_> = futures::ready!(Pin::new(&mut self.lines).poll_next(cx));
Poll::Ready(match result {
// We've received a message we should broadcast to others.
Some(Ok(message)) => Some(Ok(Message::Broadcast(message))),
// An error occurred.
Some(Err(e)) => Some(Err(e)),
// The stream has been exhausted.
None => None,
})
}
}
/// Process an individual chat client
async fn process(
state: Arc<Mutex<Shared>>,
@@ -241,28 +199,32 @@ async fn process(
}
// Process incoming messages until our stream is exhausted by a disconnect.
while let Some(result) = peer.next().await {
match result {
// A message was received from the current user, we should
// broadcast this message to the other users.
Ok(Message::Broadcast(msg)) => {
let mut state = state.lock().await;
let msg = format!("{}: {}", username, msg);
state.broadcast(addr, &msg).await;
}
// A message was received from a peer. Send it to the
// current user.
Ok(Message::Received(msg)) => {
loop {
tokio::select! {
// A message was received from a peer. Send it to the current user.
Some(msg) = peer.rx.recv() => {
peer.lines.send(&msg).await?;
}
Err(e) => {
tracing::error!(
"an error occurred while processing messages for {}; error = {:?}",
username,
e
);
}
result = peer.lines.next() => match result {
// A message was received from the current user, we should
// broadcast this message to the other users.
Some(Ok(msg)) => {
let mut state = state.lock().await;
let msg = format!("{}: {}", username, msg);
state.broadcast(addr, &msg).await;
}
// An error occurred.
Some(Err(e)) => {
tracing::error!(
"an error occurred while processing messages for {}; error = {:?}",
username,
e
);
}
// The stream has been exhausted.
None => break,
},
}
}
+98
View File
@@ -0,0 +1,98 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
use tokio::time;
use winapi::shared::winerror;
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-multi-client";
const N: usize = 10;
// The first server needs to be constructed early so that clients can
// be correctly connected. Otherwise a waiting client will error.
//
// Here we also make use of `first_pipe_instance`, which will ensure
// that there are no other servers up and running already.
let mut server = ServerOptions::new()
.first_pipe_instance(true)
.create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Artificial workload.
time::sleep(Duration::from_secs(1)).await;
for _ in 0..N {
// Wait for client to connect.
server.connect().await?;
let mut inner = server;
// Construct the next server to be connected before sending the one
// we already have of onto a task. This ensures that the server
// isn't closed (after it's done in the task) before a new one is
// available. Otherwise the client might error with
// `io::ErrorKind::NotFound`.
server = ServerOptions::new().create(PIPE_NAME)?;
let _ = tokio::spawn(async move {
let mut buf = vec![0u8; 4];
inner.read_exact(&mut buf).await?;
inner.write_all(b"pong").await?;
Ok::<_, io::Error>(())
});
}
Ok::<_, io::Error>(())
});
let mut clients = Vec::new();
for _ in 0..N {
clients.push(tokio::spawn(async move {
// This showcases a generic connect loop.
//
// We immediately try to create a client, if it's not found or
// the pipe is busy we use the specialized wait function on the
// client builder.
let mut client = loop {
match ClientOptions::new().open(PIPE_NAME) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(winerror::ERROR_PIPE_BUSY as i32) => (),
Err(e) => return Err(e),
}
time::sleep(Duration::from_millis(5)).await;
};
let mut buf = [0u8; 4];
client.write_all(b"ping").await?;
client.read_exact(&mut buf).await?;
Ok::<_, io::Error>(buf)
}));
}
for client in clients {
let result = client.await?;
assert_eq!(&result?[..], b"pong");
}
server.await??;
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+161
View File
@@ -0,0 +1,161 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use tokio::io::Interest;
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-single-client";
let server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Note: we wait for a client to connect.
server.connect().await?;
let buf = {
let mut read_buf = [0u8; 5];
let mut read_buf_cursor = 0;
loop {
server.readable().await?;
let buf = &mut read_buf[read_buf_cursor..];
match server.try_read(buf) {
Ok(n) => {
read_buf_cursor += n;
if read_buf_cursor == read_buf.len() {
break;
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
read_buf
};
{
let write_buf = b"pong\n";
let mut write_buf_cursor = 0;
loop {
let buf = &write_buf[write_buf_cursor..];
if buf.is_empty() {
break;
}
server.writable().await?;
match server.try_write(buf) {
Ok(n) => {
write_buf_cursor += n;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
}
Ok::<_, io::Error>(buf)
});
let client = tokio::spawn(async move {
// There's no need to use a connect loop here, since we know that the
// server is already up - `open` was called before spawning any of the
// tasks.
let client = ClientOptions::new().open(PIPE_NAME)?;
let mut read_buf = [0u8; 5];
let mut read_buf_cursor = 0;
let write_buf = b"ping\n";
let mut write_buf_cursor = 0;
loop {
let mut interest = Interest::READABLE;
if write_buf_cursor < write_buf.len() {
interest |= Interest::WRITABLE;
}
let ready = client.ready(interest).await?;
if ready.is_readable() {
let buf = &mut read_buf[read_buf_cursor..];
match client.try_read(buf) {
Ok(n) => {
read_buf_cursor += n;
if read_buf_cursor == read_buf.len() {
break;
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
if ready.is_writable() {
let buf = &write_buf[write_buf_cursor..];
if buf.is_empty() {
continue;
}
match client.try_write(buf) {
Ok(n) => {
write_buf_cursor += n;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
}
let buf = String::from_utf8_lossy(&read_buf).into_owned();
Ok::<_, io::Error>(buf)
});
let (server, client) = tokio::try_join!(server, client)?;
assert_eq!(server?, *b"ping\n");
assert_eq!(client?, "pong\n");
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+60
View File
@@ -0,0 +1,60 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use tokio::io::AsyncWriteExt;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-single-client";
let server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Note: we wait for a client to connect.
server.connect().await?;
let mut server = BufReader::new(server);
let mut buf = String::new();
server.read_line(&mut buf).await?;
server.write_all(b"pong\n").await?;
Ok::<_, io::Error>(buf)
});
let client = tokio::spawn(async move {
// There's no need to use a connect loop here, since we know that the
// server is already up - `open` was called before spawning any of the
// tasks.
let client = ClientOptions::new().open(PIPE_NAME)?;
let mut client = BufReader::new(client);
let mut buf = String::new();
client.write_all(b"ping\n").await?;
client.read_line(&mut buf).await?;
Ok::<_, io::Error>(buf)
});
let (server, client) = tokio::try_join!(server, client)?;
assert_eq!(server?, "ping\n");
assert_eq!(client?, "pong\n");
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+1 -1
View File
@@ -149,7 +149,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
fn handle_request(line: &str, db: &Arc<Database>) -> Response {
let request = match Request::parse(&line) {
let request = match Request::parse(line) {
Ok(req) => req,
Err(e) => return Response::Error { msg: e },
};
+14 -10
View File
@@ -221,8 +221,9 @@ mod date {
use std::cell::RefCell;
use std::fmt::{self, Write};
use std::str;
use std::time::SystemTime;
use time::{self, Duration};
use httpdate::HttpDate;
pub struct Now(());
@@ -252,22 +253,26 @@ mod date {
struct LastRenderedNow {
bytes: [u8; 128],
amt: usize,
next_update: time::Timespec,
unix_date: u64,
}
thread_local!(static LAST: RefCell<LastRenderedNow> = RefCell::new(LastRenderedNow {
bytes: [0; 128],
amt: 0,
next_update: time::Timespec::new(0, 0),
unix_date: 0,
}));
impl fmt::Display for Now {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
LAST.with(|cache| {
let mut cache = cache.borrow_mut();
let now = time::get_time();
if now >= cache.next_update {
cache.update(now);
let now = SystemTime::now();
let now_unix = now
.duration_since(SystemTime::UNIX_EPOCH)
.map(|since_epoch| since_epoch.as_secs())
.unwrap_or(0);
if cache.unix_date != now_unix {
cache.update(now, now_unix);
}
f.write_str(cache.buffer())
})
@@ -279,11 +284,10 @@ mod date {
str::from_utf8(&self.bytes[..self.amt]).unwrap()
}
fn update(&mut self, now: time::Timespec) {
fn update(&mut self, now: SystemTime, now_unix: u64) {
self.amt = 0;
write!(LocalBuffer(self), "{}", time::at(now).rfc822()).unwrap();
self.next_update = now + Duration::seconds(1);
self.next_update.nsec = 0;
self.unix_date = now_unix;
write!(LocalBuffer(self), "{}", HttpDate::from(now)).unwrap();
}
}
@@ -1,7 +1,7 @@
error: The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled.
--> $DIR/macros_core_no_default.rs:3:1
--> tests/fail/macros_core_no_default.rs:3:1
|
3 | #[tokio::main]
| ^^^^^^^^^^^^^^
|
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -0,0 +1,8 @@
#![deny(dead_code)]
use tests_build::tokio;
#[tokio::main]
async fn f() {}
fn main() {}
@@ -0,0 +1,11 @@
error: function is never used: `f`
--> tests/fail/macros_dead_code.rs:6:10
|
6 | async fn f() {}
| ^
|
note: the lint level is defined here
--> tests/fail/macros_dead_code.rs:1:9
|
1 | #![deny(dead_code)]
| ^^^^^^^^^
+29 -3
View File
@@ -1,3 +1,5 @@
#![deny(duplicate_macro_attributes)]
use tests_build::tokio;
#[tokio::main]
@@ -12,12 +14,36 @@ async fn main_attr_has_path_args() {}
#[tokio::test]
fn test_is_not_async() {}
#[tokio::test]
async fn test_fn_has_args(_x: u8) {}
#[tokio::test(foo)]
async fn test_attr_has_args() {}
#[tokio::test(foo = 123)]
async fn test_unexpected_attr() {}
#[tokio::test(flavor = 123)]
async fn test_flavor_not_string() {}
#[tokio::test(flavor = "foo")]
async fn test_unknown_flavor() {}
#[tokio::test(flavor = "multi_thread", start_paused = false)]
async fn test_multi_thread_with_start_paused() {}
#[tokio::test(flavor = "multi_thread", worker_threads = "foo")]
async fn test_worker_threads_not_int() {}
#[tokio::test(flavor = "current_thread", worker_threads = 4)]
async fn test_worker_threads_and_current_thread() {}
#[tokio::test(crate = 456)]
async fn test_crate_not_ident_int() {}
#[tokio::test(crate = "456")]
async fn test_crate_not_ident_invalid() {}
#[tokio::test(crate = "abc::edf")]
async fn test_crate_not_ident_path() {}
#[tokio::test]
#[test]
async fn test_has_second_test_attr() {}
@@ -1,41 +1,101 @@
error: the async keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:4:1
error: the `async` keyword is missing from the function declaration
--> tests/fail/macros_invalid_input.rs:6:1
|
4 | fn main_is_not_async() {}
6 | fn main_is_not_async() {}
| ^^
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`
--> $DIR/macros_invalid_input.rs:6:15
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`
--> tests/fail/macros_invalid_input.rs:8:15
|
6 | #[tokio::main(foo)]
8 | #[tokio::main(foo)]
| ^^^
error: Must have specified ident
--> $DIR/macros_invalid_input.rs:9:15
|
9 | #[tokio::main(threadpool::bar)]
| ^^^^^^^^^^^^^^^
error: the async keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:13:1
--> tests/fail/macros_invalid_input.rs:11:15
|
13 | fn test_is_not_async() {}
11 | #[tokio::main(threadpool::bar)]
| ^^^^^^^^^^^^^^^
error: the `async` keyword is missing from the function declaration
--> tests/fail/macros_invalid_input.rs:15:1
|
15 | fn test_is_not_async() {}
| ^^
error: the test function cannot accept arguments
--> $DIR/macros_invalid_input.rs:16:27
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`
--> tests/fail/macros_invalid_input.rs:17:15
|
16 | async fn test_fn_has_args(_x: u8) {}
| ^^^^^^
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`
--> $DIR/macros_invalid_input.rs:18:15
|
18 | #[tokio::test(foo)]
17 | #[tokio::test(foo)]
| ^^^
error: second test attribute is supplied
--> $DIR/macros_invalid_input.rs:22:1
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`
--> tests/fail/macros_invalid_input.rs:20:15
|
22 | #[test]
20 | #[tokio::test(foo = 123)]
| ^^^^^^^^^
error: Failed to parse value of `flavor` as string.
--> tests/fail/macros_invalid_input.rs:23:24
|
23 | #[tokio::test(flavor = 123)]
| ^^^
error: No such runtime flavor `foo`. The runtime flavors are `current_thread` and `multi_thread`.
--> tests/fail/macros_invalid_input.rs:26:24
|
26 | #[tokio::test(flavor = "foo")]
| ^^^^^
error: The `start_paused` option requires the `current_thread` runtime flavor. Use `#[tokio::test(flavor = "current_thread")]`
--> tests/fail/macros_invalid_input.rs:29:55
|
29 | #[tokio::test(flavor = "multi_thread", start_paused = false)]
| ^^^^^
error: Failed to parse value of `worker_threads` as integer.
--> tests/fail/macros_invalid_input.rs:32:57
|
32 | #[tokio::test(flavor = "multi_thread", worker_threads = "foo")]
| ^^^^^
error: The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[tokio::test(flavor = "multi_thread")]`
--> tests/fail/macros_invalid_input.rs:35:59
|
35 | #[tokio::test(flavor = "current_thread", worker_threads = 4)]
| ^
error: Failed to parse value of `crate` as ident.
--> tests/fail/macros_invalid_input.rs:38:23
|
38 | #[tokio::test(crate = 456)]
| ^^^
error: Failed to parse value of `crate` as ident: "456"
--> tests/fail/macros_invalid_input.rs:41:23
|
41 | #[tokio::test(crate = "456")]
| ^^^^^
error: Failed to parse value of `crate` as ident: "abc::edf"
--> tests/fail/macros_invalid_input.rs:44:23
|
44 | #[tokio::test(crate = "abc::edf")]
| ^^^^^^^^^^
error: second test attribute is supplied
--> tests/fail/macros_invalid_input.rs:48:1
|
48 | #[test]
| ^^^^^^^
error: duplicated attribute
--> tests/fail/macros_invalid_input.rs:48:1
|
48 | #[test]
| ^^^^^^^
|
note: the lint level is defined here
--> tests/fail/macros_invalid_input.rs:1:9
|
1 | #![deny(duplicate_macro_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,35 @@
use tests_build::tokio;
#[tokio::main]
async fn missing_semicolon_or_return_type() {
Ok(())
}
#[tokio::main]
async fn missing_return_type() {
return Ok(());
}
#[tokio::main]
async fn extra_semicolon() -> Result<(), ()> {
/* TODO(taiki-e): help message still wrong
help: try using a variant of the expected enum
|
23 | Ok(Ok(());)
|
23 | Err(Ok(());)
|
*/
Ok(());
}
// https://github.com/tokio-rs/tokio/issues/4635
#[allow(redundant_semicolons)]
#[rustfmt::skip]
#[tokio::main]
async fn issue_4635() {
return 1;
;
}
fn main() {}
@@ -0,0 +1,48 @@
error[E0308]: mismatched types
--> tests/fail/macros_type_mismatch.rs:5:5
|
4 | async fn missing_semicolon_or_return_type() {
| - possibly return type missing here?
5 | Ok(())
| ^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
error[E0308]: mismatched types
--> tests/fail/macros_type_mismatch.rs:10:5
|
9 | async fn missing_return_type() {
| - possibly return type missing here?
10 | return Ok(());
| ^^^^^^^^^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
error[E0308]: mismatched types
--> tests/fail/macros_type_mismatch.rs:23:5
|
14 | async fn extra_semicolon() -> Result<(), ()> {
| -------------- expected `Result<(), ()>` because of return type
...
23 | Ok(());
| ^^^^^^^ expected enum `Result`, found `()`
|
= note: expected enum `Result<(), ()>`
found unit type `()`
help: try wrapping the expression in a variant of `Result`
|
23 | Ok(Ok(());)
| +++ +
23 | Err(Ok(());)
| ++++ +
error[E0308]: mismatched types
--> tests/fail/macros_type_mismatch.rs:32:5
|
30 | async fn issue_4635() {
| - possibly return type missing here?
31 | return 1;
32 | ;
| ^ expected `()`, found integer
+15
View File
@@ -2,9 +2,24 @@
fn compile_fail_full() {
let t = trybuild::TestCases::new();
#[cfg(feature = "full")]
t.pass("tests/pass/forward_args_and_output.rs");
#[cfg(feature = "full")]
t.pass("tests/pass/macros_main_return.rs");
#[cfg(feature = "full")]
t.pass("tests/pass/macros_main_loop.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_invalid_input.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_dead_code.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_type_mismatch.rs");
#[cfg(all(feature = "rt", not(feature = "full")))]
t.compile_fail("tests/fail/macros_core_no_default.rs");
+7
View File
@@ -0,0 +1,7 @@
#[cfg(feature = "full")]
#[tokio::test]
async fn test_with_semicolon_without_return_type() {
#![deny(clippy::semicolon_if_nothing_returned)]
dbg!(0);
}
@@ -0,0 +1,13 @@
use tests_build::tokio;
fn main() {}
// arguments and output type is forwarded so other macros can access them
#[tokio::test]
async fn test_fn_has_args(_x: u8) {}
#[tokio::test]
async fn test_has_output() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
@@ -0,0 +1,14 @@
use tests_build::tokio;
#[tokio::main]
async fn main() -> Result<(), ()> {
loop {
if !never() {
return Ok(());
}
}
}
fn never() -> bool {
std::time::Instant::now() > std::time::Instant::now()
}
@@ -0,0 +1,6 @@
use tests_build::tokio;
#[tokio::main]
async fn main() -> Result<(), ()> {
return Ok(());
}
+16 -2
View File
@@ -5,7 +5,23 @@ authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[[bin]]
name = "test-cat"
[[bin]]
name = "test-mem"
required-features = ["rt-net"]
[[bin]]
name = "test-process-signal"
required-features = ["rt-process-signal"]
[features]
# For mem check
rt-net = ["tokio/rt", "tokio/rt-multi-thread", "tokio/net"]
# For test-process-signal
rt-process-signal = ["rt-net", "tokio/process", "tokio/signal"]
full = [
"macros",
"rt",
@@ -23,6 +39,4 @@ rt-multi-thread = ["rt", "tokio/rt-multi-thread"]
tokio = { path = "../tokio" }
tokio-test = { path = "../tokio-test", optional = true }
doc-comment = "0.3.1"
[dev-dependencies]
futures = { version = "0.3.0", features = ["async-await"] }
+21
View File
@@ -0,0 +1,21 @@
use futures::future::poll_fn;
fn main() {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.enable_io()
.build()
.unwrap();
rt.block_on(async {
let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap();
tokio::spawn(async move {
loop {
poll_fn(|cx| listener.poll_accept(cx)).await.unwrap();
}
});
});
std::thread::sleep(std::time::Duration::from_millis(50));
drop(rt);
}
@@ -0,0 +1,11 @@
// https://github.com/tokio-rs/tokio/issues/3550
fn main() {
for _ in 0..1000 {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
drop(rt);
}
}
+52 -1
View File
@@ -1,11 +1,13 @@
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
use tokio::join;
use tokio::process::{Child, Command};
use tokio_test::assert_ok;
use futures::future::{self, FutureExt};
use std::convert::TryInto;
use std::env;
use std::io;
use std::process::{ExitStatus, Stdio};
@@ -139,3 +141,52 @@ async fn try_wait() {
// Can't get id after process has exited
assert_eq!(child.id(), None);
}
#[tokio::test]
async fn pipe_from_one_command_to_another() {
let mut first = cat().spawn().expect("first cmd");
let mut third = cat().spawn().expect("third cmd");
// Convert ChildStdout to Stdio
let second_stdin: Stdio = first
.stdout
.take()
.expect("first.stdout")
.try_into()
.expect("first.stdout into Stdio");
// Convert ChildStdin to Stdio
let second_stdout: Stdio = third
.stdin
.take()
.expect("third.stdin")
.try_into()
.expect("third.stdin into Stdio");
let mut second = cat()
.stdin(second_stdin)
.stdout(second_stdout)
.spawn()
.expect("first cmd");
let msg = "hello world! please pipe this message through";
let mut stdin = first.stdin.take().expect("first.stdin");
let write = async move { stdin.write_all(msg.as_bytes()).await };
let mut stdout = third.stdout.take().expect("third.stdout");
let read = async move {
let mut data = String::new();
stdout.read_to_string(&mut data).await.map(|_| data)
};
let (read, write, first_status, second_status, third_status) =
join!(read, write, first.wait(), second.wait(), third.wait());
assert_eq!(msg, read.expect("read result"));
write.expect("write result");
assert!(first_status.expect("first status").success());
assert!(second_status.expect("second status").success());
assert!(third_status.expect("third status").success());
}
+66
View File
@@ -1,3 +1,68 @@
# 1.7.0 (December 15th, 2021)
- macros: address remainging clippy::semicolon_if_nothing_returned warning ([#4252])
[#4252]: https://github.com/tokio-rs/tokio/pull/4252
# 1.6.0 (November 16th, 2021)
- macros: fix mut patterns in `select!` macro ([#4211])
[#4211]: https://github.com/tokio-rs/tokio/pull/4211
# 1.5.1 (October 29th, 2021)
- macros: fix type resolution error in `#[tokio::main]` ([#4176])
[#4176]: https://github.com/tokio-rs/tokio/pull/4176
# 1.5.0 (October 13th, 2021)
- macros: make tokio-macros attributes more IDE friendly ([#4162])
[#4162]: https://github.com/tokio-rs/tokio/pull/4162
# 1.4.1 (September 30th, 2021)
Reverted: run `current_thread` inside `LocalSet` ([#4027])
# 1.4.0 (September 29th, 2021)
(yanked)
### Changed
- macros: run `current_thread` inside `LocalSet` ([#4027])
- macros: explicitly relaxed clippy lint for `.expect()` in runtime entry macro ([#4030])
### Fixed
- macros: fix invalid error messages in functions wrapped with `#[main]` or `#[test]` ([#4067])
[#4027]: https://github.com/tokio-rs/tokio/pull/4027
[#4030]: https://github.com/tokio-rs/tokio/pull/4030
[#4067]: https://github.com/tokio-rs/tokio/pull/4067
# 1.3.0 (July 7, 2021)
- macros: don't trigger `clippy::unwrap_used` ([#3926])
[#3926]: https://github.com/tokio-rs/tokio/pull/3926
# 1.2.0 (May 14, 2021)
- macros: forward input arguments in `#[tokio::test]` ([#3691])
- macros: improve diagnostics on type mismatch ([#3766])
- macros: various error message improvements ([#3677])
[#3677]: https://github.com/tokio-rs/tokio/pull/3677
[#3691]: https://github.com/tokio-rs/tokio/pull/3691
[#3766]: https://github.com/tokio-rs/tokio/pull/3766
# 1.1.0 (February 5, 2021)
- add `start_paused` option to macros ([#3492])
# 1.0.0 (December 23, 2020)
- track `tokio` 1.0 release.
@@ -55,3 +120,4 @@
[#2177]: https://github.com/tokio-rs/tokio/pull/2177
[#2225]: https://github.com/tokio-rs/tokio/pull/2225
[#3038]: https://github.com/tokio-rs/tokio/pull/3038
[#3492]: https://github.com/tokio-rs/tokio/pull/3492
+3 -6
View File
@@ -2,18 +2,15 @@
name = "tokio-macros"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-macros-1.0.x" git tag.
version = "1.0.0"
version = "1.7.0"
edition = "2018"
rust-version = "1.49"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-macros/1.0.0/tokio_macros"
description = """
Tokio's proc macros.
"""
@@ -27,7 +24,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0.7"
quote = "1"
syn = { version = "1.0.3", features = ["full"] }
syn = { version = "1.0.56", features = ["full"] }
[dev-dependencies]
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2020 Tokio Contributors
Copyright (c) 2022 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+265 -104
View File
@@ -1,7 +1,10 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;
use proc_macro2::{Ident, Span};
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::Parser;
// syn::AttributeArgs does not implement syn::Parse
type AttributeArgs = syn::punctuated::Punctuated<syn::NestedMeta, syn::Token![,]>;
#[derive(Clone, Copy, PartialEq)]
enum RuntimeFlavor {
@@ -25,13 +28,26 @@ impl RuntimeFlavor {
struct FinalConfig {
flavor: RuntimeFlavor,
worker_threads: Option<usize>,
start_paused: Option<bool>,
crate_name: Option<String>,
}
/// Config used in case of the attribute not being able to build a valid config
const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig {
flavor: RuntimeFlavor::CurrentThread,
worker_threads: None,
start_paused: None,
crate_name: None,
};
struct Configuration {
rt_multi_thread_available: bool,
default_flavor: RuntimeFlavor,
flavor: Option<RuntimeFlavor>,
worker_threads: Option<(usize, Span)>,
start_paused: Option<(bool, Span)>,
is_test: bool,
crate_name: Option<String>,
}
impl Configuration {
@@ -44,6 +60,9 @@ impl Configuration {
},
flavor: None,
worker_threads: None,
start_paused: None,
is_test,
crate_name: None,
}
}
@@ -79,31 +98,77 @@ impl Configuration {
Ok(())
}
fn set_start_paused(&mut self, start_paused: syn::Lit, span: Span) -> Result<(), syn::Error> {
if self.start_paused.is_some() {
return Err(syn::Error::new(span, "`start_paused` set multiple times."));
}
let start_paused = parse_bool(start_paused, span, "start_paused")?;
self.start_paused = Some((start_paused, span));
Ok(())
}
fn set_crate_name(&mut self, name: syn::Lit, span: Span) -> Result<(), syn::Error> {
if self.crate_name.is_some() {
return Err(syn::Error::new(span, "`crate` set multiple times."));
}
let name_ident = parse_ident(name, span, "crate")?;
self.crate_name = Some(name_ident.to_string());
Ok(())
}
fn macro_name(&self) -> &'static str {
if self.is_test {
"tokio::test"
} else {
"tokio::main"
}
}
fn build(&self) -> Result<FinalConfig, syn::Error> {
let flavor = self.flavor.unwrap_or(self.default_flavor);
use RuntimeFlavor::*;
match (flavor, self.worker_threads) {
(CurrentThread, Some((_, worker_threads_span))) => Err(syn::Error::new(
worker_threads_span,
"The `worker_threads` option requires the `multi_thread` runtime flavor.",
)),
(CurrentThread, None) => Ok(FinalConfig {
flavor,
worker_threads: None,
}),
(Threaded, worker_threads) if self.rt_multi_thread_available => Ok(FinalConfig {
flavor,
worker_threads: worker_threads.map(|(val, _span)| val),
}),
let worker_threads = match (flavor, self.worker_threads) {
(CurrentThread, Some((_, worker_threads_span))) => {
let msg = format!(
"The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[{}(flavor = \"multi_thread\")]`",
self.macro_name(),
);
return Err(syn::Error::new(worker_threads_span, msg));
}
(CurrentThread, None) => None,
(Threaded, worker_threads) if self.rt_multi_thread_available => {
worker_threads.map(|(val, _span)| val)
}
(Threaded, _) => {
let msg = if self.flavor.is_none() {
"The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled."
} else {
"The runtime flavor `multi_thread` requires the `rt-multi-thread` feature."
};
Err(syn::Error::new(Span::call_site(), msg))
return Err(syn::Error::new(Span::call_site(), msg));
}
}
};
let start_paused = match (flavor, self.start_paused) {
(Threaded, Some((_, start_paused_span))) => {
let msg = format!(
"The `start_paused` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \"current_thread\")]`",
self.macro_name(),
);
return Err(syn::Error::new(start_paused_span, msg));
}
(CurrentThread, Some((start_paused, _))) => Some(start_paused),
(_, None) => None,
};
Ok(FinalConfig {
crate_name: self.crate_name.clone(),
flavor,
worker_threads,
start_paused,
})
}
}
@@ -113,12 +178,12 @@ fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result<usize, syn::Error
Ok(value) => Ok(value),
Err(e) => Err(syn::Error::new(
span,
format!("Failed to parse {} as integer: {}", field, e),
format!("Failed to parse value of `{}` as integer: {}", field, e),
)),
},
_ => Err(syn::Error::new(
span,
format!("Failed to parse {} as integer.", field),
format!("Failed to parse value of `{}` as integer.", field),
)),
}
}
@@ -129,68 +194,111 @@ fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result<String, syn::E
syn::Lit::Verbatim(s) => Ok(s.to_string()),
_ => Err(syn::Error::new(
span,
format!("Failed to parse {} as string.", field),
format!("Failed to parse value of `{}` as string.", field),
)),
}
}
fn parse_knobs(
mut input: syn::ItemFn,
args: syn::AttributeArgs,
fn parse_ident(lit: syn::Lit, span: Span, field: &str) -> Result<Ident, syn::Error> {
match lit {
syn::Lit::Str(s) => {
let err = syn::Error::new(
span,
format!(
"Failed to parse value of `{}` as ident: \"{}\"",
field,
s.value()
),
);
let path = s.parse::<syn::Path>().map_err(|_| err.clone())?;
path.get_ident().cloned().ok_or(err)
}
_ => Err(syn::Error::new(
span,
format!("Failed to parse value of `{}` as ident.", field),
)),
}
}
fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result<bool, syn::Error> {
match bool {
syn::Lit::Bool(b) => Ok(b.value),
_ => Err(syn::Error::new(
span,
format!("Failed to parse value of `{}` as bool.", field),
)),
}
}
fn build_config(
input: syn::ItemFn,
args: AttributeArgs,
is_test: bool,
rt_multi_thread: bool,
) -> Result<TokenStream, syn::Error> {
let sig = &mut input.sig;
let body = &input.block;
let attrs = &input.attrs;
let vis = input.vis;
if sig.asyncness.is_none() {
let msg = "the async keyword is missing from the function declaration";
return Err(syn::Error::new_spanned(sig.fn_token, msg));
) -> Result<FinalConfig, syn::Error> {
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return Err(syn::Error::new_spanned(input.sig.fn_token, msg));
}
sig.asyncness = None;
let macro_name = if is_test {
"tokio::test"
} else {
"tokio::main"
};
let mut config = Configuration::new(is_test, rt_multi_thread);
let macro_name = config.macro_name();
for arg in args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
let ident = namevalue.path.get_ident();
if ident.is_none() {
let msg = "Must have specified ident";
return Err(syn::Error::new_spanned(namevalue, msg));
}
match ident.unwrap().to_string().to_lowercase().as_str() {
let ident = namevalue
.path
.get_ident()
.ok_or_else(|| {
syn::Error::new_spanned(&namevalue, "Must have specified ident")
})?
.to_string()
.to_lowercase();
match ident.as_str() {
"worker_threads" => {
config.set_worker_threads(namevalue.lit.clone(), namevalue.span())?;
config.set_worker_threads(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"flavor" => {
config.set_flavor(namevalue.lit.clone(), namevalue.span())?;
config.set_flavor(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"start_paused" => {
config.set_start_paused(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"core_threads" => {
let msg = "Attribute `core_threads` is renamed to `worker_threads`";
return Err(syn::Error::new_spanned(namevalue, msg));
}
"crate" => {
config.set_crate_name(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
name => {
let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name);
let msg = format!(
"Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`",
name,
);
return Err(syn::Error::new_spanned(namevalue, msg));
}
}
}
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
let ident = path.get_ident();
if ident.is_none() {
let msg = "Must have specified ident";
return Err(syn::Error::new_spanned(path, msg));
}
let name = ident.unwrap().to_string().to_lowercase();
let name = path
.get_ident()
.ok_or_else(|| syn::Error::new_spanned(&path, "Must have specified ident"))?
.to_string()
.to_lowercase();
let msg = match name.as_str() {
"threaded_scheduler" | "multi_thread" => {
format!(
@@ -204,11 +312,11 @@ fn parse_knobs(
macro_name
)
}
"flavor" | "worker_threads" => {
"flavor" | "worker_threads" | "start_paused" => {
format!("The `{}` attribute requires an argument.", name)
}
name => {
format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name)
format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`", name)
}
};
return Err(syn::Error::new_spanned(path, msg));
@@ -222,79 +330,132 @@ fn parse_knobs(
}
}
let config = config.build()?;
config.build()
}
fn parse_knobs(mut input: syn::ItemFn, is_test: bool, config: FinalConfig) -> TokenStream {
input.sig.asyncness = None;
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let crate_name = config.crate_name.as_deref().unwrap_or("tokio");
let crate_ident = Ident::new(crate_name, last_stmt_start_span);
let mut rt = match config.flavor {
RuntimeFlavor::CurrentThread => quote! {
tokio::runtime::Builder::new_current_thread()
RuntimeFlavor::CurrentThread => quote_spanned! {last_stmt_start_span=>
#crate_ident::runtime::Builder::new_current_thread()
},
RuntimeFlavor::Threaded => quote! {
tokio::runtime::Builder::new_multi_thread()
RuntimeFlavor::Threaded => quote_spanned! {last_stmt_start_span=>
#crate_ident::runtime::Builder::new_multi_thread()
},
};
if let Some(v) = config.worker_threads {
rt = quote! { #rt.worker_threads(#v) };
}
if let Some(v) = config.start_paused {
rt = quote! { #rt.start_paused(#v) };
}
let header = {
if is_test {
quote! {
#[::core::prelude::v1::test]
}
} else {
quote! {}
let header = if is_test {
quote! {
#[::core::prelude::v1::test]
}
} else {
quote! {}
};
let body = &input.block;
let brace_token = input.block.brace_token;
input.block = syn::parse2(quote_spanned! {last_stmt_end_span=>
{
let body = async #body;
#[allow(clippy::expect_used, clippy::diverging_sub_expression)]
{
return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body);
}
}
})
.expect("Parsing failure");
input.block.brace_token = brace_token;
let result = quote! {
#header
#(#attrs)*
#vis #sig {
#rt
.enable_all()
.build()
.unwrap()
.block_on(async #body)
}
#input
};
Ok(result.into())
result.into()
}
fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
tokens.extend(TokenStream::from(error.into_compile_error()));
tokens
}
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
let config = if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
let msg = "the main function cannot accept arguments";
return syn::Error::new_spanned(&input.sig.ident, msg)
.to_compile_error()
.into();
}
Err(syn::Error::new_spanned(&input.sig.ident, msg))
} else {
AttributeArgs::parse_terminated
.parse(args)
.and_then(|args| build_config(input.clone(), args, false, rt_multi_thread))
};
parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
match config {
Ok(config) => parse_knobs(input, false, config),
Err(e) => token_stream_with_error(parse_knobs(input, false, DEFAULT_ERROR_CONFIG), e),
}
}
pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
let config = if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
Err(syn::Error::new_spanned(&attr, msg))
} else {
AttributeArgs::parse_terminated
.parse(args)
.and_then(|args| build_config(input.clone(), args, true, rt_multi_thread))
};
for attr in &input.attrs {
if attr.path.is_ident("test") {
let msg = "second test attribute is supplied";
return syn::Error::new_spanned(&attr, msg)
.to_compile_error()
.into();
}
match config {
Ok(config) => parse_knobs(input, true, config),
Err(e) => token_stream_with_error(parse_knobs(input, true, DEFAULT_ERROR_CONFIG), e),
}
if !input.sig.inputs.is_empty() {
let msg = "the test function cannot accept arguments";
return syn::Error::new_spanned(&input.sig.inputs, msg)
.to_compile_error()
.into();
}
parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}
+104 -24
View File
@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-macros/1.0.0")]
#![allow(clippy::needless_doctest_main)]
#![warn(
missing_debug_implementations,
@@ -6,7 +5,6 @@
rust_2018_idioms,
unreachable_pub
)]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
@@ -144,12 +142,58 @@ use proc_macro::TokenStream;
/// }
/// ```
///
/// ### NOTE:
/// ### Configure the runtime to start with time paused
///
/// If you rename the Tokio crate in your dependencies this macro will not work.
/// If you must rename the current version of Tokio because you're also using an
/// older version of Tokio, you _must_ make the current version of Tokio
/// available as `tokio` in the module where this macro is expanded.
/// ```rust
/// #[tokio::main(flavor = "current_thread", start_paused = true)]
/// async fn main() {
/// println!("Hello world");
/// }
/// ```
///
/// Equivalent code not using `#[tokio::main]`
///
/// ```rust
/// fn main() {
/// tokio::runtime::Builder::new_current_thread()
/// .enable_all()
/// .start_paused(true)
/// .build()
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
/// Note that `start_paused` requires the `test-util` feature to be enabled.
///
/// ### Rename package
///
/// ```rust
/// use tokio as tokio1;
///
/// #[tokio1::main(crate = "tokio1")]
/// async fn main() {
/// println!("Hello world");
/// }
/// ```
///
/// Equivalent code not using `#[tokio::main]`
///
/// ```rust
/// use tokio as tokio1;
///
/// fn main() {
/// tokio1::runtime::Builder::new_multi_thread()
/// .enable_all()
/// .build()
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
@@ -189,12 +233,32 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
/// }
/// ```
///
/// ### NOTE:
/// ### Rename package
///
/// If you rename the Tokio crate in your dependencies this macro will not work.
/// If you must rename the current version of Tokio because you're also using an
/// older version of Tokio, you _must_ make the current version of Tokio
/// available as `tokio` in the module where this macro is expanded.
/// ```rust
/// use tokio as tokio1;
///
/// #[tokio1::main(crate = "tokio1")]
/// async fn main() {
/// println!("Hello world");
/// }
/// ```
///
/// Equivalent code not using `#[tokio::main]`
///
/// ```rust
/// use tokio as tokio1;
///
/// fn main() {
/// tokio1::runtime::Builder::new_multi_thread()
/// .enable_all()
/// .build()
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
@@ -225,12 +289,27 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
/// }
/// ```
///
/// ### NOTE:
/// ### Configure the runtime to start with time paused
///
/// If you rename the Tokio crate in your dependencies this macro will not work.
/// If you must rename the current version of Tokio because you're also using an
/// older version of Tokio, you _must_ make the current version of Tokio
/// available as `tokio` in the module where this macro is expanded.
/// ```no_run
/// #[tokio::test(start_paused = true)]
/// async fn my_test() {
/// assert!(true);
/// }
/// ```
///
/// Note that `start_paused` requires the `test-util` feature to be enabled.
///
/// ### Rename package
///
/// ```rust
/// use tokio as tokio1;
///
/// #[tokio1::test(crate = "tokio1")]
/// async fn my_test() {
/// println!("Hello world");
/// }
/// ```
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(args, item, true)
@@ -246,13 +325,6 @@ pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
/// assert!(true);
/// }
/// ```
///
/// ### NOTE:
///
/// If you rename the Tokio crate in your dependencies this macro will not work.
/// If you must rename the current version of Tokio because you're also using an
/// older version of Tokio, you _must_ make the current version of Tokio
/// available as `tokio` in the module where this macro is expanded.
#[proc_macro_attribute]
pub fn test_rt(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(args, item, false)
@@ -293,3 +365,11 @@ pub fn test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream {
pub fn select_priv_declare_output_enum(input: TokenStream) -> TokenStream {
select::declare_output_enum(input)
}
/// Implementation detail of the `select!` macro. This macro is **not** intended
/// to be used as part of the public API and is permitted to change.
#[proc_macro]
#[doc(hidden)]
pub fn select_priv_clean_pattern(input: TokenStream) -> TokenStream {
select::clean_pattern_macro(input)
}
+67
View File
@@ -41,3 +41,70 @@ pub(crate) fn declare_output_enum(input: TokenStream) -> TokenStream {
pub(super) type Mask = #mask;
})
}
pub(crate) fn clean_pattern_macro(input: TokenStream) -> TokenStream {
// If this isn't a pattern, we return the token stream as-is. The select!
// macro is using it in a location requiring a pattern, so an error will be
// emitted there.
let mut input: syn::Pat = match syn::parse(input.clone()) {
Ok(it) => it,
Err(_) => return input,
};
clean_pattern(&mut input);
quote::ToTokens::into_token_stream(input).into()
}
// Removes any occurrences of ref or mut in the provided pattern.
fn clean_pattern(pat: &mut syn::Pat) {
match pat {
syn::Pat::Box(_box) => {}
syn::Pat::Lit(_literal) => {}
syn::Pat::Macro(_macro) => {}
syn::Pat::Path(_path) => {}
syn::Pat::Range(_range) => {}
syn::Pat::Rest(_rest) => {}
syn::Pat::Verbatim(_tokens) => {}
syn::Pat::Wild(_underscore) => {}
syn::Pat::Ident(ident) => {
ident.by_ref = None;
ident.mutability = None;
if let Some((_at, pat)) = &mut ident.subpat {
clean_pattern(&mut *pat);
}
}
syn::Pat::Or(or) => {
for case in or.cases.iter_mut() {
clean_pattern(case);
}
}
syn::Pat::Slice(slice) => {
for elem in slice.elems.iter_mut() {
clean_pattern(elem);
}
}
syn::Pat::Struct(struct_pat) => {
for field in struct_pat.fields.iter_mut() {
clean_pattern(&mut field.pat);
}
}
syn::Pat::Tuple(tuple) => {
for elem in tuple.elems.iter_mut() {
clean_pattern(elem);
}
}
syn::Pat::TupleStruct(tuple) => {
for elem in tuple.pat.elems.iter_mut() {
clean_pattern(elem);
}
}
syn::Pat::Reference(reference) => {
reference.mutability = None;
clean_pattern(&mut *reference.pat);
}
syn::Pat::Type(type_pat) => {
clean_pattern(&mut *type_pat.pat);
}
_ => {}
}
}
+68 -1
View File
@@ -1,8 +1,75 @@
# 0.1.8 (October 29, 2021)
- stream: add `From<Receiver<T>>` impl for receiver streams ([#4080])
- stream: impl `FromIterator` for `StreamMap` ([#4052])
- signal: make windows docs for signal module show up on unix builds ([#3770])
[#3770]: https://github.com/tokio-rs/tokio/pull/3770
[#4052]: https://github.com/tokio-rs/tokio/pull/4052
[#4080]: https://github.com/tokio-rs/tokio/pull/4080
# 0.1.7 (July 7, 2021)
### Fixed
- sync: fix watch wrapper ([#3914])
- time: fix `Timeout::size_hint` ([#3902])
[#3902]: https://github.com/tokio-rs/tokio/pull/3902
[#3914]: https://github.com/tokio-rs/tokio/pull/3914
# 0.1.6 (May 14, 2021)
### Added
- stream: implement `Error` and `Display` for `BroadcastStreamRecvError` ([#3745])
### Fixed
- stream: avoid yielding in `AllFuture` and `AnyFuture` ([#3625])
[#3745]: https://github.com/tokio-rs/tokio/pull/3745
[#3625]: https://github.com/tokio-rs/tokio/pull/3625
# 0.1.5 (March 20, 2021)
### Fixed
- stream: documentation note for throttle `Unpin` ([#3600])
[#3600]: https://github.com/tokio-rs/tokio/pull/3600
# 0.1.4 (March 9, 2021)
Added
- signal: add `Signal` wrapper ([#3510])
Fixed
- stream: remove duplicate `doc_cfg` declaration ([#3561])
- sync: yield initial value in `WatchStream` ([#3576])
[#3510]: https://github.com/tokio-rs/tokio/pull/3510
[#3561]: https://github.com/tokio-rs/tokio/pull/3561
[#3576]: https://github.com/tokio-rs/tokio/pull/3576
# 0.1.3 (February 5, 2021)
Added
- sync: add wrapper for broadcast and watch ([#3384], [#3504])
[#3384]: https://github.com/tokio-rs/tokio/pull/3384
[#3504]: https://github.com/tokio-rs/tokio/pull/3504
# 0.1.2 (January 12, 2021)
Fixed
- docs: fix some wrappers missing in documentation (#3378)
- docs: fix some wrappers missing in documentation ([#3378])
[#3378]: https://github.com/tokio-rs/tokio/pull/3378
# 0.1.1 (January 4, 2021)
+14 -9
View File
@@ -2,18 +2,15 @@
name = "tokio-stream"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-stream-0.1.x" git tag.
version = "0.1.2"
version = "0.1.8"
edition = "2018"
rust-version = "1.49"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-stream/0.1.2/tokio_stream"
description = """
Utilities to work with `Stream` and `tokio`.
"""
@@ -25,20 +22,28 @@ time = ["tokio/time"]
net = ["tokio/net"]
io-util = ["tokio/io-util"]
fs = ["tokio/fs"]
sync = ["tokio/sync", "tokio-util"]
signal = ["tokio/signal"]
[dependencies]
futures-core = { version = "0.3.0" }
pin-project-lite = "0.2.0"
tokio = { version = "1.0", features = ["sync"] }
tokio = { version = "1.8.0", path = "../tokio", features = ["sync"] }
tokio-util = { version = "0.7.0", path = "../tokio-util", optional = true }
[dev-dependencies]
tokio = { version = "1.0", features = ["full", "test-util"] }
tokio-test = { path = "../tokio-test" }
tokio = { version = "1.2.0", path = "../tokio", features = ["full", "test-util"] }
async-stream = "0.3"
tokio-test = { path = "../tokio-test" }
futures = { version = "0.3", default-features = false }
proptest = "0.10.0"
proptest = "1"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
# Issue #3770
#
# This should allow `docsrs` to be read across projects, so that `tokio-stream`
# can pick up stubbed types exported by `tokio`.
rustc-args = ["--cfg", "docsrs"]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2020 Tokio Contributors
Copyright (c) 2022 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+4 -9
View File
@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-stream/0.1.2")]
#![allow(
clippy::cognitive_complexity,
clippy::large_enum_variant,
@@ -10,18 +9,11 @@
rust_2018_idioms,
unreachable_pub
)]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg_attr(docsrs, feature(doc_cfg))]
//! Stream utilities for Tokio.
//!
@@ -85,6 +77,9 @@ pub mod wrappers;
mod stream_ext;
pub use stream_ext::{collect::FromStream, StreamExt};
cfg_time! {
pub use stream_ext::timeout::{Elapsed, Timeout};
}
mod empty;
pub use empty::{empty, Empty};
+20
View File
@@ -38,6 +38,26 @@ macro_rules! cfg_time {
}
}
macro_rules! cfg_sync {
($($item:item)*) => {
$(
#[cfg(feature = "sync")]
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
$item
)*
}
}
macro_rules! cfg_signal {
($($item:item)*) => {
$(
#[cfg(feature = "signal")]
#[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
$item
)*
}
}
macro_rules! ready {
($e:expr $(,)?) => {
match $e {
+99 -5
View File
@@ -1,3 +1,4 @@
use core::future::Future;
use futures_core::Stream;
mod all;
@@ -27,6 +28,9 @@ use fuse::Fuse;
mod map;
use map::Map;
mod map_while;
use map_while::MapWhile;
mod merge;
use merge::Merge;
@@ -39,17 +43,20 @@ use skip::Skip;
mod skip_while;
use skip_while::SkipWhile;
mod try_next;
use try_next::TryNext;
mod take;
use take::Take;
mod take_while;
use take_while::TakeWhile;
mod then;
use then::Then;
mod try_next;
use try_next::TryNext;
cfg_time! {
mod timeout;
pub(crate) mod timeout;
use timeout::Timeout;
use tokio::time::Duration;
mod throttle;
@@ -197,6 +204,93 @@ pub trait StreamExt: Stream {
Map::new(self, f)
}
/// Map this stream's items to a different type for as long as determined by
/// the provided closure. A stream of the target type will be returned,
/// which will yield elements until the closure returns `None`.
///
/// The provided closure is executed over all elements of this stream as
/// they are made available, until it returns `None`. It is executed inline
/// with calls to [`poll_next`](Stream::poll_next). Once `None` is returned,
/// the underlying stream will not be polled again.
///
/// Note that this function consumes the stream passed into it and returns a
/// wrapped version of it, similar to the [`Iterator::map_while`] method in the
/// standard library.
///
/// # Examples
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{self as stream, StreamExt};
///
/// let stream = stream::iter(1..=10);
/// let mut stream = stream.map_while(|x| {
/// if x < 4 {
/// Some(x + 3)
/// } else {
/// None
/// }
/// });
/// assert_eq!(stream.next().await, Some(4));
/// assert_eq!(stream.next().await, Some(5));
/// assert_eq!(stream.next().await, Some(6));
/// assert_eq!(stream.next().await, None);
/// # }
/// ```
fn map_while<T, F>(self, f: F) -> MapWhile<Self, F>
where
F: FnMut(Self::Item) -> Option<T>,
Self: Sized,
{
MapWhile::new(self, f)
}
/// Maps this stream's items asynchronously to a different type, returning a
/// new stream of the resulting type.
///
/// The provided closure is executed over all elements of this stream as
/// they are made available, and the returned future is executed. Only one
/// future is executed at the time.
///
/// Note that this function consumes the stream passed into it and returns a
/// wrapped version of it, similar to the existing `then` methods in the
/// standard library.
///
/// Be aware that if the future is not `Unpin`, then neither is the `Stream`
/// returned by this method. To handle this, you can use `tokio::pin!` as in
/// the example below or put the stream in a `Box` with `Box::pin(stream)`.
///
/// # Examples
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{self as stream, StreamExt};
///
/// async fn do_async_work(value: i32) -> i32 {
/// value + 3
/// }
///
/// let stream = stream::iter(1..=3);
/// let stream = stream.then(do_async_work);
///
/// tokio::pin!(stream);
///
/// assert_eq!(stream.next().await, Some(4));
/// assert_eq!(stream.next().await, Some(5));
/// assert_eq!(stream.next().await, Some(6));
/// # }
/// ```
fn then<F, Fut>(self, f: F) -> Then<Self, Fut, F>
where
F: FnMut(Self::Item) -> Fut,
Fut: Future,
Self: Sized,
{
Then::new(self, f)
}
/// Combine two streams into one by interleaving the output of both as it
/// is produced.
///
@@ -515,7 +609,7 @@ pub trait StreamExt: Stream {
/// Skip elements from the underlying stream while the provided predicate
/// resolves to `true`.
///
/// This function, like [`Iterator::skip_while`], will ignore elemets from the
/// This function, like [`Iterator::skip_while`], will ignore elements from the
/// stream until the predicate `f` resolves to `false`. Once one element
/// returns false, the rest of the elements will be yielded.
///
+12 -9
View File
@@ -38,18 +38,21 @@ where
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
let next = futures_core::ready!(Pin::new(me.stream).poll_next(cx));
let mut stream = Pin::new(me.stream);
match next {
Some(v) => {
if !(me.f)(v) {
Poll::Ready(false)
} else {
cx.waker().wake_by_ref();
Poll::Pending
// Take a maximum of 32 items from the stream before yielding.
for _ in 0..32 {
match futures_core::ready!(stream.as_mut().poll_next(cx)) {
Some(v) => {
if !(me.f)(v) {
return Poll::Ready(false);
}
}
None => return Poll::Ready(true),
}
None => Poll::Ready(true),
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
+12 -9
View File
@@ -38,18 +38,21 @@ where
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
let next = futures_core::ready!(Pin::new(me.stream).poll_next(cx));
let mut stream = Pin::new(me.stream);
match next {
Some(v) => {
if (me.f)(v) {
Poll::Ready(true)
} else {
cx.waker().wake_by_ref();
Poll::Pending
// Take a maximum of 32 items from the stream before yielding.
for _ in 0..32 {
match futures_core::ready!(stream.as_mut().poll_next(cx)) {
Some(v) => {
if (me.f)(v) {
return Poll::Ready(true);
}
}
None => return Poll::Ready(false),
}
None => Poll::Ready(false),
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
+6 -6
View File
@@ -66,17 +66,17 @@ where
use Poll::Ready;
loop {
let mut me = self.as_mut().project();
let me = self.as_mut().project();
let item = match ready!(me.stream.poll_next(cx)) {
Some(item) => item,
None => {
return Ready(U::finalize(sealed::Internal, &mut me.collection));
return Ready(U::finalize(sealed::Internal, me.collection));
}
};
if !U::extend(sealed::Internal, &mut me.collection, item) {
return Ready(U::finalize(sealed::Internal, &mut me.collection));
if !U::extend(sealed::Internal, me.collection, item) {
return Ready(U::finalize(sealed::Internal, me.collection));
}
}
}
@@ -113,7 +113,7 @@ impl<T: AsRef<str>> sealed::FromStreamPriv<T> for String {
}
fn finalize(_: sealed::Internal, collection: &mut String) -> String {
mem::replace(collection, String::new())
mem::take(collection)
}
}
@@ -132,7 +132,7 @@ impl<T> sealed::FromStreamPriv<T> for Vec<T> {
}
fn finalize(_: sealed::Internal, collection: &mut Vec<T>) -> Vec<T> {
mem::replace(collection, vec![])
mem::take(collection)
}
}
+52
View File
@@ -0,0 +1,52 @@
use crate::Stream;
use core::fmt;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;
pin_project! {
/// Stream for the [`map_while`](super::StreamExt::map_while) method.
#[must_use = "streams do nothing unless polled"]
pub struct MapWhile<St, F> {
#[pin]
stream: St,
f: F,
}
}
impl<St, F> fmt::Debug for MapWhile<St, F>
where
St: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapWhile")
.field("stream", &self.stream)
.finish()
}
}
impl<St, F> MapWhile<St, F> {
pub(super) fn new(stream: St, f: F) -> Self {
MapWhile { stream, f }
}
}
impl<St, F, T> Stream for MapWhile<St, F>
where
St: Stream,
F: FnMut(St::Item) -> Option<T>,
{
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
let me = self.project();
let f = me.f;
me.stream.poll_next(cx).map(|opt| opt.and_then(f))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.stream.size_hint();
(0, upper)
}
}
+83
View File
@@ -0,0 +1,83 @@
use crate::Stream;
use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;
pin_project! {
/// Stream for the [`then`](super::StreamExt::then) method.
#[must_use = "streams do nothing unless polled"]
pub struct Then<St, Fut, F> {
#[pin]
stream: St,
#[pin]
future: Option<Fut>,
f: F,
}
}
impl<St, Fut, F> fmt::Debug for Then<St, Fut, F>
where
St: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Then")
.field("stream", &self.stream)
.finish()
}
}
impl<St, Fut, F> Then<St, Fut, F> {
pub(super) fn new(stream: St, f: F) -> Self {
Then {
stream,
future: None,
f,
}
}
}
impl<St, F, Fut> Stream for Then<St, Fut, F>
where
St: Stream,
Fut: Future,
F: FnMut(St::Item) -> Fut,
{
type Item = Fut::Output;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Fut::Output>> {
let mut me = self.project();
loop {
if let Some(future) = me.future.as_mut().as_pin_mut() {
match future.poll(cx) {
Poll::Ready(item) => {
me.future.set(None);
return Poll::Ready(Some(item));
}
Poll::Pending => return Poll::Pending,
}
}
match me.stream.as_mut().poll_next(cx) {
Poll::Ready(Some(item)) => {
me.future.set(Some((me.f)(item)));
}
Poll::Ready(None) => return Poll::Ready(None),
Poll::Pending => return Poll::Pending,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let future_len = if self.future.is_some() { 1 } else { 0 };
let (lower, upper) = self.stream.size_hint();
let lower = lower.saturating_add(future_len);
let upper = upper.and_then(|upper| upper.checked_add(future_len));
(lower, upper)
}
}
+2 -1
View File
@@ -23,7 +23,8 @@ where
}
pin_project! {
/// Stream for the [`throttle`](throttle) function.
/// Stream for the [`throttle`](throttle) function. This object is `!Unpin`. If you need it to
/// implement `Unpin` you can pin your throttle like this: `Box::pin(your_throttle)`.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Throttle<T> {
+12 -1
View File
@@ -69,7 +69,18 @@ impl<S: Stream> Stream for Timeout<S> {
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.stream.size_hint()
let (lower, upper) = self.stream.size_hint();
// The timeout stream may insert an error before and after each message
// from the underlying stream, but no more than one error between each
// message. Hence the upper bound is computed as 2x+1.
// Using a helper function to enable use of question mark operator.
fn twice_plus_one(value: Option<usize>) -> Option<usize> {
value?.checked_mul(2)?.checked_add(1)
}
(lower, twice_plus_one(upper))
}
}
+32 -6
View File
@@ -364,11 +364,11 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use tokio_stream::{StreamMap, pending};
///
/// let mut a = HashMap::new();
/// let mut a = StreamMap::new();
/// assert!(a.is_empty());
/// a.insert(1, "a");
/// a.insert(1, pending::<i32>());
/// assert!(!a.is_empty());
/// ```
pub fn is_empty(&self) -> bool {
@@ -568,6 +568,32 @@ where
}
}
impl<K, V> std::iter::FromIterator<(K, V)> for StreamMap<K, V>
where
K: Hash + Eq,
{
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let iterator = iter.into_iter();
let (lower_bound, _) = iterator.size_hint();
let mut stream_map = Self::with_capacity(lower_bound);
for (key, value) in iterator {
stream_map.insert(key, value);
}
stream_map
}
}
impl<K, V> Extend<(K, V)> for StreamMap<K, V> {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (K, V)>,
{
self.entries.extend(iter);
}
}
mod rand {
use std::cell::Cell;
@@ -605,10 +631,10 @@ mod rand {
/// Fast random number generate
///
/// Implement xorshift64+: 2 32-bit xorshift sequences added together.
/// Shift triplet [17,7,16] was calculated as indicated in Marsaglia's
/// Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
/// Shift triplet `[17,7,16]` was calculated as indicated in Marsaglia's
/// Xorshift paper: <https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf>
/// This generator passes the SmallCrush suite, part of TestU01 framework:
/// http://simul.iro.umontreal.ca/testu01/tu01.html
/// <http://simul.iro.umontreal.ca/testu01/tu01.html>
#[derive(Debug)]
pub(crate) struct FastRand {
one: Cell<u32>,
+27
View File
@@ -1,11 +1,38 @@
//! Wrappers for Tokio types that implement `Stream`.
/// Error types for the wrappers.
pub mod errors {
cfg_sync! {
pub use crate::wrappers::broadcast::BroadcastStreamRecvError;
}
}
mod mpsc_bounded;
pub use mpsc_bounded::ReceiverStream;
mod mpsc_unbounded;
pub use mpsc_unbounded::UnboundedReceiverStream;
cfg_sync! {
mod broadcast;
pub use broadcast::BroadcastStream;
mod watch;
pub use watch::WatchStream;
}
cfg_signal! {
#[cfg(unix)]
mod signal_unix;
#[cfg(unix)]
pub use signal_unix::SignalStream;
#[cfg(any(windows, docsrs))]
mod signal_windows;
#[cfg(any(windows, docsrs))]
pub use signal_windows::{CtrlCStream, CtrlBreakStream};
}
cfg_time! {
mod interval;
pub use interval::IntervalStream;
+79
View File
@@ -0,0 +1,79 @@
use std::pin::Pin;
use tokio::sync::broadcast::error::RecvError;
use tokio::sync::broadcast::Receiver;
use futures_core::Stream;
use tokio_util::sync::ReusableBoxFuture;
use std::fmt;
use std::task::{Context, Poll};
/// A wrapper around [`tokio::sync::broadcast::Receiver`] that implements [`Stream`].
///
/// [`tokio::sync::broadcast::Receiver`]: struct@tokio::sync::broadcast::Receiver
/// [`Stream`]: trait@crate::Stream
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
pub struct BroadcastStream<T> {
inner: ReusableBoxFuture<'static, (Result<T, RecvError>, Receiver<T>)>,
}
/// An error returned from the inner stream of a [`BroadcastStream`].
#[derive(Debug, PartialEq, Clone)]
pub enum BroadcastStreamRecvError {
/// The receiver lagged too far behind. Attempting to receive again will
/// return the oldest message still retained by the channel.
///
/// Includes the number of skipped messages.
Lagged(u64),
}
impl fmt::Display for BroadcastStreamRecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BroadcastStreamRecvError::Lagged(amt) => write!(f, "channel lagged by {}", amt),
}
}
}
impl std::error::Error for BroadcastStreamRecvError {}
async fn make_future<T: Clone>(mut rx: Receiver<T>) -> (Result<T, RecvError>, Receiver<T>) {
let result = rx.recv().await;
(result, rx)
}
impl<T: 'static + Clone + Send> BroadcastStream<T> {
/// Create a new `BroadcastStream`.
pub fn new(rx: Receiver<T>) -> Self {
Self {
inner: ReusableBoxFuture::new(make_future(rx)),
}
}
}
impl<T: 'static + Clone + Send> Stream for BroadcastStream<T> {
type Item = Result<T, BroadcastStreamRecvError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let (result, rx) = ready!(self.inner.poll(cx));
self.inner.set(make_future(rx));
match result {
Ok(item) => Poll::Ready(Some(Ok(item))),
Err(RecvError::Closed) => Poll::Ready(None),
Err(RecvError::Lagged(n)) => {
Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n))))
}
}
}
}
impl<T> fmt::Debug for BroadcastStream<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BroadcastStream").finish()
}
}
impl<T: 'static + Clone + Send> From<Receiver<T>> for BroadcastStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
@@ -57,3 +57,9 @@ impl<T> AsMut<Receiver<T>> for ReceiverStream<T> {
&mut self.inner
}
}
impl<T> From<Receiver<T>> for ReceiverStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
@@ -51,3 +51,9 @@ impl<T> AsMut<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
&mut self.inner
}
}
impl<T> From<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
fn from(recv: UnboundedReceiver<T>) -> Self {
Self::new(recv)
}
}
+46
View File
@@ -0,0 +1,46 @@
use crate::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::signal::unix::Signal;
/// A wrapper around [`Signal`] that implements [`Stream`].
///
/// [`Signal`]: struct@tokio::signal::unix::Signal
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(all(unix, feature = "signal"))))]
pub struct SignalStream {
inner: Signal,
}
impl SignalStream {
/// Create a new `SignalStream`.
pub fn new(interval: Signal) -> Self {
Self { inner: interval }
}
/// Get back the inner `Signal`.
pub fn into_inner(self) -> Signal {
self.inner
}
}
impl Stream for SignalStream {
type Item = ();
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
self.inner.poll_recv(cx)
}
}
impl AsRef<Signal> for SignalStream {
fn as_ref(&self) -> &Signal {
&self.inner
}
}
impl AsMut<Signal> for SignalStream {
fn as_mut(&mut self) -> &mut Signal {
&mut self.inner
}
}
@@ -0,0 +1,88 @@
use crate::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::signal::windows::{CtrlBreak, CtrlC};
/// A wrapper around [`CtrlC`] that implements [`Stream`].
///
/// [`CtrlC`]: struct@tokio::signal::windows::CtrlC
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "signal"))))]
pub struct CtrlCStream {
inner: CtrlC,
}
impl CtrlCStream {
/// Create a new `CtrlCStream`.
pub fn new(interval: CtrlC) -> Self {
Self { inner: interval }
}
/// Get back the inner `CtrlC`.
pub fn into_inner(self) -> CtrlC {
self.inner
}
}
impl Stream for CtrlCStream {
type Item = ();
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
self.inner.poll_recv(cx)
}
}
impl AsRef<CtrlC> for CtrlCStream {
fn as_ref(&self) -> &CtrlC {
&self.inner
}
}
impl AsMut<CtrlC> for CtrlCStream {
fn as_mut(&mut self) -> &mut CtrlC {
&mut self.inner
}
}
/// A wrapper around [`CtrlBreak`] that implements [`Stream`].
///
/// [`CtrlBreak`]: struct@tokio::signal::windows::CtrlBreak
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "signal"))))]
pub struct CtrlBreakStream {
inner: CtrlBreak,
}
impl CtrlBreakStream {
/// Create a new `CtrlBreakStream`.
pub fn new(interval: CtrlBreak) -> Self {
Self { inner: interval }
}
/// Get back the inner `CtrlBreak`.
pub fn into_inner(self) -> CtrlBreak {
self.inner
}
}
impl Stream for CtrlBreakStream {
type Item = ();
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
self.inner.poll_recv(cx)
}
}
impl AsRef<CtrlBreak> for CtrlBreakStream {
fn as_ref(&self) -> &CtrlBreak {
&self.inner
}
}
impl AsMut<CtrlBreak> for CtrlBreakStream {
fn as_mut(&mut self) -> &mut CtrlBreak {
&mut self.inner
}
}
+102
View File
@@ -0,0 +1,102 @@
use std::pin::Pin;
use tokio::sync::watch::Receiver;
use futures_core::Stream;
use tokio_util::sync::ReusableBoxFuture;
use std::fmt;
use std::task::{Context, Poll};
use tokio::sync::watch::error::RecvError;
/// A wrapper around [`tokio::sync::watch::Receiver`] that implements [`Stream`].
///
/// This stream will always start by yielding the current value when the WatchStream is polled,
/// regardless of whether it was the initial value or sent afterwards.
///
/// # Examples
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{StreamExt, wrappers::WatchStream};
/// use tokio::sync::watch;
///
/// let (tx, rx) = watch::channel("hello");
/// let mut rx = WatchStream::new(rx);
///
/// assert_eq!(rx.next().await, Some("hello"));
///
/// tx.send("goodbye").unwrap();
/// assert_eq!(rx.next().await, Some("goodbye"));
/// # }
/// ```
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{StreamExt, wrappers::WatchStream};
/// use tokio::sync::watch;
///
/// let (tx, rx) = watch::channel("hello");
/// let mut rx = WatchStream::new(rx);
///
/// tx.send("goodbye").unwrap();
/// assert_eq!(rx.next().await, Some("goodbye"));
/// # }
/// ```
///
/// [`tokio::sync::watch::Receiver`]: struct@tokio::sync::watch::Receiver
/// [`Stream`]: trait@crate::Stream
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
pub struct WatchStream<T> {
inner: ReusableBoxFuture<'static, (Result<(), RecvError>, Receiver<T>)>,
}
async fn make_future<T: Clone + Send + Sync>(
mut rx: Receiver<T>,
) -> (Result<(), RecvError>, Receiver<T>) {
let result = rx.changed().await;
(result, rx)
}
impl<T: 'static + Clone + Send + Sync> WatchStream<T> {
/// Create a new `WatchStream`.
pub fn new(rx: Receiver<T>) -> Self {
Self {
inner: ReusableBoxFuture::new(async move { (Ok(()), rx) }),
}
}
}
impl<T: Clone + 'static + Send + Sync> Stream for WatchStream<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let (result, mut rx) = ready!(self.inner.poll(cx));
match result {
Ok(_) => {
let received = (*rx.borrow_and_update()).clone();
self.inner.set(make_future(rx));
Poll::Ready(Some(received))
}
Err(_) => {
self.inner.set(make_future(rx));
Poll::Ready(None)
}
}
}
}
impl<T> Unpin for WatchStream<T> {}
impl<T> fmt::Debug for WatchStream<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WatchStream").finish()
}
}
impl<T: 'static + Clone + Send + Sync> From<Receiver<T>> for WatchStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
+2
View File
@@ -1,3 +1,5 @@
#![allow(clippy::diverging_sub_expression)]
use std::rc::Rc;
#[allow(dead_code)]
+2 -2
View File
@@ -89,12 +89,12 @@ fn size_overflow() {
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::max_value(), Some(usize::max_value()))
(usize::MAX, Some(usize::MAX))
}
}
let m1 = Monster;
let m2 = Monster;
let m = m1.chain(m2);
assert_eq!(m.size_hint(), (usize::max_value(), None));
assert_eq!(m.size_hint(), (usize::MAX, None));
}
+2 -2
View File
@@ -72,12 +72,12 @@ fn size_overflow() {
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::max_value(), Some(usize::max_value()))
(usize::MAX, Some(usize::MAX))
}
}
let m1 = Monster;
let m2 = Monster;
let m = m1.merge(m2);
assert_eq!(m.size_hint(), (usize::max_value(), None));
assert_eq!(m.size_hint(), (usize::MAX, None));
}
+2 -2
View File
@@ -1,10 +1,10 @@
#![cfg(feature = "full")]
#![cfg(all(feature = "time", feature = "sync", feature = "io-util"))]
use tokio::time::{self, sleep, Duration};
use tokio_stream::{self, StreamExt};
use tokio_test::*;
use futures::StreamExt as _;
use futures::stream;
async fn maybe_sleep(idx: i32) -> i32 {
if idx % 2 == 0 {
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#![cfg(all(feature = "time", feature = "sync", feature = "io-util"))]
use tokio::time;
use tokio_stream::StreamExt;
+29
View File
@@ -0,0 +1,29 @@
#![cfg(feature = "sync")]
use tokio::sync::watch;
use tokio_stream::wrappers::WatchStream;
use tokio_stream::StreamExt;
#[tokio::test]
async fn message_not_twice() {
let (tx, rx) = watch::channel("hello");
let mut counter = 0;
let mut stream = WatchStream::new(rx).map(move |payload| {
println!("{}", payload);
if payload == "goodbye" {
counter += 1;
}
if counter >= 2 {
panic!("too many goodbyes");
}
});
let task = tokio::spawn(async move { while stream.next().await.is_some() {} });
// Send goodbye just once
tx.send("goodbye").unwrap();
drop(tx);
task.await.unwrap();
}
+12
View File
@@ -1,3 +1,15 @@
# 0.4.2 (May 14, 2021)
- test: add `assert_elapsed!` macro ([#3728])
[#3728]: https://github.com/tokio-rs/tokio/pull/3728
# 0.4.1 (March 10, 2021)
- Fix `io::Mock` to be `Send` and `Sync` ([#3594])
[#3594]: https://github.com/tokio-rs/tokio/pull/3594
# 0.4.0 (December 23, 2020)
- Track `tokio` 1.0 release.
+5 -8
View File
@@ -2,33 +2,30 @@
name = "tokio-test"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-test-0.4.x" git tag.
version = "0.4.0"
version = "0.4.2"
edition = "2018"
rust-version = "1.49"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-test/0.4.0/tokio_test"
description = """
Testing utilities for Tokio- and futures-based code
"""
categories = ["asynchronous", "testing"]
[dependencies]
tokio = { version = "1.0.0", path = "../tokio", features = ["rt", "sync", "time", "test-util"] }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
tokio = { version = "1.2.0", path = "../tokio", features = ["rt", "sync", "time", "test-util"] }
tokio-stream = { version = "0.1.1", path = "../tokio-stream" }
async-stream = "0.3"
bytes = "1.0.0"
futures-core = "0.3.0"
[dev-dependencies]
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
tokio = { version = "1.2.0", path = "../tokio", features = ["full"] }
futures-util = "0.3.0"
[package.metadata.docs.rs]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2020 Tokio Contributors
Copyright (c) 2022 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+4 -8
View File
@@ -21,6 +21,7 @@
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio::sync::mpsc;
use tokio::time::{self, Duration, Instant, Sleep};
use tokio_stream::wrappers::UnboundedReceiverStream;
use futures_core::{ready, Stream};
use std::collections::VecDeque;
@@ -69,8 +70,7 @@ struct Inner {
waiting: Option<Instant>,
sleep: Option<Pin<Box<Sleep>>>,
read_wait: Option<Waker>,
// rx: mpsc::UnboundedReceiver<Action>,
rx: Pin<Box<dyn Stream<Item = Action> + Send>>,
rx: UnboundedReceiverStream<Action>,
}
impl Builder {
@@ -185,13 +185,9 @@ impl Handle {
impl Inner {
fn new(actions: VecDeque<Action>) -> (Inner, Handle) {
let (tx, mut rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel();
let rx = Box::pin(async_stream::stream! {
while let Some(item) = rx.recv().await {
yield item;
}
});
let rx = UnboundedReceiverStream::new(rx);
let inner = Inner {
actions,
+3 -5
View File
@@ -1,17 +1,15 @@
#![doc(html_root_url = "https://docs.rs/tokio-test/0.4.0")]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
//! Tokio and Futures based testing utilites
//! Tokio and Futures based testing utilities
pub mod io;
@@ -22,9 +20,9 @@ pub mod task;
/// future completes.
///
/// For more information, see the documentation for
/// [`tokio::runtime::current_thread::Runtime::block_on`][runtime-block-on].
/// [`tokio::runtime::Runtime::block_on`][runtime-block-on].
///
/// [runtime-block-on]: https://docs.rs/tokio/0.2.0-alpha.2/tokio/runtime/current_thread/struct.Runtime.html#method.block_on
/// [runtime-block-on]: https://docs.rs/tokio/1.3.0/tokio/runtime/struct.Runtime.html#method.block_on
pub fn block_on<F: std::future::Future>(future: F) -> F::Output {
use tokio::runtime;
+34
View File
@@ -259,3 +259,37 @@ macro_rules! assert_err {
}
}};
}
/// Asserts that an exact duration has elapsed since since the start instant ±1ms.
///
/// ```rust
/// use tokio::time::{self, Instant};
/// use std::time::Duration;
/// use tokio_test::assert_elapsed;
/// # async fn test_time_passed() {
///
/// let start = Instant::now();
/// let dur = Duration::from_millis(50);
/// time::sleep(dur).await;
/// assert_elapsed!(start, dur);
/// # }
/// ```
///
/// This 1ms buffer is required because Tokio's hashed-wheel timer has finite time resolution and
/// will not always sleep for the exact interval.
#[macro_export]
macro_rules! assert_elapsed {
($start:expr, $dur:expr) => {{
let elapsed = $start.elapsed();
// type ascription improves compiler error when wrong type is passed
let lower: std::time::Duration = $dur;
// Handles ms rounding
assert!(
elapsed >= lower && elapsed <= lower + std::time::Duration::from_millis(1),
"actual = {:?}, expected = {:?}",
elapsed,
lower
);
}};
}
+1 -1
View File
@@ -180,7 +180,7 @@ impl ThreadWaker {
}
}
/// Clears any previously received wakes, avoiding potential spurrious
/// Clears any previously received wakes, avoiding potential spurious
/// wake notifications. This should only be called immediately before running the
/// task.
fn clear(&self) {
+154 -2
View File
@@ -1,4 +1,153 @@
# 0.6.2 (January 21, 2020)
# 0.7.1 (February 21, 2022)
### Added
- codec: add `length_field_type` to `LengthDelimitedCodec` builder ([#4508])
- io: add `StreamReader::into_inner_with_chunk()` ([#4559])
### Changed
- switch from log to tracing ([#4539])
### Fixed
- sync: fix waker update condition in `CancellationToken` ([#4497])
- bumped tokio dependency to 1.6 to satisfy minimum requirements ([#4490])
[#4490]: https://github.com/tokio-rs/tokio/pull/4490
[#4497]: https://github.com/tokio-rs/tokio/pull/4497
[#4508]: https://github.com/tokio-rs/tokio/pull/4508
[#4539]: https://github.com/tokio-rs/tokio/pull/4539
[#4559]: https://github.com/tokio-rs/tokio/pull/4559
# 0.7.0 (February 9, 2022)
### Added
- task: add `spawn_pinned` ([#3370])
- time: add `shrink_to_fit` and `compact` methods to `DelayQueue` ([#4170])
- codec: improve `Builder::max_frame_length` docs ([#4352])
- codec: add mutable reference getters for codecs to pinned `Framed` ([#4372])
- net: add generic trait to combine `UnixListener` and `TcpListener` ([#4385])
- codec: implement `Framed::map_codec` ([#4427])
- codec: implement `Encoder<BytesMut>` for `BytesCodec` ([#4465])
### Changed
- sync: add lifetime parameter to `ReusableBoxFuture` ([#3762])
- sync: refactored `PollSender<T>` to fix a subtly broken `Sink<T>` implementation ([#4214])
- time: remove error case from the infallible `DelayQueue::poll_elapsed` ([#4241])
[#3370]: https://github.com/tokio-rs/tokio/pull/3370
[#4170]: https://github.com/tokio-rs/tokio/pull/4170
[#4352]: https://github.com/tokio-rs/tokio/pull/4352
[#4372]: https://github.com/tokio-rs/tokio/pull/4372
[#4385]: https://github.com/tokio-rs/tokio/pull/4385
[#4427]: https://github.com/tokio-rs/tokio/pull/4427
[#4465]: https://github.com/tokio-rs/tokio/pull/4465
[#3762]: https://github.com/tokio-rs/tokio/pull/3762
[#4214]: https://github.com/tokio-rs/tokio/pull/4214
[#4241]: https://github.com/tokio-rs/tokio/pull/4241
# 0.6.9 (October 29, 2021)
### Added
- codec: implement `Clone` for `LengthDelimitedCodec` ([#4089])
- io: add `SyncIoBridge` ([#4146])
### Fixed
- time: update deadline on removal in `DelayQueue` ([#4178])
- codec: Update stream impl for Framed to return None after Err ([#4166])
[#4089]: https://github.com/tokio-rs/tokio/pull/4089
[#4146]: https://github.com/tokio-rs/tokio/pull/4146
[#4166]: https://github.com/tokio-rs/tokio/pull/4166
[#4178]: https://github.com/tokio-rs/tokio/pull/4178
# 0.6.8 (September 3, 2021)
### Added
- sync: add drop guard for `CancellationToken` ([#3839])
- compact: added `AsyncSeek` compat ([#4078])
- time: expose `Key` used in `DelayQueue`'s `Expired` ([#4081])
- io: add `with_capacity` to `ReaderStream` ([#4086])
### Fixed
- codec: remove unnecessary `doc(cfg(...))` ([#3989])
[#3839]: https://github.com/tokio-rs/tokio/pull/3839
[#4078]: https://github.com/tokio-rs/tokio/pull/4078
[#4081]: https://github.com/tokio-rs/tokio/pull/4081
[#4086]: https://github.com/tokio-rs/tokio/pull/4086
[#3989]: https://github.com/tokio-rs/tokio/pull/3989
# 0.6.7 (May 14, 2021)
### Added
- udp: make `UdpFramed` take `Borrow<UdpSocket>` ([#3451])
- compat: implement `AsRawFd`/`AsRawHandle` for `Compat<T>` ([#3765])
[#3451]: https://github.com/tokio-rs/tokio/pull/3451
[#3765]: https://github.com/tokio-rs/tokio/pull/3765
# 0.6.6 (April 12, 2021)
### Added
- util: makes `Framed` and `FramedStream` resumable after eof ([#3272])
- util: add `PollSemaphore::{add_permits, available_permits}` ([#3683])
### Fixed
- chore: avoid allocation if `PollSemaphore` is unused ([#3634])
[#3272]: https://github.com/tokio-rs/tokio/pull/3272
[#3634]: https://github.com/tokio-rs/tokio/pull/3634
[#3683]: https://github.com/tokio-rs/tokio/pull/3683
# 0.6.5 (March 20, 2021)
### Fixed
- util: annotate time module as requiring `time` feature ([#3606])
[#3606]: https://github.com/tokio-rs/tokio/pull/3606
# 0.6.4 (March 9, 2021)
### Added
- codec: `AnyDelimiter` codec ([#3406])
- sync: add pollable `mpsc::Sender` ([#3490])
### Fixed
- codec: `LinesCodec` should only return `MaxLineLengthExceeded` once per line ([#3556])
- sync: fuse PollSemaphore ([#3578])
[#3406]: https://github.com/tokio-rs/tokio/pull/3406
[#3490]: https://github.com/tokio-rs/tokio/pull/3490
[#3556]: https://github.com/tokio-rs/tokio/pull/3556
[#3578]: https://github.com/tokio-rs/tokio/pull/3578
# 0.6.3 (January 31, 2021)
### Added
- sync: add `ReusableBoxFuture` utility ([#3464])
### Changed
- sync: use `ReusableBoxFuture` for `PollSemaphore` ([#3463])
- deps: remove `async-stream` dependency ([#3463])
- deps: remove `tokio-stream` dependency ([#3487])
# 0.6.2 (January 21, 2021)
### Added
@@ -8,7 +157,7 @@
- time: fix panics on updating `DelayQueue` entries ([#3270])
# 0.6.1 (January 12, 2020)
# 0.6.1 (January 12, 2021)
### Added
@@ -72,6 +221,9 @@
- Initial release
[#3487]: https://github.com/tokio-rs/tokio/pull/3487
[#3464]: https://github.com/tokio-rs/tokio/pull/3464
[#3463]: https://github.com/tokio-rs/tokio/pull/3463
[#3444]: https://github.com/tokio-rs/tokio/pull/3444
[#3387]: https://github.com/tokio-rs/tokio/pull/3387
[#3364]: https://github.com/tokio-rs/tokio/pull/3364
+17 -17
View File
@@ -2,18 +2,15 @@
name = "tokio-util"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-util-0.6.x" git tag.
version = "0.6.2"
# - Create "tokio-util-0.7.x" git tag.
version = "0.7.1"
edition = "2018"
rust-version = "1.49"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-util/0.6.2/tokio_util"
description = """
Additional utilities for working with Tokio.
"""
@@ -24,35 +21,38 @@ categories = ["asynchronous"]
default = []
# Shorthand for enabling everything
full = ["codec", "compat", "io", "time", "net", "rt"]
full = ["codec", "compat", "io-util", "time", "net", "rt"]
net = ["tokio/net"]
compat = ["futures-io",]
codec = []
codec = ["tracing"]
time = ["tokio/time","slab"]
io = []
rt = ["tokio/rt"]
io-util = ["io", "tokio/rt", "tokio/io-util"]
rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"]
__docs_rs = ["futures-util"]
[dependencies]
tokio = { version = "1.0.0" }
tokio-stream = { version = "0.1" }
tokio = { version = "1.18.0", path = "../tokio", features = ["sync"] }
bytes = "1.0.0"
futures-core = "0.3.0"
futures-sink = "0.3.0"
futures-io = { version = "0.3.0", optional = true }
futures-util = { version = "0.3.0", optional = true }
log = "0.4"
pin-project-lite = "0.2.0"
slab = { version = "0.4.1", optional = true } # Backs `DelayQueue`
async-stream = "0.3.0"
slab = { version = "0.4.4", optional = true } # Backs `DelayQueue`
tracing = { version = "0.1.25", default-features = false, features = ["std"], optional = true }
[target.'cfg(tokio_unstable)'.dependencies]
hashbrown = { version = "0.12.0", optional = true }
[dev-dependencies]
tokio = { version = "1.0.0", features = ["full"] }
tokio-test = { version = "0.4.0" }
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
tokio-test = { version = "0.4.0", path = "../tokio-test" }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
async-stream = "0.3.0"
futures = "0.3.0"
futures-test = "0.3.5"
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2020 Tokio Contributors
Copyright (c) 2022 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+1 -1
View File
@@ -1,6 +1,6 @@
# tokio-util
Utilities for encoding and decoding frames.
Utilities for working with Tokio.
## License
+22
View File
@@ -38,6 +38,18 @@ macro_rules! cfg_io {
}
}
cfg_io! {
macro_rules! cfg_io_util {
($($item:item)*) => {
$(
#[cfg(feature = "io-util")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
$item
)*
}
}
}
macro_rules! cfg_rt {
($($item:item)*) => {
$(
@@ -47,3 +59,13 @@ macro_rules! cfg_rt {
)*
}
}
macro_rules! cfg_time {
($($item:item)*) => {
$(
#[cfg(feature = "time")]
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
$item
)*
}
}
+263
View File
@@ -0,0 +1,263 @@
use crate::codec::decoder::Decoder;
use crate::codec::encoder::Encoder;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::{cmp, fmt, io, str, usize};
const DEFAULT_SEEK_DELIMITERS: &[u8] = b",;\n\r";
const DEFAULT_SEQUENCE_WRITER: &[u8] = b",";
/// A simple [`Decoder`] and [`Encoder`] implementation that splits up data into chunks based on any character in the given delimiter string.
///
/// [`Decoder`]: crate::codec::Decoder
/// [`Encoder`]: crate::codec::Encoder
///
/// # Example
/// Decode string of bytes containing various different delimiters.
///
/// [`BytesMut`]: bytes::BytesMut
/// [`Error`]: std::io::Error
///
/// ```
/// use tokio_util::codec::{AnyDelimiterCodec, Decoder};
/// use bytes::{BufMut, BytesMut};
///
/// #
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), std::io::Error> {
/// let mut codec = AnyDelimiterCodec::new(b",;\r\n".to_vec(),b";".to_vec());
/// let buf = &mut BytesMut::new();
/// buf.reserve(200);
/// buf.put_slice(b"chunk 1,chunk 2;chunk 3\n\r");
/// assert_eq!("chunk 1", codec.decode(buf).unwrap().unwrap());
/// assert_eq!("chunk 2", codec.decode(buf).unwrap().unwrap());
/// assert_eq!("chunk 3", codec.decode(buf).unwrap().unwrap());
/// assert_eq!("", codec.decode(buf).unwrap().unwrap());
/// assert_eq!(None, codec.decode(buf).unwrap());
/// # Ok(())
/// # }
/// ```
///
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AnyDelimiterCodec {
// Stored index of the next index to examine for the delimiter character.
// This is used to optimize searching.
// For example, if `decode` was called with `abc` and the delimiter is '{}', it would hold `3`,
// because that is the next index to examine.
// The next time `decode` is called with `abcde}`, the method will
// only look at `de}` before returning.
next_index: usize,
/// The maximum length for a given chunk. If `usize::MAX`, chunks will be
/// read until a delimiter character is reached.
max_length: usize,
/// Are we currently discarding the remainder of a chunk which was over
/// the length limit?
is_discarding: bool,
/// The bytes that are using for search during decode
seek_delimiters: Vec<u8>,
/// The bytes that are using for encoding
sequence_writer: Vec<u8>,
}
impl AnyDelimiterCodec {
/// Returns a `AnyDelimiterCodec` for splitting up data into chunks.
///
/// # Note
///
/// The returned `AnyDelimiterCodec` will not have an upper bound on the length
/// of a buffered chunk. See the documentation for [`new_with_max_length`]
/// for information on why this could be a potential security risk.
///
/// [`new_with_max_length`]: crate::codec::AnyDelimiterCodec::new_with_max_length()
pub fn new(seek_delimiters: Vec<u8>, sequence_writer: Vec<u8>) -> AnyDelimiterCodec {
AnyDelimiterCodec {
next_index: 0,
max_length: usize::MAX,
is_discarding: false,
seek_delimiters,
sequence_writer,
}
}
/// Returns a `AnyDelimiterCodec` with a maximum chunk length limit.
///
/// If this is set, calls to `AnyDelimiterCodec::decode` will return a
/// [`AnyDelimiterCodecError`] when a chunk exceeds the length limit. Subsequent calls
/// will discard up to `limit` bytes from that chunk until a delimiter
/// character is reached, returning `None` until the delimiter over the limit
/// has been fully discarded. After that point, calls to `decode` will
/// function as normal.
///
/// # Note
///
/// Setting a length limit is highly recommended for any `AnyDelimiterCodec` which
/// will be exposed to untrusted input. Otherwise, the size of the buffer
/// that holds the chunk currently being read is unbounded. An attacker could
/// exploit this unbounded buffer by sending an unbounded amount of input
/// without any delimiter characters, causing unbounded memory consumption.
///
/// [`AnyDelimiterCodecError`]: crate::codec::AnyDelimiterCodecError
pub fn new_with_max_length(
seek_delimiters: Vec<u8>,
sequence_writer: Vec<u8>,
max_length: usize,
) -> Self {
AnyDelimiterCodec {
max_length,
..AnyDelimiterCodec::new(seek_delimiters, sequence_writer)
}
}
/// Returns the maximum chunk length when decoding.
///
/// ```
/// use std::usize;
/// use tokio_util::codec::AnyDelimiterCodec;
///
/// let codec = AnyDelimiterCodec::new(b",;\n".to_vec(), b";".to_vec());
/// assert_eq!(codec.max_length(), usize::MAX);
/// ```
/// ```
/// use tokio_util::codec::AnyDelimiterCodec;
///
/// let codec = AnyDelimiterCodec::new_with_max_length(b",;\n".to_vec(), b";".to_vec(), 256);
/// assert_eq!(codec.max_length(), 256);
/// ```
pub fn max_length(&self) -> usize {
self.max_length
}
}
impl Decoder for AnyDelimiterCodec {
type Item = Bytes;
type Error = AnyDelimiterCodecError;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Bytes>, AnyDelimiterCodecError> {
loop {
// Determine how far into the buffer we'll search for a delimiter. If
// there's no max_length set, we'll read to the end of the buffer.
let read_to = cmp::min(self.max_length.saturating_add(1), buf.len());
let new_chunk_offset = buf[self.next_index..read_to].iter().position(|b| {
self.seek_delimiters
.iter()
.any(|delimiter| *b == *delimiter)
});
match (self.is_discarding, new_chunk_offset) {
(true, Some(offset)) => {
// If we found a new chunk, discard up to that offset and
// then stop discarding. On the next iteration, we'll try
// to read a chunk normally.
buf.advance(offset + self.next_index + 1);
self.is_discarding = false;
self.next_index = 0;
}
(true, None) => {
// Otherwise, we didn't find a new chunk, so we'll discard
// everything we read. On the next iteration, we'll continue
// discarding up to max_len bytes unless we find a new chunk.
buf.advance(read_to);
self.next_index = 0;
if buf.is_empty() {
return Ok(None);
}
}
(false, Some(offset)) => {
// Found a chunk!
let new_chunk_index = offset + self.next_index;
self.next_index = 0;
let mut chunk = buf.split_to(new_chunk_index + 1);
chunk.truncate(chunk.len() - 1);
let chunk = chunk.freeze();
return Ok(Some(chunk));
}
(false, None) if buf.len() > self.max_length => {
// Reached the maximum length without finding a
// new chunk, return an error and start discarding on the
// next call.
self.is_discarding = true;
return Err(AnyDelimiterCodecError::MaxChunkLengthExceeded);
}
(false, None) => {
// We didn't find a chunk or reach the length limit, so the next
// call will resume searching at the current offset.
self.next_index = read_to;
return Ok(None);
}
}
}
}
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Bytes>, AnyDelimiterCodecError> {
Ok(match self.decode(buf)? {
Some(frame) => Some(frame),
None => {
// return remaining data, if any
if buf.is_empty() {
None
} else {
let chunk = buf.split_to(buf.len());
self.next_index = 0;
Some(chunk.freeze())
}
}
})
}
}
impl<T> Encoder<T> for AnyDelimiterCodec
where
T: AsRef<str>,
{
type Error = AnyDelimiterCodecError;
fn encode(&mut self, chunk: T, buf: &mut BytesMut) -> Result<(), AnyDelimiterCodecError> {
let chunk = chunk.as_ref();
buf.reserve(chunk.len() + 1);
buf.put(chunk.as_bytes());
buf.put(self.sequence_writer.as_ref());
Ok(())
}
}
impl Default for AnyDelimiterCodec {
fn default() -> Self {
Self::new(
DEFAULT_SEEK_DELIMITERS.to_vec(),
DEFAULT_SEQUENCE_WRITER.to_vec(),
)
}
}
/// An error occurred while encoding or decoding a chunk.
#[derive(Debug)]
pub enum AnyDelimiterCodecError {
/// The maximum chunk length was exceeded.
MaxChunkLengthExceeded,
/// An IO error occurred.
Io(io::Error),
}
impl fmt::Display for AnyDelimiterCodecError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AnyDelimiterCodecError::MaxChunkLengthExceeded => {
write!(f, "max chunk length exceeded")
}
AnyDelimiterCodecError::Io(e) => write!(f, "{}", e),
}
}
}
impl From<io::Error> for AnyDelimiterCodecError {
fn from(e: io::Error) -> AnyDelimiterCodecError {
AnyDelimiterCodecError::Io(e)
}
}
impl std::error::Error for AnyDelimiterCodecError {}
+10
View File
@@ -74,3 +74,13 @@ impl Encoder<Bytes> for BytesCodec {
Ok(())
}
}
impl Encoder<BytesMut> for BytesCodec {
type Error = io::Error;
fn encode(&mut self, data: BytesMut, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(data.len());
buf.put(data);
Ok(())
}
}
+21 -2
View File
@@ -16,6 +16,20 @@ use std::io;
/// implementing stateful streaming parsers. In many cases, though, this type
/// will simply be a unit struct (e.g. `struct HttpDecoder`).
///
/// For some underlying data-sources, namely files and FIFOs,
/// it's possible to temporarily read 0 bytes by reaching EOF.
///
/// In these cases `decode_eof` will be called until it signals
/// fullfillment of all closing frames by returning `Ok(None)`.
/// After that, repeated attempts to read from the [`Framed`] or [`FramedRead`]
/// will not invoke `decode` or `decode_eof` again, until data can be read
/// during a retry.
///
/// It is up to the Decoder to keep track of a restart after an EOF,
/// and to decide how to handle such an event by, for example,
/// allowing frames to cross EOF boundaries, re-emitting opening frames, or
/// resetting the entire internal state.
///
/// [`Framed`]: crate::codec::Framed
/// [`FramedRead`]: crate::codec::FramedRead
pub trait Decoder {
@@ -115,13 +129,18 @@ pub trait Decoder {
/// This method defaults to calling `decode` and returns an error if
/// `Ok(None)` is returned while there is unconsumed data in `buf`.
/// Typically this doesn't need to be implemented unless the framing
/// protocol differs near the end of the stream.
/// protocol differs near the end of the stream, or if you need to construct
/// frames _across_ eof boundaries on sources that can be resumed.
///
/// Note that the `buf` argument may be empty. If a previous call to
/// `decode_eof` consumed all the bytes in the buffer, `decode_eof` will be
/// called again until it returns `None`, indicating that there are no more
/// frames to yield. This behavior enables returning finalization frames
/// that may not be based on inbound data.
///
/// Once `None` has been returned, `decode_eof` won't be called again until
/// an attempt to resume the stream has been made, where the underlying stream
/// actually returned more data.
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match self.decode(buf)? {
Some(frame) => Ok(Some(frame)),
@@ -153,7 +172,7 @@ pub trait Decoder {
/// calling `split` on the [`Framed`] returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
///
/// [`Stream`]: tokio_stream::Stream
/// [`Stream`]: futures_core::Stream
/// [`Sink`]: futures_sink::Sink
/// [`Framed`]: crate::codec::Framed
fn framed<T: AsyncRead + AsyncWrite + Sized>(self, io: T) -> Framed<T, Self>
+40 -5
View File
@@ -2,8 +2,8 @@ use crate::codec::decoder::Decoder;
use crate::codec::encoder::Encoder;
use crate::codec::framed_impl::{FramedImpl, RWFrames, ReadFrame, WriteFrame};
use futures_core::Stream;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_stream::Stream;
use bytes::BytesMut;
use futures_sink::Sink;
@@ -20,7 +20,7 @@ pin_project! {
/// You can create a `Framed` instance by using the [`Decoder::framed`] adapter, or
/// by using the `new` function seen below.
///
/// [`Stream`]: tokio_stream::Stream
/// [`Stream`]: futures_core::Stream
/// [`Sink`]: futures_sink::Sink
/// [`AsyncRead`]: tokio::io::AsyncRead
/// [`Decoder::framed`]: crate::codec::Decoder::framed()
@@ -52,7 +52,12 @@ where
/// calling [`split`] on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
///
/// [`Stream`]: tokio_stream::Stream
/// Note that, for some byte sources, the stream can be resumed after an EOF
/// by reading from it, even after it has returned `None`. Repeated attempts
/// to do so, without new data available, continue to return `None` without
/// creating more (closing) frames.
///
/// [`Stream`]: futures_core::Stream
/// [`Sink`]: futures_sink::Sink
/// [`Decode`]: crate::codec::Decoder
/// [`Encoder`]: crate::codec::Encoder
@@ -86,7 +91,7 @@ where
/// calling [`split`] on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
///
/// [`Stream`]: tokio_stream::Stream
/// [`Stream`]: futures_core::Stream
/// [`Sink`]: futures_sink::Sink
/// [`Decode`]: crate::codec::Decoder
/// [`Encoder`]: crate::codec::Encoder
@@ -101,6 +106,7 @@ where
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(capacity),
has_errored: false,
},
write: WriteFrame::default(),
},
@@ -131,7 +137,7 @@ impl<T, U> Framed<T, U> {
/// calling [`split`] on the `Framed` returned by this method, which will
/// break them into separate objects, allowing them to interact more easily.
///
/// [`Stream`]: tokio_stream::Stream
/// [`Stream`]: futures_core::Stream
/// [`Sink`]: futures_sink::Sink
/// [`Decoder`]: crate::codec::Decoder
/// [`Encoder`]: crate::codec::Encoder
@@ -198,6 +204,35 @@ impl<T, U> Framed<T, U> {
&mut self.inner.codec
}
/// Maps the codec `U` to `C`, preserving the read and write buffers
/// wrapped by `Framed`.
///
/// Note that care should be taken to not tamper with the underlying codec
/// as it may corrupt the stream of frames otherwise being worked with.
pub fn map_codec<C, F>(self, map: F) -> Framed<T, C>
where
F: FnOnce(U) -> C,
{
// This could be potentially simplified once rust-lang/rust#86555 hits stable
let parts = self.into_parts();
Framed::from_parts(FramedParts {
io: parts.io,
codec: map(parts.codec),
read_buf: parts.read_buf,
write_buf: parts.write_buf,
_priv: (),
})
}
/// Returns a mutable reference to the underlying codec wrapped by
/// `Framed`.
///
/// Note that care should be taken to not tamper with the underlying codec
/// as it may corrupt the stream of frames otherwise being worked with.
pub fn codec_pin_mut(self: Pin<&mut Self>) -> &mut U {
self.project().inner.project().codec
}
/// Returns a reference to the read buffer.
pub fn read_buffer(&self) -> &BytesMut {
&self.inner.state.read.buffer
+102 -17
View File
@@ -1,18 +1,18 @@
use crate::codec::decoder::Decoder;
use crate::codec::encoder::Encoder;
use futures_core::Stream;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_stream::Stream;
use bytes::BytesMut;
use futures_core::ready;
use futures_sink::Sink;
use log::trace;
use pin_project_lite::pin_project;
use std::borrow::{Borrow, BorrowMut};
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tracing::trace;
pin_project! {
#[derive(Debug)]
@@ -27,10 +27,12 @@ pin_project! {
const INITIAL_CAPACITY: usize = 8 * 1024;
const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY;
#[derive(Debug)]
pub(crate) struct ReadFrame {
pub(crate) eof: bool,
pub(crate) is_readable: bool,
pub(crate) buffer: BytesMut,
pub(crate) has_errored: bool,
}
pub(crate) struct WriteFrame {
@@ -49,6 +51,7 @@ impl Default for ReadFrame {
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
has_errored: false,
}
}
}
@@ -72,6 +75,7 @@ impl From<BytesMut> for ReadFrame {
buffer,
is_readable: size > 0,
eof: false,
has_errored: false,
}
}
}
@@ -120,42 +124,123 @@ where
let mut pinned = self.project();
let state: &mut ReadFrame = pinned.state.borrow_mut();
// The following loops implements a state machine with each state corresponding
// to a combination of the `is_readable` and `eof` flags. States persist across
// loop entries and most state transitions occur with a return.
//
// The initial state is `reading`.
//
// | state | eof | is_readable | has_errored |
// |---------|-------|-------------|-------------|
// | reading | false | false | false |
// | framing | false | true | false |
// | pausing | true | true | false |
// | paused | true | false | false |
// | errored | <any> | <any> | true |
// `decode_eof` returns Err
// ┌────────────────────────────────────────────────────────┐
// `decode_eof` returns │ │
// `Ok(Some)` │ │
// ┌─────┐ │ `decode_eof` returns After returning │
// Read 0 bytes ├─────▼──┴┐ `Ok(None)` ┌────────┐ ◄───┐ `None` ┌───▼─────┐
// ┌────────────────►│ Pausing ├───────────────────────►│ Paused ├─┐ └───────────┤ Errored │
// │ └─────────┘ └─┬──▲───┘ │ └───▲───▲─┘
// Pending read │ │ │ │ │ │
// ┌──────┐ │ `decode` returns `Some` │ └─────┘ │ │
// │ │ │ ┌──────┐ │ Pending │ │
// │ ┌────▼──┴─┐ Read n>0 bytes ┌┴──────▼─┐ read n>0 bytes │ read │ │
// └─┤ Reading ├───────────────►│ Framing │◄────────────────────────┘ │ │
// └──┬─▲────┘ └─────┬──┬┘ │ │
// │ │ │ │ `decode` returns Err │ │
// │ └───decode` returns `None`──┘ └───────────────────────────────────────────────────────┘ │
// │ read returns Err │
// └────────────────────────────────────────────────────────────────────────────────────────────┘
loop {
// Repeatedly call `decode` or `decode_eof` as long as it is
// "readable". Readable is defined as not having returned `None`. If
// the upstream has returned EOF, and the decoder is no longer
// readable, it can be assumed that the decoder will never become
// readable again, at which point the stream is terminated.
// Return `None` if we have encountered an error from the underlying decoder
// See: https://github.com/tokio-rs/tokio/issues/3976
if state.has_errored {
// preparing has_errored -> paused
trace!("Returning None and setting paused");
state.is_readable = false;
state.has_errored = false;
return Poll::Ready(None);
}
// Repeatedly call `decode` or `decode_eof` while the buffer is "readable",
// i.e. it _might_ contain data consumable as a frame or closing frame.
// Both signal that there is no such data by returning `None`.
//
// If `decode` couldn't read a frame and the upstream source has returned eof,
// `decode_eof` will attempt to decode the remaining bytes as closing frames.
//
// If the underlying AsyncRead is resumable, we may continue after an EOF,
// but must finish emitting all of it's associated `decode_eof` frames.
// Furthermore, we don't want to emit any `decode_eof` frames on retried
// reads after an EOF unless we've actually read more data.
if state.is_readable {
// pausing or framing
if state.eof {
let frame = pinned.codec.decode_eof(&mut state.buffer)?;
// pausing
let frame = pinned.codec.decode_eof(&mut state.buffer).map_err(|err| {
trace!("Got an error, going to errored state");
state.has_errored = true;
err
})?;
if frame.is_none() {
state.is_readable = false; // prepare pausing -> paused
}
// implicit pausing -> pausing or pausing -> paused
return Poll::Ready(frame.map(Ok));
}
// framing
trace!("attempting to decode a frame");
if let Some(frame) = pinned.codec.decode(&mut state.buffer)? {
if let Some(frame) = pinned.codec.decode(&mut state.buffer).map_err(|op| {
trace!("Got an error, going to errored state");
state.has_errored = true;
op
})? {
trace!("frame decoded from buffer");
// implicit framing -> framing
return Poll::Ready(Some(Ok(frame)));
}
// framing -> reading
state.is_readable = false;
}
assert!(!state.eof);
// Otherwise, try to read more data and try again. Make sure we've
// got room for at least one byte to read to ensure that we don't
// get a spurious 0 that looks like EOF
// reading or paused
// If we can't build a frame yet, try to read more data and try again.
// Make sure we've got room for at least one byte to read to ensure
// that we don't get a spurious 0 that looks like EOF.
state.buffer.reserve(1);
let bytect = match poll_read_buf(pinned.inner.as_mut(), cx, &mut state.buffer)? {
let bytect = match poll_read_buf(pinned.inner.as_mut(), cx, &mut state.buffer).map_err(
|err| {
trace!("Got an error, going to errored state");
state.has_errored = true;
err
},
)? {
Poll::Ready(ct) => ct,
// implicit reading -> reading or implicit paused -> paused
Poll::Pending => return Poll::Pending,
};
if bytect == 0 {
if state.eof {
// We're already at an EOF, and since we've reached this path
// we're also not readable. This implies that we've already finished
// our `decode_eof` handling, so we can simply return `None`.
// implicit paused -> paused
return Poll::Ready(None);
}
// prepare reading -> paused
state.eof = true;
} else {
// prepare paused -> framing or noop reading -> framing
state.eof = false;
}
// paused -> framing or reading -> framing or reading -> pausing
state.is_readable = true;
}
}
@@ -193,7 +278,7 @@ where
while !pinned.state.borrow_mut().buffer.is_empty() {
let WriteFrame { buffer } = pinned.state.borrow_mut();
trace!("writing; remaining={}", buffer.len());
trace!(remaining = buffer.len(), "writing;");
let n = ready!(poll_write_buf(pinned.inner.as_mut(), cx, buffer))?;
+29 -2
View File
@@ -1,8 +1,8 @@
use crate::codec::framed_impl::{FramedImpl, ReadFrame};
use crate::codec::Decoder;
use futures_core::Stream;
use tokio::io::AsyncRead;
use tokio_stream::Stream;
use bytes::BytesMut;
use futures_sink::Sink;
@@ -14,7 +14,7 @@ use std::task::{Context, Poll};
pin_project! {
/// A [`Stream`] of messages decoded from an [`AsyncRead`].
///
/// [`Stream`]: tokio_stream::Stream
/// [`Stream`]: futures_core::Stream
/// [`AsyncRead`]: tokio::io::AsyncRead
pub struct FramedRead<T, D> {
#[pin]
@@ -51,6 +51,7 @@ where
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(capacity),
has_errored: false,
},
},
}
@@ -107,6 +108,32 @@ impl<T, D> FramedRead<T, D> {
&mut self.inner.codec
}
/// Maps the decoder `D` to `C`, preserving the read buffer
/// wrapped by `Framed`.
pub fn map_decoder<C, F>(self, map: F) -> FramedRead<T, C>
where
F: FnOnce(D) -> C,
{
// This could be potentially simplified once rust-lang/rust#86555 hits stable
let FramedImpl {
inner,
state,
codec,
} = self.inner;
FramedRead {
inner: FramedImpl {
inner,
state,
codec: map(codec),
},
}
}
/// Returns a mutable reference to the underlying decoder.
pub fn decoder_pin_mut(self: Pin<&mut Self>) -> &mut D {
self.project().inner.project().codec
}
/// Returns a reference to the read buffer.
pub fn read_buffer(&self) -> &BytesMut {
&self.inner.state.buffer
+27 -1
View File
@@ -1,8 +1,8 @@
use crate::codec::encoder::Encoder;
use crate::codec::framed_impl::{FramedImpl, WriteFrame};
use futures_core::Stream;
use tokio::io::AsyncWrite;
use tokio_stream::Stream;
use bytes::BytesMut;
use futures_sink::Sink;
@@ -88,6 +88,32 @@ impl<T, E> FramedWrite<T, E> {
&mut self.inner.codec
}
/// Maps the encoder `E` to `C`, preserving the write buffer
/// wrapped by `Framed`.
pub fn map_encoder<C, F>(self, map: F) -> FramedWrite<T, C>
where
F: FnOnce(E) -> C,
{
// This could be potentially simplified once rust-lang/rust#86555 hits stable
let FramedImpl {
inner,
state,
codec,
} = self.inner;
FramedWrite {
inner: FramedImpl {
inner,
state,
codec: map(codec),
},
}
}
/// Returns a mutable reference to the underlying encoder.
pub fn encoder_pin_mut(self: Pin<&mut Self>) -> &mut E {
self.project().inner.project().codec
}
/// Returns a reference to the write buffer.
pub fn write_buffer(&self) -> &BytesMut {
&self.inner.state.buffer
+74 -20
View File
@@ -84,7 +84,7 @@
//! # fn bind_read<T: AsyncRead>(io: T) {
//! LengthDelimitedCodec::builder()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .length_adjustment(0) // default value
//! .num_skip(0) // Do not strip frame header
//! .new_read(io);
@@ -118,7 +118,7 @@
//! # fn bind_read<T: AsyncRead>(io: T) {
//! LengthDelimitedCodec::builder()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .length_adjustment(0) // default value
//! // `num_skip` is not needed, the default is to skip
//! .new_read(io);
@@ -150,7 +150,7 @@
//! # fn bind_read<T: AsyncRead>(io: T) {
//! LengthDelimitedCodec::builder()
//! .length_field_offset(0) // default value
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .length_adjustment(-2) // size of head
//! .num_skip(0)
//! .new_read(io);
@@ -228,7 +228,7 @@
//! # fn bind_read<T: AsyncRead>(io: T) {
//! LengthDelimitedCodec::builder()
//! .length_field_offset(1) // length of hdr1
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .length_adjustment(1) // length of hdr2
//! .num_skip(3) // length of hdr1 + LEN
//! .new_read(io);
@@ -274,7 +274,7 @@
//! # fn bind_read<T: AsyncRead>(io: T) {
//! LengthDelimitedCodec::builder()
//! .length_field_offset(1) // length of hdr1
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .length_adjustment(-3) // length of hdr1 + LEN, negative
//! .num_skip(3)
//! .new_read(io);
@@ -350,7 +350,7 @@
//! # fn write_frame<T: AsyncWrite>(io: T) {
//! # let _ =
//! LengthDelimitedCodec::builder()
//! .length_field_length(2)
//! .length_field_type::<u16>()
//! .new_write(io);
//! # }
//! # pub fn main() {}
@@ -379,7 +379,7 @@ use tokio::io::{AsyncRead, AsyncWrite};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::error::Error as StdError;
use std::io::{self, Cursor};
use std::{cmp, fmt};
use std::{cmp, fmt, mem};
/// Configure length delimited `LengthDelimitedCodec`s.
///
@@ -421,7 +421,7 @@ pub struct LengthDelimitedCodecError {
/// See [module level] documentation for more detail.
///
/// [module level]: index.html
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct LengthDelimitedCodec {
// Configuration values
builder: Builder,
@@ -486,7 +486,7 @@ impl LengthDelimitedCodec {
// Skip the required bytes
src.advance(self.builder.length_field_offset);
// match endianess
// match endianness
let n = if self.builder.length_field_is_big_endian {
src.get_uint(field_len)
} else {
@@ -535,14 +535,14 @@ impl LengthDelimitedCodec {
Ok(Some(n))
}
fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
fn decode_data(&self, n: usize, src: &mut BytesMut) -> Option<BytesMut> {
// At this point, the buffer has already had the required capacity
// reserved. All there is to do is read.
if src.len() < n {
return Ok(None);
return None;
}
Ok(Some(src.split_to(n)))
Some(src.split_to(n))
}
}
@@ -562,7 +562,7 @@ impl Decoder for LengthDelimitedCodec {
DecodeState::Data(n) => n,
};
match self.decode_data(n, src)? {
match self.decode_data(n, src) {
Some(data) => {
// Update the decode state
self.state = DecodeState::Head;
@@ -629,6 +629,24 @@ impl Default for LengthDelimitedCodec {
// ===== impl Builder =====
mod builder {
/// Types that can be used with `Builder::length_field_type`.
pub trait LengthFieldType {}
impl LengthFieldType for u8 {}
impl LengthFieldType for u16 {}
impl LengthFieldType for u32 {}
impl LengthFieldType for u64 {}
#[cfg(any(
target_pointer_width = "8",
target_pointer_width = "16",
target_pointer_width = "32",
target_pointer_width = "64",
))]
impl LengthFieldType for usize {}
}
impl Builder {
/// Creates a new length delimited codec builder with default configuration
/// values.
@@ -642,7 +660,7 @@ impl Builder {
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_length(2)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
@@ -746,7 +764,7 @@ impl Builder {
}
}
/// Sets the max frame length
/// Sets the max frame length in bytes
///
/// This configuration option applies to both encoding and decoding. The
/// default value is 8MB.
@@ -767,7 +785,7 @@ impl Builder {
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// .max_frame_length(8 * 1024)
/// .max_frame_length(8 * 1024 * 1024)
/// .new_read(io);
/// # }
/// # pub fn main() {}
@@ -777,6 +795,42 @@ impl Builder {
self
}
/// Sets the unsigned integer type used to represent the length field.
///
/// The default type is [`u32`]. The max type is [`u64`] (or [`usize`] on
/// 64-bit targets).
///
/// # Examples
///
/// ```
/// # use tokio::io::AsyncRead;
/// use tokio_util::codec::LengthDelimitedCodec;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// .length_field_type::<u32>()
/// .new_read(io);
/// # }
/// # pub fn main() {}
/// ```
///
/// Unlike [`Builder::length_field_length`], this does not fail at runtime
/// and instead produces a compile error:
///
/// ```compile_fail
/// # use tokio::io::AsyncRead;
/// # use tokio_util::codec::LengthDelimitedCodec;
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// .length_field_type::<u128>()
/// .new_read(io);
/// # }
/// # pub fn main() {}
/// ```
pub fn length_field_type<T: builder::LengthFieldType>(&mut self) -> &mut Self {
self.length_field_length(mem::size_of::<T>())
}
/// Sets the number of bytes used to represent the length field
///
/// The default value is `4`. The max value is `8`.
@@ -878,7 +932,7 @@ impl Builder {
/// # pub fn main() {
/// LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_length(2)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_codec();
@@ -902,7 +956,7 @@ impl Builder {
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_length(2)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
@@ -925,7 +979,7 @@ impl Builder {
/// # use tokio_util::codec::LengthDelimitedCodec;
/// # fn write_frame<T: AsyncWrite>(io: T) {
/// LengthDelimitedCodec::builder()
/// .length_field_length(2)
/// .length_field_type::<u16>()
/// .new_write(io);
/// # }
/// # pub fn main() {}
@@ -947,7 +1001,7 @@ impl Builder {
/// # fn write_frame<T: AsyncRead + AsyncWrite>(io: T) {
/// # let _ =
/// LengthDelimitedCodec::builder()
/// .length_field_length(2)
/// .length_field_type::<u16>()
/// .new_framed(io);
/// # }
/// # pub fn main() {}
+3 -3
View File
@@ -133,7 +133,7 @@ impl Decoder for LinesCodec {
buf.advance(read_to);
self.next_index = 0;
if buf.is_empty() {
return Err(LinesCodecError::MaxLineLengthExceeded);
return Ok(None);
}
}
(false, Some(offset)) => {
@@ -203,12 +203,12 @@ impl Default for LinesCodec {
}
}
/// An error occured while encoding or decoding a line.
/// An error occurred while encoding or decoding a line.
#[derive(Debug)]
pub enum LinesCodecError {
/// The maximum line length was exceeded.
MaxLineLengthExceeded,
/// An IO error occured.
/// An IO error occurred.
Io(io::Error),
}
+4 -1
View File
@@ -246,7 +246,7 @@
//!
//! [`AsyncRead`]: tokio::io::AsyncRead
//! [`AsyncWrite`]: tokio::io::AsyncWrite
//! [`Stream`]: tokio_stream::Stream
//! [`Stream`]: futures_core::Stream
//! [`Sink`]: futures_sink::Sink
//! [`SinkExt::close`]: https://docs.rs/futures/0.3/futures/sink/trait.SinkExt.html#method.close
//! [`FramedRead`]: struct@crate::codec::FramedRead
@@ -285,3 +285,6 @@ pub use self::length_delimited::{LengthDelimitedCodec, LengthDelimitedCodecError
mod lines_codec;
pub use self::lines_codec::{LinesCodec, LinesCodecError};
mod any_delimiter_codec;
pub use self::any_delimiter_codec::{AnyDelimiterCodec, AnyDelimiterCodecError};
+58 -1
View File
@@ -13,6 +13,7 @@ pin_project! {
pub struct Compat<T> {
#[pin]
inner: T,
seek_pos: Option<io::SeekFrom>,
}
}
@@ -80,7 +81,10 @@ impl<T: tokio::io::AsyncWrite> TokioAsyncWriteCompatExt for T {}
impl<T> Compat<T> {
fn new(inner: T) -> Self {
Self { inner }
Self {
inner,
seek_pos: None,
}
}
/// Get a reference to the `Future`, `Stream`, `AsyncRead`, or `AsyncWrite` object
@@ -215,3 +219,56 @@ where
tokio::io::AsyncWrite::poll_shutdown(self.project().inner, cx)
}
}
impl<T: tokio::io::AsyncSeek> futures_io::AsyncSeek for Compat<T> {
fn poll_seek(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: io::SeekFrom,
) -> Poll<io::Result<u64>> {
if self.seek_pos != Some(pos) {
self.as_mut().project().inner.start_seek(pos)?;
*self.as_mut().project().seek_pos = Some(pos);
}
let res = ready!(self.as_mut().project().inner.poll_complete(cx));
*self.as_mut().project().seek_pos = None;
Poll::Ready(res.map(|p| p as u64))
}
}
impl<T: futures_io::AsyncSeek> tokio::io::AsyncSeek for Compat<T> {
fn start_seek(mut self: Pin<&mut Self>, pos: io::SeekFrom) -> io::Result<()> {
*self.as_mut().project().seek_pos = Some(pos);
Ok(())
}
fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
let pos = match self.seek_pos {
None => {
// tokio 1.x AsyncSeek recommends calling poll_complete before start_seek.
// We don't have to guarantee that the value returned by
// poll_complete called without start_seek is correct,
// so we'll return 0.
return Poll::Ready(Ok(0));
}
Some(pos) => pos,
};
let res = ready!(self.as_mut().project().inner.poll_seek(cx, pos));
*self.as_mut().project().seek_pos = None;
Poll::Ready(res.map(|p| p as u64))
}
}
#[cfg(unix)]
impl<T: std::os::unix::io::AsRawFd> std::os::unix::io::AsRawFd for Compat<T> {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.inner.as_raw_fd()
}
}
#[cfg(windows)]
impl<T: std::os::windows::io::AsRawHandle> std::os::windows::io::AsRawHandle for Compat<T> {
fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
self.inner.as_raw_handle()
}
}

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