zng_task/lib.rs
1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3//!
4//! Parallel async tasks and async task runners.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12use std::{
13 any::Any,
14 fmt,
15 hash::Hash,
16 mem, panic,
17 pin::Pin,
18 sync::{
19 Arc,
20 atomic::{AtomicBool, Ordering},
21 },
22 task::Poll,
23};
24
25use zng_app_context::{LocalContext, app_local};
26use zng_time::Deadline;
27use zng_var::{ResponseVar, VarValue, response_done_var, response_var};
28
29#[cfg(test)]
30mod tests;
31
32mod reexports;
33pub use reexports::*;
34
35use crate::parking_lot::Mutex;
36
37pub mod channel;
38pub mod fs;
39pub mod io;
40
41mod ui;
42pub use ui::*;
43
44pub mod http;
45
46pub mod process;
47
48mod rayon_ctx;
49
50mod progress;
51pub use progress::*;
52
53/// Spawn a parallel async task, this function is not blocking and the `task` starts executing immediately.
54///
55/// # Parallel
56///
57/// The task runs in the primary [`rayon`] thread-pool, every [`poll`](Future::poll) happens inside a call to `rayon::spawn`.
58///
59/// You can use parallel iterators, `join` or any of rayon's utilities inside `task` to make it multi-threaded,
60/// otherwise it will run in a single thread at a time, still not blocking the UI.
61///
62/// The [`rayon`] crate is re-exported in `task::rayon` for convenience and compatibility.
63///
64/// # Async
65///
66/// The `task` is also a future so you can `.await`, after each `.await` the task continues executing in whatever `rayon` thread
67/// is free, so the `task` should either be doing CPU intensive work or awaiting, blocking IO operations
68/// block the thread from being used by other tasks reducing overall performance. You can use [`wait`] for IO
69/// or blocking operations and for networking you can use any of the async crates, as long as they start their own *event reactor*.
70///
71/// The `task` lives inside the [`Waker`] when awaiting and inside `rayon::spawn` when running.
72///
73/// # Examples
74///
75/// ```
76/// # use zng_task::{self as task, *, rayon::iter::*};
77/// # use zng_var::*;
78/// # struct SomeStruct { sum_response: ResponseVar<usize> }
79/// # impl SomeStruct {
80/// fn on_event(&mut self) {
81/// let (responder, response) = response_var();
82/// self.sum_response = response;
83///
84/// task::spawn(async move {
85/// let r = (0..1000).into_par_iter().map(|i| i * i).sum();
86///
87/// responder.respond(r);
88/// });
89/// }
90///
91/// fn on_update(&mut self) {
92/// if let Some(result) = self.sum_response.rsp_new() {
93/// println!("sum of squares 0..1000: {result}");
94/// }
95/// }
96/// # }
97/// ```
98///
99/// The example uses the `rayon` parallel iterator to compute a result and uses a [`response_var`] to send the result to the UI.
100/// The task captures the caller [`LocalContext`] so the response variable will set correctly.
101///
102/// Note that this function is the most basic way to spawn a parallel task where you must setup channels to the rest of the app yourself,
103/// you can use [`respond`] to avoid having to manually set a response, or [`run`] to `.await` the result.
104///
105/// # Panic Handling
106///
107/// If the `task` panics the panic message is logged as an error, and can observed using [`set_spawn_panic_handler`]. It
108/// is otherwise ignored.
109///
110/// # Unwind Safety
111///
112/// This function disables the [unwind safety validation], meaning that in case of a panic shared
113/// data can end-up in an invalid, but still memory safe, state. If you are worried about that only use
114/// poisoning mutexes or atomics to mutate shared data or use [`run_catch`] to detect a panic or [`run`]
115/// to propagate a panic.
116///
117/// [unwind safety validation]: std::panic::UnwindSafe
118/// [`Waker`]: std::task::Waker
119/// [`rayon`]: https://docs.rs/rayon
120/// [`LocalContext`]: zng_app_context::LocalContext
121/// [`response_var`]: zng_var::response_var
122pub fn spawn<F>(task: impl IntoFuture<IntoFuture = F>)
123where
124 F: Future<Output = ()> + Send + 'static,
125{
126 Arc::new(RayonTask {
127 ctx: LocalContext::capture(),
128 fut: Mutex::new(Some(Box::pin(task.into_future()))),
129 })
130 .poll()
131}
132
133/// Polls the `task` once immediately on the calling thread, if the `task` is pending, continues execution in [`spawn`].
134pub fn poll_spawn<F>(task: impl IntoFuture<IntoFuture = F>)
135where
136 F: Future<Output = ()> + Send + 'static,
137{
138 struct PollRayonTask {
139 fut: Mutex<Option<(RayonSpawnFut, Option<LocalContext>)>>,
140 }
141 impl PollRayonTask {
142 // start task in calling thread
143 fn poll(self: Arc<Self>) {
144 let mut task = self.fut.lock();
145 let (mut t, _) = task.take().unwrap();
146
147 let waker = self.clone().into();
148
149 match t.as_mut().poll(&mut std::task::Context::from_waker(&waker)) {
150 Poll::Ready(()) => {}
151 Poll::Pending => {
152 let ctx = LocalContext::capture();
153 *task = Some((t, Some(ctx)));
154 }
155 }
156 }
157 }
158 impl std::task::Wake for PollRayonTask {
159 fn wake(self: Arc<Self>) {
160 // continue task in spawn threads
161 if let Some((task, Some(ctx))) = self.fut.lock().take() {
162 Arc::new(RayonTask {
163 ctx,
164 fut: Mutex::new(Some(Box::pin(task))),
165 })
166 .poll();
167 }
168 }
169 }
170
171 Arc::new(PollRayonTask {
172 fut: Mutex::new(Some((Box::pin(task.into_future()), None))),
173 })
174 .poll()
175}
176
177type RayonSpawnFut = Pin<Box<dyn Future<Output = ()> + Send>>;
178
179// A future that is its own waker that polls inside rayon spawn tasks.
180struct RayonTask {
181 ctx: LocalContext,
182 fut: Mutex<Option<RayonSpawnFut>>,
183}
184impl RayonTask {
185 fn poll(self: Arc<Self>) {
186 ::rayon::spawn(move || {
187 // this `Option<Fut>` dance is used to avoid a `poll` after `Ready` or panic.
188 let mut task = self.fut.lock();
189 if let Some(mut t) = task.take() {
190 let waker = self.clone().into();
191
192 // load app context
193 self.ctx.clone().with_context(move || {
194 let r = panic::catch_unwind(panic::AssertUnwindSafe(move || {
195 // poll future
196 if t.as_mut().poll(&mut std::task::Context::from_waker(&waker)).is_pending() {
197 // not done
198 *task = Some(t);
199 }
200 }));
201 if let Err(p) = r {
202 let p = TaskPanicError::new(p);
203 tracing::error!("panic in `task::spawn`: {}", p.panic_str().unwrap_or(""));
204 on_spawn_panic(p);
205 }
206 });
207 }
208 })
209 }
210}
211impl std::task::Wake for RayonTask {
212 fn wake(self: Arc<Self>) {
213 self.poll()
214 }
215}
216
217/// Rayon join with local context.
218///
219/// This function captures the [`LocalContext`] of the calling thread and propagates it to the threads that run the
220/// operations.
221///
222/// See `rayon::join` for more details about join.
223///
224/// [`LocalContext`]: zng_app_context::LocalContext
225pub fn join<A, B, RA, RB>(op_a: A, op_b: B) -> (RA, RB)
226where
227 A: FnOnce() -> RA + Send,
228 B: FnOnce() -> RB + Send,
229 RA: Send,
230 RB: Send,
231{
232 self::join_context(move |_| op_a(), move |_| op_b())
233}
234
235/// Rayon join context with local context.
236///
237/// This function captures the [`LocalContext`] of the calling thread and propagates it to the threads that run the
238/// operations.
239///
240/// See `rayon::join_context` for more details about join.
241///
242/// [`LocalContext`]: zng_app_context::LocalContext
243pub fn join_context<A, B, RA, RB>(op_a: A, op_b: B) -> (RA, RB)
244where
245 A: FnOnce(::rayon::FnContext) -> RA + Send,
246 B: FnOnce(::rayon::FnContext) -> RB + Send,
247 RA: Send,
248 RB: Send,
249{
250 let ctx = LocalContext::capture();
251 let ctx = &ctx;
252 ::rayon::join_context(
253 move |a| {
254 if a.migrated() {
255 ctx.clone().with_context(|| op_a(a))
256 } else {
257 op_a(a)
258 }
259 },
260 move |b| {
261 if b.migrated() {
262 ctx.clone().with_context(|| op_b(b))
263 } else {
264 op_b(b)
265 }
266 },
267 )
268}
269
270/// Rayon scope with local context.
271///
272/// This function captures the [`LocalContext`] of the calling thread and propagates it to the threads that run the
273/// operations.
274///
275/// See `rayon::scope` for more details about scope.
276///
277/// [`LocalContext`]: zng_app_context::LocalContext
278pub fn scope<'scope, OP, R>(op: OP) -> R
279where
280 OP: FnOnce(ScopeCtx<'_, 'scope>) -> R + Send,
281 R: Send,
282{
283 let ctx = LocalContext::capture();
284
285 // Cast `&'_ ctx` to `&'scope ctx` to "inject" the context in the scope.
286 // Is there a better way to do this? I hope so.
287 //
288 // SAFETY:
289 // * We are extending `'_` to `'scope`, that is one of the documented valid usages of `transmute`.
290 // * No use after free because `rayon::scope` joins all threads before returning and we only drop `ctx` after.
291 let ctx_ref: &'_ LocalContext = &ctx;
292 let ctx_scope_ref: &'scope LocalContext = unsafe { std::mem::transmute(ctx_ref) };
293
294 let r = ::rayon::scope(move |s| {
295 op(ScopeCtx {
296 scope: s,
297 ctx: ctx_scope_ref,
298 })
299 });
300
301 drop(ctx);
302
303 r
304}
305
306/// Represents a fork-join scope which can be used to spawn any number of tasks that run in the caller's thread context.
307///
308/// See [`scope`] for more details.
309#[derive(Clone, Copy, Debug)]
310pub struct ScopeCtx<'a, 'scope: 'a> {
311 scope: &'a ::rayon::Scope<'scope>,
312 ctx: &'scope LocalContext,
313}
314impl<'a, 'scope: 'a> ScopeCtx<'a, 'scope> {
315 /// Spawns a job into the fork-join scope `self`. The job runs in the captured thread context.
316 ///
317 /// See `rayon::Scope::spawn` for more details.
318 pub fn spawn<F>(self, f: F)
319 where
320 F: FnOnce(ScopeCtx<'_, 'scope>) + Send + 'scope,
321 {
322 let ctx = self.ctx;
323 self.scope
324 .spawn(move |s| ctx.clone().with_context(move || f(ScopeCtx { scope: s, ctx })));
325 }
326}
327
328/// Spawn a parallel async task that can also be `.await` for the task result.
329///
330/// # Parallel
331///
332/// The task runs in the primary [`rayon`] thread-pool, every [`poll`](Future::poll) happens inside a call to `rayon::spawn`.
333///
334/// You can use parallel iterators, `join` or any of rayon's utilities inside `task` to make it multi-threaded,
335/// otherwise it will run in a single thread at a time, still not blocking the UI.
336///
337/// The [`rayon`] crate is re-exported in `task::rayon` for convenience and compatibility.
338///
339/// # Async
340///
341/// The `task` is also a future so you can `.await`, after each `.await` the task continues executing in whatever `rayon` thread
342/// is free, so the `task` should either be doing CPU intensive work or awaiting, blocking IO operations
343/// block the thread from being used by other tasks reducing overall performance. You can use [`wait`] for IO
344/// or blocking operations and for networking you can use any of the async crates, as long as they start their own *event reactor*.
345///
346/// The `task` lives inside the [`Waker`] when awaiting and inside `rayon::spawn` when running.
347///
348/// # Examples
349///
350/// ```
351/// # use zng_task::{self as task, rayon::iter::*};
352/// # struct SomeStruct { sum: usize }
353/// # async fn read_numbers() -> Vec<usize> { vec![] }
354/// # impl SomeStruct {
355/// async fn on_event(&mut self) {
356/// self.sum = task::run(async { read_numbers().await.par_iter().map(|i| i * i).sum() }).await;
357/// }
358/// # }
359/// ```
360///
361/// The example `.await` for some numbers and then uses a parallel iterator to compute a result, this all runs in parallel
362/// because it is inside a `run` task. The task result is then `.await` inside one of the UI async tasks. Note that the
363/// task captures the caller [`LocalContext`] so you can interact with variables and UI services directly inside the task too.
364///
365/// # Cancellation
366///
367/// The task starts running immediately, awaiting the returned future merely awaits for a message from the worker threads and
368/// that means the `task` future is not owned by the returned future. Usually to *cancel* a future you only need to drop it,
369/// in this task dropping the returned future will only drop the `task` once it reaches a `.await` point and detects that the
370/// result channel is disconnected.
371///
372/// If you want to deterministically known that the `task` was cancelled use a cancellation signal.
373///
374/// # Panic Propagation
375///
376/// If the `task` panics the panic is resumed in the awaiting thread using [`resume_unwind`]. You
377/// can use [`run_catch`] to get the panic as an error instead.
378///
379/// [`resume_unwind`]: panic::resume_unwind
380/// [`Waker`]: std::task::Waker
381/// [`rayon`]: https://docs.rs/rayon
382/// [`LocalContext`]: zng_app_context::LocalContext
383pub async fn run<R, T>(task: impl IntoFuture<IntoFuture = T>) -> R
384where
385 R: Send + 'static,
386 T: Future<Output = R> + Send + 'static,
387{
388 match run_catch(task).await {
389 Ok(r) => r,
390 Err(p) => panic::resume_unwind(p.payload),
391 }
392}
393
394/// Like [`run`] but catches panics.
395///
396/// This task works the same and has the same utility as [`run`], except if returns panic messages
397/// as an error instead of propagating the panic.
398///
399/// # Unwind Safety
400///
401/// This function disables the [unwind safety validation], meaning that in case of a panic shared
402/// data can end-up in an invalid, but still memory safe, state. If you are worried about that only use
403/// poisoning mutexes or atomics to mutate shared data or discard all shared data used in the `task`
404/// if this function returns an error.
405///
406/// [unwind safety validation]: std::panic::UnwindSafe
407pub async fn run_catch<R, T>(task: impl IntoFuture<IntoFuture = T>) -> Result<R, TaskPanicError>
408where
409 R: Send + 'static,
410 T: Future<Output = R> + Send + 'static,
411{
412 type Fut<R> = Pin<Box<dyn Future<Output = R> + Send>>;
413
414 // A future that is its own waker that polls inside the rayon primary thread-pool.
415 struct RayonCatchTask<R> {
416 ctx: LocalContext,
417 fut: Mutex<Option<Fut<R>>>,
418 sender: flume::Sender<Result<R, TaskPanicError>>,
419 }
420 impl<R: Send + 'static> RayonCatchTask<R> {
421 fn poll(self: Arc<Self>) {
422 let sender = self.sender.clone();
423 if sender.is_disconnected() {
424 return; // cancel.
425 }
426 ::rayon::spawn(move || {
427 // this `Option<Fut>` dance is used to avoid a `poll` after `Ready` or panic.
428 let mut task = self.fut.lock();
429 if let Some(mut t) = task.take() {
430 let waker = self.clone().into();
431 let mut cx = std::task::Context::from_waker(&waker);
432
433 self.ctx.clone().with_context(|| {
434 let r = panic::catch_unwind(panic::AssertUnwindSafe(|| t.as_mut().poll(&mut cx)));
435 match r {
436 Ok(Poll::Ready(r)) => {
437 drop(task);
438 let _ = sender.send(Ok(r));
439 }
440 Ok(Poll::Pending) => {
441 *task = Some(t);
442 }
443 Err(p) => {
444 drop(task);
445 let _ = sender.send(Err(TaskPanicError::new(p)));
446 }
447 }
448 });
449 }
450 })
451 }
452 }
453 impl<R: Send + 'static> std::task::Wake for RayonCatchTask<R> {
454 fn wake(self: Arc<Self>) {
455 self.poll()
456 }
457 }
458
459 let (sender, receiver) = channel::bounded(1);
460
461 Arc::new(RayonCatchTask {
462 ctx: LocalContext::capture(),
463 fut: Mutex::new(Some(Box::pin(task.into_future()))),
464 sender: sender.into(),
465 })
466 .poll();
467
468 receiver.recv().await.unwrap()
469}
470
471/// Spawn a parallel async task that will send its result to a [`ResponseVar<R>`].
472///
473/// The [`run`] documentation explains how `task` is *parallel* and *async*. The `task` starts executing immediately.
474///
475/// # Examples
476///
477/// ```
478/// # use zng_task::{self as task, rayon::iter::*};
479/// # use zng_var::*;
480/// # struct SomeStruct { sum_response: ResponseVar<usize> }
481/// # async fn read_numbers() -> Vec<usize> { vec![] }
482/// # impl SomeStruct {
483/// fn on_event(&mut self) {
484/// self.sum_response = task::respond(async { read_numbers().await.par_iter().map(|i| i * i).sum() });
485/// }
486///
487/// fn on_update(&mut self) {
488/// if let Some(result) = self.sum_response.rsp_new() {
489/// println!("sum of squares: {result}");
490/// }
491/// }
492/// # }
493/// ```
494///
495/// The example `.await` for some numbers and then uses a parallel iterator to compute a result. The result is send to
496/// `sum_response` that is a [`ResponseVar<R>`].
497///
498/// # Cancellation
499///
500/// Dropping the [`ResponseVar<R>`] does not cancel the `task`, it will still run to completion.
501///
502/// # Panic Handling
503///
504/// If the `task` panics the panic is logged as an error and resumed in the response var modify closure.
505///
506/// [`resume_unwind`]: panic::resume_unwind
507/// [`ResponseVar<R>`]: zng_var::ResponseVar
508/// [`response_var`]: zng_var::response_var
509pub fn respond<R, F>(task: F) -> ResponseVar<R>
510where
511 R: VarValue,
512 F: Future<Output = R> + Send + 'static,
513{
514 type Fut<R> = Pin<Box<dyn Future<Output = R> + Send>>;
515
516 let (responder, response) = response_var();
517
518 // A future that is its own waker that polls inside the rayon primary thread-pool.
519 struct RayonRespondTask<R: VarValue> {
520 ctx: LocalContext,
521 fut: Mutex<Option<Fut<R>>>,
522 responder: zng_var::ResponderVar<R>,
523 }
524 impl<R: VarValue> RayonRespondTask<R> {
525 fn poll(self: Arc<Self>) {
526 let responder = self.responder.clone();
527 if responder.strong_count() == 2 {
528 return; // cancel.
529 }
530 ::rayon::spawn(move || {
531 // this `Option<Fut>` dance is used to avoid a `poll` after `Ready` or panic.
532 let mut task = self.fut.lock();
533 if let Some(mut t) = task.take() {
534 let waker = self.clone().into();
535 let mut cx = std::task::Context::from_waker(&waker);
536
537 self.ctx.clone().with_context(|| {
538 let r = panic::catch_unwind(panic::AssertUnwindSafe(|| t.as_mut().poll(&mut cx)));
539 match r {
540 Ok(Poll::Ready(r)) => {
541 drop(task);
542
543 responder.respond(r);
544 }
545 Ok(Poll::Pending) => {
546 *task = Some(t);
547 }
548 Err(p) => {
549 let p = TaskPanicError::new(p);
550 tracing::error!("panic in `task::respond`: {}", p.panic_str().unwrap_or(""));
551 drop(task);
552 responder.modify(move |_| panic::resume_unwind(p.payload));
553 }
554 }
555 });
556 }
557 })
558 }
559 }
560 impl<R: VarValue> std::task::Wake for RayonRespondTask<R> {
561 fn wake(self: Arc<Self>) {
562 self.poll()
563 }
564 }
565
566 Arc::new(RayonRespondTask {
567 ctx: LocalContext::capture(),
568 fut: Mutex::new(Some(Box::pin(task))),
569 responder,
570 })
571 .poll();
572
573 response
574}
575
576/// Polls the `task` once immediately on the calling thread, if the `task` is ready returns the response already set,
577/// if the `task` is pending continues execution like [`respond`].
578pub fn poll_respond<R, F>(task: impl IntoFuture<IntoFuture = F>) -> ResponseVar<R>
579where
580 R: VarValue,
581 F: Future<Output = R> + Send + 'static,
582{
583 enum QuickResponse<R: VarValue> {
584 Quick(Option<R>),
585 Response(zng_var::ResponderVar<R>),
586 }
587 let task = task.into_future();
588 let q = Arc::new(Mutex::new(QuickResponse::Quick(None)));
589 poll_spawn(zng_clone_move::async_clmv!(q, {
590 let rsp = task.await;
591
592 match &mut *q.lock() {
593 QuickResponse::Quick(q) => *q = Some(rsp),
594 QuickResponse::Response(r) => r.respond(rsp),
595 }
596 }));
597
598 let mut q = q.lock();
599 match &mut *q {
600 QuickResponse::Quick(q) if q.is_some() => response_done_var(q.take().unwrap()),
601 _ => {
602 let (responder, response) = response_var();
603 *q = QuickResponse::Response(responder);
604 response
605 }
606 }
607}
608
609/// Create a parallel `task` that blocks awaiting for an IO operation, the `task` starts on the first `.await`.
610///
611/// # Parallel
612///
613/// The `task` runs in the [`blocking`] thread-pool which is optimized for awaiting blocking operations.
614/// If the `task` is computation heavy you should use [`run`] and then `wait` inside that task for the
615/// parts that are blocking.
616///
617/// # Examples
618///
619/// ```
620/// # fn main() { }
621/// # use zng_task as task;
622/// # async fn example() {
623/// task::wait(|| std::fs::read_to_string("file.txt")).await
624/// # ; }
625/// ```
626///
627/// The example reads a file, that is a blocking file IO operation, most of the time is spend waiting for the operating system,
628/// so we offload this to a `wait` task. The task can be `.await` inside a [`run`] task or inside one of the UI tasks
629/// like in a async event handler.
630///
631/// # Async Read/Write
632///
633/// For [`std::io::Read`] and [`std::io::Write`] operations you can also use [`io`] and [`fs`] alternatives when you don't
634/// have or want the full file in memory or when you want to apply multiple operations to the file.
635///
636/// # Panic Propagation
637///
638/// If the `task` panics the panic is resumed in the awaiting thread using [`resume_unwind`]. You
639/// can use [`wait_catch`] to get the panic as an error instead.
640///
641/// [`blocking`]: https://docs.rs/blocking
642/// [`resume_unwind`]: panic::resume_unwind
643pub async fn wait<T, F>(task: F) -> T
644where
645 F: FnOnce() -> T + Send + 'static,
646 T: Send + 'static,
647{
648 match wait_catch(task).await {
649 Ok(r) => r,
650 Err(p) => panic::resume_unwind(p.payload),
651 }
652}
653
654/// Like [`wait`] but catches panics.
655///
656/// This task works the same and has the same utility as [`wait`], except if returns panic messages
657/// as an error instead of propagating the panic.
658///
659/// # Unwind Safety
660///
661/// This function disables the [unwind safety validation], meaning that in case of a panic shared
662/// data can end-up in an invalid, but still memory safe, state. If you are worried about that only use
663/// poisoning mutexes or atomics to mutate shared data or discard all shared data used in the `task`
664/// if this function returns an error.
665///
666/// [unwind safety validation]: std::panic::UnwindSafe
667pub async fn wait_catch<T, F>(task: F) -> Result<T, TaskPanicError>
668where
669 F: FnOnce() -> T + Send + 'static,
670 T: Send + 'static,
671{
672 let mut ctx = LocalContext::capture();
673 blocking::unblock(move || ctx.with_context(move || panic::catch_unwind(panic::AssertUnwindSafe(task))))
674 .await
675 .map_err(TaskPanicError::new)
676}
677
678/// Fire and forget a [`wait`] task. The `task` starts executing immediately.
679///
680/// # Panic Handling
681///
682/// If the `task` panics the panic message is logged as an error, and can observed using [`set_spawn_panic_handler`]. It
683/// is otherwise ignored.
684///
685/// # Unwind Safety
686///
687/// This function disables the [unwind safety validation], meaning that in case of a panic shared
688/// data can end-up in an invalid (still memory safe) state. If you are worried about that only use
689/// poisoning mutexes or atomics to mutate shared data or use [`wait_catch`] to detect a panic or [`wait`]
690/// to propagate a panic.
691///
692/// [unwind safety validation]: std::panic::UnwindSafe
693pub fn spawn_wait<F>(task: F)
694where
695 F: FnOnce() + Send + 'static,
696{
697 spawn(async move {
698 if let Err(p) = wait_catch(task).await {
699 tracing::error!("parallel `spawn_wait` task panicked: {}", p.panic_str().unwrap_or(""));
700 on_spawn_panic(p);
701 }
702 });
703}
704
705/// Like [`spawn_wait`], but the task will send its result to a [`ResponseVar<R>`].
706///
707/// # Cancellation
708///
709/// Dropping the [`ResponseVar<R>`] does not cancel the `task`, it will still run to completion.
710///
711/// # Panic Handling
712///
713/// If the `task` panics the panic is logged as an error and resumed in the response var modify closure.
714pub fn wait_respond<R, F>(task: F) -> ResponseVar<R>
715where
716 R: VarValue,
717 F: FnOnce() -> R + Send + 'static,
718{
719 let (responder, response) = response_var();
720 spawn_wait(move || match panic::catch_unwind(panic::AssertUnwindSafe(task)) {
721 Ok(r) => responder.respond(r),
722 Err(p) => {
723 let p = TaskPanicError::new(p);
724 tracing::error!("panic in `task::wait_respond`: {}", p.panic_str().unwrap_or(""));
725 responder.modify(move |_| panic::resume_unwind(p.payload));
726 }
727 });
728 response
729}
730
731/// Blocks the thread until the `task` future finishes.
732///
733/// The crate [`futures-lite`] is used to execute the task.
734///
735/// # Examples
736///
737/// Test a [`run`] call:
738///
739/// ```
740/// use zng_task as task;
741/// # use zng_unit::*;
742/// # async fn foo(u: u8) -> Result<u8, ()> { task::deadline(1.ms()).await; Ok(u) }
743///
744/// # #[test]
745/// # fn __() { }
746/// pub fn run_ok() {
747/// let r = task::block_on(task::run(async { foo(32).await }));
748///
749/// # let value =
750/// r.expect("foo(32) was not Ok");
751/// # assert_eq!(32, value);
752/// }
753/// # run_ok();
754/// ```
755///
756/// # No App Context
757///
758/// If this is called inside an app thread a warning is logged and the app context is removed,
759/// the `task` never runs in an app context. This is done to avoid deadlocks where tasks depend
760/// on app updates to complete.
761///
762/// You should never block an app thread anyway, use `UPDATES.run` to run arbitrary futures, or
763/// `async_hn!` to declare async event handlers.
764///
765/// [`futures-lite`]: https://docs.rs/futures-lite/
766pub fn block_on<F>(task: impl IntoFuture<IntoFuture = F>) -> F::Output
767where
768 F: Future,
769{
770 let task = task.into_future();
771
772 if zng_app_context::LocalContext::current_app().is_some() {
773 tracing::warn!("cannot `block_on` in an app context, task will not run in context");
774
775 zng_app_context::LocalContext::new().with_context(|| futures_lite::future::block_on(task))
776 } else {
777 futures_lite::future::block_on(task)
778 }
779}
780
781/// Continuous poll the `task` until if finishes.
782///
783/// This function is useful for implementing some async tests only, futures don't expect to be polled
784/// continuously. This function is only available in test builds.
785#[cfg(any(test, doc, feature = "test_util"))]
786pub fn spin_on<F>(task: impl IntoFuture<IntoFuture = F>) -> F::Output
787where
788 F: Future,
789{
790 use std::pin::pin;
791
792 let mut task = pin!(task.into_future());
793 block_on(future_fn(|cx| match task.as_mut().poll(cx) {
794 Poll::Ready(r) => Poll::Ready(r),
795 Poll::Pending => {
796 cx.waker().wake_by_ref();
797 Poll::Pending
798 }
799 }))
800}
801
802/// Executor used in async doc tests.
803///
804/// If `spin` is `true` the [`spin_on`] executor is used with a timeout of 500 milliseconds.
805/// IF `spin` is `false` the [`block_on`] executor is used with a timeout of 5 seconds.
806#[cfg(any(test, doc, feature = "test_util"))]
807pub fn doc_test<F>(spin: bool, task: impl IntoFuture<IntoFuture = F>) -> F::Output
808where
809 F: Future,
810{
811 use zng_unit::TimeUnits;
812
813 if spin {
814 spin_on(with_deadline(task, 500.ms())).expect("async doc-test timeout")
815 } else {
816 block_on(with_deadline(task, 5.secs())).expect("async doc-test timeout")
817 }
818}
819
820/// A future that is [`Pending`] once and wakes the current task.
821///
822/// After the first `.await` the future is always [`Ready`] and on the first `.await` it calls [`wake`].
823///
824/// [`Pending`]: std::task::Poll::Pending
825/// [`Ready`]: std::task::Poll::Ready
826/// [`wake`]: std::task::Waker::wake
827pub async fn yield_now() {
828 struct YieldNowFut(bool);
829 impl Future for YieldNowFut {
830 type Output = ();
831
832 fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
833 if self.0 {
834 Poll::Ready(())
835 } else {
836 self.0 = true;
837 cx.waker().wake_by_ref();
838 Poll::Pending
839 }
840 }
841 }
842
843 YieldNowFut(false).await
844}
845
846/// A future that is [`Pending`] until the `deadline` is reached.
847///
848/// # Examples
849///
850/// Await 5 seconds in a [`spawn`] parallel task:
851///
852/// ```
853/// use zng_task as task;
854/// use zng_unit::*;
855///
856/// task::spawn(async {
857/// println!("waiting 5 seconds..");
858/// task::deadline(5.secs()).await;
859/// println!("5 seconds elapsed.")
860/// });
861/// ```
862///
863/// The future runs on an app provider timer executor, or on the [`futures_timer`] by default.
864///
865/// Note that deadlines from [`Duration`](std::time::Duration) starts *counting* at the moment this function is called,
866/// not at the moment of the first `.await` call.
867///
868/// [`Pending`]: std::task::Poll::Pending
869/// [`futures_timer`]: https://docs.rs/futures-timer
870pub fn deadline(deadline: impl Into<Deadline>) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> {
871 let deadline = deadline.into();
872 if zng_app_context::LocalContext::current_app().is_some() {
873 DEADLINE_SV.read().0(deadline)
874 } else {
875 default_deadline(deadline)
876 }
877}
878
879app_local! {
880 static DEADLINE_SV: (DeadlineService, bool) = const { (default_deadline, false) };
881}
882
883type DeadlineService = fn(Deadline) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>>;
884
885fn default_deadline(deadline: Deadline) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> {
886 if let Some(timeout) = deadline.time_left() {
887 Box::pin(futures_timer::Delay::new(timeout))
888 } else {
889 Box::pin(std::future::ready(()))
890 }
891}
892
893/// Deadline APP integration.
894#[expect(non_camel_case_types)]
895pub struct DEADLINE_APP;
896
897impl DEADLINE_APP {
898 /// Called by the app implementer to setup the [`deadline`] executor.
899 ///
900 /// If no app calls this the [`futures_timer`] executor is used.
901 ///
902 /// [`futures_timer`]: https://docs.rs/futures-timer
903 ///
904 /// # Panics
905 ///
906 /// Panics if called more than once for the same app.
907 pub fn init_deadline_service(&self, service: DeadlineService) {
908 let (prev, already_set) = mem::replace(&mut *DEADLINE_SV.write(), (service, true));
909 if already_set {
910 *DEADLINE_SV.write() = (prev, true);
911 panic!("deadline service already inited for this app");
912 }
913 }
914}
915
916/// Implements a [`Future`] from a closure.
917///
918/// # Examples
919///
920/// A future that is ready with a closure returns `Some(R)`.
921///
922/// ```
923/// use std::task::Poll;
924/// use zng_task as task;
925///
926/// async fn ready_some<R>(mut closure: impl FnMut() -> Option<R>) -> R {
927/// task::future_fn(|cx| match closure() {
928/// Some(r) => Poll::Ready(r),
929/// None => Poll::Pending,
930/// })
931/// .await
932/// }
933/// ```
934pub async fn future_fn<T, F>(fn_: F) -> T
935where
936 F: FnMut(&mut std::task::Context) -> Poll<T>,
937{
938 struct PollFn<F>(F);
939 impl<F> Unpin for PollFn<F> {}
940 impl<T, F: FnMut(&mut std::task::Context<'_>) -> Poll<T>> Future for PollFn<F> {
941 type Output = T;
942
943 fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
944 (self.0)(cx)
945 }
946 }
947 PollFn(fn_).await
948}
949
950/// Error when [`with_deadline`] reach a time limit before a task finishes.
951#[derive(Debug, Clone, Copy)]
952#[non_exhaustive]
953pub struct DeadlineError {}
954impl fmt::Display for DeadlineError {
955 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
956 write!(f, "reached deadline")
957 }
958}
959impl std::error::Error for DeadlineError {}
960
961/// Add a [`deadline`] to a future.
962///
963/// Returns the `fut` output or [`DeadlineError`] if the deadline elapses first.
964pub async fn with_deadline<O, F: Future<Output = O>>(
965 fut: impl IntoFuture<IntoFuture = F>,
966 deadline: impl Into<Deadline>,
967) -> Result<F::Output, DeadlineError> {
968 let deadline = deadline.into();
969 any!(async { Ok(fut.await) }, async {
970 self::deadline(deadline).await;
971 Err(DeadlineError {})
972 })
973 .await
974}
975
976/// <span data-del-macro-root></span> A future that *zips* other futures.
977///
978/// The macro input is a comma separated list of future expressions. The macro output is a future
979/// that when ".awaited" produces a tuple of results in the same order as the inputs.
980///
981/// At least one input future is required and any number of futures is accepted. For more than
982/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
983/// some IDEs.
984///
985/// Each input must implement [`IntoFuture`]. Note that each input must be known at compile time, use the [`fn@all`] async
986/// function to await on all futures in a dynamic list of futures.
987///
988/// # Examples
989///
990/// Await for three different futures to complete:
991///
992/// ```
993/// use zng_task as task;
994///
995/// # task::doc_test(false, async {
996/// let (a, b, c) = task::all!(task::run(async { 'a' }), task::wait(|| "b"), async { b"c" }).await;
997/// # });
998/// ```
999#[macro_export]
1000macro_rules! all {
1001 ($fut0:expr $(,)?) => { $crate::__all! { fut0: $fut0; } };
1002 ($fut0:expr, $fut1:expr $(,)?) => {
1003 $crate::__all! {
1004 fut0: $fut0;
1005 fut1: $fut1;
1006 }
1007 };
1008 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1009 $crate::__all! {
1010 fut0: $fut0;
1011 fut1: $fut1;
1012 fut2: $fut2;
1013 }
1014 };
1015 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1016 $crate::__all! {
1017 fut0: $fut0;
1018 fut1: $fut1;
1019 fut2: $fut2;
1020 fut3: $fut3;
1021 }
1022 };
1023 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1024 $crate::__all! {
1025 fut0: $fut0;
1026 fut1: $fut1;
1027 fut2: $fut2;
1028 fut3: $fut3;
1029 fut4: $fut4;
1030 }
1031 };
1032 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1033 $crate::__all! {
1034 fut0: $fut0;
1035 fut1: $fut1;
1036 fut2: $fut2;
1037 fut3: $fut3;
1038 fut4: $fut4;
1039 fut5: $fut5;
1040 }
1041 };
1042 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1043 $crate::__all! {
1044 fut0: $fut0;
1045 fut1: $fut1;
1046 fut2: $fut2;
1047 fut3: $fut3;
1048 fut4: $fut4;
1049 fut5: $fut5;
1050 fut6: $fut6;
1051 }
1052 };
1053 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1054 $crate::__all! {
1055 fut0: $fut0;
1056 fut1: $fut1;
1057 fut2: $fut2;
1058 fut3: $fut3;
1059 fut4: $fut4;
1060 fut5: $fut5;
1061 fut6: $fut6;
1062 fut7: $fut7;
1063 }
1064 };
1065 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__all; $($fut),+ } }
1066}
1067
1068#[doc(hidden)]
1069#[macro_export]
1070macro_rules! __all {
1071 ($($ident:ident: $fut:expr;)+) => {
1072 {
1073 $(let mut $ident = $crate::FutureOrOutput::Future(std::future::IntoFuture::into_future($fut));)+
1074 $crate::future_fn(move |cx| {
1075 use std::task::Poll;
1076
1077 let mut pending = false;
1078
1079 $(
1080 if let $crate::FutureOrOutput::Future(fut) = &mut $ident {
1081 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1082 // Future::poll call, so it will not move.
1083 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1084 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1085 $ident = $crate::FutureOrOutput::Output(r);
1086 } else {
1087 pending = true;
1088 }
1089 }
1090 )+
1091
1092 if pending {
1093 Poll::Pending
1094 } else {
1095 Poll::Ready(($($ident.take_output()),+))
1096 }
1097 })
1098 }
1099 }
1100}
1101
1102#[doc(hidden)]
1103pub enum FutureOrOutput<F: Future> {
1104 Future(F),
1105 Output(F::Output),
1106 Taken,
1107}
1108impl<F: Future> FutureOrOutput<F> {
1109 pub fn take_output(&mut self) -> F::Output {
1110 match std::mem::replace(self, Self::Taken) {
1111 FutureOrOutput::Output(o) => o,
1112 _ => unreachable!(),
1113 }
1114 }
1115}
1116
1117/// A future that awaits on all `futures` at the same time and returns all results when all futures are ready.
1118///
1119/// This is the dynamic version of [`all!`].
1120pub async fn all<F: IntoFuture>(futures: impl IntoIterator<Item = F>) -> Vec<F::Output> {
1121 let mut futures: Vec<_> = futures.into_iter().map(|f| FutureOrOutput::Future(f.into_future())).collect();
1122 future_fn(move |cx| {
1123 let mut pending = false;
1124 for input in &mut futures {
1125 if let FutureOrOutput::Future(fut) = input {
1126 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1127 // Future::poll call, so it will not move.
1128 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1129 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1130 *input = FutureOrOutput::Output(r);
1131 } else {
1132 pending = true;
1133 }
1134 }
1135 }
1136
1137 if pending {
1138 Poll::Pending
1139 } else {
1140 Poll::Ready(futures.iter_mut().map(FutureOrOutput::take_output).collect())
1141 }
1142 })
1143 .await
1144}
1145
1146/// <span data-del-macro-root></span> A future that awaits for the first future that is ready.
1147///
1148/// The macro input is comma separated list of future expressions, the futures must
1149/// all have the same output type. The macro output is a future that when ".awaited" produces
1150/// a single output type instance returned by the first input future that completes.
1151///
1152/// At least one input future is required and any number of futures is accepted. For more than
1153/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
1154/// some IDEs.
1155///
1156/// If two futures are ready at the same time the result of the first future in the input list is used.
1157/// After one future is ready the other futures are not polled again and are dropped.
1158///
1159/// Each input must implement [`IntoFuture`] with the same `Output` type. Note that each input must be
1160/// known at compile time, use the [`fn@any`] async function to await on all futures in a dynamic list of futures.
1161///
1162/// # Examples
1163///
1164/// Await for the first of three futures to complete:
1165///
1166/// ```
1167/// use zng_task as task;
1168/// use zng_unit::*;
1169///
1170/// # task::doc_test(false, async {
1171/// let r = task::any!(
1172/// task::run(async {
1173/// task::deadline(300.ms()).await;
1174/// 'a'
1175/// }),
1176/// task::wait(|| 'b'),
1177/// async {
1178/// task::deadline(300.ms()).await;
1179/// 'c'
1180/// }
1181/// )
1182/// .await;
1183///
1184/// assert_eq!('b', r);
1185/// # });
1186/// ```
1187#[macro_export]
1188macro_rules! any {
1189 ($fut0:expr $(,)?) => { $crate::__any! { fut0: $fut0; } };
1190 ($fut0:expr, $fut1:expr $(,)?) => {
1191 $crate::__any! {
1192 fut0: $fut0;
1193 fut1: $fut1;
1194 }
1195 };
1196 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1197 $crate::__any! {
1198 fut0: $fut0;
1199 fut1: $fut1;
1200 fut2: $fut2;
1201 }
1202 };
1203 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1204 $crate::__any! {
1205 fut0: $fut0;
1206 fut1: $fut1;
1207 fut2: $fut2;
1208 fut3: $fut3;
1209 }
1210 };
1211 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1212 $crate::__any! {
1213 fut0: $fut0;
1214 fut1: $fut1;
1215 fut2: $fut2;
1216 fut3: $fut3;
1217 fut4: $fut4;
1218 }
1219 };
1220 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1221 $crate::__any! {
1222 fut0: $fut0;
1223 fut1: $fut1;
1224 fut2: $fut2;
1225 fut3: $fut3;
1226 fut4: $fut4;
1227 fut5: $fut5;
1228 }
1229 };
1230 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1231 $crate::__any! {
1232 fut0: $fut0;
1233 fut1: $fut1;
1234 fut2: $fut2;
1235 fut3: $fut3;
1236 fut4: $fut4;
1237 fut5: $fut5;
1238 fut6: $fut6;
1239 }
1240 };
1241 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1242 $crate::__any! {
1243 fut0: $fut0;
1244 fut1: $fut1;
1245 fut2: $fut2;
1246 fut3: $fut3;
1247 fut4: $fut4;
1248 fut5: $fut5;
1249 fut6: $fut6;
1250 fut7: $fut7;
1251 }
1252 };
1253 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__any; $($fut),+ } }
1254}
1255#[doc(hidden)]
1256#[macro_export]
1257macro_rules! __any {
1258 ($($ident:ident: $fut:expr;)+) => {
1259 {
1260 $(let mut $ident = std::future::IntoFuture::into_future($fut);)+
1261 $crate::future_fn(move |cx| {
1262 use std::task::Poll;
1263 $(
1264 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1265 // Future::poll call, so it will not move.
1266 let mut $ident = unsafe { std::pin::Pin::new_unchecked(&mut $ident) };
1267 if let Poll::Ready(r) = $ident.as_mut().poll(cx) {
1268 return Poll::Ready(r)
1269 }
1270 )+
1271
1272 Poll::Pending
1273 })
1274 }
1275 }
1276}
1277#[doc(hidden)]
1278pub use zng_task_proc_macros::task_any_all as __proc_any_all;
1279
1280/// A future that awaits on all `futures` at the same time and returns the first result when the first future is ready.
1281///
1282/// This is the dynamic version of [`any!`].
1283pub async fn any<F: IntoFuture>(futures: impl IntoIterator<Item = F>) -> F::Output {
1284 let mut futures: Vec<_> = futures.into_iter().map(IntoFuture::into_future).collect();
1285 future_fn(move |cx| {
1286 for fut in &mut futures {
1287 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1288 // Future::poll call, so it will not move.
1289 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1290 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1291 return Poll::Ready(r);
1292 }
1293 }
1294 Poll::Pending
1295 })
1296 .await
1297}
1298
1299/// <span data-del-macro-root></span> A future that waits for the first future that is ready with an `Ok(T)` result.
1300///
1301/// The macro input is comma separated list of future expressions, the futures must
1302/// all have the same output `Result<T, E>` type, but each can have a different `E`. The macro output is a future
1303/// that when ".awaited" produces a single output of type `Result<T, (E0, E1, ..)>` that is `Ok(T)` if any of the futures
1304/// is `Ok(T)` or is `Err((E0, E1, ..))` is all futures are `Err`.
1305///
1306/// At least one input future is required and any number of futures is accepted. For more than
1307/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
1308/// some IDEs.
1309///
1310/// If two futures are ready and `Ok(T)` at the same time the result of the first future in the input list is used.
1311/// After one future is ready and `Ok(T)` the other futures are not polled again and are dropped. After a future
1312/// is ready and `Err(E)` it is also not polled again and dropped.
1313///
1314/// Each input must implement [`IntoFuture`] with the same `Output` type. Note that each input must be
1315/// known at compile time, use the [`fn@any_ok`] async function to await on all futures in a dynamic list of futures.
1316///
1317/// # Examples
1318///
1319/// Await for the first of three futures to complete with `Ok`:
1320///
1321/// ```
1322/// use zng_task as task;
1323/// # #[derive(Debug, PartialEq)]
1324/// # pub struct FooError;
1325/// # task::doc_test(false, async {
1326/// let r = task::any_ok!(
1327/// task::run(async { Err::<char, _>("error") }),
1328/// task::wait(|| Ok::<_, FooError>('b')),
1329/// async { Err::<char, _>(FooError) }
1330/// )
1331/// .await;
1332///
1333/// assert_eq!(Ok('b'), r);
1334/// # });
1335/// ```
1336#[macro_export]
1337macro_rules! any_ok {
1338 ($fut0:expr $(,)?) => { $crate::__any_ok! { fut0: $fut0; } };
1339 ($fut0:expr, $fut1:expr $(,)?) => {
1340 $crate::__any_ok! {
1341 fut0: $fut0;
1342 fut1: $fut1;
1343 }
1344 };
1345 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1346 $crate::__any_ok! {
1347 fut0: $fut0;
1348 fut1: $fut1;
1349 fut2: $fut2;
1350 }
1351 };
1352 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1353 $crate::__any_ok! {
1354 fut0: $fut0;
1355 fut1: $fut1;
1356 fut2: $fut2;
1357 fut3: $fut3;
1358 }
1359 };
1360 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1361 $crate::__any_ok! {
1362 fut0: $fut0;
1363 fut1: $fut1;
1364 fut2: $fut2;
1365 fut3: $fut3;
1366 fut4: $fut4;
1367 }
1368 };
1369 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1370 $crate::__any_ok! {
1371 fut0: $fut0;
1372 fut1: $fut1;
1373 fut2: $fut2;
1374 fut3: $fut3;
1375 fut4: $fut4;
1376 fut5: $fut5;
1377 }
1378 };
1379 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1380 $crate::__any_ok! {
1381 fut0: $fut0;
1382 fut1: $fut1;
1383 fut2: $fut2;
1384 fut3: $fut3;
1385 fut4: $fut4;
1386 fut5: $fut5;
1387 fut6: $fut6;
1388 }
1389 };
1390 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1391 $crate::__any_ok! {
1392 fut0: $fut0;
1393 fut1: $fut1;
1394 fut2: $fut2;
1395 fut3: $fut3;
1396 fut4: $fut4;
1397 fut5: $fut5;
1398 fut6: $fut6;
1399 fut7: $fut7;
1400 }
1401 };
1402 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__any_ok; $($fut),+ } }
1403}
1404
1405#[doc(hidden)]
1406#[macro_export]
1407macro_rules! __any_ok {
1408 ($($ident:ident: $fut: expr;)+) => {
1409 {
1410 $(let mut $ident = $crate::FutureOrOutput::Future(std::future::IntoFuture::into_future($fut));)+
1411 $crate::future_fn(move |cx| {
1412 use std::task::Poll;
1413
1414 let mut pending = false;
1415
1416 $(
1417 if let $crate::FutureOrOutput::Future(fut) = &mut $ident {
1418 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1419 // Future::poll call, so it will not move.
1420 let mut fut = unsafe { std::pin::Pin::new_unchecked(fut) };
1421 if let Poll::Ready(r) = fut.as_mut().poll(cx) {
1422 match r {
1423 Ok(r) => return Poll::Ready(Ok(r)),
1424 Err(e) => {
1425 $ident = $crate::FutureOrOutput::Output(Err(e));
1426 }
1427 }
1428 } else {
1429 pending = true;
1430 }
1431 }
1432 )+
1433
1434 if pending {
1435 Poll::Pending
1436 } else {
1437 Poll::Ready(Err((
1438 $($ident.take_output().unwrap_err()),+
1439 )))
1440 }
1441 })
1442 }
1443 }
1444}
1445
1446/// A future that awaits on all `futures` at the same time and returns when any future is `Ok(_)` or all are `Err(_)`.
1447///
1448/// This is the dynamic version of [`all_some!`].
1449pub async fn any_ok<Ok, Err, F: IntoFuture<Output = Result<Ok, Err>>>(futures: impl IntoIterator<Item = F>) -> Result<Ok, Vec<Err>> {
1450 let mut futures: Vec<_> = futures.into_iter().map(|f| FutureOrOutput::Future(f.into_future())).collect();
1451 future_fn(move |cx| {
1452 let mut pending = false;
1453 for input in &mut futures {
1454 if let FutureOrOutput::Future(fut) = input {
1455 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1456 // Future::poll call, so it will not move.
1457 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1458 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1459 match r {
1460 Ok(r) => return Poll::Ready(Ok(r)),
1461 Err(e) => *input = FutureOrOutput::Output(Err(e)),
1462 }
1463 } else {
1464 pending = true;
1465 }
1466 }
1467 }
1468
1469 if pending {
1470 Poll::Pending
1471 } else {
1472 Poll::Ready(Err(futures
1473 .iter_mut()
1474 .map(|f| match f.take_output() {
1475 Ok(_) => unreachable!(),
1476 Err(e) => e,
1477 })
1478 .collect()))
1479 }
1480 })
1481 .await
1482}
1483
1484/// <span data-del-macro-root></span> A future that is ready when any of the futures is ready and `Some(T)`.
1485///
1486/// The macro input is comma separated list of future expressions, the futures must
1487/// all have the same output `Option<T>` type. The macro output is a future that when ".awaited" produces
1488/// a single output type instance returned by the first input future that completes with a `Some`.
1489/// If all futures complete with a `None` the output is `None`.
1490///
1491/// At least one input future is required and any number of futures is accepted. For more than
1492/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
1493/// some IDEs.
1494///
1495/// If two futures are ready and `Some(T)` at the same time the result of the first future in the input list is used.
1496/// After one future is ready and `Some(T)` the other futures are not polled again and are dropped. After a future
1497/// is ready and `None` it is also not polled again and dropped.
1498///
1499/// Each input must implement [`IntoFuture`] with the same `Output` type. Note that each input must be
1500/// known at compile time, use the [`fn@any_some`] async function to await on all futures in a dynamic list of futures.
1501///
1502/// # Examples
1503///
1504/// Await for the first of three futures to complete with `Some`:
1505///
1506/// ```
1507/// use zng_task as task;
1508/// # task::doc_test(false, async {
1509/// let r = task::any_some!(task::run(async { None::<char> }), task::wait(|| Some('b')), async { None::<char> }).await;
1510///
1511/// assert_eq!(Some('b'), r);
1512/// # });
1513/// ```
1514#[macro_export]
1515macro_rules! any_some {
1516 ($fut0:expr $(,)?) => { $crate::__any_some! { fut0: $fut0; } };
1517 ($fut0:expr, $fut1:expr $(,)?) => {
1518 $crate::__any_some! {
1519 fut0: $fut0;
1520 fut1: $fut1;
1521 }
1522 };
1523 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1524 $crate::__any_some! {
1525 fut0: $fut0;
1526 fut1: $fut1;
1527 fut2: $fut2;
1528 }
1529 };
1530 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1531 $crate::__any_some! {
1532 fut0: $fut0;
1533 fut1: $fut1;
1534 fut2: $fut2;
1535 fut3: $fut3;
1536 }
1537 };
1538 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1539 $crate::__any_some! {
1540 fut0: $fut0;
1541 fut1: $fut1;
1542 fut2: $fut2;
1543 fut3: $fut3;
1544 fut4: $fut4;
1545 }
1546 };
1547 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1548 $crate::__any_some! {
1549 fut0: $fut0;
1550 fut1: $fut1;
1551 fut2: $fut2;
1552 fut3: $fut3;
1553 fut4: $fut4;
1554 fut5: $fut5;
1555 }
1556 };
1557 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1558 $crate::__any_some! {
1559 fut0: $fut0;
1560 fut1: $fut1;
1561 fut2: $fut2;
1562 fut3: $fut3;
1563 fut4: $fut4;
1564 fut5: $fut5;
1565 fut6: $fut6;
1566 }
1567 };
1568 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1569 $crate::__any_some! {
1570 fut0: $fut0;
1571 fut1: $fut1;
1572 fut2: $fut2;
1573 fut3: $fut3;
1574 fut4: $fut4;
1575 fut5: $fut5;
1576 fut6: $fut6;
1577 fut7: $fut7;
1578 }
1579 };
1580 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__any_some; $($fut),+ } }
1581}
1582
1583#[doc(hidden)]
1584#[macro_export]
1585macro_rules! __any_some {
1586 ($($ident:ident: $fut: expr;)+) => {
1587 {
1588 $(let mut $ident = Some(std::future::IntoFuture::into_future($fut));)+
1589 $crate::future_fn(move |cx| {
1590 use std::task::Poll;
1591
1592 let mut pending = false;
1593
1594 $(
1595 if let Some(fut) = $ident.as_mut() {
1596 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1597 // Future::poll call, so it will not move.
1598 let mut fut = unsafe { std::pin::Pin::new_unchecked(fut) };
1599 if let Poll::Ready(r) = fut.as_mut().poll(cx) {
1600 if let Some(r) = r {
1601 return Poll::Ready(Some(r));
1602 }
1603 $ident = None;
1604 } else {
1605 pending = true;
1606 }
1607 }
1608 )+
1609
1610 if pending {
1611 Poll::Pending
1612 } else {
1613 Poll::Ready(None)
1614 }
1615 })
1616 }
1617 }
1618}
1619
1620/// A future that awaits on all `futures` at the same time and returns when any future is `Some(_)` or all are `None`.
1621///
1622/// This is the dynamic version of [`all_some!`].
1623pub async fn any_some<Some, F: IntoFuture<Output = Option<Some>>>(futures: impl IntoIterator<Item = F>) -> Option<Some> {
1624 let mut futures: Vec<_> = futures.into_iter().map(|f| Some(f.into_future())).collect();
1625 future_fn(move |cx| {
1626 let mut pending = false;
1627 for input in &mut futures {
1628 if let Some(fut) = input {
1629 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1630 // Future::poll call, so it will not move.
1631 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1632 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1633 match r {
1634 Some(r) => return Poll::Ready(Some(r)),
1635 None => *input = None,
1636 }
1637 } else {
1638 pending = true;
1639 }
1640 }
1641 }
1642
1643 if pending { Poll::Pending } else { Poll::Ready(None) }
1644 })
1645 .await
1646}
1647
1648/// <span data-del-macro-root></span> A future that is ready when all futures are ready with an `Ok(T)` result or
1649/// any future is ready with an `Err(E)` result.
1650///
1651/// The output type is `Result<(T0, T1, ..), E>`, the `Ok` type is a tuple with all the `Ok` values, the error
1652/// type is the first error encountered, the input futures must have the same `Err` type but can have different
1653/// `Ok` types.
1654///
1655/// At least one input future is required and any number of futures is accepted. For more than
1656/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
1657/// some IDEs.
1658///
1659/// If two futures are ready and `Err(E)` at the same time the result of the first future in the input list is used.
1660/// After one future is ready and `Err(T)` the other futures are not polled again and are dropped. After a future
1661/// is ready it is also not polled again and dropped.
1662///
1663/// Each input must implement [`IntoFuture`] with the same `Output` type. Note that each input must be
1664/// known at compile time, use the [`fn@all_ok`] async function to await on all futures in a dynamic list of futures.
1665///
1666/// # Examples
1667///
1668/// Await for the first of three futures to complete with `Ok(T)`:
1669///
1670/// ```
1671/// use zng_task as task;
1672/// # #[derive(Debug, PartialEq)]
1673/// # struct FooError;
1674/// # task::doc_test(false, async {
1675/// let r = task::all_ok!(
1676/// task::run(async { Ok::<_, FooError>('a') }),
1677/// task::wait(|| Ok::<_, FooError>('b')),
1678/// async { Ok::<_, FooError>('c') }
1679/// )
1680/// .await;
1681///
1682/// assert_eq!(Ok(('a', 'b', 'c')), r);
1683/// # });
1684/// ```
1685///
1686/// And in if any completes with `Err(E)`:
1687///
1688/// ```
1689/// use zng_task as task;
1690/// # #[derive(Debug, PartialEq)]
1691/// # struct FooError;
1692/// # task::doc_test(false, async {
1693/// let r = task::all_ok!(task::run(async { Ok('a') }), task::wait(|| Err::<char, _>(FooError)), async {
1694/// Ok('c')
1695/// })
1696/// .await;
1697///
1698/// assert_eq!(Err(FooError), r);
1699/// # });
1700/// ```
1701#[macro_export]
1702macro_rules! all_ok {
1703 ($fut0:expr $(,)?) => { $crate::__all_ok! { fut0: $fut0; } };
1704 ($fut0:expr, $fut1:expr $(,)?) => {
1705 $crate::__all_ok! {
1706 fut0: $fut0;
1707 fut1: $fut1;
1708 }
1709 };
1710 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1711 $crate::__all_ok! {
1712 fut0: $fut0;
1713 fut1: $fut1;
1714 fut2: $fut2;
1715 }
1716 };
1717 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1718 $crate::__all_ok! {
1719 fut0: $fut0;
1720 fut1: $fut1;
1721 fut2: $fut2;
1722 fut3: $fut3;
1723 }
1724 };
1725 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1726 $crate::__all_ok! {
1727 fut0: $fut0;
1728 fut1: $fut1;
1729 fut2: $fut2;
1730 fut3: $fut3;
1731 fut4: $fut4;
1732 }
1733 };
1734 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1735 $crate::__all_ok! {
1736 fut0: $fut0;
1737 fut1: $fut1;
1738 fut2: $fut2;
1739 fut3: $fut3;
1740 fut4: $fut4;
1741 fut5: $fut5;
1742 }
1743 };
1744 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1745 $crate::__all_ok! {
1746 fut0: $fut0;
1747 fut1: $fut1;
1748 fut2: $fut2;
1749 fut3: $fut3;
1750 fut4: $fut4;
1751 fut5: $fut5;
1752 fut6: $fut6;
1753 }
1754 };
1755 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1756 $crate::__all_ok! {
1757 fut0: $fut0;
1758 fut1: $fut1;
1759 fut2: $fut2;
1760 fut3: $fut3;
1761 fut4: $fut4;
1762 fut5: $fut5;
1763 fut6: $fut6;
1764 fut7: $fut7;
1765 }
1766 };
1767 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__all_ok; $($fut),+ } }
1768}
1769
1770#[doc(hidden)]
1771#[macro_export]
1772macro_rules! __all_ok {
1773 ($($ident:ident: $fut: expr;)+) => {
1774 {
1775 $(let mut $ident = $crate::FutureOrOutput::Future(std::future::IntoFuture::into_future($fut));)+
1776 $crate::future_fn(move |cx| {
1777 use std::task::Poll;
1778
1779 let mut pending = false;
1780
1781 $(
1782 if let $crate::FutureOrOutput::Future(fut) = &mut $ident {
1783 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1784 // Future::poll call, so it will not move.
1785 let mut fut = unsafe { std::pin::Pin::new_unchecked(fut) };
1786 if let Poll::Ready(r) = fut.as_mut().poll(cx) {
1787 match r {
1788 Ok(r) => {
1789 $ident = $crate::FutureOrOutput::Output(Ok(r))
1790 },
1791 Err(e) => return Poll::Ready(Err(e)),
1792 }
1793 } else {
1794 pending = true;
1795 }
1796 }
1797 )+
1798
1799 if pending {
1800 Poll::Pending
1801 } else {
1802 Poll::Ready(Ok((
1803 $($ident.take_output().unwrap()),+
1804 )))
1805 }
1806 })
1807 }
1808 }
1809}
1810
1811/// A future that awaits on all `futures` at the same time and returns when all futures are `Ok(_)` or any future is `Err(_)`.
1812///
1813/// This is the dynamic version of [`all_ok!`].
1814pub async fn all_ok<Ok, Err, F: IntoFuture<Output = Result<Ok, Err>>>(futures: impl IntoIterator<Item = F>) -> Result<Vec<Ok>, Err> {
1815 let mut futures: Vec<_> = futures.into_iter().map(|f| FutureOrOutput::Future(f.into_future())).collect();
1816 future_fn(move |cx| {
1817 let mut pending = false;
1818 for input in &mut futures {
1819 if let FutureOrOutput::Future(fut) = input {
1820 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1821 // Future::poll call, so it will not move.
1822 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
1823 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
1824 match r {
1825 Ok(r) => *input = FutureOrOutput::Output(Ok(r)),
1826 Err(e) => return Poll::Ready(Err(e)),
1827 }
1828 } else {
1829 pending = true;
1830 }
1831 }
1832 }
1833
1834 if pending {
1835 Poll::Pending
1836 } else {
1837 Poll::Ready(Ok(futures
1838 .iter_mut()
1839 .map(|f| f.take_output().unwrap_or_else(|_| unreachable!()))
1840 .collect()))
1841 }
1842 })
1843 .await
1844}
1845
1846/// <span data-del-macro-root></span> A future that is ready when all futures are ready with `Some(T)` or when any
1847/// is future ready with `None`.
1848///
1849/// The macro input is comma separated list of future expressions, the futures must
1850/// all have the `Option<T>` output type, but each can have a different `T`. The macro output is a future that when ".awaited"
1851/// produces `Some<(T0, T1, ..)>` if all futures where `Some(T)` or `None` if any of the futures where `None`.
1852///
1853/// At least one input future is required and any number of futures is accepted. For more than
1854/// eight futures a proc-macro is used which may cause code auto-complete to stop working in
1855/// some IDEs.
1856///
1857/// After one future is ready and `None` the other futures are not polled again and are dropped. After a future
1858/// is ready it is also not polled again and dropped.
1859///
1860/// Each input must implement [`IntoFuture`] with the same `Output` type. Note that each input must be
1861/// known at compile time, use the [`fn@all_some`] async function to await on all futures in a dynamic list of futures.
1862///
1863/// # Examples
1864///
1865/// Await for the first of three futures to complete with `Some`:
1866///
1867/// ```
1868/// use zng_task as task;
1869/// # task::doc_test(false, async {
1870/// let r = task::all_some!(task::run(async { Some('a') }), task::wait(|| Some('b')), async { Some('c') }).await;
1871///
1872/// assert_eq!(Some(('a', 'b', 'c')), r);
1873/// # });
1874/// ```
1875///
1876/// Completes with `None` if any future completes with `None`:
1877///
1878/// ```
1879/// # use zng_task as task;
1880/// # task::doc_test(false, async {
1881/// let r = task::all_some!(task::run(async { Some('a') }), task::wait(|| None::<char>), async { Some('b') }).await;
1882///
1883/// assert_eq!(None, r);
1884/// # });
1885/// ```
1886#[macro_export]
1887macro_rules! all_some {
1888 ($fut0:expr $(,)?) => { $crate::__all_some! { fut0: $fut0; } };
1889 ($fut0:expr, $fut1:expr $(,)?) => {
1890 $crate::__all_some! {
1891 fut0: $fut0;
1892 fut1: $fut1;
1893 }
1894 };
1895 ($fut0:expr, $fut1:expr, $fut2:expr $(,)?) => {
1896 $crate::__all_some! {
1897 fut0: $fut0;
1898 fut1: $fut1;
1899 fut2: $fut2;
1900 }
1901 };
1902 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr $(,)?) => {
1903 $crate::__all_some! {
1904 fut0: $fut0;
1905 fut1: $fut1;
1906 fut2: $fut2;
1907 fut3: $fut3;
1908 }
1909 };
1910 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr $(,)?) => {
1911 $crate::__all_some! {
1912 fut0: $fut0;
1913 fut1: $fut1;
1914 fut2: $fut2;
1915 fut3: $fut3;
1916 fut4: $fut4;
1917 }
1918 };
1919 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr $(,)?) => {
1920 $crate::__all_some! {
1921 fut0: $fut0;
1922 fut1: $fut1;
1923 fut2: $fut2;
1924 fut3: $fut3;
1925 fut4: $fut4;
1926 fut5: $fut5;
1927 }
1928 };
1929 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr $(,)?) => {
1930 $crate::__all_some! {
1931 fut0: $fut0;
1932 fut1: $fut1;
1933 fut2: $fut2;
1934 fut3: $fut3;
1935 fut4: $fut4;
1936 fut5: $fut5;
1937 fut6: $fut6;
1938 }
1939 };
1940 ($fut0:expr, $fut1:expr, $fut2:expr, $fut3:expr, $fut4:expr, $fut5:expr, $fut6:expr, $fut7:expr $(,)?) => {
1941 $crate::__all_some! {
1942 fut0: $fut0;
1943 fut1: $fut1;
1944 fut2: $fut2;
1945 fut3: $fut3;
1946 fut4: $fut4;
1947 fut5: $fut5;
1948 fut6: $fut6;
1949 fut7: $fut7;
1950 }
1951 };
1952 ($($fut:expr),+ $(,)?) => { $crate::__proc_any_all!{ $crate::__all_some; $($fut),+ } }
1953}
1954
1955#[doc(hidden)]
1956#[macro_export]
1957macro_rules! __all_some {
1958 ($($ident:ident: $fut: expr;)+) => {
1959 {
1960 $(let mut $ident = $crate::FutureOrOutput::Future(std::future::IntoFuture::into_future($fut));)+
1961 $crate::future_fn(move |cx| {
1962 use std::task::Poll;
1963
1964 let mut pending = false;
1965
1966 $(
1967 if let $crate::FutureOrOutput::Future(fut) = &mut $ident {
1968 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
1969 // Future::poll call, so it will not move.
1970 let mut fut = unsafe { std::pin::Pin::new_unchecked(fut) };
1971 if let Poll::Ready(r) = fut.as_mut().poll(cx) {
1972 if r.is_none() {
1973 return Poll::Ready(None);
1974 }
1975
1976 $ident = $crate::FutureOrOutput::Output(r);
1977 } else {
1978 pending = true;
1979 }
1980 }
1981 )+
1982
1983 if pending {
1984 Poll::Pending
1985 } else {
1986 Poll::Ready(Some((
1987 $($ident.take_output().unwrap()),+
1988 )))
1989 }
1990 })
1991 }
1992 }
1993}
1994
1995/// A future that awaits on all `futures` at the same time and returns when all futures are `Some(_)` or any future is `None`.
1996///
1997/// This is the dynamic version of [`all_some!`].
1998pub async fn all_some<Some, F: IntoFuture<Output = Option<Some>>>(futures: impl IntoIterator<Item = F>) -> Option<Vec<Some>> {
1999 let mut futures: Vec<_> = futures.into_iter().map(|f| FutureOrOutput::Future(f.into_future())).collect();
2000 future_fn(move |cx| {
2001 let mut pending = false;
2002 for input in &mut futures {
2003 if let FutureOrOutput::Future(fut) = input {
2004 // SAFETY: the closure owns $ident and is an exclusive borrow inside a
2005 // Future::poll call, so it will not move.
2006 let mut fut_mut = unsafe { std::pin::Pin::new_unchecked(fut) };
2007 if let Poll::Ready(r) = fut_mut.as_mut().poll(cx) {
2008 match r {
2009 Some(r) => *input = FutureOrOutput::Output(Some(r)),
2010 None => return Poll::Ready(None),
2011 }
2012 } else {
2013 pending = true;
2014 }
2015 }
2016 }
2017
2018 if pending {
2019 Poll::Pending
2020 } else {
2021 Poll::Ready(Some(futures.iter_mut().map(|f| f.take_output().unwrap()).collect()))
2022 }
2023 })
2024 .await
2025}
2026
2027/// A future that will await until [`set`] is called.
2028///
2029/// # Examples
2030///
2031/// Spawns a parallel task that only writes to stdout after the main thread sets the signal:
2032///
2033/// ```
2034/// use zng_clone_move::async_clmv;
2035/// use zng_task::{self as task, *};
2036///
2037/// let signal = SignalOnce::default();
2038///
2039/// task::spawn(async_clmv!(signal, {
2040/// signal.await;
2041/// println!("After Signal!");
2042/// }));
2043///
2044/// signal.set();
2045/// ```
2046///
2047/// [`set`]: SignalOnce::set
2048#[derive(Default, Clone)]
2049pub struct SignalOnce(Arc<SignalInner>);
2050impl fmt::Debug for SignalOnce {
2051 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2052 write!(f, "SignalOnce({})", self.is_set())
2053 }
2054}
2055impl PartialEq for SignalOnce {
2056 fn eq(&self, other: &Self) -> bool {
2057 Arc::ptr_eq(&self.0, &other.0)
2058 }
2059}
2060impl Eq for SignalOnce {}
2061impl Hash for SignalOnce {
2062 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2063 Arc::as_ptr(&self.0).hash(state)
2064 }
2065}
2066impl SignalOnce {
2067 /// New unsigned.
2068 pub fn new() -> Self {
2069 Self::default()
2070 }
2071
2072 /// New signaled.
2073 pub fn new_set() -> Self {
2074 let s = Self::new();
2075 s.set();
2076 s
2077 }
2078
2079 /// If the signal was set.
2080 pub fn is_set(&self) -> bool {
2081 self.0.signaled.load(Ordering::Relaxed)
2082 }
2083
2084 /// Sets the signal and awakes listeners.
2085 pub fn set(&self) {
2086 if !self.0.signaled.swap(true, Ordering::Relaxed) {
2087 let listeners = mem::take(&mut *self.0.listeners.lock());
2088 for listener in listeners {
2089 listener.wake();
2090 }
2091 }
2092 }
2093}
2094impl Future for SignalOnce {
2095 type Output = ();
2096
2097 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<()> {
2098 if self.0.signaled.load(Ordering::Relaxed) {
2099 return Poll::Ready(());
2100 }
2101
2102 let mut listeners = self.0.listeners.lock();
2103 if self.0.signaled.load(Ordering::Relaxed) {
2104 return Poll::Ready(());
2105 }
2106
2107 let waker = cx.waker();
2108 if !listeners.iter().any(|w| w.will_wake(waker)) {
2109 listeners.push(waker.clone());
2110 }
2111
2112 Poll::Pending
2113 }
2114}
2115
2116#[derive(Default)]
2117struct SignalInner {
2118 signaled: AtomicBool,
2119 listeners: Mutex<Vec<std::task::Waker>>,
2120}
2121
2122/// A [`Waker`] that dispatches a wake call to multiple other wakers.
2123///
2124/// This is useful for sharing one wake source with multiple [`Waker`] clients that may not be all
2125/// known at the moment the first request is made.
2126///
2127/// [`Waker`]: std::task::Waker
2128#[derive(Clone)]
2129pub struct McWaker(Arc<WakeVec>);
2130
2131#[derive(Default)]
2132struct WakeVec(Mutex<Vec<std::task::Waker>>);
2133impl WakeVec {
2134 fn push(&self, waker: std::task::Waker) -> bool {
2135 let mut v = self.0.lock();
2136
2137 let return_waker = v.is_empty();
2138
2139 v.push(waker);
2140
2141 return_waker
2142 }
2143
2144 fn cancel(&self) {
2145 let mut v = self.0.lock();
2146
2147 debug_assert!(!v.is_empty(), "called cancel on an empty McWaker");
2148
2149 v.clear();
2150 }
2151}
2152impl std::task::Wake for WakeVec {
2153 fn wake(self: Arc<Self>) {
2154 for w in mem::take(&mut *self.0.lock()) {
2155 w.wake();
2156 }
2157 }
2158}
2159impl McWaker {
2160 /// New empty waker.
2161 pub fn empty() -> Self {
2162 Self(Arc::new(WakeVec::default()))
2163 }
2164
2165 /// Register a `waker` to wake once when `self` awakes.
2166 ///
2167 /// Returns `Some(self as waker)` if `self` was previously empty, if `None` is returned [`Poll::Pending`] must
2168 /// be returned, if a waker is returned the shared resource must be polled using the waker, if the shared resource
2169 /// is ready [`cancel`] must be called.
2170 ///
2171 /// [`cancel`]: Self::cancel
2172 pub fn push(&self, waker: std::task::Waker) -> Option<std::task::Waker> {
2173 if self.0.push(waker) { Some(self.0.clone().into()) } else { None }
2174 }
2175
2176 /// Clear current registered wakers.
2177 pub fn cancel(&self) {
2178 self.0.cancel()
2179 }
2180}
2181
2182/// Panic payload, captured by [`std::panic::catch_unwind`].
2183#[non_exhaustive]
2184pub struct TaskPanicError {
2185 /// Panic payload.
2186 pub payload: Box<dyn Any + Send + 'static>,
2187}
2188impl TaskPanicError {
2189 /// New from panic payload.
2190 pub fn new(payload: Box<dyn Any + Send + 'static>) -> Self {
2191 Self { payload }
2192 }
2193
2194 /// Get the panic string if the `payload` is string like.
2195 pub fn panic_str(&self) -> Option<&str> {
2196 extract_panic_message(&self.payload)
2197 }
2198}
2199impl fmt::Debug for TaskPanicError {
2200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2201 f.debug_struct("TaskPanicError").field("panic_str()", &self.panic_str()).finish()
2202 }
2203}
2204impl fmt::Display for TaskPanicError {
2205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2206 if let Some(s) = self.panic_str() { f.write_str(s) } else { Ok(()) }
2207 }
2208}
2209impl std::error::Error for TaskPanicError {}
2210
2211type SpawnPanicHandler = Box<dyn FnMut(TaskPanicError) + Send + 'static>;
2212
2213pub(crate) fn extract_panic_message(p: &dyn Any) -> Option<&str> {
2214 if let Some(s) = p.downcast_ref::<&'static str>() {
2215 Some(s)
2216 } else if let Some(s) = p.downcast_ref::<String>() {
2217 Some(s)
2218 } else {
2219 None
2220 }
2221}
2222
2223app_local! {
2224 // Mutex for Sync only
2225 static SPAWN_PANIC_HANDLERS: Option<Mutex<SpawnPanicHandler>> = None;
2226}
2227
2228/// Set a `handler` that is called when spawn tasks panic.
2229///
2230/// On panic the tasks [`spawn`], [`poll_spawn`] and [`spawn_wait`] log an error, notifies the `handler` and otherwise ignores the panic.
2231///
2232/// The handler is set for the process lifetime, only handler can be set per app. The handler is called inside the same [`LocalContext`]
2233/// and thread the task that panicked was called in.
2234///
2235/// ```
2236/// # macro_rules! example { () => {
2237/// task::set_spawn_panic_handler(|p| {
2238/// UPDATES
2239/// .run_hn_once(hn_once!(|_| {
2240/// std::panic::resume_unwind(p.payload);
2241/// }))
2242/// .perm();
2243/// });
2244/// # }}
2245/// ```
2246///
2247/// The example above shows how to set a handler that propagates the panic to the app main thread.
2248///
2249/// # Panics
2250///
2251/// Panics if another handler is already set in the same app.
2252///
2253/// Panics if no app is running in the caller thread.
2254pub fn set_spawn_panic_handler(handler: impl FnMut(TaskPanicError) + Send + 'static) {
2255 let mut h = SPAWN_PANIC_HANDLERS.try_write().expect("a spawn panic handler is already set");
2256 assert!(h.is_none(), "a spawn panic handler is already set");
2257 *h = Some(Mutex::new(Box::new(handler)));
2258}
2259
2260fn on_spawn_panic(p: TaskPanicError) {
2261 if let Some(f) = &mut *SPAWN_PANIC_HANDLERS.write() {
2262 f.get_mut()(p)
2263 }
2264}