Compare commits

...
Author SHA1 Message Date
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
Alice Ryhl 35b1a4d0b3 chore: prepare Tokio 1.1.0 (#3462) 2021-01-22 23:05:37 +01:00
Alice Ryhl 6da5087b06 sync: improve bounded mpsc documentation (#3458) 2021-01-22 19:28:37 +01:00
Alice Ryhl c6f08120d0 task: add LocalSet example (#3438) 2021-01-21 16:36:26 +01:00
Alice Ryhl 29bd5fad5c sync: add link to PollSemaphore (#3456) 2021-01-21 15:20:55 +01:00
Alice Ryhl f2a048d990 time: document that Sleep is not Unpin (#3457) 2021-01-21 15:19:17 +01:00
Alice Ryhl 198363f4f1 chore: prepare tokio-util 0.6.2 (#3453) 2021-01-21 11:46:50 +01:00
vitalyd 5b7c7d565a io: use a sealed trait to constrain VecWithInitialized (#3450) 2021-01-21 11:32:42 +01:00
Blas Rodriguez Irizar 117fc2ef3e tests: fix ping pong saturation (#3390) 2021-01-21 11:02:40 +01:00
William Bain c4f66ed121 util: fix panics on updating DelayQueue entries (#3270) 2021-01-21 10:56:44 +01:00
Oğuz Bilgener 7d5b12c509 sync: fix panic in broadcast::Receiver drop (#3434) 2021-01-20 23:12:51 +01:00
Alice Ryhl cc0911aa64 net: update datagram docs on splitting (#3448) 2021-01-20 16:28:57 +01:00
Henry Gomersall 6f8a4d7a0b docs: trivial typo fix (#3449) 2021-01-20 16:28:35 +01:00
Arve Knudsen fdde5583f8 runtime: consolidate errors for context missing (#3441) 2021-01-20 14:29:13 +01:00
Rain 36cf95ab62 io: add ReadBuf::inner_mut (#3443) 2021-01-20 13:56:14 +01:00
Alice Ryhl 27b2d681e6 util: add pollable Semaphore (#3444) 2021-01-20 09:53:31 +01:00
Alice Ryhl c1cf6b7504 io: keep track of initialized bytes in read_to_end (#3426) 2021-01-20 09:49:24 +01:00
Henry Gomersall 5402c948ee io: clarify AsyncFd docs about changes of the inner fd (#3430) 2021-01-17 21:39:58 +01:00
Carl Lerche 2af9b755c5 Merge branch 'tokio-1.0.x' 2021-01-16 11:36:21 -08:00
Jacob O'Toole 7ac44a2d28 process: add documentation to process::Child fields (#3437) 2021-01-16 19:42:51 +01:00
Carl Lerche 3dc5f6c0ab chore: release tokio v1.0.2 (#3429) 2021-01-15 15:05:38 -08:00
Alice Ryhl 0a7117fd9a io: fix unsoundness in read_to_end (#3428) 2021-01-15 15:05:38 -08:00
Carl Lerche 5d35c907f6 chore: release tokio v1.0.2 (#3429) 2021-01-14 16:37:40 -08:00
Alice Ryhl ad8fb41103 io: fix unsoundness in read_to_end (#3428) 2021-01-14 15:09:07 -08:00
Nylonicious ecc32d1dca sync: add RwLock try_read and try_write methods (#3400)
Closes #2284
2021-01-14 15:05:07 -08:00
Markus Westerlind 204603b7de rt: reduce duplicated code in task harness (#3314)
Task spawning is a common operation that results in a lot of instantiations
of the task code. Reducing the amount of generated code should lead to
faster compile times overall.

This patch extracts code that does not depend on a type parameter into
functions with fewer or no type parameters at all. Reducing the amount of
duplicated code.
2021-01-14 10:07:56 -08:00
Taiki Endo 30b4a7486a chore: use CARGO_BIN_EXE instead of inspecting env::current_exe() (#3427) 2021-01-14 09:59:37 -08:00
Taiki Endo 0595902ba4 Update issue template (#3425)
`cargo tree` subcommand is available by default since Rust 1.44.
2021-01-14 23:09:05 +09:00
Lucio FrancoandAlice Ryhl 672be92a03 mpsc: Add Sender::try_reserve function (#3418)
* mpsc: Add `Sender::try_reserve` function

* Update tokio/src/sync/mpsc/bounded.rs

Co-authored-by: Alice Ryhl <[email protected]>

* Fix doc links

Co-authored-by: Alice Ryhl <[email protected]>
2021-01-13 14:24:23 -05:00
Alice Ryhl 766a89bf94 chore: prepare tokio-stream 0.1.2 (#3414) 2021-01-12 21:38:51 +01:00
David Kellum 8b9bb41809 docs: add tokio 1.0 policies to contributing guide (#3386) 2021-01-12 21:15:44 +01:00
Taiki Endo d37486dd06 util: remove path deps (#3413)
* util: remove path deps

* ci: run clippy with --all-features

* ci: run tests with --all-features on FreeBSD CI
2021-01-13 00:19:57 +09:00
Daiki Mizukami ed667c669a chore: prepare tokio-util v0.6.1 release (#3402) 2021-01-12 12:46:07 +01:00
Milan da09213c9f doc: typo fixes (#3401) 2021-01-11 21:39:50 -08:00
Taiki Endo 40d959263b macros: fix unused_braces in generated code (#3404) 2021-01-11 19:20:40 +09:00
Shantanu Sharma 0b8bdf9d32 runtime: fix typo (#3385) 2021-01-10 20:59:14 +09:00
cssivision 51a7082d13 docs: test-util feature is not enabled with full (#3397) 2021-01-09 14:01:10 +01:00
Cameron 22c27b9282 task: wake LocalSet on spawn_local (#3369) 2021-01-09 11:46:51 +01:00
David Raifaizen 2fe2f0401b util: expose FramedWrite/Framed::write_buffer/write_buffer_mut 2021-01-08 23:20:07 +01:00
Rust大闸蟹 e42317b072 chore: remove macro_rules semicolon (#3381)
fix build warning
2021-01-06 15:46:37 +09:00
Alice Ryhl 3549092a0c docs: fix tokio-stream features not being displayed (#3378) 2021-01-05 11:43:09 +01:00
Alice Ryhl 3b840fb305 stream: remove path deps (#3376) 2021-01-04 21:04:22 +01:00
Alice Ryhl 4beb1862ac chore: prepare tokio-stream 0.1.1 (#3374) 2021-01-04 19:46:01 +01:00
Alice Ryhl 7f17822ed9 stream: add Stream wrappers in tokio-stream (#3343) 2021-01-04 19:03:18 +01:00
cssivision 3b6bee822d net: add try_read_buf and try_recv_buf (#3351) 2021-01-02 10:37:34 +01:00
Rob Ede 56272b2ec7 stream: move async-stream to dev-deps (#3366) 2021-01-02 13:43:41 +09:00
John-John Tedro 53707f5d9d sync: remove underused internal Borrow wrapper (#3363) 2021-01-01 13:04:38 -08:00
Daiki Mizukami 36918e05e5 util: add more get_{ref,mut,pin_mut} methods (#3364)
This commit adds:

- Framed::get_pin_mut
- FramedRead::get_pin_mut
- FramedWrite::get_pin_mut
- StreamReader::get_ref
- StreamReader::get_mut
- StreamReader::get_pin_mut
- StreamReader::into_inner
2021-01-01 13:05:15 +01:00
Arniu Tseng cbd4f4472e docs: update CHANGELOG.md (#3336) 2020-12-27 16:36:36 +01:00
Danilo MartinsandDanilo 2d9bea8d63 runtime: fix typo (#3354)
Co-authored-by: Danilo <[email protected]>
2020-12-27 16:17:00 +01:00
zhongjnandAlice Ryhl 0048d43713 macros: improve select! error message (#3352)
Co-authored-by: Alice Ryhl <[email protected]>
2020-12-27 23:50:32 +09:00
Taiki Endo 770044caa7 chore: replace deprecated compare_and_swap with compare_exchange (#3331) 2020-12-27 10:44:21 +01:00
AJ Frantz c4929264bc examples: adjust buffering in examples (#3328) 2020-12-27 10:43:02 +01:00
Alice Ryhl 4d7b73f5b3 chore: create stream_ext module (#3342) 2020-12-26 17:05:51 +01:00
Alice Ryhl 2330edc875 chore: prepare tokio 1.0.1 release (#3347) 2020-12-25 22:20:05 +01:00
Alice Ryhl fe2664a4e1 sync: remove RwLockWriteGuard::map and RwLockWriteGuard::try_map (#3345) 2020-12-25 21:36:48 +01:00
Laurențiu Nicola 1eefbc250a docs: remove stream feature from docs (#3335) 2020-12-24 23:17:18 +09:00
Carl Lerche a66017f049 chore: prepare Tokio 1.0 release (#3319) 2020-12-23 09:26:14 -08:00
Paolo Barbolini aa6597ba66 compat: update traits naming to match tokio 1.0 (#3324) 2020-12-23 09:15:56 -08:00
Taiki Endo ce0e9c67cf chore: Revert "use #[non_exhaustive] instead of private unit field" (#3323)
This reverts commit 575938d457.
2020-12-23 08:27:58 -08:00
Taiki Endo 575938d457 chore: use #[non_exhaustive] instead of private unit field (#3320) 2020-12-23 22:48:33 +09:00
Carl Lerche 0deaeb8494 chore: remove unused slab dependency (#3318) 2020-12-22 21:56:22 -08:00
Luke Steensen a8dda19da4 chore: update to released bytes 1.0 (#3317) 2020-12-22 17:09:26 -08:00
Sean McArthur be9fdb697d time: make Interval::poll_tick() public (#3316) 2020-12-22 12:31:14 -08:00
Carl Lerche 2ee9520d10 fs: misc small API tweaks (#3315) 2020-12-22 11:13:41 -08:00
Carlos B 7d28e4cdbb examples: add futures executor threadpool (#3198) 2020-12-22 20:08:43 +01:00
Alice Ryhl 0b83b3b8cc fs,sync: expose poll_ fns on misc types (#3308)
Includes methods on:

* fs::DirEntry
* io::Lines
* io::Split
* sync::mpsc::Receiver
* sync::misc::UnboundedReceiver
2020-12-22 09:28:14 -08:00
Alice Ryhl f95ad18980 net: clarify when wakeups are sent (#3310) 2020-12-22 07:38:14 -08:00
Taiki Endo eee3ca65d6 deps: update rand to 0.8, loom to 0.4 (#3307) 2020-12-22 10:28:35 +01:00
Alice Ryhl 564c943309 io: rename AsyncFd::with_io() and rm with_poll() (#3306) 2020-12-21 15:42:38 -08:00
BhargavandAlice Ryhl c7671a0384 io: add _mut variants of methods on AsyncFd (#3304)
Co-authored-by: Alice Ryhl <[email protected]>
2020-12-21 22:51:28 +01:00
Carl Lerche 2893359988 chore: update to bytes 1.0 git branch (#3301)
Updates the code base to track the `bytes` git branch. This is in
preparation for the 1.0 release.

Closes #3058
2020-12-19 15:57:16 -08:00
Carl Lerche 5e5f513542 chore: remove some left over stream feature code (#3300)
Removes the `stream` feature flag from `Cargo.toml` and removes the
`futures-core` dependency. Once `Stream` lands in `std`, a feature flag
is most likely not needed.
2020-12-19 14:15:00 -08:00
Arve Knudsen 1b70507894 net: remove {Tcp,Unix}Stream::shutdown() (#3298)
`shutdown()` on `AsyncWrite` performs a TCP shutdown. This avoids method
conflicts.

Closes #3294
2020-12-19 12:17:52 -08:00
Alice Ryhl 78f2340d25 tokio: remove prelude (#3299)
Closes: #3257
2020-12-19 11:42:24 -08:00
Florian Hübsch e41e6cddbb docs: tokio::main macro is also supported on rt (#3243)
Fixes: #3144
Refs: #2225
2020-12-19 19:12:08 +01:00
Lucio Franco b99b00eb30 rt: change max_threads to max_blocking_threads (#3287)
Fixes #2802
2020-12-19 08:04:04 -08:00
Alice Ryhl d948ccedfc chore: fix stress test (#3297) 2020-12-19 12:11:10 +01:00
Alice RyhlandLucio Franco 3ecaf9fd9a codec: write documentation for codec (#3283)
Co-authored-by: Lucio Franco <[email protected]>
2020-12-18 21:32:27 +01:00
Carl Lerche abd4c00255 time: enforce current_thread rt for time::pause (#3289)
Pausing time is a capability added to assist with testing Tokio code
dependent on time. Currently, the capability implicitly requires the
current_thread runtime.

This change enforces the requirement by panicking if called from a
multi-threaded runtime.
2020-12-17 15:37:08 -08:00
Lucio FrancoandAlice Ryhl c5861ef62f docs: Add more comprehensive stream docs (#3286)
* docs: Add more comprehensive stream docs

* Apply suggestions from code review

Co-authored-by: Alice Ryhl <[email protected]>

* Fix doc tests

Co-authored-by: Alice Ryhl <[email protected]>
2020-12-17 11:46:09 -05:00
Lucio Franco 59e4b35f49 stream: Fix a few doc issues (#3285) 2020-12-17 10:35:49 -05:00
Carl Lerche d74d17307d time: remove Box from Sleep (#3278)
Removes the box from `Sleep`, taking advantage of intrusive wakers. The
`Sleep` future is now `!Unpin`.

Closes #3267
2020-12-16 21:51:34 -08:00
Lucio Franco 8efa62013b Move stream items into tokio-stream (#3277)
This change removes all references to `Stream` from
within the `tokio` crate and moves them into a new
`tokio-stream` crate. Most types have had their
`impl Stream` removed as well in-favor of their
inherent methods.

Closes #2870
2020-12-15 20:24:38 -08:00
Zahari Dichev fcce78b33a sync: add Semaphore::close (#3065)
## Motivation
The need to expose `Semaphore::close` as explained in #3061. 

## Solution
Expose `Semaphore::close`

Signed-off-by: Zahari Dichev <[email protected]>
2020-12-15 10:22:45 -08:00
Carl Lerche 79d25b0a48 tracing: switch to unstable for 1.0. (#3266)
Enabling `tracing` integration now requires compiling with `--cfg
tokio_unstable`. Once `tracing-core` guarantees the same level of
stability as Tokio 1.0, unstable can be removed.

Closes #3258
2020-12-14 17:22:31 -08:00
Carl Lerche 3f29212cb7 fs: use cfgs on fns instead of OS ext traits (#3264)
Instead of using OS specific extension traits, OS specific methods are
moved onto the structs themselves and guarded with `cfg`. The API
documentation should highlight the function is platform specific.

Closes #2925
2020-12-14 09:29:10 -08:00
Joshua Nelson 48961fac89 Document SinkExt and other futures traits on docs.rs (#3271)
These are extremely hard to find if you don't already know they exist.
2020-12-14 10:28:36 -05:00
Carl Lerche a7833e3007 sync: remove try_recv() from mpsc types (#3263)
The mpsc `try_recv()` functions have an issue where a sent message
happens-before a call to `try_recv()` but `try_recv()` returns `None`.
Fixing this is non-trivial, so the function is removed for 1.0. When the
bug is fixed, the function can be added back.

Closes #2020
2020-12-13 21:39:51 -08:00
Jacob O'Toole 1f862d2e95 sync: add watch::Sender::borrow() (#3269) 2020-12-13 20:46:11 -08:00
Sylvain Kerkour 9149d7bfae docs: mention blocking thread timeout in src/lib.rs (#3253) 2020-12-13 16:24:16 +01:00
cssivision 4c55419453 net: add UnixStream readiness and non-blocking ops (#3246) 2020-12-13 16:21:11 +01:00
Aldas f26f444f42 doc: added tracing to the feature flags section (#3254) 2020-12-13 15:26:56 +01:00
cssivision be2cb7a5ce net: check for false-positives in TcpStream::ready doc test (#3255) 2020-12-13 15:24:59 +01:00
Sunjay Varma df20c162ae sync: add blocking_recv method to UnboundedReceiver, similar to Receiver::blocking_recv (#3262) 2020-12-12 08:47:35 -08:00
Alice Ryhl c1ec469ad2 util: add constructors to TokioContext (#3221) 2020-12-11 20:41:22 -08:00
Lucio Franco b01b2dacf2 net: update TcpStream::poll_peek to use ReadBuf (#3259)
Closes #2987
2020-12-11 20:40:24 -08:00
Evan Cameron 68717c7efa net: remove empty udp module (#3260) 2020-12-11 14:45:57 -05:00
Alice Ryhl 69e62ef89e sync: make TryAcquireError public (#3250)
The [`Semaphore::try_acquire`][1] method currently returns a private error type.

[1]: https://docs.rs/tokio/0.3/tokio/sync/struct.Semaphore.html#method.try_acquire
2020-12-10 19:56:05 -08:00
Nylonicious 16c2e0983c net: Pass SocketAddr by value (#3125) 2020-12-10 14:58:27 -05:00
Yusuke Tanaka 4b1d76ec8f docs: fix typo in signal module documentation (#3249) 2020-12-10 08:11:45 -08:00
Clemens Koza 9646b4bce3 toml: enable test-util feature for the playground (#3224) 2020-12-10 10:39:05 +01:00
Alice Ryhland@tijsvd f60860af7e watch: fix spurious wakeup (#3234)
Co-authored-by: @tijsvd
2020-12-10 09:46:01 +01:00
cssivision 2a30e13f38 net: expose poll_* methods on UnixDatagram (#3223) 2020-12-10 08:36:43 +01:00
Nylonicious 52cd240053 task: add missing feature flags for task_local and spawn_blocking (#3237) 2020-12-09 23:49:28 +01:00
Carl Lerche 473ddaa277 chore: prepare for Tokio 1.0 work (#3238) 2020-12-09 09:42:05 -08:00
bdonlan 9706ca92a8 time: Fix race condition in timer drop (#3229)
Dropping a timer on the millisecond that it was scheduled for, when it was on
the pending list, could result in a panic previously, as we did not record the
pending-list state in cached_when.

Hopefully fixes: ZcashFoundation/zebra#1452
2020-12-08 16:42:43 -08:00
Blas Rodriguez Irizar fc7a4b3c6e chore: fix stress test (#3233) 2020-12-09 07:38:25 +09:00
Blas Rodriguez Irizar e01391351b Add stress test (#3222)
Created a simple echo TCP server that on two different runtimes that is
called from a GitHub action using Valgrind to ensure that there are
no memory leaks.

Fixes: #3022
2020-12-07 21:12:22 -08:00
bdonlan 57dffb9dfe rt: fix deadlock in shutdown (#3228)
Previously, the runtime shutdown logic would first-hand control over all cores
to a single thread, which would sequentially shut down all tasks on the core
and then wait for them to complete.

This could deadlock when one task is waiting for a later core's task to
complete. For example, in the newly added test, we have a `block_in_place` task
that is waiting for another task to be dropped. If the latter task adds its
core to the shutdown list later than the former, we end up waiting forever for
the `block_in_place` task to complete.

Additionally, there also was a bug wherein we'd attempt to park on the parker
after shutting it down which was fixed as part of the refactors above.

This change restructures the code to bring all tasks to a halt (and do any
parking needed) before we collapse to a single thread to avoid this deadlock.

There was also an issue in which canceled tasks would not unpark the
originating thread, due to what appears to be some sort of optimization gone
wrong. This has been fixed to be much more conservative in selecting when not
to unpark the source thread (this may be too conservative; please take a look
at the changes to `release()`).

Fixes: #2789
2020-12-07 20:55:02 -08:00
Carl Lerche 62023dffe5 sync: forward port 0.2 mpsc test (#3225)
Forward ports the test included in #3215. The mpsc sempahore has been
replaced in 0.3 and does not include the bug being fixed.
2020-12-07 11:24:15 -08:00
Fuyang Liu 0707f4c192 net: add TcpStream::into_std (#3189) 2020-12-06 14:33:04 +01:00
Iban Eguia 0dbba13984 deps: replace lazy_static with once_cell (#3187) 2020-12-04 10:23:13 +01:00
John-John Tedro a125ebd745 rt: fix panic in task abort when off rt (#3159)
A call to `JoinHandle::abort` releases a task. When called from outside of the runtime,
this panics due to the current implementation checking for a thread-local worker context.

This change makes accessing the thread-local context optional under release, by falling
back to remotely marking a task remotely as dropped. Behaving the same as if the core
was stolen by another worker.

Fixes #3157
2020-12-03 21:29:59 -08:00
Eliza Weisman 00500d1b35 util: prepare v0.5.1 release (#3210)
### Added

- io: `poll_read_buf` util fn (#2972).
- io: `poll_write_buf` util fn with vectored write support (#3156).

Signed-off-by: Eliza Weisman <[email protected]>
2020-12-03 15:30:52 -08:00
Eliza Weisman 647299866a util: add writev-aware poll_write_buf (#3156)
## Motivation

In Tokio 0.2, `AsyncRead` and `AsyncWrite` had `poll_write_buf` and
`poll_read_buf` methods for reading and writing to implementers of
`bytes` `Buf` and `BufMut` traits. In 0.3, these were removed, but
`poll_read_buf` was added as a free function in `tokio-util`. However,
there is currently no `poll_write_buf`.

Now that `AsyncWrite` has regained support for vectored writes in #3149,
there's a lot of potential benefit in having a `poll_write_buf` that
uses vectored writes when supported and non-vectored writes when not
supported, so that users don't have to reimplement this.

## Solution

This PR adds a `poll_write_buf` function to `tokio_util::io`, analogous
to the existing `poll_read_buf` function.

This function writes from a `Buf` to an `AsyncWrite`, advancing the
`Buf`'s internal cursor. In addition, when the `AsyncWrite` supports
vectored writes (i.e. its `is_write_vectored` method returns `true`),
it will use vectored IO.

I copied the documentation for this functions from the docs from Tokio
0.2's `AsyncWrite::poll_write_buf` , with some minor modifications as
appropriate.

Finally, I fixed a minor issue in the existing docs for `poll_read_buf`
and `read_buf`, and updated `tokio_util::codec` to use `poll_write_buf`.

Signed-off-by: Eliza Weisman <[email protected]>
2020-12-03 11:19:16 -08:00
Blas Rodriguez Irizar a6051a61ec sync: make add_permits panic with usize::MAX >> 3 permits (#3188) 2020-12-02 22:58:28 +01:00
cssivision a8e0f0a919 example: add back udp-codec example (#3205) 2020-12-01 12:20:20 +09:00
Alan Somers 7ae8135b62 process: fix the process_kill_on_drop.rs test on non-Linux systems (#3203)
"disown" is a bash builtin, not part of POSIX sh.
2020-12-01 10:20:49 +09:00
Alan Somers 353b0544a0 ci: reenable CI on FreeBSD i686 (#3204)
It was temporarily disabled in 06c473e628
and never reenabled.
2020-12-01 10:20:18 +09:00
Alan Somers 128495168d ci: switch FreeBSD CI environment to 12.2-RELEASE (#3202)
12.1 will be EoL in two months.
2020-12-01 10:19:54 +09:00
Carl Lerche 08548583b9 chore: prepare v0.3.5 release (#3201) 2020-11-30 12:57:31 -08:00
HK416-is-all-you-need 7707ba88ef io: add AsyncFd::with_interest (#3167)
Fixes #3072
2020-11-30 11:11:18 -08:00
Ivan Tham 72d6346c0d macros: #[tokio::main] can be used on non-main (#3199) 2020-11-30 17:34:11 +01:00
Kyle Kosic a85fdb884d runtime: test for shutdown_timeout(0) (#3196) 2020-11-29 21:30:19 +01:00
Alice Ryhl c55d846f4b util: add rt to tokio-util full feature (#3194) 2020-11-29 09:48:31 +01:00
Max Sharnoff 0acd06b42a runtime: fix shutdown_timeout(0) blocking (#3174) 2020-11-28 19:31:13 +01:00
Niklas Fiekas 4912943419 signal: expose CtrlC stream on windows (#3186)
* Make tokio::signal::windows::ctrl_c() public.
* Stop referring to private tokio::signal::windows::Event in module
  documentation.

Closes #3178
2020-11-27 19:53:17 +00:00
Rajiv Chauhan 5e406a7a47 macros: fix outdated documentation (#3180)
1. Changed 0.2 to 0.3
2. Changed ‘multi’ to ‘single’ to indicate that the behavior is single threaded
2020-11-26 19:46:15 +01:00
Max Sharnoff de33ee85ce time: replace 'ouClockTimeide' in internal docs with 'outside' (#3171) 2020-11-24 10:23:20 +01:00
漂流 874fc3320b codec: add read_buffer_mut to FramedRead (#3166) 2020-11-24 09:39:16 +01:00
bdonlan ae67851f11 time: use intrusive lists for timer tracking (#3080)
More-or-less a half-rewrite of the current time driver, supporting the
use of intrusive futures for timer registration.

Fixes: #3028, #3069
2020-11-23 10:42:50 -08:00
Eliza Weisman f927f01a34 macros: fix rustfmt on 1.48.0 (#3160)
## Motivation

Looks like the Rust 1.48.0 version of `rustfmt` changed some formatting
rules (fixed some bugs?), and some of the code in `tokio-macros` is no
longer correctly formatted. This is breaking CI.

## Solution

This commit runs rustfmt on Rust 1.48.0. This fixes CI.

Closes #3158
2020-11-20 10:19:26 -08:00
cssivision 49abfdb2ac util: fix typo in udp/frame.rs (#3154) 2020-11-20 15:06:14 +09:00
Carl Lerche 479c545c20 chore: prepare v0.3.4 release (#3152) 2020-11-18 12:38:13 -08:00
Sean McArthur 34fcef258b io: add vectored writes to AsyncWrite (#3149)
This adds `AsyncWrite::poll_write_vectored`, and implements it for
`TcpStream` and `UnixStream`.

Refs: #3135.
2020-11-18 10:41:47 -08:00
Zeki Sherif 7d11aa8668 net: add SO_LINGER get/set to TcpStream (#3143) 2020-11-17 09:58:00 -08:00
Carl Lerche 0ea2307650 net: add UdpSocket readiness and non-blocking ops (#3138)
Adds `ready()`, `readable()`, and `writable()` async methods for waiting
for socket readiness. Adds `try_send`, `try_send_to`, `try_recv`, and
`try_recv_from` for performing non-blocking operations on the socket.

This is the UDP equivalent of #3130.
2020-11-16 15:44:01 -08:00
Zahari Dichev d0ebb41547 sync: add Notify::notify_waiters (#3098)
This PR makes `Notify::notify_waiters` public. The method
already exists, but it changes the way `notify_waiters`,
is used. Previously in order for the consumer to
register interest, in a notification triggered by
`notify_waiters`, the `Notified` future had to be
polled. This introduced friction when using the api
as the future had to be pinned before polled.

This change introduces a counter that tracks how many
times `notified_waiters` has been called. Upon creation of
the future the number of times is loaded. When first
polled the future compares this number with the count
state of the `Notify` type. This avoids the need for
registering the waiter upfront.

Fixes: #3066
2020-11-16 12:49:35 -08:00
Eliza Weisman f5cb4c2042 net: Add send/recv buf size methods to TcpSocket (#3145)
This commit adds `set_{send, recv}_buffer_size` methods to `TcpSocket`
for setting the size of the TCP send and receive buffers, and `{send,
recv}_buffer_size` methods for returning the current value. These just
call into similar methods on `mio`'s `TcpSocket` type, which were added
in tokio-rs/mio#1384.

Refs: #3082

Signed-off-by: Eliza Weisman <[email protected]>
2020-11-16 12:29:03 -08:00
masnagam 4e39c9b818 net: restore TcpStream::{poll_read_ready, poll_write_ready} (#2743) 2020-11-16 09:51:06 -08:00
Carl Lerche 97c2c4203c chore: automate running benchmarks (#3140)
Uses Github actions to run benchmarks.
2020-11-13 19:30:52 -08:00
Taiki Endo 60366ca0fa chore: update pin-project-lite to 0.2.0 (#3139) 2020-11-13 15:24:06 -08:00
Carl Lerche 850bfc9efa net: add missing doc cfg on TcpSocket (#3137)
This adds the missing `net` feature flag in the generated API
documentation.
2020-11-13 11:05:22 -08:00
Carl Lerche 02b1117dca net: add TcpStream::ready and non-blocking ops (#3130)
Adds function to await for readiness on the TcpStream and non-blocking read/write functions.

`async fn TcpStream::ready(Interest)` waits for socket readiness satisfying **any** of the specified
interest. There are also two shorthand functions, `readable()` and `writable()`.

Once the stream is in a ready state, the caller may perform non-blocking operations on it using
`try_read()` and `try_write()`. These function return `WouldBlock` if the stream is not, in fact, ready.

The await readiness function are similar to `AsyncFd`, but do not require a guard. The guard in
`AsyncFd` protect against a potential race between receiving the readiness notification and clearing
it. The guard is needed as Tokio does not control the operations. With `TcpStream`, the `try_read()`
and `try_write()` function handle clearing stream readiness as needed.

This also exposes `Interest` and `Ready`, both defined in Tokio as wrappers for Mio types. These
types will also be useful for fixing #3072 .

Other I/O types, such as `TcpListener`, `UdpSocket`, `Unix*` should get similar functions, but this
is left for later PRs.

Refs: #3130
2020-11-12 20:07:43 -08:00
Nylonicious 685da8dadd fs: small documentation fixes (#3133) 2020-11-12 10:24:13 +01:00
Alice Ryhl 6a0e23c654 ci: minimal version check (#3131) 2020-11-11 23:08:34 +01:00
Alice Ryhl 9d0c0dd22c time: document maximum sleep duration (#3126) 2020-11-11 11:31:22 -08:00
Alice Ryhl 6d5423f3e9 stream: add docs regarding futures' StreamExt (#3128) 2020-11-11 11:20:14 -08:00
Ivan Petkov ebb8bab060 process: fix potential file descriptor leak (#3129) 2020-11-11 11:10:27 -08:00
Carl Lerche ce891a4df1 io: driver internal cleanup (#3124)
* Removes duplicated code by moving it to `Registration`.
* impl `Deref` for `PollEvented` to avoid `get_ref()`.
* Avoid extra waker clones in I/O driver.
* Add `Interest` wrapper around `mio::Interest`.
2020-11-11 09:28:21 -08:00
David Kellum d869e16990 Minor cleanup of parking_lot feature, now in full (#3119)
## Motivation

Some small cleanup items are apparent after merge of #2951

## Solution

Delete a now incorrect comment in Cargo.toml, and remove a now redundant CI test step.
2020-11-10 15:01:58 -08:00
Carl Lerche e1256d8ca4 io: update AsyncFd to use Registration (#3113) 2020-11-10 09:40:20 -08:00
Darius Carrier a52f5071bf sync: add acquire_many and try_acquire_many to Sempahore (#3067)
Fixes: #1550
2020-11-10 09:39:30 -08:00
Taiki Endo f1f8c3cde6 chore: update proptest and nix (#3110) 2020-11-08 20:47:44 +09:00
Oliver Gould c2e843d928 tokio-test: Update bytes to v0.6 (#3107) 2020-11-08 05:54:41 +09:00
bdonlanandBryan Donlan a43ec09b55 async_fd: make into_inner() deregister the fd (#3104)
* async_fd: make into_inner() deregister the fd

Fixes: #3103

* make clippy happy

Co-authored-by: Bryan Donlan <[email protected]>
2020-11-07 10:12:06 +01:00
Maarten de Vries 90c2a510e2 net: report PID in UCred for Solaris and Illumos. (#3085) 2020-11-06 17:04:19 +01:00
Alice Ryhl f51ddc5958 net: add set_nonblocking to doc (#3100) 2020-11-06 17:01:22 +01:00
Evan Cameron 47658a6da5 util: resurrect UdpFramed (#3044) 2020-11-06 16:59:15 +01:00
bdonlanandBryan Donlan d7e3fcb9ee rt: remove last slab dependency (#2917)
This removes the last slab dependency by replacing the current slab-based
JoinHandle tracking with one based on HashMap instead.

Co-authored-by: Bryan Donlan <[email protected]>
2020-11-05 10:38:37 -08:00
0b3918bce9 rt: bring back a public Handle type (#3076)
Signed-off-by: Marc-Antoine Perennou <[email protected]>
Co-authored-by: Alice Ryhl <[email protected]>
Co-authored-by: Carl Lerche <[email protected]>
2020-11-05 13:00:13 +01:00
Akira Hayakawa e309da0bee util: remove stream feature flag from DelayQueue (#3087) 2020-11-03 09:20:24 +01:00
Carl Lerche bbc8eb0f91 chore: update CI badge (#3091) 2020-11-03 09:17:47 +01:00
Artem Vorotnikov 06c7e73e99 stream: fix StreamMap Default bound (#3093) 2020-11-03 09:09:05 +01:00
Carl Lerche 42de3bc7a4 chore: prepare v0.3.3 release (#3090) 2020-11-02 15:36:17 -08:00
Alice Ryhl 20a2b9e263 rt: add missing Send bound (#3089) 2020-11-02 15:30:07 -08:00
Zeki Sherif ae4e8d7ad1 net: add get/set reuseport, reuseaddr, localaddr for TcpSocket (#3083) 2020-11-02 12:59:56 -08:00
Alice Ryhl 7a18ca2be0 doc: add from_std change to CHANGELOG (#3075) 2020-11-02 10:25:43 -08:00
Naja Melan 4a7b7c52d1 util: copy paste error in documentation for Compat (#3088) 2020-11-02 13:25:51 +01:00
Eliza Weisman fede3db76a tracing: replace future names with spawn locations in task spans (#3074)
## Motivation

Currently, the per-task `tracing` spans generated by tokio's `tracing`
feature flag include the `std::any::type_name` of the future that was
spawned. When future combinators and/or libraries like Tower are in use,
these future names can get _quite_ long. Furthermore, when formatting
the `tracing` spans with their parent spans as context, any other task
spans in the span context where the future was spawned from can _also_
include extremely long future names.

In some cases, this can result in extremely high memory use just to
store the future names. For example, in Linkerd, when we enable
`tokio=trace` to enable the task spans, there's a spawned task whose
future name is _232990 characters long_. A proxy with only 14 spawned
tasks generates a task list that's over 690 KB. Enabling task spans
under load results in the process getting OOM killed very quickly.

## Solution

This branch removes future type names from the spans generated by
`spawn`. As a replacement, to allow identifying which `spawn` call a
span corresponds to, the task span now contains the source code location
where `spawn` was called, when the compiler supports the
`#[track_caller]` attribute. Since `track_caller` was stabilized in Rust
1.46.0, and our minimum supported Rust version is 1.45.0, we can't
assume that `#[track_caller]` is always available. Instead, we have a
RUSTFLAGS cfg, `tokio_track_caller`, that guards whether or not we use
it. I've also added a `build.rs` that detects the compiler minor
version, and sets the cfg flag automatically if the current compiler
version is >= 1.46. This means users shouldn't have to enable
`tokio_track_caller` manually.

Here's the trace output from the `chat` example, before this change:
![Screenshot_20201030_110157](https://user-images.githubusercontent.com/2796466/97741071-6d408800-1a9f-11eb-9ed6-b25e72f58c7b.png)
...and after:
![Screenshot_20201030_110303](https://user-images.githubusercontent.com/2796466/97741112-7e899480-1a9f-11eb-9197-c5a3f9ea1c05.png)

Closes #3073

Signed-off-by: Eliza Weisman <[email protected]>
2020-11-01 10:48:44 -08:00
Dirkjan Ochtman 2b23aa7389 util: add back public poll_read_buf() function (#3079)
This was accidentally removed in #3064.
2020-11-01 10:22:22 +01:00
Finn Behrens 382ee6bf5d net: add pid to tokio::net::unix::UCred (#2633) 2020-10-31 10:30:55 +01:00
Carl Lerche 24ed874e81 chore: prepare tokio-util v0.5.0 release (#3078) 2020-10-30 11:26:15 -07:00
Dirkjan Ochtman 3965d91a5e util: update to bytes 0.6 (#3071)
Copies the implementation of poll_read_buf() from tokio::io::util::read_buf.
2020-10-29 10:45:19 -07:00
Dirkjan Ochtman a3ef4e4cf5 util: deduplicate implementations of poll_read_buf() (#3064) 2020-10-29 13:20:38 +01:00
Naja Melan 34eb47dde5 runtime: block_on should NOT be called from async context (#3070) 2020-10-29 12:10:42 +01:00
Tom Kaitchuck c8a484bbb2 tokio: remove unused dependency (#3063)
Signed-off-by: Tom Kaitchuck <[email protected]>
2020-10-28 08:06:53 +01:00
Carl Lerche 9097ae548f chore: prepare v0.3.2 release (#3059) 2020-10-27 14:31:39 -07:00
Carl Lerche d78655337a Revert "util: upgrade tokio-util to bytes 0.6 (#3052)" (#3060)
This reverts commit fe2b997.

We are avoiding adding poll_read_buf to tokio itself for now. The patch is
reverted now in order to not block the v0.3.2 release (#3059).
2020-10-27 13:42:00 -07:00
Zahari Dichev 38605c5c85 net: change mention of net2 (#3056) 2020-10-27 09:34:17 -07:00
Dirkjan Ochtman fe2b997675 util: upgrade tokio-util to bytes 0.6 (#3052) 2020-10-27 09:30:29 +01:00
Sean McArthur 6d0ba19af5 sync: make oneshot::Sender::poll_closed public again (#3032) 2020-10-26 08:54:25 -07:00
Alice Ryhl cbb8fe6069 udp: add UdpSocket::take_error (#3051) 2020-10-26 12:50:48 +01:00
Alice Ryhl a9da220923 oneshot: update closed() docs to use tokio::select! (#3050) 2020-10-26 11:44:46 +01:00
Alice Ryhl 1c28c3b0a8 macros: prepare tokio-macros 0.3.1 (#3042) 2020-10-26 10:02:39 +01:00
nickelc e31bd321ef readme: update the MSRV to 1.45 (#3048) 2020-10-26 09:46:15 +01:00
nickelc c30ce1f65c docs: remove max_threads mentions in tokio-macros (#3038) 2020-10-24 22:34:56 +02:00
Alice Ryhl a95378a850 io: expand on de-initialization of ReadBuf (#3035) 2020-10-24 22:29:19 +02:00
Zahari Dichev ce173fdc91 docs: update docs for from_std functions (#3016)
Fixes: #3007
2020-10-24 14:26:01 +02:00
Zahari Dichev e804f88d60 sync: add mem::forget to RwLockWriteGuard::downgrade. (#2957)
Currently when `RwLockWriteGuard::downgrade` the `MAX_READS - 1`
permits are added to the semaphore. When `RwLockWriteGuard::drop`
gets invoked however another `MAX_READS` permits are added. This
results in releasing more permits that were actually aquired when
downgrading a write to a read lock. This is why we need to call
`mem::forget` on the `RwLockWriteGuard` in order to avoid
invoking the destructor.

Fixes: #2941
2020-10-23 10:07:00 -07:00
bdonlan c153913211 io: Add AsyncFd, fix io::driver shutdown (#2903)
* io: Add AsyncFd

This adds AsyncFd, a unix-only structure to allow for read/writability states
to be monitored for arbitrary file descriptors.

Issue: #2728

* driver: fix shutdown notification unreliability

Previously, there was a race window in which an IO driver shutting down could
fail to notify ScheduledIo instances of this state; in particular, notification
of outstanding ScheduledIo registrations was driven by `Driver::drop`, but
registrations bypass `Driver` and go directly to a `Weak<Inner>`. The `Driver`
holds the `Arc<Inner>` keeping `Inner` alive, but it's possible that a new
handle could be registered (or a new readiness future created for an existing
handle) after the `Driver::drop` handler runs and prior to `Inner` being
dropped.

This change fixes this in two parts: First, notification of outstanding
ScheduledIo handles is pushed down into the drop method of `Inner` instead,
and, second, we add state to ScheduledIo to ensure that we remember that the IO
driver we're bound to has shut down after the initial shutdown notification, so
that subsequent readiness future registrations can immediately return (instead
of potentially blocking indefinitely).

Fixes: #2924
2020-10-22 14:12:41 -07:00
Evan Cameron 358e4f9f80 tokio: add back poll_* for udp (#2981) 2020-10-22 09:58:00 -07:00
Zhang Jingqiang adf822f5cc net: fix typo (#3023) 2020-10-22 08:59:47 +02:00
Carl Lerche d14cbf9116 chore: prepare v0.3.1 release (#3021) 2020-10-21 16:23:35 -07:00
Carl Lerche 8bfb1c92ce sync: revert Clone impl for broadcast::Receiver (#3020)
The `Receiver` handle maintains a position in the broadcast channel for
itself. Cloning implies copying the state of the value. Intuitively,
cloning a `broadcast::Receiver` would return a new receiver with an
identical position. However, the current implementation returns a new
`Receiver` positioned at the tail of the channel.

This behavior subtlety is why `new_subscriber()` is used to create
`Receiver` handles. An alternate API should consider the position issue.

Refs: #2933
2020-10-21 15:14:52 -07:00
Carl Lerche b48fec9655 net: fix use-after-free in slab compaction (#3019)
An off-by-one bug results in freeing the incorrect page. This
also adds an `asan` CI job.

Fixes: 3014
2020-10-21 14:43:57 -07:00
Carl Lerche 8dbc3c7937 io: add AsyncReadExt::read_buf (#3003)
Brings back `read_buf` from 0.2. This will be stabilized as part of 1.0.
2020-10-21 14:08:49 -07:00
Marc-Antoine Perennou 7fbfa9b649 tokio: deduplicate spawn_blocking (#3017)
Move common code and tracing integration into Handle

Fixes #2998
Closes #3004

Signed-off-by: Marc-Antoine Perennou <[email protected]>
2020-10-21 20:00:48 +02:00
Nikolai Kuklin 7d7b79e1d5 sync: add is_closed method to watch sender (#2991) 2020-10-21 13:35:13 +02:00
Zahari Dichev 8f37544a79 io: explain how to determine number of bytes read in AsyncRead (#3011)
Fixes: #2999
2020-10-21 13:32:50 +02:00
Philip Kannegaard Hayes 43d0714898 sync: remove extra clone in Semaphore::[try_]acquire_owned (#3015) 2020-10-21 08:16:03 +02:00
Zahari Dichev 16e272ea4b fs: flush on shutdown (#3009)
Fixes: #2950
2020-10-20 17:42:32 +02:00
John-John Tedro 6d99e1c7de util: prevent read buffer from being swapped during a read_poll (#2993) 2020-10-20 11:14:02 +02:00
pluth f73a2ad238 docs: adjust TcpListener::from_std documentation to match behavior (#3002) 2020-10-19 21:37:00 -07:00
Alice Ryhl c793ead0c3 runtime: remove unneeded #[cfg(feature = "rt")] (#2996) 2020-10-19 21:35:33 -07:00
Marc-Antoine Perennou 2696794771 tokio: add Runtime::spawn_blocking (#2980)
This allows writing

rt.spawn_blocking(f);

instead of

let _enter = rt.enter();
tokio::task::spawn_blocking(f);

Signed-off-by: Marc-Antoine Perennou <[email protected]>
2020-10-19 18:49:16 +02:00
nickelc cfd643d691 docs: fix typo in runtime module documentation (#2992) 2020-10-19 15:33:10 +02:00
John-John Tedro 8d17261a4b util: add a poll_read_buf shim to tokio-util (#2972) 2020-10-19 11:06:06 +02:00
Zahari Dichev 423ecc187a io: add copy_buf (#2884) 2020-10-19 10:15:25 +02:00
Zephyr Shannon fb28caa90c sync: implement Clone for broadcast::Receiver (#2933) 2020-10-19 10:12:40 +02:00
Evan Cameron e88e64bcc0 docs: fix typos on UdpSocket (#2979) 2020-10-17 12:13:23 +02:00
messense 3cc6ce7a99 doc: update version to 0.3 in module documentation (#2974) 2020-10-16 13:49:30 +02:00
Alice Ryhl 81db03204d Fix doc typo (#2967) 2020-10-16 12:37:21 +02:00
John-John Tedro 1644511bdf Update documentation of AsyncRead to reflect use of ReadBuf 2020-10-16 11:55:35 +02:00
Carl Lerche dc9742fbea chore: post release Cargo.toml fixes (#2963) 2020-10-15 11:46:10 -07:00
358 changed files with 23826 additions and 6569 deletions
+8 -9
View File
@@ -1,17 +1,17 @@
freebsd_instance:
image: freebsd-12-1-release-amd64
image: freebsd-12-2-release-amd64
# 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 12.0
name: FreeBSD
env:
LOOM_MAX_PREEMPTIONS: 2
RUSTFLAGS: -Dwarnings
setup_script:
- pkg install -y curl
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain stable
- . $HOME/.cargo/env
@@ -21,10 +21,9 @@ task:
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo test --all
- cargo test --all --all-features
- cargo doc --all --no-deps
# TODO: Re-enable
# i686_test_script:
# - . $HOME/.cargo/env
# - |
# cargo test --all --exclude tokio-macros --target i686-unknown-freebsd
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --all-features --target i686-unknown-freebsd
+1 -6
View File
@@ -9,12 +9,7 @@ assignees: ''
**Version**
List the versions of all `tokio` crates you are using. The easiest way to get
this information is using `cargo-tree`.
`cargo install cargo-tree`
(see install here: https://github.com/sfackler/cargo-tree)
Then:
this information is using `cargo tree` subcommand:
`cargo tree | grep tokio`
+55
View File
@@ -0,0 +1,55 @@
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
+71 -8
View File
@@ -1,8 +1,8 @@
on:
push:
branches: ["master"]
branches: ["master", "tokio-*.x"]
pull_request:
branches: ["master"]
branches: ["master", "tokio-*.x"]
name: CI
@@ -28,6 +28,7 @@ jobs:
- clippy
- docs
- loom
- valgrind
steps:
- run: exit 0
@@ -53,11 +54,6 @@ jobs:
run: cargo test --features full
working-directory: tokio
# Check `tokio` with `full + parking_lot` to make sure it compiles.
- name: check tokio full,parking_lot
run: cargo check --features full,parking_lot
working-directory: tokio
# Test **all** crates in the workspace with all features.
- name: test all --all-features
run: cargo test --workspace --all-features
@@ -72,6 +68,37 @@ jobs:
run: cargo hack test --each-feature
working-directory: tests-build
valgrind:
name: valgrind
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- 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 --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 --leak-check=full --show-leak-kinds=all ./target/debug/test-process-signal
test-unstable:
name: test tokio full --unstable
runs-on: ${{ matrix.os }}
@@ -112,6 +139,21 @@ jobs:
- name: miri
run: cargo miri test --features rt,rt-multi-thread,sync task
working-directory: tokio
san:
name: san
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
override: true
- name: asan
run: cargo test --all-features --target x86_64-unknown-linux-gnu --lib -- --test-threads 1
working-directory: tokio
env:
RUSTFLAGS: -Z sanitizer=address
ASAN_OPTIONS: detect_leaks=0
cross:
name: cross
@@ -171,6 +213,26 @@ jobs:
- name: "test --workspace --all-features"
run: cargo check --workspace --all-features
minimal-versions:
name: minimal-versions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.nightly }}
override: true
- name: Install cargo-hack
run: cargo install cargo-hack
- name: "check --all-features -Z minimal-versions"
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 check --all-features
fmt:
name: fmt
runs-on: ubuntu-latest
@@ -202,7 +264,7 @@ jobs:
# Run clippy
- name: "clippy --all"
run: cargo clippy --all --tests
run: cargo clippy --all --tests --all-features
docs:
name: docs
@@ -230,6 +292,7 @@ jobs:
- loom_pool::group_b
- loom_pool::group_c
- loom_pool::group_d
- time::driver
steps:
- uses: actions/checkout@v2
- name: Install Rust
+32
View File
@@ -0,0 +1,32 @@
name: Stress Test
on:
pull_request:
push:
branches:
- master
jobs:
stess-test:
name: Stress Test
runs-on: ubuntu-latest
strategy:
matrix:
stress-test:
- simple_echo_tcp
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Install Valgrind
run: |
sudo apt-get update -y
sudo apt-get install -y valgrind
# Compiles each of the stress test examples.
- name: Compile stress test examples
run: cargo build -p stress-test --release --example ${{ matrix.stress-test }}
# Runs each of the examples using Valgrind. Detects leaks and displays them.
- name: Run valgrind
run: valgrind --leak-check=full --show-leak-kinds=all ./target/release/examples/${{ matrix.stress-test }}
+59 -13
View File
@@ -124,17 +124,27 @@ 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
```
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:
@@ -427,11 +437,14 @@ _Adapted from the [Node.js contributing guide][node]_.
## Keeping track of issues and PRs
The Tokio GitHub repository has a lot of issues and PRs, which is not easy to
keep track of. This section explains the meaning of various labels, as well as
our [GitHub project][project]. The section is primarily targeted at maintainers.
The Tokio GitHub repository has a lot of issues and PRs to keep track of. This
section explains the meaning of various labels, as well as our [GitHub
project][project]. The section is primarily targeted at maintainers. Most
contributors aren't able to set these labels.
**Area.** The area label describes the crates relevant to this issue or PR.
### Area
The area label describes the crates relevant to this issue or PR.
- **A-tokio** This issue concerns the main Tokio crate.
- **A-tokio-util** This issue concerns the `tokio-util` crate.
@@ -442,7 +455,7 @@ our [GitHub project][project]. The section is primarily targeted at maintainers.
be used for the procedural macros, and not `join!` or `select!`.
- **A-ci** This issue concerns our GitHub Actions setup.
**Category.** The category label describes the category.
### Category
- **C-bug** This is a bug-report. Bug-fix PRs use `C-enhancement` instead.
- **C-enhancement** This is a PR that adds a new features.
@@ -460,8 +473,7 @@ our [GitHub project][project]. The section is primarily targeted at maintainers.
- **C-request** A non-feature request, e.g. "please add deprecation notices to
`-alpha.*` versions of crates"
**Call for participation.** I don't know why it's called `E-`. Many issues are
missing a difficulty rating, and you should feel free to add one.
### Calls for participation
- **E-help-wanted** Stuff where we want help. Often seen together with `C-bug`
or `C-feature-accepted`.
@@ -473,7 +485,13 @@ missing a difficulty rating, and you should feel free to add one.
- **E-needs-mvce** This bug is missing a minimal complete and verifiable
example.
**Module.** A more fine groaned categorization than area.
The "E-" prefix is the same as used in the Rust compiler repository. Some
issues are missing a difficulty rating, but feel free to ask on our Discord
server if you want to know how difficult an issue likely is.
### Module
The module label provides a more fine grained categorization than **Area**.
- **M-blocking** Things relevant to `spawn_blocking`, `block_in_place`.
- **M-codec** The `tokio_util::codec` module.
@@ -486,13 +504,14 @@ missing a difficulty rating, and you should feel free to add one.
- **M-process** The `tokio::process` module.
- **M-runtime** The `tokio::runtime` module.
- **M-signal** The `tokio::signal` module.
- **M-stream** The `tokio::stream` module.
- **M-sync** The `tokio::sync` module.
- **M-task** The `tokio::task` module.
- **M-time** The `tokio::time` module.
- **M-tracing** Tracing support in Tokio.
**Topic.** Some extra information.
### Topic
Some extra information.
- **T-docs** This is about documentation.
- **T-performance** This is about performance.
@@ -502,6 +521,34 @@ Any label not listed here is not in active use.
[project]: https://github.com/orgs/tokio-rs/projects/1
## LTS guarantees
Tokio ≥1.0.0 comes with LTS guarantees:
* A minimum of 5 years of maintenance.
* A minimum of 3 years before a hypothetical 2.0 release.
The goal of these guarantees is to provide stability to the ecosystem.
## Mininum Supported Rust Version (MSRV)
* All Tokio ≥1.0.0 releases will support at least a 6-month old Rust
compiler release.
* The MSRV will only be increased on 1.x releases.
## Versioning Policy
With Tokio ≥1.0.0:
* Patch (1.\_.x) releases _should only_ contain bug fixes or documentation
changes. Besides this, these releases should not substantially change
runtime behavior.
* Minor (1.x) releases may contain new functionality, MSRV increases (see
above), minor dependency updates, deprecations, and larger internal
implementation changes.
This is as defined by [Semantic Versioning 2.0](https://semver.org/).
## Releasing
Since the Tokio project consists of a number of crates, many of which depend on
@@ -534,9 +581,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
+2
View File
@@ -4,11 +4,13 @@ members = [
"tokio",
"tokio-macros",
"tokio-test",
"tokio-stream",
"tokio-util",
# Internal
"benches",
"examples",
"stress-test",
"tests-build",
"tests-integration",
]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2019 Tokio Contributors
Copyright (c) 2021 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+14 -7
View File
@@ -14,22 +14,21 @@ the Rust programming language. It is:
[![Crates.io][crates-badge]][crates-url]
[![MIT licensed][mit-badge]][mit-url]
[![Build Status][azure-badge]][azure-url]
[![Build Status][actions-badge]][actions-url]
[![Discord chat][discord-badge]][discord-url]
[crates-badge]: https://img.shields.io/crates/v/tokio.svg
[crates-url]: https://crates.io/crates/tokio
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[mit-url]: https://github.com/tokio-rs/tokio/blob/master/LICENSE
[azure-badge]: https://dev.azure.com/tokio-rs/Tokio/_apis/build/status/tokio-rs.tokio?branchName=master
[azure-url]: https://dev.azure.com/tokio-rs/Tokio/_build/latest?definitionId=1&branchName=master
[actions-badge]: https://github.com/tokio-rs/tokio/workflows/CI/badge.svg
[actions-url]: https://github.com/tokio-rs/tokio/actions?query=workflow%3ACI+branch%3Amaster
[discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord&style=flat-square
[discord-url]: https://discord.gg/tokio
[Website](https://tokio.rs) |
[Guides](https://tokio.rs/tokio/tutorial) |
[API Docs](https://docs.rs/tokio/latest/tokio) |
[Roadmap](https://github.com/tokio-rs/tokio/blob/master/ROADMAP.md) |
[Chat](https://discord.gg/tokio)
## Overview
@@ -51,11 +50,19 @@ 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:
```text
[dependencies]
tokio = { version = "1.4.0", features = ["full"] }
```
Then, on your main.rs:
```rust,no_run
use tokio::net::TcpListener;
use tokio::prelude::*;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -157,7 +164,7 @@ several other libraries, including:
## Supported Rust Versions
Tokio is built against the latest stable release. The minimum supported version is 1.39.
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.
-67
View File
@@ -1,67 +0,0 @@
# Tokio Roadmap
## A Roadmap to 1.0
The question of "why not 1.0?" has come up a few times. After all, Tokio 0.1 has
been stable for three years. The short answer: because it isn't time. There is
nobody who would rather ship a Tokio 1.0 than us. It also isn't something to rush.
After all, `async / await` only landed in the stable Rust channel weeks ago.
There has been no significant production validation yet, except maybe fuchsia
and that seems like a fairly specialized use case. This release of Tokio
includes significant new code and new strategies with feature flags. Also, there
are still big open questions, such as the [proposed changes][pr-1744] to
`AsyncRead` and `AsyncWrite`.
Tokio 1.0 will be released as soon as the APIs are proven to handle real-world
production cases.
### Tokio 1.0 in Q3 2020 with LTS support
The Tokio 1.0 release will be **no later** than Q3 2020. It will also come with
"long-term support" guarantees:
* A minimum of 5 years of maintenance.
* A minimum of 3 years before a hypothetical 2.0 release.
When Tokio 1.0 is released in Q3 2020, on-going support, security fixes, and
critical bug fixes are guaranteed until **at least** Q3 2025. Tokio 2.0 will not
be released until **at least** Q3 2023 (though, ideally there will never be a
Tokio 2.0 release).
### How to get there
While Tokio 0.1 probably should have been a 1.0, Tokio 0.2 will be a **true**
0.2 release. There will be breaking change releases every 2 ~ 3 months until 1.0.
These changes will be **much** smaller than going from 0.1 -> 0.2. It is
expected that the 1.0 release will look a lot like 0.2.
### What is expected to change
The biggest change will be the `AsyncRead` and `AsyncWrite` traits. Based on
experience gained over the past 3 years, there are a couple of issues to
address:
* Be able to **safely** use uninitialized memory as a read buffer.
* Practical read vectored and write vectored APIs.
There are a few strategies to solve these problems. These strategies need to be
investigated and the solution validated. You can see [this comment][pr-1744-comment] for a
detailed statement of the problem.
The other major change, which has been in the works for a while, is updating
Mio. Mio 0.6 was first released almost 4 years ago and has not had a breaking
change since. Mio 0.7 has been in the works for a while. It includes a full
rewrite of the windows support as well as a refined API. More will be written
about this shortly.
Finally, now that the API is starting to stabilize, effort will be put into
documentation. Tokio 0.2 is being released before updating the website and many
of the old content will no longer be relevant. In the coming weeks, expect to
see updates there.
So, we have our work cut out for us. We hope you enjoy this 0.2 release and are
looking forward to your feedback and help.
[pr-1744]: https://github.com/tokio-rs/tokio/pull/1744
[pr-1744-comment]: https://github.com/tokio-rs/tokio/pull/1744#issuecomment-553575438
+5 -5
View File
@@ -5,7 +5,7 @@ publish = false
edition = "2018"
[dependencies]
tokio = { version = "0.3.0", path = "../tokio", features = ["full"] }
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
bencher = "0.1.5"
[target.'cfg(unix)'.dependencies]
@@ -17,13 +17,13 @@ path = "spawn.rs"
harness = false
[[bench]]
name = "mpsc"
path = "mpsc.rs"
name = "sync_mpsc"
path = "sync_mpsc.rs"
harness = false
[[bench]]
name = "scheduler"
path = "scheduler.rs"
name = "rt_multi_threaded"
path = "rt_multi_threaded.rs"
harness = false
+8 -4
View File
@@ -30,22 +30,26 @@ fn create_100_000_medium(b: &mut Bencher) {
}
fn send_medium(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let (tx, mut rx) = mpsc::channel::<Medium>(1000);
let _ = tx.try_send([0; 64]);
let _ = rt.block_on(tx.send([0; 64]));
rx.try_recv().unwrap();
rt.block_on(rx.recv()).unwrap();
});
}
fn send_large(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let (tx, mut rx) = mpsc::channel::<Large>(1000);
let _ = tx.try_send([[0; 64]; 64]);
let _ = rt.block_on(tx.send([[0; 64]; 64]));
rx.try_recv().unwrap();
rt.block_on(rx.recv()).unwrap();
});
}
+17 -4
View File
@@ -7,18 +7,22 @@ edition = "2018"
# If you copy one of the examples into a new project, you should be using
# [dependencies] instead.
[dev-dependencies]
tokio = { version = "0.3.0", path = "../tokio", features = ["full", "tracing"] }
tokio = { version = "1.0.0", features = ["full", "tracing"] }
tokio-util = { version = "0.6.3", features = ["full"] }
tokio-stream = { version = "0.1" }
tracing = "0.1"
tracing-subscriber = { version = "0.2.7", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log"] }
tokio-util = { version = "0.4.0", path = "../tokio-util", features = ["full"] }
bytes = "0.5"
futures = "0.3.0"
bytes = "1.0.0"
futures = { version = "0.3.0", features = ["thread-pool"]}
http = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
httparse = "1.0"
time = "0.1"
once_cell = "1.5.2"
[[example]]
name = "chat"
@@ -63,3 +67,12 @@ path = "udp-codec.rs"
[[example]]
name = "tinyhttp"
path = "tinyhttp.rs"
[[example]]
name = "custom-executor"
path = "custom-executor.rs"
[[example]]
name = "custom-executor-tokio-context"
path = "custom-executor-tokio-context.rs"
+26 -61
View File
@@ -27,9 +27,9 @@
#![warn(rust_2018_idioms)]
use tokio::net::{TcpListener, TcpStream};
use tokio::stream::{Stream, StreamExt};
use tokio::sync::{mpsc, Mutex};
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>> {
@@ -168,43 +166,6 @@ impl Peer {
}
}
#[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>>,
@@ -238,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,
},
}
}
+2 -2
View File
@@ -92,7 +92,7 @@ mod tcp {
mod udp {
use bytes::Bytes;
use futures::{future, Sink, SinkExt, Stream, StreamExt};
use futures::{Sink, SinkExt, Stream, StreamExt};
use std::error::Error;
use std::io;
use std::net::SocketAddr;
@@ -114,7 +114,7 @@ mod udp {
let socket = UdpSocket::bind(&bind_addr).await?;
socket.connect(addr).await?;
future::try_join(send(stdin, &socket), recv(stdout, &socket)).await?;
tokio::try_join!(send(stdin, &socket), recv(stdout, &socket))?;
Ok(())
}
+32
View File
@@ -0,0 +1,32 @@
// This example shows how to use the tokio runtime with any other executor
//
//It takes advantage from RuntimeExt which provides the extension to customize your
//runtime.
use tokio::net::TcpListener;
use tokio::runtime::Builder;
use tokio::sync::oneshot;
use tokio_util::context::RuntimeExt;
fn main() {
let (tx, rx) = oneshot::channel();
let rt1 = Builder::new_multi_thread()
.worker_threads(1)
// no timer!
.build()
.unwrap();
let rt2 = Builder::new_multi_thread()
.worker_threads(1)
.enable_all()
.build()
.unwrap();
// Without the `HandleExt.wrap()` there would be a panic because there is
// no timer running, since it would be referencing runtime r1.
let _ = rt1.block_on(rt2.wrap(async move {
let listener = TcpListener::bind("0.0.0.0:0").await.unwrap();
println!("addr: {:?}", listener.local_addr());
tx.send(()).unwrap();
}));
futures::executor::block_on(rx).unwrap();
}
+56
View File
@@ -0,0 +1,56 @@
// This example shows how to use the tokio runtime with any other executor
//
// The main components are a spawn fn that will wrap futures in a special future
// that will always enter the tokio context on poll. This only spawns one extra thread
// to manage and run the tokio drivers in the background.
use tokio::net::TcpListener;
use tokio::sync::oneshot;
fn main() {
let (tx, rx) = oneshot::channel();
my_custom_runtime::spawn(async move {
let listener = TcpListener::bind("0.0.0.0:0").await.unwrap();
println!("addr: {:?}", listener.local_addr());
tx.send(()).unwrap();
});
futures::executor::block_on(rx).unwrap();
}
mod my_custom_runtime {
use once_cell::sync::Lazy;
use std::future::Future;
use tokio_util::context::TokioContext;
pub fn spawn(f: impl Future<Output = ()> + Send + 'static) {
EXECUTOR.spawn(f);
}
struct ThreadPool {
inner: futures::executor::ThreadPool,
rt: tokio::runtime::Runtime,
}
static EXECUTOR: Lazy<ThreadPool> = Lazy::new(|| {
// Spawn tokio runtime on a single background thread
// enabling IO and timers.
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let inner = futures::executor::ThreadPool::builder().create().unwrap();
ThreadPool { inner, rt }
});
impl ThreadPool {
fn spawn(&self, f: impl Future<Output = ()> + Send + 'static) {
let handle = self.rt.handle().clone();
self.inner.spawn_ok(TokioContext::new(f, handle));
}
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
// which will allow all of our clients to be processed concurrently.
tokio::spawn(async move {
let mut buf = [0; 1024];
let mut buf = vec![0; 1024];
// In a loop, read data from the socket and write the data back.
loop {
+1 -1
View File
@@ -55,7 +55,7 @@
#![warn(rust_2018_idioms)]
use tokio::net::TcpListener;
use tokio::stream::StreamExt;
use tokio_stream::StreamExt;
use tokio_util::codec::{BytesCodec, Decoder};
use std::env;
+1 -2
View File
@@ -26,7 +26,6 @@ use tokio::io;
use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream};
use futures::future::try_join;
use futures::FutureExt;
use std::env;
use std::error::Error;
@@ -74,7 +73,7 @@ async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<
wi.shutdown().await
};
try_join(client_to_server, server_to_client).await?;
tokio::try_join!(client_to_server, server_to_client)?;
Ok(())
}
+1 -1
View File
@@ -42,7 +42,7 @@
#![warn(rust_2018_idioms)]
use tokio::net::TcpListener;
use tokio::stream::StreamExt;
use tokio_stream::StreamExt;
use tokio_util::codec::{Framed, LinesCodec};
use futures::SinkExt;
+1 -1
View File
@@ -20,7 +20,7 @@ use http::{header::HeaderValue, Request, Response, StatusCode};
extern crate serde_derive;
use std::{env, error::Error, fmt, io};
use tokio::net::{TcpListener, TcpStream};
use tokio::stream::StreamExt;
use tokio_stream::StreamExt;
use tokio_util::codec::{Decoder, Encoder, Framed};
#[tokio::main]
+2 -8
View File
@@ -1,8 +1,3 @@
fn main() {}
// Disabled while future of UdpFramed is decided on.
// See https://github.com/tokio-rs/tokio/issues/2830
/*
//! This example leverages `BytesCodec` to create a UDP client and server which
//! speak a custom protocol.
//!
@@ -14,8 +9,8 @@ fn main() {}
#![warn(rust_2018_idioms)]
use tokio::net::UdpSocket;
use tokio::stream::StreamExt;
use tokio::{io, time};
use tokio_stream::StreamExt;
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
@@ -50,7 +45,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let b = pong(&mut b);
// Run both futures simultaneously of `a` and `b` sending messages back and forth.
match futures::future::try_join(a, b).await {
match tokio::try_join!(a, b) {
Err(e) => println!("an error occurred; error = {:?}", e),
_ => println!("done!"),
}
@@ -83,4 +78,3 @@ async fn pong(socket: &mut UdpFramed<BytesCodec>) -> Result<(), io::Error> {
Ok(())
}
*/
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "stress-test"
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { path = "../tokio/", features = ["full"] }
[dev-dependencies]
rand = "0.8"
+58
View File
@@ -0,0 +1,58 @@
//! Simple TCP echo server to check memory leaks using Valgrind.
use std::{thread::sleep, time::Duration};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpSocket},
runtime::Builder,
sync::oneshot,
};
const TCP_ENDPOINT: &str = "127.0.0.1:8080";
const NUM_MSGS: usize = 100;
const MSG_SIZE: usize = 1024;
fn main() {
let rt = Builder::new_multi_thread().enable_io().build().unwrap();
let rt2 = Builder::new_multi_thread().enable_io().build().unwrap();
rt.spawn(async {
let listener = TcpListener::bind(TCP_ENDPOINT).await.unwrap();
let (mut socket, _) = listener.accept().await.unwrap();
let (mut rd, mut wr) = socket.split();
while tokio::io::copy(&mut rd, &mut wr).await.is_ok() {}
});
// wait a bit so that the listener binds.
sleep(Duration::from_millis(100));
// create a channel to let the main thread know that all the messages were sent and received.
let (tx, mut rx) = oneshot::channel();
rt2.spawn(async {
let addr = TCP_ENDPOINT.parse().unwrap();
let socket = TcpSocket::new_v4().unwrap();
let mut stream = socket.connect(addr).await.unwrap();
let mut buff = [0; MSG_SIZE];
for _ in 0..NUM_MSGS {
let one_mega_random_bytes: Vec<u8> =
(0..MSG_SIZE).map(|_| rand::random::<u8>()).collect();
stream
.write_all(one_mega_random_bytes.as_slice())
.await
.unwrap();
stream.read(&mut buff).await.unwrap();
}
tx.send(()).unwrap();
});
loop {
// check that we're done.
match rx.try_recv() {
Err(oneshot::error::TryRecvError::Empty) => (),
Err(oneshot::error::TryRecvError::Closed) => panic!("channel got closed..."),
Ok(()) => break,
}
}
}
+18 -3
View File
@@ -12,12 +12,27 @@ 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]
#[test]
async fn test_has_second_test_attr() {}
@@ -1,10 +1,10 @@
error: the async keyword is missing from the function declaration
error: the `async` keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:4:1
|
4 | fn main_is_not_async() {}
| ^^
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`
--> $DIR/macros_invalid_input.rs:6:15
|
6 | #[tokio::main(foo)]
@@ -16,26 +16,56 @@ error: Must have specified ident
9 | #[tokio::main(threadpool::bar)]
| ^^^^^^^^^^^^^^^
error: the async keyword is missing from the function declaration
error: the `async` keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:13:1
|
13 | 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`
--> $DIR/macros_invalid_input.rs:15: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)]
15 | #[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`
--> $DIR/macros_invalid_input.rs:18:15
|
22 | #[test]
18 | #[tokio::test(foo = 123)]
| ^^^^^^^^^
error: Failed to parse value of `flavor` as string.
--> $DIR/macros_invalid_input.rs:21:24
|
21 | #[tokio::test(flavor = 123)]
| ^^^
error: No such runtime flavor `foo`. The runtime flavors are `current_thread` and `multi_thread`.
--> $DIR/macros_invalid_input.rs:24:24
|
24 | #[tokio::test(flavor = "foo")]
| ^^^^^
error: The `start_paused` option requires the `current_thread` runtime flavor. Use `#[tokio::test(flavor = "current_thread")]`
--> $DIR/macros_invalid_input.rs:27:55
|
27 | #[tokio::test(flavor = "multi_thread", start_paused = false)]
| ^^^^^
error: Failed to parse value of `worker_threads` as integer.
--> $DIR/macros_invalid_input.rs:30:57
|
30 | #[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")]`
--> $DIR/macros_invalid_input.rs:33:59
|
33 | #[tokio::test(flavor = "current_thread", worker_threads = 4)]
| ^
error: second test attribute is supplied
--> $DIR/macros_invalid_input.rs:37:1
|
37 | #[test]
| ^^^^^^^
+3
View File
@@ -2,6 +2,9 @@
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.compile_fail("tests/fail/macros_invalid_input.rs");
@@ -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(())
}
+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", "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);
}
}
+53 -11
View File
@@ -1,26 +1,19 @@
#![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};
fn cat() -> Command {
let mut me = env::current_exe().unwrap();
me.pop();
if me.ends_with("deps") {
me.pop();
}
me.push("test-cat");
let mut cmd = Command::new(me);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_test-cat"));
cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
cmd
}
@@ -148,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());
}
+21 -5
View File
@@ -1,3 +1,17 @@
# 1.1.0 (February 5, 2021)
- add `start_paused` option to macros ([#3492])
# 1.0.0 (December 23, 2020)
- track `tokio` 1.0 release.
# 0.3.1 (October 25, 2020)
### Fixed
- fix incorrect docs regarding `max_threads` option ([#3038])
# 0.3.0 (October 15, 2020)
- Track `tokio` 0.3 release.
@@ -38,9 +52,11 @@
- Initial release
[#2225]: https://github.com/tokio-rs/tokio/pull/2225
[#2177]: https://github.com/tokio-rs/tokio/pull/2177
[#2152]: https://github.com/tokio-rs/tokio/pull/2152
[#2038]: https://github.com/tokio-rs/tokio/pull/2038
[#2022]: https://github.com/tokio-rs/tokio/pull/2022
[#1954]: https://github.com/tokio-rs/tokio/pull/1954
[#2022]: https://github.com/tokio-rs/tokio/pull/2022
[#2038]: https://github.com/tokio-rs/tokio/pull/2038
[#2152]: https://github.com/tokio-rs/tokio/pull/2152
[#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
+4 -6
View File
@@ -2,23 +2,21 @@
name = "tokio-macros"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.3.x" git tag.
version = "0.3.0"
# - Create "tokio-macros-1.0.x" git tag.
version = "1.1.0"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-macros/0.3.0/tokio_macros"
documentation = "https://docs.rs/tokio-macros/1.1.0/tokio_macros"
description = """
Tokio's proc macros.
"""
categories = ["asynchronous"]
publish = false
[lib]
proc-macro = true
@@ -31,7 +29,7 @@ quote = "1"
syn = { version = "1.0.3", features = ["full"] }
[dev-dependencies]
tokio = { version = "0.3.0", path = "../tokio", features = ["full"] }
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
[package.metadata.docs.rs]
all-features = true
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2019 Tokio Contributors
Copyright (c) 2021 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+125 -67
View File
@@ -1,7 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;
#[derive(Clone, Copy, PartialEq)]
enum RuntimeFlavor {
@@ -25,6 +24,7 @@ impl RuntimeFlavor {
struct FinalConfig {
flavor: RuntimeFlavor,
worker_threads: Option<usize>,
start_paused: Option<bool>,
}
struct Configuration {
@@ -32,6 +32,8 @@ struct Configuration {
default_flavor: RuntimeFlavor,
flavor: Option<RuntimeFlavor>,
worker_threads: Option<(usize, Span)>,
start_paused: Option<(bool, Span)>,
is_test: bool,
}
impl Configuration {
@@ -44,6 +46,8 @@ impl Configuration {
},
flavor: None,
worker_threads: None,
start_paused: None,
is_test,
}
}
@@ -79,31 +83,67 @@ 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 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 {
flavor,
worker_threads,
start_paused,
})
}
}
@@ -113,12 +153,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,7 +169,17 @@ 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_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),
)),
}
}
@@ -140,24 +190,13 @@ fn parse_knobs(
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));
if input.sig.asyncness.take().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 {
@@ -169,17 +208,32 @@ fn parse_knobs(
}
match ident.unwrap().to_string().to_lowercase().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));
}
name => {
let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `max_threads`", name);
let msg = format!(
"Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`",
name,
);
return Err(syn::Error::new_spanned(namevalue, msg));
}
}
@@ -193,17 +247,23 @@ fn parse_knobs(
let name = ident.unwrap().to_string().to_lowercase();
let msg = match name.as_str() {
"threaded_scheduler" | "multi_thread" => {
format!("Set the runtime flavor with #[{}(flavor = \"multi_thread\")].", macro_name)
},
format!(
"Set the runtime flavor with #[{}(flavor = \"multi_thread\")].",
macro_name
)
}
"basic_scheduler" | "current_thread" | "single_threaded" => {
format!("Set the runtime flavor with #[{}(flavor = \"current_thread\")].", macro_name)
},
"flavor" | "worker_threads" => {
format!(
"Set the runtime flavor with #[{}(flavor = \"current_thread\")].",
macro_name
)
}
"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`", name)
}
};
return Err(syn::Error::new_spanned(path, msg));
}
@@ -229,27 +289,32 @@ fn parse_knobs(
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;
input.block = syn::parse_quote! {
{
#rt
.enable_all()
.build()
.unwrap()
.block_on(async #body)
}
};
let result = quote! {
#header
#(#attrs)*
#vis #sig {
#rt
.enable_all()
.build()
.unwrap()
.block_on(async { #body })
}
#input
};
Ok(result.into())
@@ -283,12 +348,5 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool)
}
}
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())
}
+65 -27
View File
@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-macros/0.3.0")]
#![allow(clippy::needless_doctest_main)]
#![warn(
missing_debug_implementations,
@@ -24,8 +23,8 @@ mod select;
use proc_macro::TokenStream;
/// Marks async function to be executed by the selected runtime. This macro helps
/// set up a `Runtime` without requiring the user to use
/// Marks async function to be executed by the selected runtime. This macro
/// helps set up a `Runtime` without requiring the user to use
/// [Runtime](../tokio/runtime/struct.Runtime.html) or
/// [Builder](../tokio/runtime/struct.Builder.html) directly.
///
@@ -35,6 +34,12 @@ use proc_macro::TokenStream;
/// [Builder](../tokio/runtime/struct.Builder.html), which provides a more
/// powerful interface.
///
/// Note: This macro can be used on any function and not just the `main`
/// function. Using it on a non-main function makes the function behave as if it
/// was synchronous by starting a new runtime each time it is called. If the
/// function is called often, it is preferable to create the runtime using the
/// runtime builder so the runtime can be reused across calls.
///
/// # Multi-threaded runtime
///
/// To use the multi-threaded runtime, the macro can be configured using
@@ -47,6 +52,9 @@ use proc_macro::TokenStream;
/// The `worker_threads` option configures the number of worker threads, and
/// defaults to the number of cpus on the system. This is the default flavor.
///
/// Note: The multi-threaded runtime requires the `rt-multi-thread` feature
/// flag.
///
/// # Current thread runtime
///
/// To use the single-threaded runtime known as the `current_thread` runtime,
@@ -135,12 +143,38 @@ use proc_macro::TokenStream;
/// }
/// ```
///
/// ### Configure the runtime to start with time paused
///
/// ```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.
///
/// ### NOTE:
///
/// If you rename the tokio crate in your dependencies this macro will not work.
/// If you must rename the 0.2 version of tokio because you're also using the
/// 0.1 version of tokio, you _must_ make the tokio 0.2 crate available as
/// `tokio` in the module where this macro is expanded.
/// 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]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
@@ -182,11 +216,10 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
///
/// ### NOTE:
///
/// If you rename the tokio crate in your dependencies this macro
/// will not work. If you must rename the 0.2 version of tokio because
/// you're also using the 0.1 version of tokio, you _must_ make the
/// tokio 0.2 crate available as `tokio` in the module where this
/// macro is expanded.
/// 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]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
@@ -208,7 +241,7 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
///
/// ### Using default
///
/// The default test runtime is multi-threaded.
/// The default test runtime is single-threaded.
///
/// ```no_run
/// #[tokio::test]
@@ -217,13 +250,23 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
/// }
/// ```
///
/// ### Configure the runtime to start with time paused
///
/// ```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.
///
/// ### NOTE:
///
/// If you rename the tokio crate in your dependencies this macro
/// will not work. If you must rename the 0.2 version of tokio because
/// you're also using the 0.1 version of tokio, you _must_ make the
/// tokio 0.2 crate available as `tokio` in the module where this
/// macro is expanded.
/// 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(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(args, item, true)
@@ -231,10 +274,6 @@ pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
/// Marks async function to be executed by runtime, suitable to test environment
///
/// ## Options:
///
/// - `max_threads=n` - Sets max threads to `n`.
///
/// ## Usage
///
/// ```no_run
@@ -246,11 +285,10 @@ pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
///
/// ### NOTE:
///
/// If you rename the tokio crate in your dependencies this macro
/// will not work. If you must rename the 0.2 version of tokio because
/// you're also using the 0.1 version of tokio, you _must_ make the
/// tokio 0.2 crate available as `tokio` in the module where this
/// macro is expanded.
/// 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)
+56
View File
@@ -0,0 +1,56 @@
# 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])
[#3378]: https://github.com/tokio-rs/tokio/pull/3378
# 0.1.1 (January 4, 2021)
Added
- add `Stream` wrappers ([#3343])
Fixed
- move `async-stream` to `dev-dependencies` ([#3366])
[#3366]: https://github.com/tokio-rs/tokio/pull/3366
[#3343]: https://github.com/tokio-rs/tokio/pull/3343
# 0.1.0 (December 23, 2020)
- Initial release
+46
View File
@@ -0,0 +1,46 @@
[package]
name = "tokio-stream"
# When releasing to crates.io:
# - Remove path dependencies
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-stream-0.1.x" git tag.
version = "0.1.5"
edition = "2018"
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.5/tokio_stream"
description = """
Utilities to work with `Stream` and `tokio`.
"""
categories = ["asynchronous"]
[features]
default = ["time"]
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.2.0", path = "../tokio", features = ["sync"] }
tokio-util = { version = "0.6.3", optional = true }
[dev-dependencies]
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 = "1"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2021 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::marker::PhantomData;
use core::pin::Pin;
@@ -24,7 +24,7 @@ unsafe impl<T> Sync for Empty<T> {}
/// Basic usage:
///
/// ```
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::pin::Pin;
use core::task::{Context, Poll};
@@ -8,6 +8,7 @@ use core::task::{Context, Poll};
#[must_use = "streams do nothing unless polled"]
pub struct Iter<I> {
iter: I,
yield_amt: usize,
}
impl<I> Unpin for Iter<I> {}
@@ -20,7 +21,7 @@ impl<I> Unpin for Iter<I> {}
///
/// ```
/// # async fn dox() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(vec![17, 19]);
///
@@ -35,6 +36,7 @@ where
{
Iter {
iter: i.into_iter(),
yield_amt: 0,
}
}
@@ -45,9 +47,18 @@ where
type Item = I::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<I::Item>> {
let coop = ready!(crate::coop::poll_proceed(cx));
coop.made_progress();
Poll::Ready(self.iter.next())
// TODO: add coop back
if self.yield_amt >= 32 {
self.yield_amt = 0;
cx.waker().wake_by_ref();
Poll::Pending
} else {
self.yield_amt += 1;
Poll::Ready(self.iter.next())
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
+98
View File
@@ -0,0 +1,98 @@
#![allow(
clippy::cognitive_complexity,
clippy::large_enum_variant,
clippy::needless_doctest_main
)]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![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))
))]
//! Stream utilities for Tokio.
//!
//! A `Stream` is an asynchronous sequence of values. It can be thought of as
//! an asynchronous version of the standard library's `Iterator` trait.
//!
//! This crate provides helpers to work with them. For examples of usage and a more in-depth
//! description of streams you can also refer to the [streams
//! tutorial](https://tokio.rs/tokio/tutorial/streams) on the tokio website.
//!
//! # Iterating over a Stream
//!
//! Due to similarities with the standard library's `Iterator` trait, some new
//! users may assume that they can use `for in` syntax to iterate over a
//! `Stream`, but this is unfortunately not possible. Instead, you can use a
//! `while let` loop as follows:
//!
//! ```rust
//! use tokio_stream::{self as stream, StreamExt};
//!
//! #[tokio::main]
//! async fn main() {
//! let mut stream = stream::iter(vec![0, 1, 2]);
//!
//! while let Some(value) = stream.next().await {
//! println!("Got {}", value);
//! }
//! }
//! ```
//!
//! # Returning a Stream from a function
//!
//! A common way to stream values from a function is to pass in the sender
//! half of a channel and use the receiver as the stream. This requires awaiting
//! both futures to ensure progress is made. Another alternative is the
//! [async-stream] crate, which contains macros that provide a `yield` keyword
//! and allow you to return an `impl Stream`.
//!
//! [async-stream]: https://docs.rs/async-stream
//!
//! # Conversion to and from AsyncRead/AsyncWrite
//!
//! It is often desirable to convert a `Stream` into an [`AsyncRead`],
//! especially when dealing with plaintext formats streamed over the network.
//! The opposite conversion from an [`AsyncRead`] into a `Stream` is also
//! another commonly required feature. To enable these conversions,
//! [`tokio-util`] provides the [`StreamReader`] and [`ReaderStream`]
//! types when the io feature is enabled.
//!
//! [`tokio-util`]: https://docs.rs/tokio-util/0.4/tokio_util/codec/index.html
//! [`tokio::io`]: https://docs.rs/tokio/1.0/tokio/io/index.html
//! [`AsyncRead`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncRead.html
//! [`AsyncWrite`]: https://docs.rs/tokio/1.0/tokio/io/trait.AsyncWrite.html
//! [`ReaderStream`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.ReaderStream.html
//! [`StreamReader`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.StreamReader.html
#[macro_use]
mod macros;
pub mod wrappers;
mod stream_ext;
pub use stream_ext::{collect::FromStream, StreamExt};
mod empty;
pub use empty::{empty, Empty};
mod iter;
pub use iter::{iter, Iter};
mod once;
pub use once::{once, Once};
mod pending;
pub use pending::{pending, Pending};
mod stream_map;
pub use stream_map::StreamMap;
#[doc(no_inline)]
pub use futures_core::Stream;
+68
View File
@@ -0,0 +1,68 @@
macro_rules! cfg_fs {
($($item:item)*) => {
$(
#[cfg(feature = "fs")]
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
$item
)*
}
}
macro_rules! cfg_io_util {
($($item:item)*) => {
$(
#[cfg(feature = "io-util")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
$item
)*
}
}
macro_rules! cfg_net {
($($item:item)*) => {
$(
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
$item
)*
}
}
macro_rules! cfg_time {
($($item:item)*) => {
$(
#[cfg(feature = "time")]
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
$item
)*
}
}
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 {
std::task::Poll::Ready(t) => t,
std::task::Poll::Pending => return std::task::Poll::Pending,
}
};
}
@@ -1,4 +1,4 @@
use crate::stream::{self, Iter, Stream};
use crate::{Iter, Stream};
use core::option;
use core::pin::Pin;
@@ -20,7 +20,7 @@ impl<I> Unpin for Once<I> {}
/// # Examples
///
/// ```
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -35,7 +35,7 @@ impl<I> Unpin for Once<I> {}
/// ```
pub fn once<T>(value: T) -> Once<T> {
Once {
iter: stream::iter(Some(value).into_iter()),
iter: crate::iter(Some(value).into_iter()),
}
}
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::marker::PhantomData;
use core::pin::Pin;
@@ -16,7 +16,7 @@ unsafe impl<T> Sync for Pending<T> {}
/// Creates a stream that is never ready
///
/// The returned stream is never ready. Attempting to call
/// [`next()`](crate::stream::StreamExt::next) will never complete. Use
/// [`next()`](crate::StreamExt::next) will never complete. Use
/// [`stream::empty()`](super::empty()) to obtain a stream that is is
/// immediately empty but returns no values.
///
@@ -25,7 +25,7 @@ unsafe impl<T> Sync for Pending<T> {}
/// Basic usage:
///
/// ```no_run
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -1,57 +1,4 @@
//! Stream utilities for Tokio.
//!
//! A `Stream` is an asynchronous sequence of values. It can be thought of as
//! an asynchronous version of the standard library's `Iterator` trait.
//!
//! This module provides helpers to work with them. For examples of usage and a more in-depth
//! description of streams you can also refer to the [streams
//! tutorial](https://tokio.rs/tokio/tutorial/streams) on the tokio website.
//!
//! # Iterating over a Stream
//!
//! Due to similarities with the standard library's `Iterator` trait, some new
//! users may assume that they can use `for in` syntax to iterate over a
//! `Stream`, but this is unfortunately not possible. Instead, you can use a
//! `while let` loop as follows:
//!
//! ```rust
//! use tokio::stream::{self, StreamExt};
//!
//! #[tokio::main]
//! async fn main() {
//! let mut stream = stream::iter(vec![0, 1, 2]);
//!
//! while let Some(value) = stream.next().await {
//! println!("Got {}", value);
//! }
//! }
//! ```
//!
//! # Returning a Stream from a function
//!
//! A common way to stream values from a function is to pass in the sender
//! half of a channel and use the receiver as the stream. This requires awaiting
//! both futures to ensure progress is made. Another alternative is the
//! [async-stream] crate, which contains macros that provide a `yield` keyword
//! and allow you to return an `impl Stream`.
//!
//! [async-stream]: https://docs.rs/async-stream
//!
//! # Conversion to and from AsyncRead/AsyncWrite
//!
//! It is often desirable to convert a `Stream` into an [`AsyncRead`],
//! especially when dealing with plaintext formats streamed over the network.
//! The opposite conversion from an [`AsyncRead`] into a `Stream` is also
//! another commonly required feature. To enable these conversions,
//! [`tokio-util`] provides the [`StreamReader`] and [`ReaderStream`]
//! types when the io feature is enabled.
//!
//! [tokio-util]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
//! [`tokio::io`]: crate::io
//! [`AsyncRead`]: crate::io::AsyncRead
//! [`AsyncWrite`]: crate::io::AsyncWrite
//! [`ReaderStream`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.ReaderStream.html
//! [`StreamReader`]: https://docs.rs/tokio-util/0.4/tokio_util/io/struct.StreamReader.html
use futures_core::Stream;
mod all;
use all::AllFuture;
@@ -62,12 +9,8 @@ use any::AnyFuture;
mod chain;
use chain::Chain;
mod collect;
use collect::Collect;
pub use collect::FromStream;
mod empty;
pub use empty::{empty, Empty};
pub(crate) mod collect;
use collect::{Collect, FromStream};
mod filter;
use filter::Filter;
@@ -81,9 +24,6 @@ use fold::FoldFuture;
mod fuse;
use fuse::Fuse;
mod iter;
pub use iter::{iter, Iter};
mod map;
use map::Map;
@@ -93,15 +33,6 @@ use merge::Merge;
mod next;
use next::Next;
mod once;
pub use once::{once, Once};
mod pending;
pub use pending::{pending, Pending};
mod stream_map;
pub use stream_map::StreamMap;
mod skip;
use skip::Skip;
@@ -120,16 +51,44 @@ use take_while::TakeWhile;
cfg_time! {
mod timeout;
use timeout::Timeout;
use crate::time::Duration;
use tokio::time::Duration;
mod throttle;
use crate::stream::throttle::{throttle, Throttle};
use throttle::{throttle, Throttle};
}
#[doc(no_inline)]
pub use futures_core::Stream;
/// An extension trait for `Stream`s that provides a variety of convenient
/// combinator functions.
/// An extension trait for the [`Stream`] trait that provides a variety of
/// convenient combinator functions.
///
/// Be aware that the `Stream` trait in Tokio is a re-export of the trait found
/// in the [futures] crate, however both Tokio and futures provide separate
/// `StreamExt` utility traits, and some utilities are only available on one of
/// these traits. Click [here][futures-StreamExt] to see the other `StreamExt`
/// trait in the futures crate.
///
/// If you need utilities from both `StreamExt` traits, you should prefer to
/// import one of them, and use the other through the fully qualified call
/// syntax. For example:
/// ```
/// // import one of the traits:
/// use futures::stream::StreamExt;
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() {
///
/// let a = tokio_stream::iter(vec![1, 3, 5]);
/// let b = tokio_stream::iter(vec![2, 4, 6]);
///
/// // use the fully qualified call syntax for the other trait:
/// let merged = tokio_stream::StreamExt::merge(a, b);
///
/// // use normal call notation for futures::stream::StreamExt::collect
/// let output: Vec<_> = merged.collect().await;
/// assert_eq!(output, vec![1, 2, 3, 4, 5, 6]);
/// # }
/// ```
///
/// [`Stream`]: crate::Stream
/// [futures]: https://docs.rs/futures
/// [futures-StreamExt]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html
pub trait StreamExt: Stream {
/// Consumes and returns the next value in the stream or `None` if the
/// stream is finished.
@@ -152,7 +111,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(1..=3);
///
@@ -188,7 +147,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(vec![Ok(1), Ok(2), Err("nope")]);
///
@@ -220,7 +179,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let stream = stream::iter(1..=3);
/// let mut stream = stream.map(|x| x + 3);
@@ -253,16 +212,17 @@ pub trait StreamExt: Stream {
///
/// For merging multiple streams, consider using [`StreamMap`] instead.
///
/// [`StreamMap`]: crate::stream::StreamMap
/// [`StreamMap`]: crate::StreamMap
///
/// # Examples
///
/// ```
/// use tokio::stream::StreamExt;
/// use tokio_stream::{StreamExt, Stream};
/// use tokio::sync::mpsc;
/// use tokio::time;
///
/// use std::time::Duration;
/// use std::pin::Pin;
///
/// # /*
/// #[tokio::main]
@@ -270,8 +230,21 @@ pub trait StreamExt: Stream {
/// # #[tokio::main(flavor = "current_thread")]
/// async fn main() {
/// # time::pause();
/// let (tx1, rx1) = mpsc::channel(10);
/// let (tx2, rx2) = mpsc::channel(10);
/// let (tx1, mut rx1) = mpsc::channel::<usize>(10);
/// let (tx2, mut rx2) = mpsc::channel::<usize>(10);
///
/// // Convert the channels to a `Stream`.
/// let rx1 = Box::pin(async_stream::stream! {
/// while let Some(item) = rx1.recv().await {
/// yield item;
/// }
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
///
/// let rx2 = Box::pin(async_stream::stream! {
/// while let Some(item) = rx2.recv().await {
/// yield item;
/// }
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
///
/// let mut rx = rx1.merge(rx2);
///
@@ -334,7 +307,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let stream = stream::iter(1..=8);
/// let mut evens = stream.filter(|x| x % 2 == 0);
@@ -370,7 +343,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let stream = stream::iter(1..=8);
/// let mut evens = stream.filter_map(|x| {
@@ -402,7 +375,7 @@ pub trait StreamExt: Stream {
/// # Examples
///
/// ```
/// use tokio::stream::{Stream, StreamExt};
/// use tokio_stream::{Stream, StreamExt};
///
/// use std::pin::Pin;
/// use std::task::{Context, Poll};
@@ -467,7 +440,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(1..=10).take(3);
///
@@ -496,7 +469,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(1..=10).take_while(|x| *x <= 3);
///
@@ -522,7 +495,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let mut stream = stream::iter(1..=10).skip(7);
///
@@ -553,7 +526,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
/// let mut stream = stream::iter(vec![1,2,3,4,1]).skip_while(|x| *x < 3);
///
/// assert_eq!(Some(3), stream.next().await);
@@ -596,7 +569,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let a = [1, 2, 3];
///
@@ -611,7 +584,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let a = [1, 2, 3];
///
@@ -655,7 +628,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let a = [1, 2, 3];
///
@@ -670,7 +643,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// let a = [1, 2, 3];
///
@@ -699,7 +672,7 @@ pub trait StreamExt: Stream {
/// # Examples
///
/// ```
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -739,7 +712,7 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, *};
/// use tokio_stream::{self as stream, *};
///
/// let s = stream::iter(vec![1u8, 2, 3]);
/// let sum = s.fold(0, |acc, x| acc + x).await;
@@ -766,7 +739,9 @@ pub trait StreamExt: Stream {
/// `collect` streams all values, awaiting as needed. Values are pushed into
/// a collection. A number of different target collection types are
/// supported, including [`Vec`](std::vec::Vec),
/// [`String`](std::string::String), and [`Bytes`](bytes::Bytes).
/// [`String`](std::string::String), and [`Bytes`].
///
/// [`Bytes`]: https://docs.rs/bytes/0.6.0/bytes/struct.Bytes.html
///
/// # `Result`
///
@@ -785,7 +760,7 @@ pub trait StreamExt: Stream {
/// Basic usage:
///
/// ```
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -802,7 +777,7 @@ pub trait StreamExt: Stream {
/// Collecting a stream of `Result` values
///
/// ```
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
///
/// #[tokio::main]
/// async fn main() {
@@ -858,11 +833,12 @@ pub trait StreamExt: Stream {
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, StreamExt};
/// use tokio_stream::{self as stream, StreamExt};
/// use std::time::Duration;
/// # let int_stream = stream::iter(1..=3);
///
/// let mut int_stream = int_stream.timeout(Duration::from_secs(1));
/// let int_stream = int_stream.timeout(Duration::from_secs(1));
/// tokio::pin!(int_stream);
///
/// // When no items time out, we get the 3 elements in succession:
/// assert_eq!(int_stream.try_next().await, Ok(Some(1)));
@@ -903,10 +879,11 @@ pub trait StreamExt: Stream {
/// Create a throttled stream.
/// ```rust,no_run
/// use std::time::Duration;
/// use tokio::stream::StreamExt;
/// use tokio_stream::StreamExt;
///
/// # async fn dox() {
/// let mut item_stream = futures::stream::repeat("one").throttle(Duration::from_secs(2));
/// let item_stream = futures::stream::repeat("one").throttle(Duration::from_secs(2));
/// tokio::pin!(item_stream);
///
/// loop {
/// // The string will be produced at most every 2 seconds
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -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
}
}
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -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
}
}
@@ -1,4 +1,5 @@
use crate::stream::{Fuse, Stream};
use crate::stream_ext::Fuse;
use crate::Stream;
use core::pin::Pin;
use core::task::{Context, Poll};
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -26,7 +26,7 @@ pin_project! {
}
}
/// Convert from a [`Stream`](crate::stream::Stream).
/// Convert from a [`Stream`](crate::Stream).
///
/// This trait is not intended to be used directly. Instead, call
/// [`StreamExt::collect()`](super::StreamExt::collect).
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use pin_project_lite::pin_project;
use std::pin::Pin;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,4 +1,5 @@
use crate::stream::{Fuse, Stream};
use crate::stream_ext::Fuse;
use crate::Stream;
use core::pin::Pin;
use core::task::{Context, Poll};
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::cmp;
use core::fmt;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use core::fmt;
use core::pin::Pin;
@@ -1,7 +1,7 @@
//! Slow down a stream by enforcing a delay between items.
use crate::stream::Stream;
use crate::time::{Duration, Instant, Sleep};
use crate::Stream;
use tokio::time::{Duration, Instant, Sleep};
use std::future::Future;
use std::marker::Unpin;
@@ -14,14 +14,8 @@ pub(super) fn throttle<T>(duration: Duration, stream: T) -> Throttle<T>
where
T: Stream,
{
let delay = if duration == Duration::from_millis(0) {
None
} else {
Some(Sleep::new_timeout(Instant::now() + duration, duration))
};
Throttle {
delay,
delay: tokio::time::sleep_until(Instant::now() + duration),
duration,
has_delayed: true,
stream,
@@ -29,12 +23,13 @@ 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> {
// `None` when duration is zero.
delay: Option<Sleep>,
#[pin]
delay: Sleep,
duration: Duration,
// Set to true when `delay` has returned ready, but `stream` hasn't.
@@ -75,23 +70,29 @@ impl<T: Unpin> Throttle<T> {
impl<T: Stream> Stream for Throttle<T> {
type Item = T::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
if !self.has_delayed && self.delay.is_some() {
ready!(Pin::new(self.as_mut().project().delay.as_mut().unwrap()).poll(cx));
*self.as_mut().project().has_delayed = true;
fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
let mut me = self.project();
let dur = *me.duration;
if !*me.has_delayed && !is_zero(dur) {
ready!(me.delay.as_mut().poll(cx));
*me.has_delayed = true;
}
let value = ready!(self.as_mut().project().stream.poll_next(cx));
let value = ready!(me.stream.poll_next(cx));
if value.is_some() {
let dur = self.duration;
if let Some(ref mut delay) = self.as_mut().project().delay {
delay.reset(Instant::now() + dur);
if !is_zero(dur) {
me.delay.reset(Instant::now() + dur);
}
*self.as_mut().project().has_delayed = false;
*me.has_delayed = false;
}
Poll::Ready(value)
}
}
fn is_zero(dur: Duration) -> bool {
dur == Duration::from_millis(0)
}
@@ -1,10 +1,12 @@
use crate::stream::{Fuse, Stream};
use crate::time::{error::Elapsed, Instant, Sleep};
use crate::stream_ext::Fuse;
use crate::Stream;
use tokio::time::{Instant, Sleep};
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;
use std::fmt;
use std::time::Duration;
pin_project! {
@@ -14,16 +16,21 @@ pin_project! {
pub struct Timeout<S> {
#[pin]
stream: Fuse<S>,
#[pin]
deadline: Sleep,
duration: Duration,
poll_deadline: bool,
}
}
/// Error returned by `Timeout`.
#[derive(Debug, PartialEq)]
pub struct Elapsed(());
impl<S: Stream> Timeout<S> {
pub(super) fn new(stream: S, duration: Duration) -> Self {
let next = Instant::now() + duration;
let deadline = Sleep::new_timeout(next, duration);
let deadline = tokio::time::sleep_until(next);
Timeout {
stream: Fuse::new(stream),
@@ -37,22 +44,24 @@ impl<S: Stream> Timeout<S> {
impl<S: Stream> Stream for Timeout<S> {
type Item = Result<S::Item, Elapsed>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.as_mut().project().stream.poll_next(cx) {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let me = self.project();
match me.stream.poll_next(cx) {
Poll::Ready(v) => {
if v.is_some() {
let next = Instant::now() + self.duration;
self.as_mut().project().deadline.reset(next);
*self.as_mut().project().poll_deadline = true;
let next = Instant::now() + *me.duration;
me.deadline.reset(next);
*me.poll_deadline = true;
}
return Poll::Ready(v.map(Ok));
}
Poll::Pending => {}
};
if self.poll_deadline {
ready!(Pin::new(self.as_mut().project().deadline).poll(cx));
*self.as_mut().project().poll_deadline = false;
if *me.poll_deadline {
ready!(me.deadline.poll(cx));
*me.poll_deadline = false;
return Poll::Ready(Some(Err(Elapsed::new())));
}
@@ -63,3 +72,25 @@ impl<S: Stream> Stream for Timeout<S> {
self.stream.size_hint()
}
}
// ===== impl Elapsed =====
impl Elapsed {
pub(crate) fn new() -> Self {
Elapsed(())
}
}
impl fmt::Display for Elapsed {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"deadline has elapsed".fmt(fmt)
}
}
impl std::error::Error for Elapsed {}
impl From<Elapsed> for std::io::Error {
fn from(_err: Elapsed) -> std::io::Error {
std::io::ErrorKind::TimedOut.into()
}
}
@@ -1,4 +1,5 @@
use crate::stream::{Next, Stream};
use crate::stream_ext::Next;
use crate::Stream;
use core::future::Future;
use core::marker::PhantomPinned;
@@ -1,4 +1,4 @@
use crate::stream::Stream;
use crate::Stream;
use std::borrow::Borrow;
use std::hash::Hash;
@@ -42,9 +42,9 @@ use std::task::{Context, Poll};
/// to be merged, it may be advisable to use tasks sending values on a shared
/// [`mpsc`] channel.
///
/// [`StreamExt::merge`]: crate::stream::StreamExt::merge
/// [`mpsc`]: crate::sync::mpsc
/// [`pin!`]: macro@pin
/// [`StreamExt::merge`]: crate::StreamExt::merge
/// [`mpsc`]: https://docs.rs/tokio/1.0/tokio/sync/mpsc/index.html
/// [`pin!`]: https://docs.rs/tokio/1.0/tokio/macro.pin.html
/// [`Box::pin`]: std::boxed::Box::pin
///
/// # Examples
@@ -52,13 +52,27 @@ use std::task::{Context, Poll};
/// Merging two streams, then remove them after receiving the first value
///
/// ```
/// use tokio::stream::{StreamExt, StreamMap};
/// use tokio_stream::{StreamExt, StreamMap, Stream};
/// use tokio::sync::mpsc;
/// use std::pin::Pin;
///
/// #[tokio::main]
/// async fn main() {
/// let (tx1, rx1) = mpsc::channel(10);
/// let (tx2, rx2) = mpsc::channel(10);
/// let (tx1, mut rx1) = mpsc::channel::<usize>(10);
/// let (tx2, mut rx2) = mpsc::channel::<usize>(10);
///
/// // Convert the channels to a `Stream`.
/// let rx1 = Box::pin(async_stream::stream! {
/// while let Some(item) = rx1.recv().await {
/// yield item;
/// }
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
///
/// let rx2 = Box::pin(async_stream::stream! {
/// while let Some(item) = rx2.recv().await {
/// yield item;
/// }
/// }) as Pin<Box<dyn Stream<Item = usize> + Send>>;
///
/// tokio::spawn(async move {
/// tx1.send(1).await.unwrap();
@@ -103,7 +117,7 @@ use std::task::{Context, Poll};
/// sent to the client over a socket.
///
/// ```no_run
/// use tokio::stream::{Stream, StreamExt, StreamMap};
/// use tokio_stream::{Stream, StreamExt, StreamMap};
///
/// enum Command {
/// Join(String),
@@ -112,13 +126,13 @@ use std::task::{Context, Poll};
///
/// fn commands() -> impl Stream<Item = Command> {
/// // Streams in user commands by parsing `stdin`.
/// # tokio::stream::pending()
/// # tokio_stream::pending()
/// }
///
/// // Join a channel, returns a stream of messages received on the channel.
/// fn join(channel: &str) -> impl Stream<Item = String> + Unpin {
/// // left as an exercise to the reader
/// # tokio::stream::pending()
/// # tokio_stream::pending()
/// }
///
/// #[tokio::main]
@@ -156,7 +170,7 @@ use std::task::{Context, Poll};
/// }
/// }
/// ```
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct StreamMap<K, V> {
/// Streams stored in the map
entries: Vec<(K, V)>,
@@ -170,7 +184,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -193,7 +207,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -217,7 +231,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, Pending};
/// use tokio_stream::{StreamMap, Pending};
///
/// let map: StreamMap<&str, Pending<()>> = StreamMap::new();
/// ```
@@ -233,7 +247,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, Pending};
/// use tokio_stream::{StreamMap, Pending};
///
/// let map: StreamMap<&str, Pending<()>> = StreamMap::with_capacity(10);
/// ```
@@ -250,7 +264,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -273,7 +287,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -296,7 +310,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -320,7 +334,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, Pending};
/// use tokio_stream::{StreamMap, Pending};
///
/// let map: StreamMap<i32, Pending<()>> = StreamMap::with_capacity(100);
/// assert!(map.capacity() >= 100);
@@ -334,7 +348,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut a = StreamMap::new();
/// assert_eq!(a.len(), 0);
@@ -367,7 +381,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut a = StreamMap::new();
/// a.insert(1, pending::<i32>());
@@ -388,7 +402,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
///
@@ -416,7 +430,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
/// map.insert(1, pending::<i32>());
@@ -445,7 +459,7 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use tokio::stream::{StreamMap, pending};
/// use tokio_stream::{StreamMap, pending};
///
/// let mut map = StreamMap::new();
/// map.insert(1, pending::<i32>());
@@ -476,7 +490,7 @@ where
fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll<Option<(usize, V::Item)>> {
use Poll::*;
let start = crate::util::thread_rng_n(self.entries.len() as u32) as usize;
let start = self::rand::thread_rng_n(self.entries.len() as u32) as usize;
let mut idx = start;
for _ in 0..self.entries.len() {
@@ -513,6 +527,12 @@ where
}
}
impl<K, V> Default for StreamMap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> Stream for StreamMap<K, V>
where
K: Clone + Unpin,
@@ -547,3 +567,98 @@ where
ret
}
}
mod rand {
use std::cell::Cell;
mod loom {
#[cfg(not(loom))]
pub(crate) mod rand {
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash, Hasher};
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering::Relaxed;
static COUNTER: AtomicU32 = AtomicU32::new(1);
pub(crate) fn seed() -> u64 {
let rand_state = RandomState::new();
let mut hasher = rand_state.build_hasher();
// Hash some unique-ish data to generate some new state
COUNTER.fetch_add(1, Relaxed).hash(&mut hasher);
// Get the seed
hasher.finish()
}
}
#[cfg(loom)]
pub(crate) mod rand {
pub(crate) fn seed() -> u64 {
1
}
}
}
/// 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
/// This generator passes the SmallCrush suite, part of TestU01 framework:
/// http://simul.iro.umontreal.ca/testu01/tu01.html
#[derive(Debug)]
pub(crate) struct FastRand {
one: Cell<u32>,
two: Cell<u32>,
}
impl FastRand {
/// Initialize a new, thread-local, fast random number generator.
pub(crate) fn new(seed: u64) -> FastRand {
let one = (seed >> 32) as u32;
let mut two = seed as u32;
if two == 0 {
// This value cannot be zero
two = 1;
}
FastRand {
one: Cell::new(one),
two: Cell::new(two),
}
}
pub(crate) fn fastrand_n(&self, n: u32) -> u32 {
// This is similar to fastrand() % n, but faster.
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
let mul = (self.fastrand() as u64).wrapping_mul(n as u64);
(mul >> 32) as u32
}
fn fastrand(&self) -> u32 {
let mut s1 = self.one.get();
let s0 = self.two.get();
s1 ^= s1 << 17;
s1 = s1 ^ s0 ^ s1 >> 7 ^ s0 >> 16;
self.one.set(s0);
self.two.set(s1);
s0.wrapping_add(s1)
}
}
// Used by `StreamMap`
pub(crate) fn thread_rng_n(n: u32) -> u32 {
thread_local! {
static THREAD_RNG: FastRand = FastRand::new(loom::rand::seed());
}
THREAD_RNG.with(|rng| rng.fastrand_n(n))
}
}
+71
View File
@@ -0,0 +1,71 @@
//! Wrappers for Tokio types that implement `Stream`.
//!
#![cfg_attr(
unix,
doc = "You are viewing documentation built under unix. To view windows-specific wrappers, change to the `x86_64-pc-windows-msvc` platform."
)]
#![cfg_attr(
windows,
doc = "You are viewing documentation built under windows. To view unix-specific wrappers, change to the `x86_64-unknown-linux-gnu` platform."
)]
/// 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(windows)]
mod signal_windows;
#[cfg(windows)]
pub use signal_windows::{CtrlCStream, CtrlBreakStream};
}
cfg_time! {
mod interval;
pub use interval::IntervalStream;
}
cfg_net! {
mod tcp_listener;
pub use tcp_listener::TcpListenerStream;
#[cfg(unix)]
mod unix_listener;
#[cfg(unix)]
pub use unix_listener::UnixListenerStream;
}
cfg_io_util! {
mod split;
pub use split::SplitStream;
mod lines;
pub use lines::LinesStream;
}
cfg_fs! {
mod read_dir;
pub use read_dir::ReadDirStream;
}
+63
View File
@@ -0,0 +1,63 @@
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<(Result<T, RecvError>, Receiver<T>)>,
}
/// An error returned from the inner stream of a [`BroadcastStream`].
#[derive(Debug, PartialEq)]
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),
}
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()
}
}
+50
View File
@@ -0,0 +1,50 @@
use crate::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::time::{Instant, Interval};
/// A wrapper around [`Interval`] that implements [`Stream`].
///
/// [`Interval`]: struct@tokio::time::Interval
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
pub struct IntervalStream {
inner: Interval,
}
impl IntervalStream {
/// Create a new `IntervalStream`.
pub fn new(interval: Interval) -> Self {
Self { inner: interval }
}
/// Get back the inner `Interval`.
pub fn into_inner(self) -> Interval {
self.inner
}
}
impl Stream for IntervalStream {
type Item = Instant;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
self.inner.poll_tick(cx).map(Some)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(std::usize::MAX, None)
}
}
impl AsRef<Interval> for IntervalStream {
fn as_ref(&self) -> &Interval {
&self.inner
}
}
impl AsMut<Interval> for IntervalStream {
fn as_mut(&mut self) -> &mut Interval {
&mut self.inner
}
}
+60
View File
@@ -0,0 +1,60 @@
use crate::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, Lines};
pin_project! {
/// A wrapper around [`tokio::io::Lines`] that implements [`Stream`].
///
/// [`tokio::io::Lines`]: struct@tokio::io::Lines
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct LinesStream<R> {
#[pin]
inner: Lines<R>,
}
}
impl<R> LinesStream<R> {
/// Create a new `LinesStream`.
pub fn new(lines: Lines<R>) -> Self {
Self { inner: lines }
}
/// Get back the inner `Lines`.
pub fn into_inner(self) -> Lines<R> {
self.inner
}
/// Obtain a pinned reference to the inner `Lines<R>`.
#[allow(clippy::wrong_self_convention)] // https://github.com/rust-lang/rust-clippy/issues/4546
pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Lines<R>> {
self.project().inner
}
}
impl<R: AsyncBufRead> Stream for LinesStream<R> {
type Item = io::Result<String>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.project()
.inner
.poll_next_line(cx)
.map(Result::transpose)
}
}
impl<R> AsRef<Lines<R>> for LinesStream<R> {
fn as_ref(&self) -> &Lines<R> {
&self.inner
}
}
impl<R> AsMut<Lines<R>> for LinesStream<R> {
fn as_mut(&mut self) -> &mut Lines<R> {
&mut self.inner
}
}
+59
View File
@@ -0,0 +1,59 @@
use crate::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::mpsc::Receiver;
/// A wrapper around [`tokio::sync::mpsc::Receiver`] that implements [`Stream`].
///
/// [`tokio::sync::mpsc::Receiver`]: struct@tokio::sync::mpsc::Receiver
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
pub struct ReceiverStream<T> {
inner: Receiver<T>,
}
impl<T> ReceiverStream<T> {
/// Create a new `ReceiverStream`.
pub fn new(recv: Receiver<T>) -> Self {
Self { inner: recv }
}
/// Get back the inner `Receiver`.
pub fn into_inner(self) -> Receiver<T> {
self.inner
}
/// Closes the receiving half of a channel without dropping it.
///
/// This prevents any further messages from being sent on the channel while
/// still enabling the receiver to drain messages that are buffered. Any
/// outstanding [`Permit`] values will still be able to send messages.
///
/// To guarantee no messages are dropped, after calling `close()`, you must
/// receive all items from the stream until `None` is returned.
///
/// [`Permit`]: struct@tokio::sync::mpsc::Permit
pub fn close(&mut self) {
self.inner.close()
}
}
impl<T> Stream for ReceiverStream<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.poll_recv(cx)
}
}
impl<T> AsRef<Receiver<T>> for ReceiverStream<T> {
fn as_ref(&self) -> &Receiver<T> {
&self.inner
}
}
impl<T> AsMut<Receiver<T>> for ReceiverStream<T> {
fn as_mut(&mut self) -> &mut Receiver<T> {
&mut self.inner
}
}
@@ -0,0 +1,53 @@
use crate::Stream;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::mpsc::UnboundedReceiver;
/// A wrapper around [`tokio::sync::mpsc::UnboundedReceiver`] that implements [`Stream`].
///
/// [`tokio::sync::mpsc::UnboundedReceiver`]: struct@tokio::sync::mpsc::UnboundedReceiver
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
pub struct UnboundedReceiverStream<T> {
inner: UnboundedReceiver<T>,
}
impl<T> UnboundedReceiverStream<T> {
/// Create a new `UnboundedReceiverStream`.
pub fn new(recv: UnboundedReceiver<T>) -> Self {
Self { inner: recv }
}
/// Get back the inner `UnboundedReceiver`.
pub fn into_inner(self) -> UnboundedReceiver<T> {
self.inner
}
/// Closes the receiving half of a channel without dropping it.
///
/// This prevents any further messages from being sent on the channel while
/// still enabling the receiver to drain messages that are buffered.
pub fn close(&mut self) {
self.inner.close()
}
}
impl<T> Stream for UnboundedReceiverStream<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.poll_recv(cx)
}
}
impl<T> AsRef<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
fn as_ref(&self) -> &UnboundedReceiver<T> {
&self.inner
}
}
impl<T> AsMut<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
fn as_mut(&mut self) -> &mut UnboundedReceiver<T> {
&mut self.inner
}
}
+47
View File
@@ -0,0 +1,47 @@
use crate::Stream;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::fs::{DirEntry, ReadDir};
/// A wrapper around [`tokio::fs::ReadDir`] that implements [`Stream`].
///
/// [`tokio::fs::ReadDir`]: struct@tokio::fs::ReadDir
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
pub struct ReadDirStream {
inner: ReadDir,
}
impl ReadDirStream {
/// Create a new `ReadDirStream`.
pub fn new(read_dir: ReadDir) -> Self {
Self { inner: read_dir }
}
/// Get back the inner `ReadDir`.
pub fn into_inner(self) -> ReadDir {
self.inner
}
}
impl Stream for ReadDirStream {
type Item = io::Result<DirEntry>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.poll_next_entry(cx).map(Result::transpose)
}
}
impl AsRef<ReadDir> for ReadDirStream {
fn as_ref(&self) -> &ReadDir {
&self.inner
}
}
impl AsMut<ReadDir> for ReadDirStream {
fn as_mut(&mut self) -> &mut ReadDir {
&mut self.inner
}
}
+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
}
}
+60
View File
@@ -0,0 +1,60 @@
use crate::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, Split};
pin_project! {
/// A wrapper around [`tokio::io::Split`] that implements [`Stream`].
///
/// [`tokio::io::Split`]: struct@tokio::io::Split
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct SplitStream<R> {
#[pin]
inner: Split<R>,
}
}
impl<R> SplitStream<R> {
/// Create a new `SplitStream`.
pub fn new(split: Split<R>) -> Self {
Self { inner: split }
}
/// Get back the inner `Split`.
pub fn into_inner(self) -> Split<R> {
self.inner
}
/// Obtain a pinned reference to the inner `Split<R>`.
#[allow(clippy::wrong_self_convention)] // https://github.com/rust-lang/rust-clippy/issues/4546
pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Split<R>> {
self.project().inner
}
}
impl<R: AsyncBufRead> Stream for SplitStream<R> {
type Item = io::Result<Vec<u8>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.project()
.inner
.poll_next_segment(cx)
.map(Result::transpose)
}
}
impl<R> AsRef<Split<R>> for SplitStream<R> {
fn as_ref(&self) -> &Split<R> {
&self.inner
}
}
impl<R> AsMut<Split<R>> for SplitStream<R> {
fn as_mut(&mut self) -> &mut Split<R> {
&mut self.inner
}
}
+54
View File
@@ -0,0 +1,54 @@
use crate::Stream;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::net::{TcpListener, TcpStream};
/// A wrapper around [`TcpListener`] that implements [`Stream`].
///
/// [`TcpListener`]: struct@tokio::net::TcpListener
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
pub struct TcpListenerStream {
inner: TcpListener,
}
impl TcpListenerStream {
/// Create a new `TcpListenerStream`.
pub fn new(listener: TcpListener) -> Self {
Self { inner: listener }
}
/// Get back the inner `TcpListener`.
pub fn into_inner(self) -> TcpListener {
self.inner
}
}
impl Stream for TcpListenerStream {
type Item = io::Result<TcpStream>;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<io::Result<TcpStream>>> {
match self.inner.poll_accept(cx) {
Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(stream))),
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
Poll::Pending => Poll::Pending,
}
}
}
impl AsRef<TcpListener> for TcpListenerStream {
fn as_ref(&self) -> &TcpListener {
&self.inner
}
}
impl AsMut<TcpListener> for TcpListenerStream {
fn as_mut(&mut self) -> &mut TcpListener {
&mut self.inner
}
}
@@ -0,0 +1,54 @@
use crate::Stream;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::net::{UnixListener, UnixStream};
/// A wrapper around [`UnixListener`] that implements [`Stream`].
///
/// [`UnixListener`]: struct@tokio::net::UnixListener
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(all(unix, feature = "net"))))]
pub struct UnixListenerStream {
inner: UnixListener,
}
impl UnixListenerStream {
/// Create a new `UnixListenerStream`.
pub fn new(listener: UnixListener) -> Self {
Self { inner: listener }
}
/// Get back the inner `UnixListener`.
pub fn into_inner(self) -> UnixListener {
self.inner
}
}
impl Stream for UnixListenerStream {
type Item = io::Result<UnixStream>;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<io::Result<UnixStream>>> {
match self.inner.poll_accept(cx) {
Poll::Ready(Ok((stream, _))) => Poll::Ready(Some(Ok(stream))),
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
Poll::Pending => Poll::Pending,
}
}
}
impl AsRef<UnixListener> for UnixListenerStream {
fn as_ref(&self) -> &UnixListener {
&self.inner
}
}
impl AsMut<UnixListener> for UnixListenerStream {
fn as_mut(&mut self) -> &mut UnixListener {
&mut self.inner
}
}
+96
View File
@@ -0,0 +1,96 @@
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,
/// regardles 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<(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 + Unpin + 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, rx) = ready!(self.inner.poll(cx));
match result {
Ok(_) => {
let received = (*rx.borrow()).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()
}
}
+105
View File
@@ -0,0 +1,105 @@
use std::rc::Rc;
#[allow(dead_code)]
type BoxStream<T> = std::pin::Pin<Box<dyn tokio_stream::Stream<Item = T>>>;
#[allow(dead_code)]
fn require_send<T: Send>(_t: &T) {}
#[allow(dead_code)]
fn require_sync<T: Sync>(_t: &T) {}
#[allow(dead_code)]
fn require_unpin<T: Unpin>(_t: &T) {}
#[allow(dead_code)]
struct Invalid;
trait AmbiguousIfSend<A> {
fn some_item(&self) {}
}
impl<T: ?Sized> AmbiguousIfSend<()> for T {}
impl<T: ?Sized + Send> AmbiguousIfSend<Invalid> for T {}
trait AmbiguousIfSync<A> {
fn some_item(&self) {}
}
impl<T: ?Sized> AmbiguousIfSync<()> for T {}
impl<T: ?Sized + Sync> AmbiguousIfSync<Invalid> for T {}
trait AmbiguousIfUnpin<A> {
fn some_item(&self) {}
}
impl<T: ?Sized> AmbiguousIfUnpin<()> for T {}
impl<T: ?Sized + Unpin> AmbiguousIfUnpin<Invalid> for T {}
macro_rules! into_todo {
($typ:ty) => {{
let x: $typ = todo!();
x
}};
}
macro_rules! async_assert_fn {
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Send & Sync) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
require_send(&f);
require_sync(&f);
};
};
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Send & !Sync) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
require_send(&f);
AmbiguousIfSync::some_item(&f);
};
};
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Send & Sync) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
AmbiguousIfSend::some_item(&f);
require_sync(&f);
};
};
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Send & !Sync) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
AmbiguousIfSend::some_item(&f);
AmbiguousIfSync::some_item(&f);
};
};
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): !Unpin) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
AmbiguousIfUnpin::some_item(&f);
};
};
($($f:ident $(< $($generic:ty),* > )? )::+($($arg:ty),*): Unpin) => {
#[allow(unreachable_code)]
#[allow(unused_variables)]
const _: fn() = || {
let f = $($f $(::<$($generic),*>)? )::+( $( into_todo!($arg) ),* );
require_unpin(&f);
};
};
}
async_assert_fn!(tokio_stream::empty<Rc<u8>>(): Send & Sync);
async_assert_fn!(tokio_stream::pending<Rc<u8>>(): Send & Sync);
async_assert_fn!(tokio_stream::iter(std::vec::IntoIter<u8>): Send & Sync);
async_assert_fn!(tokio_stream::StreamExt::next(&mut BoxStream<()>): !Unpin);
async_assert_fn!(tokio_stream::StreamExt::try_next(&mut BoxStream<Result<(), ()>>): !Unpin);
async_assert_fn!(tokio_stream::StreamExt::all(&mut BoxStream<()>, fn(())->bool): !Unpin);
async_assert_fn!(tokio_stream::StreamExt::any(&mut BoxStream<()>, fn(())->bool): !Unpin);
async_assert_fn!(tokio_stream::StreamExt::fold(&mut BoxStream<()>, (), fn((), ())->()): !Unpin);
async_assert_fn!(tokio_stream::StreamExt::collect<Vec<()>>(&mut BoxStream<()>): !Unpin);
@@ -1,7 +1,12 @@
use tokio::stream::{self, Stream, StreamExt};
use tokio::sync::mpsc;
use tokio_stream::{self as stream, Stream, StreamExt};
use tokio_test::{assert_pending, assert_ready, task};
mod support {
pub(crate) mod mpsc;
}
use support::mpsc;
#[tokio::test]
async fn basic_usage() {
let one = stream::iter(vec![1, 2, 3]);
@@ -36,8 +41,8 @@ async fn basic_usage() {
#[tokio::test]
async fn pending_first() {
let (tx1, rx1) = mpsc::unbounded_channel();
let (tx2, rx2) = mpsc::unbounded_channel();
let (tx1, rx1) = mpsc::unbounded_channel_stream();
let (tx2, rx2) = mpsc::unbounded_channel_stream();
let mut stream = task::spawn(rx1.chain(rx2));
assert_eq!(stream.size_hint(), (0, None));
@@ -74,7 +79,7 @@ async fn pending_first() {
fn size_overflow() {
struct Monster;
impl tokio::stream::Stream for Monster {
impl tokio_stream::Stream for Monster {
type Item = ();
fn poll_next(
self: std::pin::Pin<&mut Self>,
@@ -1,7 +1,12 @@
use tokio::stream::{self, StreamExt};
use tokio::sync::mpsc;
use tokio_stream::{self as stream, StreamExt};
use tokio_test::{assert_pending, assert_ready, assert_ready_err, assert_ready_ok, task};
mod support {
pub(crate) mod mpsc;
}
use support::mpsc;
#[allow(clippy::let_unit_value)]
#[tokio::test]
async fn empty_unit() {
@@ -37,7 +42,7 @@ async fn empty_result() {
#[tokio::test]
async fn collect_vec_items() {
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let mut fut = task::spawn(rx.collect::<Vec<i32>>());
assert_pending!(fut.poll());
@@ -58,7 +63,8 @@ async fn collect_vec_items() {
#[tokio::test]
async fn collect_string_items() {
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let mut fut = task::spawn(rx.collect::<String>());
assert_pending!(fut.poll());
@@ -79,7 +85,8 @@ async fn collect_string_items() {
#[tokio::test]
async fn collect_str_items() {
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let mut fut = task::spawn(rx.collect::<String>());
assert_pending!(fut.poll());
@@ -100,7 +107,8 @@ async fn collect_str_items() {
#[tokio::test]
async fn collect_results_ok() {
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let mut fut = task::spawn(rx.collect::<Result<String, &str>>());
assert_pending!(fut.poll());
@@ -121,7 +129,8 @@ async fn collect_results_ok() {
#[tokio::test]
async fn collect_results_err() {
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let mut fut = task::spawn(rx.collect::<Result<String, &str>>());
assert_pending!(fut.poll());
@@ -1,4 +1,4 @@
use tokio::stream::{self, Stream, StreamExt};
use tokio_stream::{self as stream, Stream, StreamExt};
#[tokio::test]
async fn basic_usage() {
@@ -1,4 +1,4 @@
use tokio::stream::{Stream, StreamExt};
use tokio_stream::{Stream, StreamExt};
use std::pin::Pin;
use std::task::{Context, Poll};
@@ -1,4 +1,4 @@
use tokio::stream;
use tokio_stream as stream;
use tokio_test::task;
use std::iter;
@@ -1,8 +1,13 @@
use tokio::stream::{self, Stream, StreamExt};
use tokio::sync::mpsc;
use tokio_stream::{self as stream, Stream, StreamExt};
use tokio_test::task;
use tokio_test::{assert_pending, assert_ready};
mod support {
pub(crate) mod mpsc;
}
use support::mpsc;
#[tokio::test]
async fn merge_sync_streams() {
let mut s = stream::iter(vec![0, 2, 4, 6]).merge(stream::iter(vec![1, 3, 5]));
@@ -18,8 +23,8 @@ async fn merge_sync_streams() {
#[tokio::test]
async fn merge_async_streams() {
let (tx1, rx1) = mpsc::unbounded_channel();
let (tx2, rx2) = mpsc::unbounded_channel();
let (tx1, rx1) = mpsc::unbounded_channel_stream();
let (tx2, rx2) = mpsc::unbounded_channel_stream();
let mut rx = task::spawn(rx1.merge(rx2));
@@ -57,7 +62,7 @@ async fn merge_async_streams() {
fn size_overflow() {
struct Monster;
impl tokio::stream::Stream for Monster {
impl tokio_stream::Stream for Monster {
type Item = ();
fn poll_next(
self: std::pin::Pin<&mut Self>,
@@ -1,4 +1,4 @@
use tokio::stream::{self, Stream, StreamExt};
use tokio_stream::{self as stream, Stream, StreamExt};
#[tokio::test]
async fn basic_usage() {
@@ -1,4 +1,4 @@
use tokio::stream::{self, Stream, StreamExt};
use tokio_stream::{self as stream, Stream, StreamExt};
use tokio_test::{assert_pending, task};
#[tokio::test]
@@ -1,7 +1,12 @@
use tokio::stream::{self, pending, Stream, StreamExt, StreamMap};
use tokio::sync::mpsc;
use tokio_stream::{self as stream, pending, Stream, StreamExt, StreamMap};
use tokio_test::{assert_ok, assert_pending, assert_ready, task};
mod support {
pub(crate) mod mpsc;
}
use support::mpsc;
use std::pin::Pin;
macro_rules! assert_ready_some {
@@ -38,7 +43,8 @@ async fn empty() {
#[tokio::test]
async fn single_entry() {
let mut map = task::spawn(StreamMap::new());
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let rx = Box::pin(rx);
assert_ready_none!(map.poll_next());
@@ -76,8 +82,11 @@ async fn single_entry() {
#[tokio::test]
async fn multiple_entries() {
let mut map = task::spawn(StreamMap::new());
let (tx1, rx1) = mpsc::unbounded_channel();
let (tx2, rx2) = mpsc::unbounded_channel();
let (tx1, rx1) = mpsc::unbounded_channel_stream();
let (tx2, rx2) = mpsc::unbounded_channel_stream();
let rx1 = Box::pin(rx1);
let rx2 = Box::pin(rx2);
map.insert("foo", rx1);
map.insert("bar", rx2);
@@ -132,7 +141,9 @@ async fn multiple_entries() {
#[tokio::test]
async fn insert_remove() {
let mut map = task::spawn(StreamMap::new());
let (tx, rx) = mpsc::unbounded_channel();
let (tx, rx) = mpsc::unbounded_channel_stream();
let rx = Box::pin(rx);
assert_ready_none!(map.poll_next());
@@ -160,8 +171,11 @@ async fn insert_remove() {
#[tokio::test]
async fn replace() {
let mut map = task::spawn(StreamMap::new());
let (tx1, rx1) = mpsc::unbounded_channel();
let (tx2, rx2) = mpsc::unbounded_channel();
let (tx1, rx1) = mpsc::unbounded_channel_stream();
let (tx2, rx2) = mpsc::unbounded_channel_stream();
let rx1 = Box::pin(rx1);
let rx2 = Box::pin(rx2);
assert!(map.insert("foo", rx1).is_none());
@@ -1,7 +1,7 @@
#![cfg(feature = "full")]
use tokio::stream::{self, StreamExt};
use tokio::time::{self, sleep, Duration};
use tokio_stream::{self, StreamExt};
use tokio_test::*;
use futures::StreamExt as _;
@@ -78,7 +78,7 @@ async fn return_elapsed_errors_only_once() {
// error is returned.
assert_pending!(stream.poll_next());
//
time::advance(ms(50)).await;
time::advance(ms(51)).await;
let v = assert_ready!(stream.poll_next());
assert!(v.unwrap().is_err()); // timeout!
+15
View File
@@ -0,0 +1,15 @@
use async_stream::stream;
use tokio::sync::mpsc::{self, UnboundedSender};
use tokio_stream::Stream;
pub fn unbounded_channel_stream<T: Unpin>() -> (UnboundedSender<T>, impl Stream<Item = T>) {
let (tx, mut rx) = mpsc::unbounded_channel();
let stream = stream! {
while let Some(item) = rx.recv().await {
yield item;
}
};
(tx, stream)
}
@@ -1,8 +1,8 @@
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
use tokio::stream::StreamExt;
use tokio::time;
use tokio_stream::StreamExt;
use tokio_test::*;
use std::time::Duration;
+10
View File
@@ -1,3 +1,13 @@
# 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.
# 0.3.0 (October 15, 2020)
- Track `tokio` 0.3 release.
+8 -8
View File
@@ -2,32 +2,32 @@
name = "tokio-test"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.3.x" git tag.
version = "0.3.0"
# - Create "tokio-test-0.4.x" git tag.
version = "0.4.1"
edition = "2018"
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.3.0/tokio_test"
documentation = "https://docs.rs/tokio-test/0.4.1/tokio_test"
description = """
Testing utilities for Tokio- and futures-based code
"""
categories = ["asynchronous", "testing"]
publish = false
[dependencies]
tokio = { version = "0.3.0", path = "../tokio", features = ["rt", "stream", "sync", "time", "test-util"] }
tokio = { version = "1.2.0", path = "../tokio", features = ["rt", "sync", "time", "test-util"] }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
async-stream = "0.3"
bytes = "0.5.0"
bytes = "1.0.0"
futures-core = "0.3.0"
[dev-dependencies]
tokio = { version = "0.3.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) 2019 Tokio Contributors
Copyright (c) 2021 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
+15 -8
View File
@@ -21,9 +21,11 @@
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;
use futures_core::{ready, Stream};
use std::collections::VecDeque;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
@@ -63,13 +65,12 @@ enum Action {
WriteError(Option<Arc<io::Error>>),
}
#[derive(Debug)]
struct Inner {
actions: VecDeque<Action>,
waiting: Option<Instant>,
sleep: Option<Sleep>,
sleep: Option<Pin<Box<Sleep>>>,
read_wait: Option<Waker>,
rx: mpsc::UnboundedReceiver<Action>,
rx: UnboundedReceiverStream<Action>,
}
impl Builder {
@@ -186,6 +187,8 @@ impl Inner {
fn new(actions: VecDeque<Action>) -> (Inner, Handle) {
let (tx, rx) = mpsc::unbounded_channel();
let rx = UnboundedReceiverStream::new(rx);
let inner = Inner {
actions,
sleep: None,
@@ -200,8 +203,6 @@ impl Inner {
}
fn poll_action(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Action>> {
use futures_core::stream::Stream;
Pin::new(&mut self.rx).poll_next(cx)
}
@@ -365,7 +366,7 @@ impl AsyncRead for Mock {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Some(rem) = self.inner.remaining_wait() {
let until = Instant::now() + rem;
self.inner.sleep = Some(time::sleep_until(until));
self.inner.sleep = Some(Box::pin(time::sleep_until(until)));
} else {
self.inner.read_wait = Some(cx.waker().clone());
return Poll::Pending;
@@ -410,7 +411,7 @@ impl AsyncWrite for Mock {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Some(rem) = self.inner.remaining_wait() {
let until = Instant::now() + rem;
self.inner.sleep = Some(time::sleep_until(until));
self.inner.sleep = Some(Box::pin(time::sleep_until(until)));
} else {
panic!("unexpected WouldBlock");
}
@@ -485,3 +486,9 @@ fn is_task_ctx() -> bool {
r
}
*/
impl fmt::Debug for Inner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Inner {{...}}")
}
}
+2 -3
View File
@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-test/0.3.0")]
#![warn(
missing_debug_implementations,
missing_docs,
@@ -22,9 +21,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;
+1 -1
View File
@@ -9,7 +9,7 @@ use std::pin::Pin;
use std::sync::{Arc, Condvar, Mutex};
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use tokio::stream::Stream;
use tokio_stream::Stream;
/// TODO: dox
pub fn spawn<T>(task: T) -> Spawn<T> {

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