|
5 | 5 | //! Experimental. The library works as is, breaking changes will bump major
|
6 | 6 | //! version, but there are no guarantees of long-term support.
|
7 | 7 | //!
|
8 |
| -//! Additionally, this library uses unstable cargo feature feature of `async-std` and, for |
9 |
| -//! this reason, should be used like this: |
10 |
| -//! |
11 |
| -//! ```toml |
12 |
| -//! [dependencies.stop-token] |
13 |
| -//! version = "0.1.0" |
14 |
| -//! features = [ "unstable" ] |
15 |
| -//! ``` |
16 |
| -//! |
17 | 8 | //! # Motivation
|
18 | 9 | //!
|
19 | 10 | //! Rust futures come with a build-in cancellation mechanism: dropping a future
|
|
47 | 38 | //!
|
48 | 39 | //! ```
|
49 | 40 | //! use async_std::prelude::*;
|
| 41 | +//! use stop_token::prelude::*; |
50 | 42 | //! use stop_token::StopToken;
|
51 | 43 | //!
|
52 | 44 | //! struct Event;
|
53 | 45 | //!
|
54 |
| -//! async fn do_work(work: impl Stream<Item = Event> + Unpin, stop_token: StopToken) { |
55 |
| -//! let mut work = stop_token.stop_stream(work); |
56 |
| -//! while let Some(event) = work.next().await { |
| 46 | +//! async fn do_work(work: impl Stream<Item = Event> + Unpin, stop: StopToken) { |
| 47 | +//! let mut work = work.until(stop); |
| 48 | +//! while let Some(Ok(event)) = work.next().await { |
57 | 49 | //! process_event(event).await
|
58 | 50 | //! }
|
59 | 51 | //! }
|
|
62 | 54 | //! }
|
63 | 55 | //! ```
|
64 | 56 | //!
|
| 57 | +//! # Features |
| 58 | +//! |
| 59 | +//! The `time` submodule is empty when no features are enabled. To implement [`Deadline`] |
| 60 | +//! for `Instant` and `Duration` you can enable one of the following features: |
| 61 | +//! |
| 62 | +//! - `async-io`: for use with the `async-std` or `smol` runtimes. |
| 63 | +//! - `tokio`: for use with the `tokio` runtime. |
| 64 | +//! |
65 | 65 | //! # Lineage
|
66 | 66 | //!
|
67 | 67 | //! The cancellation system is a subset of `C#` [`CancellationToken / CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads).
|
68 |
| -//! The `StopToken / StopTokenSource` terminology is borrowed from C++ paper P0660: https://wg21.link/p0660. |
69 |
| -
|
70 |
| -use std::pin::Pin; |
71 |
| -use std::task::{Context, Poll}; |
72 |
| - |
73 |
| -use async_std::prelude::*; |
| 68 | +//! The `StopToken / StopTokenSource` terminology is borrowed from [C++ paper P0660](https://wg21.link/p0660). |
74 | 69 |
|
75 |
| -use async_std::channel::{self, Receiver, Sender}; |
76 |
| -use pin_project_lite::pin_project; |
77 |
| - |
78 |
| -enum Never {} |
79 |
| - |
80 |
| -/// `StopSource` produces `StopToken` and cancels all of its tokens on drop. |
81 |
| -/// |
82 |
| -/// # Example: |
83 |
| -/// |
84 |
| -/// ```ignore |
85 |
| -/// let stop_source = StopSource::new(); |
86 |
| -/// let stop_token = stop_source.stop_token(); |
87 |
| -/// schedule_some_work(stop_token); |
88 |
| -/// drop(stop_source); // At this point, scheduled work notices that it is canceled. |
89 |
| -/// ``` |
90 |
| -#[derive(Debug)] |
91 |
| -pub struct StopSource { |
92 |
| - /// Solely for `Drop`. |
93 |
| - _chan: Sender<Never>, |
94 |
| - stop_token: StopToken, |
95 |
| -} |
96 |
| - |
97 |
| -/// `StopToken` is a future which completes when the associated `StopSource` is dropped. |
98 |
| -#[derive(Debug, Clone)] |
99 |
| -pub struct StopToken { |
100 |
| - chan: Receiver<Never>, |
101 |
| -} |
102 |
| - |
103 |
| -impl Default for StopSource { |
104 |
| - fn default() -> StopSource { |
105 |
| - let (sender, receiver) = channel::bounded::<Never>(1); |
106 |
| - |
107 |
| - StopSource { |
108 |
| - _chan: sender, |
109 |
| - stop_token: StopToken { chan: receiver }, |
110 |
| - } |
111 |
| - } |
112 |
| -} |
| 70 | +pub mod future; |
| 71 | +pub mod stream; |
| 72 | +pub mod time; |
113 | 73 |
|
114 |
| -impl StopSource { |
115 |
| - /// Creates a new `StopSource`. |
116 |
| - pub fn new() -> StopSource { |
117 |
| - StopSource::default() |
118 |
| - } |
119 |
| - |
120 |
| - /// Produces a new `StopToken`, associated with this source. |
121 |
| - /// |
122 |
| - /// Once the source is destroyed, `StopToken` future completes. |
123 |
| - pub fn stop_token(&self) -> StopToken { |
124 |
| - self.stop_token.clone() |
125 |
| - } |
126 |
| -} |
127 |
| - |
128 |
| -impl Future for StopToken { |
129 |
| - type Output = (); |
130 |
| - |
131 |
| - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { |
132 |
| - let chan = Pin::new(&mut self.chan); |
133 |
| - match Stream::poll_next(chan, cx) { |
134 |
| - Poll::Pending => Poll::Pending, |
135 |
| - Poll::Ready(Some(never)) => match never {}, |
136 |
| - Poll::Ready(None) => Poll::Ready(()), |
137 |
| - } |
138 |
| - } |
139 |
| -} |
140 |
| - |
141 |
| -impl StopToken { |
142 |
| - /// Applies the token to the `stream`, such that the resulting stream |
143 |
| - /// produces no more items once the token becomes cancelled. |
144 |
| - pub fn stop_stream<S: Stream>(&self, stream: S) -> StopStream<S> { |
145 |
| - StopStream { |
146 |
| - stop_token: self.clone(), |
147 |
| - stream, |
148 |
| - } |
149 |
| - } |
150 |
| - |
151 |
| - /// Applies the token to the `future`, such that the resulting future |
152 |
| - /// completes with `None` if the token is cancelled. |
153 |
| - pub fn stop_future<F: Future>(&self, future: F) -> StopFuture<F> { |
154 |
| - StopFuture { |
155 |
| - stop_token: self.clone(), |
156 |
| - future, |
157 |
| - } |
158 |
| - } |
159 |
| -} |
160 |
| - |
161 |
| -pin_project! { |
162 |
| - #[derive(Debug)] |
163 |
| - pub struct StopStream<S> { |
164 |
| - #[pin] |
165 |
| - stop_token: StopToken, |
166 |
| - #[pin] |
167 |
| - stream: S, |
168 |
| - } |
169 |
| -} |
170 |
| - |
171 |
| -impl<S: Stream> Stream for StopStream<S> { |
172 |
| - type Item = S::Item; |
173 |
| - |
174 |
| - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { |
175 |
| - let this = self.project(); |
176 |
| - if let Poll::Ready(()) = this.stop_token.poll(cx) { |
177 |
| - return Poll::Ready(None); |
178 |
| - } |
179 |
| - this.stream.poll_next(cx) |
180 |
| - } |
181 |
| -} |
182 |
| - |
183 |
| -pin_project! { |
184 |
| - #[derive(Debug)] |
185 |
| - pub struct StopFuture<F> { |
186 |
| - #[pin] |
187 |
| - stop_token: StopToken, |
188 |
| - #[pin] |
189 |
| - future: F, |
190 |
| - } |
191 |
| -} |
| 74 | +mod deadline; |
| 75 | +mod stop_source; |
192 | 76 |
|
193 |
| -impl<F: Future> Future for StopFuture<F> { |
194 |
| - type Output = Option<F::Output>; |
| 77 | +pub use deadline::{IntoDeadline, TimedOutError}; |
| 78 | +pub use stop_source::{StopSource, StopToken}; |
195 | 79 |
|
196 |
| - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<F::Output>> { |
197 |
| - let this = self.project(); |
198 |
| - if let Poll::Ready(()) = this.stop_token.poll(cx) { |
199 |
| - return Poll::Ready(None); |
200 |
| - } |
201 |
| - match this.future.poll(cx) { |
202 |
| - Poll::Pending => Poll::Pending, |
203 |
| - Poll::Ready(it) => Poll::Ready(Some(it)), |
204 |
| - } |
205 |
| - } |
| 80 | +/// A prelude for `stop-token`. |
| 81 | +pub mod prelude { |
| 82 | + pub use crate::future::FutureExt as _; |
| 83 | + pub use crate::stream::StreamExt as _; |
206 | 84 | }
|
0 commit comments