Compare commits

...
Author SHA1 Message Date
Alice Ryhl d39c9ed9dc chore: prepare tokio-macros 1.4.1 (#4142)
This reverts commit 33f0a1fd2e.
2021-09-30 10:38:52 +02:00
Noah Kennedy 44cfe10ee5 chore: prepare tokio-macros 1.4.0 (#4139) 2021-09-29 23:30:47 +02:00
Frank Steffahn 1073f6e8be sync: expand Debug for Mutex<T> impl to unsized T (#4134) 2021-09-26 12:29:08 +02:00
Kai Jewson dee3236c97 sync: add watch::Sender::send_replace (#3962) 2021-09-25 22:06:40 +02:00
Noah Kennedy d9ca1517c6 net: add try_*, readable, writable, ready, and peer_addr methods to split halves (#4120) 2021-09-25 20:19:29 +02:00
你好-肚财 6c1a1d9b07 docs: add returning on the first error example for try_join! (#4133) 2021-09-25 16:04:38 +02:00
Arthur Gautier d32acd97eb net: add poll_{recv,send}_ready methods to udp and uds_datagram (#4131) 2021-09-24 20:28:18 +02:00
João Marcos Bezerra 7875f26586 docs: fixing broken links in tokio/src/lib.rs (#4132) 2021-09-24 11:16:30 +02:00
我就像屎的倒影 7ce8f05cff sync: add blocking_lock to Mutex (#4130) 2021-09-23 11:46:14 +02:00
Sean McArthur ea19606bc4 sync: fix Notify to clone the waker before locking its waiter list (#4129)
Since a waker can trigger arbitrary code, such as with a custom waker,
and even more so now that it can emit a tracing event that could do
respond, we must be careful about the internal state when that code is
triggered. The clone method of a waker is one of those instances.

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

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

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

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

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

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

## Solution

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

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

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

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

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

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

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

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

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

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

## Solution

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

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

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

    ...
}

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

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

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

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

## Motivation

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

## Solution

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

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

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

Closes #3688 

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

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

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

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

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

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

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

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

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

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

## Solution

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* fmt

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

Fixes #3228
2021-01-28 17:49:10 -08:00
Ivan Petkov 1f9765fb5f process: add missing drop child stdin to wait() (#3421) 2021-01-28 23:08:44 +01:00
Jamie 225e8ea05f sync: update RwLock doc to mention possibility of deadlock (#3389) 2021-01-28 16:38:49 +01:00
Alice Ryhl cd7526873c net: improve discoverability of TcpSocket (#3471) 2021-01-28 14:09:14 +01:00
vitalyd 4968f59af6 sync: update Sender::try_reserve doc (#3476) 2021-01-28 10:31:23 +01:00
Ivan Petkov 34f1d3d040 process: allow for ergonomically piping stdio of one child into another (#3466)
* Add `TryInto<Stdio>` impls for `ChildStd{in,out,err}` for ergonomic
  conversions into `std::process::Stdio` so callers can perform the
  conversion without needing to manipulate raw fds/handles directly
2021-01-27 01:12:54 +00:00
Ontonator f13a9dd87a tokio: update dates in CHANGELOG.md to 2021 (#3469) 2021-01-25 12:04:58 +01:00
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
457 changed files with 35534 additions and 8287 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
View File
@@ -0,0 +1 @@
msrv = "1.45"
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [tokio-rs]
+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`
+9
View File
@@ -0,0 +1,9 @@
R-loom:
- ./tokio/src/sync/*
- ./tokio/src/sync/**/*
- ./tokio-util/src/sync/*
- ./tokio-util/src/sync/**/*
- ./tokio/src/runtime/*
- ./tokio/src/runtime/**/*
-55
View File
@@ -1,55 +0,0 @@
name: Benchmark
on:
push:
branches:
- master
jobs:
benchmark:
name: Benchmark
runs-on: ubuntu-latest
strategy:
matrix:
bench:
- rt_multi_threaded
- sync_mpsc
- sync_rwlock
- sync_semaphore
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
# Run benchmark with `go test -bench` and stores the output to a file
- name: Run benchmark
run: cargo bench --bench ${{ matrix.bench }} | tee ../output.txt
working-directory: benches
# Download previous benchmark result from cache (if exists)
- name: Download previous benchmark data
uses: actions/cache@v1
with:
path: ./cache
key: ${{ runner.os }}-benchmark
# Run `github-action-benchmark` action
- name: Store benchmark result
uses: rhysd/github-action-benchmark@v1
with:
name: ${{ matrix.bench }}
# What benchmark tool the output.txt came from
tool: 'cargo'
# Where the output from the benchmark tool is stored
output-file-path: output.txt
# # Where the previous data file is stored
# external-data-json-path: ./cache/benchmark-data.json
# Workflow will fail when an alert happens
fail-on-alert: true
# GitHub API token to make a commit comment
github-token: ${{ secrets.GITHUB_TOKEN }}
# Enable alert commit comment
comment-on-alert: true
alert-comment-cc-users: '@tokio-rs/maintainers'
auto-push: true
# Upload the updated cache file for the next job by actions/cache
+80 -27
View File
@@ -1,15 +1,15 @@
on:
push:
branches: ["master"]
branches: ["master", "tokio-*.x"]
pull_request:
branches: ["master"]
branches: ["master", "tokio-*.x"]
name: CI
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2020-09-21
nightly: nightly-2021-07-09
minrust: 1.45.2
jobs:
@@ -27,7 +27,9 @@ jobs:
- fmt
- clippy
- docs
- loom
- valgrind
- loom-compile
- check-readme
steps:
- run: exit 0
@@ -44,6 +46,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
@@ -67,6 +70,45 @@ jobs:
run: cargo hack test --each-feature
working-directory: tests-build
# Build benchmarks. Run of benchmarks is done by bench.yml workflow.
- name: build benches
run: cargo build --benches
working-directory: benches
# bench.yml workflow runs benchmarks only on linux.
if: startsWith(matrix.os, 'ubuntu')
valgrind:
name: valgrind
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
- name: Install Valgrind
run: |
sudo apt-get update -y
sudo apt-get install -y valgrind
# Compile tests
- name: cargo build test-mem
run: cargo build --features rt-net --bin test-mem
working-directory: tests-integration
# Run with valgrind
- name: Run valgrind test-mem
run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/debug/test-mem
# Compile tests
- name: cargo build test-process-signal
run: cargo build --features rt-process-signal --bin test-process-signal
working-directory: tests-integration
# Run with valgrind
- name: Run valgrind test-process-signal
run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/debug/test-process-signal
test-unstable:
name: test tokio full --unstable
runs-on: ${{ matrix.os }}
@@ -80,10 +122,11 @@ jobs:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
# Run `tokio` with "unstable" cfg flag.
- name: test tokio full --cfg unstable
run: cargo test --features full
run: cargo test --all-features
working-directory: tokio
env:
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
@@ -97,6 +140,7 @@ jobs:
with:
toolchain: ${{ env.nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install Miri
run: |
set -e
@@ -116,6 +160,7 @@ jobs:
with:
toolchain: ${{ env.nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: asan
run: cargo test --all-features --target x86_64-unknown-linux-gnu --lib -- --test-threads 1
working-directory: tokio
@@ -141,6 +186,7 @@ jobs:
toolchain: stable
target: ${{ matrix.target }}
override: true
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
use-cross: true
@@ -156,6 +202,7 @@ jobs:
with:
toolchain: ${{ env.nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
@@ -177,7 +224,7 @@ jobs:
with:
toolchain: ${{ env.minrust }}
override: true
- uses: Swatinem/rust-cache@v1
- name: "test --workspace --all-features"
run: cargo check --workspace --all-features
@@ -190,6 +237,7 @@ jobs:
with:
toolchain: ${{ env.nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: Install cargo-hack
run: cargo install cargo-hack
- name: "check --all-features -Z minimal-versions"
@@ -199,7 +247,7 @@ jobs:
cargo hack --remove-dev-deps --workspace
# Update Cargo.lock to minimal version dependencies.
cargo update -Z minimal-versions
cargo check --all-features
cargo hack check --all-features --ignore-private
fmt:
name: fmt
@@ -208,6 +256,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
- name: Install rustfmt
run: rustup component add rustfmt
@@ -226,13 +275,14 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update ${{ env.minrust }} && rustup default ${{ env.minrust }}
run: rustup update 1.52.1 && rustup default 1.52.1
- uses: Swatinem/rust-cache@v1
- name: Install clippy
run: rustup component add clippy
# Run clippy
- name: "clippy --all"
run: cargo clippy --all --tests
run: cargo clippy --all --tests --all-features
docs:
name: docs
@@ -243,32 +293,35 @@ jobs:
with:
toolchain: ${{ env.nightly }}
override: true
- uses: Swatinem/rust-cache@v1
- name: "doc --lib --all-features"
run: cargo doc --lib --no-deps --all-features
run: cargo doc --lib --no-deps --all-features --document-private-items
env:
RUSTDOCFLAGS: --cfg docsrs
RUSTFLAGS: --cfg docsrs
RUSTDOCFLAGS: --cfg docsrs -Dwarnings
loom:
name: loom
loom-compile:
name: build loom tests
runs-on: ubuntu-latest
strategy:
matrix:
scope:
- --skip loom_pool
- loom_pool::group_a
- loom_pool::group_b
- loom_pool::group_c
- loom_pool::group_d
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: loom ${{ matrix.scope }}
run: cargo test --lib --release --features full -- --nocapture $SCOPE
- uses: Swatinem/rust-cache@v1
- name: build --cfg loom
run: cargo test --no-run --lib --features full
working-directory: tokio
env:
RUSTFLAGS: --cfg loom --cfg tokio_unstable -Dwarnings
LOOM_MAX_PREEMPTIONS: 2
SCOPE: ${{ matrix.scope }}
check-readme:
name: Check README
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Verify that both READMEs are identical
run: diff README.md tokio/README.md
- name: Verify that Tokio version is up to date in README
working-directory: tokio
run: grep -q "$(sed '/^version = /!d' Cargo.toml | head -n1)" README.md
+13
View File
@@ -0,0 +1,13 @@
name: "Pull Request Labeler"
on:
- pull_request_target
# See .github/labeler.yml file
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v3
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+41
View File
@@ -0,0 +1,41 @@
on:
push:
branches: ["master", "tokio-*.x"]
pull_request:
types: [labeled, opened, synchronize, reopened]
branches: ["master", "tokio-*.x"]
name: Loom
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2021-07-09
jobs:
loom:
name: loom
# base_ref is null when it's not a pull request
if: contains(github.event.pull_request.labels.*.name, 'R-loom') || (github.base_ref == null)
runs-on: ubuntu-latest
strategy:
matrix:
scope:
- --skip loom_pool
- loom_pool::group_a
- loom_pool::group_b
- loom_pool::group_c
- loom_pool::group_d
- time::driver
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- uses: Swatinem/rust-cache@v1
- name: loom ${{ matrix.scope }}
run: cargo test --lib --release --features full -- --nocapture $SCOPE
working-directory: tokio
env:
RUSTFLAGS: --cfg loom --cfg tokio_unstable -Dwarnings
LOOM_MAX_PREEMPTIONS: 2
SCOPE: ${{ matrix.scope }}
+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
- uses: Swatinem/rust-cache@v1
- 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
+41 -9
View File
@@ -29,7 +29,6 @@ the Rust programming language. It is:
[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,15 +50,23 @@ an asynchronous application.
## Example
A basic TCP echo server with Tokio:
A basic TCP echo server with Tokio.
Make sure you activated the full features of the tokio crate on Cargo.toml:
```toml
[dependencies]
tokio = { version = "1.12.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>> {
let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
@@ -133,8 +140,7 @@ several other libraries, including:
* [`tower`]: A library of modular and reusable components for building robust networking clients and servers.
* [`tracing`] (formerly `tokio-trace`): A framework for application-level
tracing and async-aware diagnostics.
* [`tracing`] (formerly `tokio-trace`): A framework for application-level tracing and async-aware diagnostics.
* [`rdbc`]: A Rust database connectivity library for MySQL, Postgres and SQLite.
@@ -157,9 +163,35 @@ several other libraries, including:
## Supported Rust Versions
Tokio is built against the latest stable release. The minimum supported version is 1.45.
The current Tokio version is not guaranteed to build on Rust versions earlier than the
minimum supported version.
Tokio 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.
## Release schedule
Tokio doesn't follow a fixed release schedule, but we typically make one to two
new minor releases each month. We make patch releases for bugfixes as necessary.
## Bug patching policy
For the purposes of making patch releases with bugfixes, we have designated
certain minor releases as LTS (long term support) releases. Whenever a bug
warrants a patch release with a fix for the bug, it will be backported and
released as a new patch release for each LTS minor version. Our current LTS
releases are:
* `1.8.x` - LTS release until February 2022.
Each LTS release will continue to receive backported fixes for at least half a
year. If you wish to use a fixed minor release in your project, we recommend
that you use an LTS release.
To use a fixed minor version, you can specify the version with a tilde. For
example, to specify that you wish to use the newest `1.8.x` patch release, you
can use the following dependency specification:
```text
tokio = { version = "~1.8", features = [...] }
```
## License
-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
+10 -1
View File
@@ -5,9 +5,13 @@ publish = false
edition = "2018"
[dependencies]
tokio = { version = "0.3.0", path = "../tokio", features = ["full"] }
tokio = { version = "1.5.0", path = "../tokio", features = ["full"] }
bencher = "0.1.5"
[dev-dependencies]
tokio-util = { version = "0.6.6", path = "../tokio-util", features = ["full"] }
tokio-stream = { path = "../tokio-stream" }
[target.'cfg(unix)'.dependencies]
libc = "0.2.42"
@@ -41,3 +45,8 @@ harness = false
name = "signal"
path = "signal.rs"
harness = false
[[bench]]
name = "fs"
path = "fs.rs"
harness = false
+103
View File
@@ -0,0 +1,103 @@
#![cfg(unix)]
use tokio_stream::StreamExt;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio_util::codec::{BytesCodec, FramedRead /*FramedWrite*/};
use bencher::{benchmark_group, benchmark_main, Bencher};
use std::fs::File as StdFile;
use std::io::Read as StdRead;
fn rt() -> tokio::runtime::Runtime {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.build()
.unwrap()
}
const BLOCK_COUNT: usize = 1_000;
const BUFFER_SIZE: usize = 4096;
const DEV_ZERO: &'static str = "/dev/zero";
fn async_read_codec(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let task = || async {
let file = File::open(DEV_ZERO).await.unwrap();
let mut input_stream = FramedRead::with_capacity(file, BytesCodec::new(), BUFFER_SIZE);
for _i in 0..BLOCK_COUNT {
let _bytes = input_stream.next().await.unwrap();
}
};
rt.block_on(task());
});
}
fn async_read_buf(b: &mut Bencher) {
let rt = rt();
b.iter(|| {
let task = || async {
let mut file = File::open(DEV_ZERO).await.unwrap();
let mut buffer = [0u8; BUFFER_SIZE];
for _i in 0..BLOCK_COUNT {
let count = file.read(&mut buffer).await.unwrap();
if count == 0 {
break;
}
}
};
rt.block_on(task());
});
}
fn async_read_std_file(b: &mut Bencher) {
let rt = rt();
let task = || async {
let mut file = tokio::task::block_in_place(|| Box::pin(StdFile::open(DEV_ZERO).unwrap()));
for _i in 0..BLOCK_COUNT {
let mut buffer = [0u8; BUFFER_SIZE];
let mut file_ref = file.as_mut();
tokio::task::block_in_place(move || {
file_ref.read_exact(&mut buffer).unwrap();
});
}
};
b.iter(|| {
rt.block_on(task());
});
}
fn sync_read(b: &mut Bencher) {
b.iter(|| {
let mut file = StdFile::open(DEV_ZERO).unwrap();
let mut buffer = [0u8; BUFFER_SIZE];
for _i in 0..BLOCK_COUNT {
file.read_exact(&mut buffer).unwrap();
}
});
}
benchmark_group!(
file,
async_read_std_file,
async_read_buf,
async_read_codec,
sync_read
);
benchmark_main!(file);
+1 -1
View File
@@ -1,4 +1,4 @@
//! Benchmark implementation details of the theaded scheduler. These benches are
//! Benchmark implementation details of the threaded scheduler. These benches are
//! intended to be used as a form of regression testing and not as a general
//! purpose benchmark demonstrating real-world performance.
+57 -37
View File
@@ -2,63 +2,83 @@
//! This essentially measure the time to enqueue a task in the local and remote
//! case.
#[macro_use]
extern crate bencher;
use bencher::{black_box, Bencher};
async fn work() -> usize {
let val = 1 + 1;
tokio::task::yield_now().await;
black_box(val)
}
fn basic_scheduler_local_spawn(bench: &mut Bencher) {
fn basic_scheduler_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn threaded_scheduler_local_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn basic_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
bench.iter(|| {
let h = runtime.spawn(work());
black_box(h);
runtime.block_on(async {
let h = tokio::spawn(work());
assert_eq!(h.await.unwrap(), 2);
});
});
}
fn threaded_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread().build().unwrap();
fn basic_scheduler_spawn10(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
bench.iter(|| {
let h = runtime.spawn(work());
black_box(h);
runtime.block_on(async {
let mut handles = Vec::with_capacity(10);
for _ in 0..10 {
handles.push(tokio::spawn(work()));
}
for handle in handles {
assert_eq!(handle.await.unwrap(), 2);
}
});
});
}
fn threaded_scheduler_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.build()
.unwrap();
bench.iter(|| {
runtime.block_on(async {
let h = tokio::spawn(work());
assert_eq!(h.await.unwrap(), 2);
});
});
}
fn threaded_scheduler_spawn10(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.build()
.unwrap();
bench.iter(|| {
runtime.block_on(async {
let mut handles = Vec::with_capacity(10);
for _ in 0..10 {
handles.push(tokio::spawn(work()));
}
for handle in handles {
assert_eq!(handle.await.unwrap(), 2);
}
});
});
}
bencher::benchmark_group!(
spawn,
basic_scheduler_local_spawn,
threaded_scheduler_local_spawn,
basic_scheduler_remote_spawn,
threaded_scheduler_remote_spawn
basic_scheduler_spawn,
basic_scheduler_spawn10,
threaded_scheduler_spawn,
threaded_scheduler_spawn10,
);
bencher::benchmark_main!(spawn);
+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();
});
}
+32 -4
View File
@@ -7,18 +7,25 @@ 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", path = "../tokio",features = ["full", "tracing"] }
tokio-util = { version = "0.6.3", path = "../tokio-util",features = ["full"] }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
tracing = "0.1"
tracing-subscriber = { version = "0.2.7", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log"] }
tokio-util = { version = "0.5.0", path = "../tokio-util", features = ["full"] }
bytes = "0.6"
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"
rand = "0.8.3"
[target.'cfg(windows)'.dev-dependencies.winapi]
version = "0.3.8"
[[example]]
name = "chat"
@@ -63,3 +70,24 @@ 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"
[[example]]
name = "named-pipe"
path = "named-pipe.rs"
[[example]]
name = "named-pipe-ready"
path = "named-pipe-ready.rs"
[[example]]
name = "named-pipe-multi-client"
path = "named-pipe-multi-client.rs"
+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 {
+98
View File
@@ -0,0 +1,98 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
use tokio::time;
use winapi::shared::winerror;
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-multi-client";
const N: usize = 10;
// The first server needs to be constructed early so that clients can
// be correctly connected. Otherwise a waiting client will error.
//
// Here we also make use of `first_pipe_instance`, which will ensure
// that there are no other servers up and running already.
let mut server = ServerOptions::new()
.first_pipe_instance(true)
.create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Artificial workload.
time::sleep(Duration::from_secs(1)).await;
for _ in 0..N {
// Wait for client to connect.
server.connect().await?;
let mut inner = server;
// Construct the next server to be connected before sending the one
// we already have of onto a task. This ensures that the server
// isn't closed (after it's done in the task) before a new one is
// available. Otherwise the client might error with
// `io::ErrorKind::NotFound`.
server = ServerOptions::new().create(PIPE_NAME)?;
let _ = tokio::spawn(async move {
let mut buf = vec![0u8; 4];
inner.read_exact(&mut buf).await?;
inner.write_all(b"pong").await?;
Ok::<_, io::Error>(())
});
}
Ok::<_, io::Error>(())
});
let mut clients = Vec::new();
for _ in 0..N {
clients.push(tokio::spawn(async move {
// This showcases a generic connect loop.
//
// We immediately try to create a client, if it's not found or
// the pipe is busy we use the specialized wait function on the
// client builder.
let mut client = loop {
match ClientOptions::new().open(PIPE_NAME) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(winerror::ERROR_PIPE_BUSY as i32) => (),
Err(e) => return Err(e),
}
time::sleep(Duration::from_millis(5)).await;
};
let mut buf = [0u8; 4];
client.write_all(b"ping").await?;
client.read_exact(&mut buf).await?;
Ok::<_, io::Error>(buf)
}));
}
for client in clients {
let result = client.await?;
assert_eq!(&result?[..], b"pong");
}
server.await??;
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+161
View File
@@ -0,0 +1,161 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use tokio::io::Interest;
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-single-client";
let server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Note: we wait for a client to connect.
server.connect().await?;
let buf = {
let mut read_buf = [0u8; 5];
let mut read_buf_cursor = 0;
loop {
server.readable().await?;
let buf = &mut read_buf[read_buf_cursor..];
match server.try_read(buf) {
Ok(n) => {
read_buf_cursor += n;
if read_buf_cursor == read_buf.len() {
break;
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
read_buf
};
{
let write_buf = b"pong\n";
let mut write_buf_cursor = 0;
loop {
let buf = &write_buf[write_buf_cursor..];
if buf.is_empty() {
break;
}
server.writable().await?;
match server.try_write(buf) {
Ok(n) => {
write_buf_cursor += n;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
}
Ok::<_, io::Error>(buf)
});
let client = tokio::spawn(async move {
// There's no need to use a connect loop here, since we know that the
// server is already up - `open` was called before spawning any of the
// tasks.
let client = ClientOptions::new().open(PIPE_NAME)?;
let mut read_buf = [0u8; 5];
let mut read_buf_cursor = 0;
let write_buf = b"ping\n";
let mut write_buf_cursor = 0;
loop {
let mut interest = Interest::READABLE;
if write_buf_cursor < write_buf.len() {
interest |= Interest::WRITABLE;
}
let ready = client.ready(interest).await?;
if ready.is_readable() {
let buf = &mut read_buf[read_buf_cursor..];
match client.try_read(buf) {
Ok(n) => {
read_buf_cursor += n;
if read_buf_cursor == read_buf.len() {
break;
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
if ready.is_writable() {
let buf = &write_buf[write_buf_cursor..];
if buf.is_empty() {
continue;
}
match client.try_write(buf) {
Ok(n) => {
write_buf_cursor += n;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
}
let buf = String::from_utf8_lossy(&read_buf).into_owned();
Ok::<_, io::Error>(buf)
});
let (server, client) = tokio::try_join!(server, client)?;
assert_eq!(server?, *b"ping\n");
assert_eq!(client?, "pong\n");
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+60
View File
@@ -0,0 +1,60 @@
use std::io;
#[cfg(windows)]
async fn windows_main() -> io::Result<()> {
use tokio::io::AsyncWriteExt;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-single-client";
let server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(async move {
// Note: we wait for a client to connect.
server.connect().await?;
let mut server = BufReader::new(server);
let mut buf = String::new();
server.read_line(&mut buf).await?;
server.write_all(b"pong\n").await?;
Ok::<_, io::Error>(buf)
});
let client = tokio::spawn(async move {
// There's no need to use a connect loop here, since we know that the
// server is already up - `open` was called before spawning any of the
// tasks.
let client = ClientOptions::new().open(PIPE_NAME)?;
let mut client = BufReader::new(client);
let mut buf = String::new();
client.write_all(b"ping\n").await?;
client.read_line(&mut buf).await?;
Ok::<_, io::Error>(buf)
});
let (server, client) = tokio::try_join!(server, client)?;
assert_eq!(server?, "ping\n");
assert_eq!(client?, "pong\n");
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
#[cfg(windows)]
{
windows_main().await?;
}
#[cfg(not(windows))]
{
println!("Named pipes are only supported on Windows!");
}
Ok(())
}
+1 -1
View File
@@ -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,
}
}
}
@@ -4,4 +4,4 @@ error: The default runtime flavor is `multi_thread`, but the `rt-multi-thread` f
3 | #[tokio::main]
| ^^^^^^^^^^^^^^
|
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -0,0 +1,8 @@
#![deny(dead_code)]
use tests_build::tokio;
#[tokio::main]
async fn f() {}
fn main() {}
@@ -0,0 +1,11 @@
error: function is never used: `f`
--> $DIR/macros_dead_code.rs:6:10
|
6 | async fn f() {}
| ^
|
note: the lint level is defined here
--> $DIR/macros_dead_code.rs:1:9
|
1 | #![deny(dead_code)]
| ^^^^^^^^^
+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]
| ^^^^^^^
@@ -0,0 +1,18 @@
use tests_build::tokio;
#[tokio::main]
async fn missing_semicolon_or_return_type() {
Ok(())
}
#[tokio::main]
async fn missing_return_type() {
return Ok(());
}
#[tokio::main]
async fn extra_semicolon() -> Result<(), ()> {
Ok(());
}
fn main() {}
@@ -0,0 +1,38 @@
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:5:5
|
5 | Ok(())
| ^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
help: consider using a semicolon here
|
5 | Ok(());
| ^
help: try adding a return type
|
4 | async fn missing_semicolon_or_return_type() -> Result<(), _> {
| ^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:10:5
|
9 | async fn missing_return_type() {
| - help: try adding a return type: `-> Result<(), _>`
10 | return Ok(());
| ^^^^^^^^^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:14:31
|
14 | async fn extra_semicolon() -> Result<(), ()> {
| --------------- ^^^^^^^^^^^^^^ expected enum `Result`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
= note: expected enum `Result<(), ()>`
found unit type `()`
+15
View File
@@ -2,9 +2,24 @@
fn compile_fail_full() {
let t = trybuild::TestCases::new();
#[cfg(feature = "full")]
t.pass("tests/pass/forward_args_and_output.rs");
#[cfg(feature = "full")]
t.pass("tests/pass/macros_main_return.rs");
#[cfg(feature = "full")]
t.pass("tests/pass/macros_main_loop.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_invalid_input.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_dead_code.rs");
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_type_mismatch.rs");
#[cfg(all(feature = "rt", not(feature = "full")))]
t.compile_fail("tests/fail/macros_core_no_default.rs");
+7
View File
@@ -0,0 +1,7 @@
#[cfg(feature = "full")]
#[tokio::test]
async fn test_with_semicolon_without_return_type() {
#![deny(clippy::semicolon_if_nothing_returned)]
dbg!(0);
}
@@ -0,0 +1,13 @@
use tests_build::tokio;
fn main() {}
// arguments and output type is forwarded so other macros can access them
#[tokio::test]
async fn test_fn_has_args(_x: u8) {}
#[tokio::test]
async fn test_has_output() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
@@ -0,0 +1,14 @@
use tests_build::tokio;
#[tokio::main]
async fn main() -> Result<(), ()> {
loop {
if !never() {
return Ok(());
}
}
}
fn never() -> bool {
std::time::Instant::now() > std::time::Instant::now()
}
@@ -0,0 +1,6 @@
use tests_build::tokio;
#[tokio::main]
async fn main() -> Result<(), ()> {
return Ok(());
}
+16 -2
View File
@@ -5,7 +5,23 @@ authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[[bin]]
name = "test-cat"
[[bin]]
name = "test-mem"
required-features = ["rt-net"]
[[bin]]
name = "test-process-signal"
required-features = ["rt-process-signal"]
[features]
# For mem check
rt-net = ["tokio/rt", "tokio/rt-multi-thread", "tokio/net"]
# For test-process-signal
rt-process-signal = ["rt", "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());
}
+46
View File
@@ -1,3 +1,48 @@
# 1.4.1 (September 30th, 2021)
Reverted: run `current_thread` inside `LocalSet` ([#4027])
# 1.4.0 (September 29th, 2021)
(yanked)
### Changed
- macros: run `current_thread` inside `LocalSet` ([#4027])
- macros: explicitly relaxed clippy lint for `.expect()` in runtime entry macro ([#4030])
### Fixed
- macros: fix invalid error messages in functions wrapped with `#[main]` or `#[test]` ([#4067])
[#4027]: https://github.com/tokio-rs/tokio/pull/4027
[#4030]: https://github.com/tokio-rs/tokio/pull/4030
[#4067]: https://github.com/tokio-rs/tokio/pull/4067
# 1.3.0 (July 7, 2021)
- macros: don't trigger `clippy::unwrap_used` ([#3926])
[#3926]: https://github.com/tokio-rs/tokio/pull/3926
# 1.2.0 (May 14, 2021)
- macros: forward input arguments in `#[tokio::test]` ([#3691])
- macros: improve diagnostics on type mismatch ([#3766])
- macros: various error message improvements ([#3677])
[#3677]: https://github.com/tokio-rs/tokio/pull/3677
[#3691]: https://github.com/tokio-rs/tokio/pull/3691
[#3766]: https://github.com/tokio-rs/tokio/pull/3766
# 1.1.0 (February 5, 2021)
- add `start_paused` option to macros ([#3492])
# 1.0.0 (December 23, 2020)
- track `tokio` 1.0 release.
# 0.3.1 (October 25, 2020)
### Fixed
@@ -51,3 +96,4 @@
[#2177]: https://github.com/tokio-rs/tokio/pull/2177
[#2225]: https://github.com/tokio-rs/tokio/pull/2225
[#3038]: https://github.com/tokio-rs/tokio/pull/3038
[#3492]: https://github.com/tokio-rs/tokio/pull/3492
+5 -6
View File
@@ -2,18 +2,17 @@
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.1"
# - Create "tokio-macros-1.0.x" git tag.
version = "1.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-macros/0.3.1/tokio_macros"
documentation = "https://docs.rs/tokio-macros/1.4.1/tokio_macros"
description = """
Tokio's proc macros.
"""
@@ -27,10 +26,10 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0.7"
quote = "1"
syn = { version = "1.0.3", features = ["full"] }
syn = { version = "1.0.56", features = ["full"] }
[dev-dependencies]
tokio = { version = "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
+177 -82
View File
@@ -1,7 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;
use quote::{quote, quote_spanned, ToTokens};
#[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,70 +190,82 @@ 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 {
syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
let ident = namevalue.path.get_ident();
if ident.is_none() {
let msg = "Must have specified ident";
return Err(syn::Error::new_spanned(namevalue, msg));
}
match ident.unwrap().to_string().to_lowercase().as_str() {
let ident = namevalue
.path
.get_ident()
.ok_or_else(|| {
syn::Error::new_spanned(&namevalue, "Must have specified ident")
})?
.to_string()
.to_lowercase();
match ident.as_str() {
"worker_threads" => {
config.set_worker_threads(namevalue.lit.clone(), namevalue.span())?;
config.set_worker_threads(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"flavor" => {
config.set_flavor(namevalue.lit.clone(), namevalue.span())?;
config.set_flavor(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"start_paused" => {
config.set_start_paused(
namevalue.lit.clone(),
syn::spanned::Spanned::span(&namevalue.lit),
)?;
}
"core_threads" => {
let msg = "Attribute `core_threads` is renamed to `worker_threads`";
return Err(syn::Error::new_spanned(namevalue, msg));
}
name => {
let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name);
let msg = format!(
"Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`",
name,
);
return Err(syn::Error::new_spanned(namevalue, msg));
}
}
}
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
let ident = path.get_ident();
if ident.is_none() {
let msg = "Must have specified ident";
return Err(syn::Error::new_spanned(path, msg));
}
let name = ident.unwrap().to_string().to_lowercase();
let name = path
.get_ident()
.ok_or_else(|| syn::Error::new_spanned(&path, "Must have specified ident"))?
.to_string()
.to_lowercase();
let msg = match name.as_str() {
"threaded_scheduler" | "multi_thread" => {
format!("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));
}
@@ -218,38 +280,78 @@ fn parse_knobs(
let config = config.build()?;
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let mut rt = match config.flavor {
RuntimeFlavor::CurrentThread => quote! {
RuntimeFlavor::CurrentThread => quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
},
RuntimeFlavor::Threaded => quote! {
RuntimeFlavor::Threaded => quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_multi_thread()
},
};
if let Some(v) = config.worker_threads {
rt = quote! { #rt.worker_threads(#v) };
}
if let Some(v) = config.start_paused {
rt = quote! { #rt.start_paused(#v) };
}
let header = {
if is_test {
quote! {
#[::core::prelude::v1::test]
}
} else {
quote! {}
let header = if is_test {
quote! {
#[::core::prelude::v1::test]
}
} else {
quote! {}
};
let body = &input.block;
let brace_token = input.block.brace_token;
let (tail_return, tail_semicolon) = match body.stmts.last() {
Some(syn::Stmt::Semi(expr, _)) => (
match expr {
syn::Expr::Return(_) => quote! { return },
_ => quote! {},
},
quote! {
;
},
),
_ => (quote! {}, quote! {}),
};
input.block = syn::parse2(quote_spanned! {last_stmt_end_span=>
{
let body = async #body;
#[allow(clippy::expect_used)]
#tail_return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body)#tail_semicolon
}
})
.expect("Parsing failure");
input.block.brace_token = brace_token;
let result = quote! {
#header
#(#attrs)*
#vis #sig {
#rt
.enable_all()
.build()
.unwrap()
.block_on(async { #body })
}
#input
};
Ok(result.into())
@@ -283,12 +385,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())
}
+66 -24
View File
@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-macros/0.3.1")]
#![allow(clippy::needless_doctest_main)]
#![warn(
missing_debug_implementations,
@@ -6,7 +5,7 @@
rust_2018_idioms,
unreachable_pub
)]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
@@ -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)
@@ -242,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)
+79
View File
@@ -0,0 +1,79 @@
# 0.1.7 (July 7, 2021)
### Fixed
- sync: fix watch wrapper ([#3914])
- time: fix `Timeout::size_hint` ([#3902])
[#3902]: https://github.com/tokio-rs/tokio/pull/3902
[#3914]: https://github.com/tokio-rs/tokio/pull/3914
# 0.1.6 (May 14, 2021)
### Added
- stream: implement `Error` and `Display` for `BroadcastStreamRecvError` ([#3745])
### Fixed
- stream: avoid yielding in `AllFuture` and `AnyFuture` ([#3625])
[#3745]: https://github.com/tokio-rs/tokio/pull/3745
[#3625]: https://github.com/tokio-rs/tokio/pull/3625
# 0.1.5 (March 20, 2021)
### Fixed
- stream: documentation note for throttle `Unpin` ([#3600])
[#3600]: https://github.com/tokio-rs/tokio/pull/3600
# 0.1.4 (March 9, 2021)
Added
- signal: add `Signal` wrapper ([#3510])
Fixed
- stream: remove duplicate `doc_cfg` declaration ([#3561])
- sync: yield initial value in `WatchStream` ([#3576])
[#3510]: https://github.com/tokio-rs/tokio/pull/3510
[#3561]: https://github.com/tokio-rs/tokio/pull/3561
[#3576]: https://github.com/tokio-rs/tokio/pull/3576
# 0.1.3 (February 5, 2021)
Added
- sync: add wrapper for broadcast and watch ([#3384], [#3504])
[#3384]: https://github.com/tokio-rs/tokio/pull/3384
[#3504]: https://github.com/tokio-rs/tokio/pull/3504
# 0.1.2 (January 12, 2021)
Fixed
- docs: fix some wrappers missing in documentation ([#3378])
[#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
+51
View File
@@ -0,0 +1,51 @@
[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.7"
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.7/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.8.0", path = "../tokio", features = ["sync"] }
tokio-util = { version = "0.6.3", path = "../tokio-util", 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"]
# Issue #3770
#
# This should allow `docsrs` to be read across projects, so that `tokio-stream`
# can pick up stubbed types exported by `tokio`.
rustc-args = ["--cfg", "docsrs"]
+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(rustdoc::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,14 +51,11 @@ 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 the [`Stream`] trait that provides a variety of
/// convenient combinator functions.
///
@@ -146,11 +74,11 @@ pub use futures_core::Stream;
/// # #[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]);
/// 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);
/// let merged = tokio_stream::StreamExt::merge(a, b);
///
/// // use normal call notation for futures::stream::StreamExt::collect
/// let output: Vec<_> = merged.collect().await;
@@ -158,7 +86,7 @@ pub use futures_core::Stream;
/// # }
/// ```
///
/// [`Stream`]: crate::stream::Stream
/// [`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 {
@@ -183,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);
///
@@ -219,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")]);
///
@@ -251,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);
@@ -284,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]
@@ -301,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);
///
@@ -365,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);
@@ -401,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| {
@@ -433,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};
@@ -498,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);
///
@@ -527,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);
///
@@ -553,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);
///
@@ -573,7 +515,7 @@ pub trait StreamExt: Stream {
/// Skip elements from the underlying stream while the provided predicate
/// resolves to `true`.
///
/// This function, like [`Iterator::skip_while`], will ignore elemets from the
/// This function, like [`Iterator::skip_while`], will ignore elements from the
/// stream until the predicate `f` resolves to `false`. Once one element
/// returns false, the rest of the elements will be yielded.
///
@@ -584,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);
@@ -627,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];
///
@@ -642,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];
///
@@ -686,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];
///
@@ -701,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];
///
@@ -730,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() {
@@ -770,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;
@@ -797,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`
///
@@ -816,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() {
@@ -833,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() {
@@ -889,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)));
@@ -934,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).
@@ -113,7 +113,7 @@ impl<T: AsRef<str>> sealed::FromStreamPriv<T> for String {
}
fn finalize(_: sealed::Internal, collection: &mut String) -> String {
mem::replace(collection, String::new())
mem::take(collection)
}
}
@@ -132,7 +132,7 @@ impl<T> sealed::FromStreamPriv<T> for Vec<T> {
}
fn finalize(_: sealed::Internal, collection: &mut Vec<T>) -> Vec<T> {
mem::replace(collection, vec![])
mem::take(collection)
}
}
@@ -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)
}
+107
View File
@@ -0,0 +1,107 @@
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! {
/// Stream returned by the [`timeout`](super::StreamExt::timeout) method.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
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 = tokio::time::sleep_until(next);
Timeout {
stream: Fuse::new(stream),
deadline,
duration,
poll_deadline: true,
}
}
}
impl<S: Stream> Stream for Timeout<S> {
type Item = Result<S::Item, Elapsed>;
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() + *me.duration;
me.deadline.reset(next);
*me.poll_deadline = true;
}
return Poll::Ready(v.map(Ok));
}
Poll::Pending => {}
};
if *me.poll_deadline {
ready!(me.deadline.poll(cx));
*me.poll_deadline = false;
return Poll::Ready(Some(Err(Elapsed::new())));
}
Poll::Pending
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.stream.size_hint();
// The timeout stream may insert an error before and after each message
// from the underlying stream, but no more than one error between each
// message. Hence the upper bound is computed as 2x+1.
// Using a helper function to enable use of question mark operator.
fn twice_plus_one(value: Option<usize>) -> Option<usize> {
value?.checked_mul(2)?.checked_add(1)
}
(lower, twice_plus_one(upper))
}
}
// ===== 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]
@@ -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);
@@ -350,11 +364,11 @@ impl<K, V> StreamMap<K, V> {
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use tokio_stream::{StreamMap, pending};
///
/// let mut a = HashMap::new();
/// let mut a = StreamMap::new();
/// assert!(a.is_empty());
/// a.insert(1, "a");
/// a.insert(1, pending::<i32>());
/// assert!(!a.is_empty());
/// ```
pub fn is_empty(&self) -> bool {
@@ -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() {
@@ -553,3 +567,115 @@ where
ret
}
}
impl<K, V> std::iter::FromIterator<(K, V)> for StreamMap<K, V>
where
K: Hash + Eq,
{
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let iterator = iter.into_iter();
let (lower_bound, _) = iterator.size_hint();
let mut stream_map = Self::with_capacity(lower_bound);
for (key, value) in iterator {
stream_map.insert(key, value);
}
stream_map
}
}
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))
}
}
+62
View File
@@ -0,0 +1,62 @@
//! Wrappers for Tokio types that implement `Stream`.
/// Error types for the wrappers.
pub mod errors {
cfg_sync! {
pub use crate::wrappers::broadcast::BroadcastStreamRecvError;
}
}
mod mpsc_bounded;
pub use mpsc_bounded::ReceiverStream;
mod mpsc_unbounded;
pub use mpsc_unbounded::UnboundedReceiverStream;
cfg_sync! {
mod broadcast;
pub use broadcast::BroadcastStream;
mod watch;
pub use watch::WatchStream;
}
cfg_signal! {
#[cfg(unix)]
mod signal_unix;
#[cfg(unix)]
pub use signal_unix::SignalStream;
#[cfg(any(windows, docsrs))]
mod signal_windows;
#[cfg(any(windows, docsrs))]
pub use signal_windows::{CtrlCStream, CtrlBreakStream};
}
cfg_time! {
mod interval;
pub use interval::IntervalStream;
}
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;
}
+79
View File
@@ -0,0 +1,79 @@
use std::pin::Pin;
use tokio::sync::broadcast::error::RecvError;
use tokio::sync::broadcast::Receiver;
use futures_core::Stream;
use tokio_util::sync::ReusableBoxFuture;
use std::fmt;
use std::task::{Context, Poll};
/// A wrapper around [`tokio::sync::broadcast::Receiver`] that implements [`Stream`].
///
/// [`tokio::sync::broadcast::Receiver`]: struct@tokio::sync::broadcast::Receiver
/// [`Stream`]: trait@crate::Stream
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
pub struct BroadcastStream<T> {
inner: ReusableBoxFuture<(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),
}
impl fmt::Display for BroadcastStreamRecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BroadcastStreamRecvError::Lagged(amt) => write!(f, "channel lagged by {}", amt),
}
}
}
impl std::error::Error for BroadcastStreamRecvError {}
async fn make_future<T: Clone>(mut rx: Receiver<T>) -> (Result<T, RecvError>, Receiver<T>) {
let result = rx.recv().await;
(result, rx)
}
impl<T: 'static + Clone + Send> BroadcastStream<T> {
/// Create a new `BroadcastStream`.
pub fn new(rx: Receiver<T>) -> Self {
Self {
inner: ReusableBoxFuture::new(make_future(rx)),
}
}
}
impl<T: 'static + Clone + Send> Stream for BroadcastStream<T> {
type Item = Result<T, BroadcastStreamRecvError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let (result, rx) = ready!(self.inner.poll(cx));
self.inner.set(make_future(rx));
match result {
Ok(item) => Poll::Ready(Some(Ok(item))),
Err(RecvError::Closed) => Poll::Ready(None),
Err(RecvError::Lagged(n)) => {
Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n))))
}
}
}
}
impl<T> fmt::Debug for BroadcastStream<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BroadcastStream").finish()
}
}
impl<T: 'static + Clone + Send> From<Receiver<T>> for BroadcastStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
+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
}
}
+65
View File
@@ -0,0 +1,65 @@
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
}
}
impl<T> From<Receiver<T>> for ReceiverStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
@@ -0,0 +1,59 @@
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
}
}
impl<T> From<UnboundedReceiver<T>> for UnboundedReceiverStream<T> {
fn from(recv: UnboundedReceiver<T>) -> Self {
Self::new(recv)
}
}
+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
}
}
+102
View File
@@ -0,0 +1,102 @@
use std::pin::Pin;
use tokio::sync::watch::Receiver;
use futures_core::Stream;
use tokio_util::sync::ReusableBoxFuture;
use std::fmt;
use std::task::{Context, Poll};
use tokio::sync::watch::error::RecvError;
/// A wrapper around [`tokio::sync::watch::Receiver`] that implements [`Stream`].
///
/// This stream will always start by yielding the current value when the WatchStream is polled,
/// regardless of whether it was the initial value or sent afterwards.
///
/// # Examples
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{StreamExt, wrappers::WatchStream};
/// use tokio::sync::watch;
///
/// let (tx, rx) = watch::channel("hello");
/// let mut rx = WatchStream::new(rx);
///
/// assert_eq!(rx.next().await, Some("hello"));
///
/// tx.send("goodbye").unwrap();
/// assert_eq!(rx.next().await, Some("goodbye"));
/// # }
/// ```
///
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio_stream::{StreamExt, wrappers::WatchStream};
/// use tokio::sync::watch;
///
/// let (tx, rx) = watch::channel("hello");
/// let mut rx = WatchStream::new(rx);
///
/// tx.send("goodbye").unwrap();
/// assert_eq!(rx.next().await, Some("goodbye"));
/// # }
/// ```
///
/// [`tokio::sync::watch::Receiver`]: struct@tokio::sync::watch::Receiver
/// [`Stream`]: trait@crate::Stream
#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
pub struct WatchStream<T> {
inner: ReusableBoxFuture<(Result<(), RecvError>, Receiver<T>)>,
}
async fn make_future<T: Clone + Send + Sync>(
mut rx: Receiver<T>,
) -> (Result<(), RecvError>, Receiver<T>) {
let result = rx.changed().await;
(result, rx)
}
impl<T: 'static + Clone + Send + Sync> WatchStream<T> {
/// Create a new `WatchStream`.
pub fn new(rx: Receiver<T>) -> Self {
Self {
inner: ReusableBoxFuture::new(async move { (Ok(()), rx) }),
}
}
}
impl<T: Clone + 'static + Send + Sync> Stream for WatchStream<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let (result, mut rx) = ready!(self.inner.poll(cx));
match result {
Ok(_) => {
let received = (*rx.borrow_and_update()).clone();
self.inner.set(make_future(rx));
Poll::Ready(Some(received))
}
Err(_) => {
self.inner.set(make_future(rx));
Poll::Ready(None)
}
}
}
}
impl<T> Unpin for WatchStream<T> {}
impl<T> fmt::Debug for WatchStream<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WatchStream").finish()
}
}
impl<T: 'static + Clone + Send + Sync> From<Receiver<T>> for WatchStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
+107
View File
@@ -0,0 +1,107 @@
#![allow(clippy::diverging_sub_expression)]
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);

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