1use core::future::Future;
2
3cfg_time!(
4 use core::time::Duration;
5);
6
7use crate::Yielder;
8
9#[cfg(feature = "smol")]
10macro_rules! join_handle {
11 ($handle:ty) => {
12 pin_project_lite::pin_project! {
13 pub struct JoinHandle<T> {
15 #[pin]
16 handle: $handle,
17 }
18 }
19
20 impl<T> From<$handle> for JoinHandle<T> {
21 fn from(handle: $handle) -> Self {
22 Self { handle }
23 }
24 }
25
26 impl<T> core::future::Future for JoinHandle<T> {
27 type Output = core::result::Result<T, $crate::spawner::handle::JoinError>;
28
29 fn poll(
30 self: core::pin::Pin<&mut Self>,
31 cx: &mut core::task::Context<'_>,
32 ) -> core::task::Poll<Self::Output> {
33 let this = self.project();
34
35 match this.handle.poll(cx) {
36 core::task::Poll::Ready(v) => core::task::Poll::Ready(Ok(v)),
37 core::task::Poll::Pending => core::task::Poll::Pending,
38 }
39 }
40 }
41 };
42}
43
44#[cfg(any(feature = "smol", feature = "wasm", feature = "embassy"))]
45pub(crate) mod handle {
46 #[derive(Debug, Clone, PartialEq, Eq)]
51 pub struct JoinError(());
52
53 impl JoinError {
54 #[inline]
56 #[cfg(any(feature = "wasm", feature = "embassy"))]
57 pub(crate) const fn new() -> Self {
58 Self(())
59 }
60 }
61
62 impl core::fmt::Display for JoinError {
63 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64 write!(f, "task failed to execute to completion")
65 }
66 }
67
68 impl core::error::Error for JoinError {}
69
70 #[cfg(feature = "std")]
71 impl From<JoinError> for std::io::Error {
72 fn from(_: JoinError) -> Self {
73 std::io::Error::other("join error")
74 }
75 }
76}
77
78pub trait JoinHandle<O>: Future<Output = Result<O, Self::JoinError>> + Unpin {
80 #[cfg(feature = "std")]
82 type JoinError: core::error::Error + Into<std::io::Error> + Send + Sync + 'static;
83
84 #[cfg(not(feature = "std"))]
86 type JoinError: core::error::Error + Send + Sync + 'static;
87
88 fn abort(self);
90
91 fn detach(self)
93 where
94 Self: Sized,
95 {
96 drop(self)
97 }
98}
99
100pub trait LocalJoinHandle<O>: Future<Output = Result<O, Self::JoinError>> + Unpin {
102 #[cfg(feature = "std")]
104 type JoinError: core::error::Error + Into<std::io::Error> + 'static;
105 #[cfg(not(feature = "std"))]
107 type JoinError: core::error::Error + 'static;
108
109 fn detach(self)
111 where
112 Self: Sized,
113 {
114 drop(self)
115 }
116}
117
118pub trait AsyncSpawner: Yielder + Copy + Send + Sync + 'static {
120 type JoinHandle<O>: JoinHandle<O> + Send + Sync + 'static
122 where
123 O: Send + 'static;
124
125 fn spawn<F>(future: F) -> Self::JoinHandle<F::Output>
127 where
128 F::Output: Send + 'static,
129 F: Future + Send + 'static;
130
131 fn spawn_detach<F>(future: F)
133 where
134 F::Output: Send + 'static,
135 F: Future + Send + 'static,
136 {
137 core::mem::drop(Self::spawn(future));
138 }
139}
140
141pub trait AsyncLocalSpawner: Yielder + Copy + 'static {
155 type JoinHandle<O>: LocalJoinHandle<O> + 'static
157 where
158 O: 'static;
159
160 fn spawn_local<F>(future: F) -> Self::JoinHandle<F::Output>
162 where
163 F::Output: 'static,
164 F: Future + 'static;
165
166 fn spawn_local_detach<F>(future: F)
168 where
169 F::Output: 'static,
170 F: Future + 'static,
171 {
172 core::mem::drop(Self::spawn_local(future));
173 }
174}
175
176pub trait AsyncBlockingSpawner: Yielder + Copy + 'static {
178 type JoinHandle<R>: JoinHandle<R> + Send + 'static
180 where
181 R: Send + 'static;
182
183 fn spawn_blocking<F, R>(f: F) -> Self::JoinHandle<R>
185 where
186 F: FnOnce() -> R + Send + 'static,
187 R: Send + 'static;
188
189 fn spawn_blocking_detach<F, R>(f: F)
191 where
192 F: FnOnce() -> R + Send + 'static,
193 R: Send + 'static,
194 {
195 Self::spawn_blocking(f).detach();
196 }
197}
198
199#[derive(Debug, Clone, Copy)]
201#[cfg(all(
202 feature = "time",
203 any(
204 feature = "tokio",
205 feature = "smol",
206 feature = "wasm",
207 feature = "embassy"
208 )
209))]
210pub(crate) struct Canceled;
211
212#[cfg(all(
213 feature = "time",
214 any(
215 feature = "tokio",
216 feature = "smol",
217 feature = "wasm",
218 feature = "embassy"
219 )
220))]
221impl core::fmt::Display for Canceled {
222 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
223 write!(f, "after canceled")
224 }
225}
226
227#[cfg(all(
228 feature = "time",
229 any(
230 feature = "tokio",
231 feature = "smol",
232 feature = "wasm",
233 feature = "embassy"
234 )
235))]
236impl core::error::Error for Canceled {}
237
238#[cfg(feature = "time")]
240#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
241#[derive(Debug)]
242pub enum AfterHandleError<E> {
243 Canceled,
245 Join(E),
247}
248
249#[cfg(feature = "time")]
250impl<E: core::fmt::Display> core::fmt::Display for AfterHandleError<E> {
251 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
252 match self {
253 Self::Canceled => write!(f, "after function was canceled"),
254 Self::Join(e) => write!(f, "{e}"),
255 }
256 }
257}
258
259#[cfg(feature = "time")]
260impl<E: core::error::Error> core::error::Error for AfterHandleError<E> {}
261
262#[cfg(all(feature = "time", feature = "std"))]
263impl<E: core::error::Error + Send + Sync + 'static> From<AfterHandleError<E>> for std::io::Error {
264 fn from(value: AfterHandleError<E>) -> Self {
265 match value {
266 AfterHandleError::Canceled => std::io::Error::other("task canceled"),
267 AfterHandleError::Join(e) => std::io::Error::other(e),
268 }
269 }
270}
271
272#[cfg(all(
273 feature = "time",
274 any(
275 feature = "tokio",
276 feature = "smol",
277 feature = "wasm",
278 feature = "embassy"
279 )
280))]
281pub(crate) struct AfterHandleSignals {
282 finished: core::sync::atomic::AtomicBool,
283 expired: core::sync::atomic::AtomicBool,
284}
285
286#[cfg(all(
287 feature = "time",
288 any(
289 feature = "tokio",
290 feature = "smol",
291 feature = "wasm",
292 feature = "embassy"
293 )
294))]
295impl AfterHandleSignals {
296 #[inline]
297 pub(crate) const fn new() -> Self {
298 Self {
299 finished: core::sync::atomic::AtomicBool::new(false),
300 expired: core::sync::atomic::AtomicBool::new(false),
301 }
302 }
303
304 #[inline]
305 pub(crate) fn set_finished(&self) {
306 self
307 .finished
308 .store(true, core::sync::atomic::Ordering::Release);
309 }
310
311 #[inline]
312 pub(crate) fn set_expired(&self) {
313 self
314 .expired
315 .store(true, core::sync::atomic::Ordering::Release);
316 }
317
318 #[inline]
319 pub(crate) fn is_finished(&self) -> bool {
320 self.finished.load(core::sync::atomic::Ordering::Acquire)
321 }
322
323 #[inline]
324 pub(crate) fn is_expired(&self) -> bool {
325 self.expired.load(core::sync::atomic::Ordering::Acquire)
326 }
327}
328
329#[cfg(feature = "time")]
333#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
334pub trait AfterHandle<F: Send + 'static>:
335 Send + Sync + Future<Output = Result<F, Self::JoinError>> + 'static
336{
337 #[cfg(feature = "std")]
339 type JoinError: core::error::Error + Into<std::io::Error> + Send + Sync + 'static;
340 #[cfg(not(feature = "std"))]
342 type JoinError: core::error::Error + 'static;
343
344 fn cancel(self) -> impl Future<Output = Option<Result<F, Self::JoinError>>> + Send;
348
349 fn reset(&self, duration: core::time::Duration);
351
352 fn abort(self);
354
355 fn detach(self)
357 where
358 Self: Sized,
359 {
360 drop(self)
361 }
362
363 fn is_expired(&self) -> bool;
365
366 fn is_finished(&self) -> bool;
368}
369
370#[cfg(feature = "time")]
372#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
373pub trait AsyncAfterSpawner: Copy + Send + Sync + 'static {
374 type Instant: crate::time::Instant;
376
377 type JoinHandle<F>: AfterHandle<F>
379 where
380 F: Send + 'static;
381
382 fn spawn_after<F>(duration: Duration, future: F) -> Self::JoinHandle<F::Output>
384 where
385 F::Output: Send + 'static,
386 F: Future + Send + 'static;
387
388 fn spawn_after_detach<F>(duration: Duration, future: F)
390 where
391 F::Output: Send + 'static,
392 F: Future + Send + 'static,
393 {
394 core::mem::drop(Self::spawn_after(duration, future));
395 }
396
397 fn spawn_after_at<F>(instant: Self::Instant, future: F) -> Self::JoinHandle<F::Output>
399 where
400 F::Output: Send + 'static,
401 F: Future + Send + 'static;
402
403 fn spawn_after_at_detach<F>(instant: Self::Instant, future: F)
405 where
406 F::Output: Send + 'static,
407 F: Future + Send + 'static,
408 {
409 Self::spawn_after_at(instant, future).detach()
410 }
411}