1use crate::{
16 AbortableJoinHandle, CommunicationTask, CompletionGuard, Executor, ExecutorBlocking,
17 ExecutorTimeout, InnerJoinHandle, JoinHandle, TimeoutError, UnboundedCommunicationTask,
18 abortable_result, error::JoinError,
19};
20use core::future::{Future, poll_fn};
21use core::marker::PhantomData;
22use core::pin::Pin;
23use core::task::{Context, Poll};
24use futures::channel::mpsc::{Receiver, UnboundedReceiver};
25use futures::channel::oneshot;
26use futures::future::{AbortHandle, BoxFuture};
27use futures::stream::FuturesUnordered;
28use futures::task::AtomicWaker;
29use futures::{FutureExt, StreamExt, TryFutureExt};
30use futures_timeout::Timeout;
31use parking_lot::Mutex;
32use pollable_map::optional::Optional;
33use std::panic::AssertUnwindSafe;
34use std::sync::atomic::AtomicBool;
35use std::sync::{Arc, Weak};
36
37struct ScopeState<'scope> {
38 inbox: Mutex<Vec<BoxFuture<'scope, ()>>>,
39 waker: AtomicWaker,
40}
41
42pub struct Scope<'scope, 'env: 'scope> {
45 state: Weak<ScopeState<'scope>>,
46 _scope: PhantomData<&'scope mut &'scope ()>,
47 _env: PhantomData<&'env mut &'env ()>,
48}
49
50impl<'scope, 'env> Scope<'scope, 'env> {
51 fn new() -> Self {
52 Self {
53 state: Weak::new(),
54 _scope: PhantomData,
55 _env: PhantomData,
56 }
57 }
58
59 fn push(&self, task: BoxFuture<'scope, ()>) {
60 if let Some(state) = self.state.upgrade() {
61 state.inbox.lock().push(task);
62 state.waker.wake();
63 }
64 }
65
66 pub fn spawn<Fut>(&'scope self, fut: Fut) -> ScopedJoinHandle<Fut::Output>
72 where
73 Fut: Future + Send + 'scope,
74 Fut::Output: Send + 'scope,
75 {
76 let (tx, rx) = oneshot::channel();
77 let wrapped: BoxFuture<'scope, ()> = async move {
78 let output = AssertUnwindSafe(fut)
79 .catch_unwind()
80 .await
81 .map_err(|_| JoinError::Panicked);
82 let _ = tx.send(output);
85 }
86 .boxed();
87
88 self.push(wrapped);
89
90 ScopedJoinHandle { rx }
91 }
92
93 pub fn spawn_abortable<Fut>(&'scope self, fut: Fut) -> AbortableJoinHandle<Fut::Output>
99 where
100 Fut: Future + Send + 'scope,
101 Fut::Output: Send + 'scope,
102 {
103 let (abort_handle, abort_reg) = AbortHandle::new_pair();
104 let abortable = abortable_result(fut, abort_reg);
105 let (tx, rx) = oneshot::channel();
106 let finished = Arc::new(AtomicBool::new(false));
107 let completion = CompletionGuard::new(finished.clone());
108
109 let wrapped: BoxFuture<'scope, ()> = async move {
110 let _completion = completion;
111 let val = abortable.await;
112 let _ = tx.send(val);
113 }
114 .boxed();
115 self.push(wrapped);
116
117 let join = JoinHandle {
118 inner: InnerJoinHandle::CustomHandle {
119 inner: Optional::new(rx),
120 handle: abort_handle,
121 finished,
122 },
123 };
124 AbortableJoinHandle::from(join)
125 }
126
127 pub fn dispatch<Fut>(&'scope self, fut: Fut)
131 where
132 Fut: Future + Send + 'scope,
133 Fut::Output: Send + 'scope,
134 {
135 drop(self.spawn(fut));
136 }
137
138 pub fn spawn_coroutine<T, F, Fut>(&'scope self, f: F) -> CommunicationTask<T>
142 where
143 F: FnMut(T) -> Fut + Send + 'scope,
144 Fut: Future<Output = ()> + Send + 'scope,
145 T: Send + 'scope,
146 {
147 self.spawn_coroutine_with_buffer(1, f)
148 }
149
150 pub fn spawn_coroutine_with_buffer<T, F, Fut>(
153 &'scope self,
154 buffer: usize,
155 mut f: F,
156 ) -> CommunicationTask<T>
157 where
158 F: FnMut(T) -> Fut + Send + 'scope,
159 Fut: Future<Output = ()> + Send + 'scope,
160 T: Send + 'scope,
161 {
162 let (tx, mut rx) = futures::channel::mpsc::channel(buffer);
163 let task_handle = self.spawn_abortable(async move {
164 while let Some(message) = rx.next().await {
165 f(message).await;
166 }
167 });
168 CommunicationTask::new(task_handle, tx)
169 }
170
171 pub fn spawn_unbounded_coroutine<T, F, Fut>(
176 &'scope self,
177 mut f: F,
178 ) -> UnboundedCommunicationTask<T>
179 where
180 F: FnMut(T) -> Fut + Send + 'scope,
181 Fut: Future<Output = ()> + Send + 'scope,
182 T: Send + 'scope,
183 {
184 let (tx, mut rx) = futures::channel::mpsc::unbounded();
185 let task_handle = self.spawn_abortable(async move {
186 while let Some(message) = rx.next().await {
187 f(message).await;
188 }
189 });
190 UnboundedCommunicationTask::new(task_handle, tx)
191 }
192
193 pub fn spawn_coroutine_with_context<T, C, F, Fut>(
198 &'scope self,
199 context: C,
200 f: F,
201 ) -> CommunicationTask<T>
202 where
203 F: FnMut(&mut C, T) -> Fut + Send + 'scope,
204 Fut: Future<Output = ()> + Send + 'scope,
205 C: Send + 'scope,
206 T: Send + 'scope,
207 {
208 self.spawn_coroutine_with_buffer_and_context(context, 1, f)
209 }
210
211 pub fn spawn_coroutine_with_buffer_and_context<T, C, F, Fut>(
214 &'scope self,
215 context: C,
216 buffer: usize,
217 mut f: F,
218 ) -> CommunicationTask<T>
219 where
220 F: FnMut(&mut C, T) -> Fut + Send + 'scope,
221 Fut: Future<Output = ()> + Send + 'scope,
222 C: Send + 'scope,
223 T: Send + 'scope,
224 {
225 let (tx, mut rx) = futures::channel::mpsc::channel(buffer);
226 let task_handle = self.spawn_abortable(async move {
227 let mut context = context;
228 while let Some(message) = rx.next().await {
229 f(&mut context, message).await;
230 }
231 });
232 CommunicationTask::new(task_handle, tx)
233 }
234
235 pub fn spawn_unbounded_coroutine_with_context<T, C, F, Fut>(
238 &'scope self,
239 context: C,
240 mut f: F,
241 ) -> UnboundedCommunicationTask<T>
242 where
243 F: FnMut(&mut C, T) -> Fut + Send + 'scope,
244 Fut: Future<Output = ()> + Send + 'scope,
245 C: Send + 'scope,
246 T: Send + 'scope,
247 {
248 let (tx, mut rx) = futures::channel::mpsc::unbounded();
249 let task_handle = self.spawn_abortable(async move {
250 let mut context = context;
251 while let Some(message) = rx.next().await {
252 f(&mut context, message).await;
253 }
254 });
255 UnboundedCommunicationTask::new(task_handle, tx)
256 }
257
258 pub fn spawn_coroutine_with_receiver<T, F, Fut>(&'scope self, f: F) -> CommunicationTask<T>
260 where
261 F: FnMut(Receiver<T>) -> Fut,
262 Fut: Future<Output = ()> + Send + 'scope,
263 {
264 self.spawn_coroutine_with_receiver_and_buffer(1, f)
265 }
266
267 pub fn spawn_coroutine_with_receiver_and_buffer<T, F, Fut>(
270 &'scope self,
271 buffer: usize,
272 mut f: F,
273 ) -> CommunicationTask<T>
274 where
275 F: FnMut(Receiver<T>) -> Fut,
276 Fut: Future<Output = ()> + Send + 'scope,
277 {
278 let (tx, rx) = futures::channel::mpsc::channel(buffer);
279 let task_handle = self.spawn_abortable(f(rx));
280 CommunicationTask::new(task_handle, tx)
281 }
282
283 pub fn spawn_coroutine_with_receiver_and_context<T, F, C, Fut>(
286 &'scope self,
287 context: C,
288 f: F,
289 ) -> CommunicationTask<T>
290 where
291 F: FnMut(C, Receiver<T>) -> Fut,
292 Fut: Future<Output = ()> + Send + 'scope,
293 {
294 self.spawn_coroutine_with_receiver_buffer_and_context(context, 1, f)
295 }
296
297 pub fn spawn_coroutine_with_receiver_buffer_and_context<T, F, C, Fut>(
300 &'scope self,
301 context: C,
302 buffer: usize,
303 mut f: F,
304 ) -> CommunicationTask<T>
305 where
306 F: FnMut(C, Receiver<T>) -> Fut,
307 Fut: Future<Output = ()> + Send + 'scope,
308 {
309 let (tx, rx) = futures::channel::mpsc::channel(buffer);
310 let task_handle = self.spawn_abortable(f(context, rx));
311 CommunicationTask::new(task_handle, tx)
312 }
313
314 pub fn spawn_unbounded_coroutine_with_receiver<T, F, Fut>(
316 &'scope self,
317 mut f: F,
318 ) -> UnboundedCommunicationTask<T>
319 where
320 F: FnMut(UnboundedReceiver<T>) -> Fut,
321 Fut: Future<Output = ()> + Send + 'scope,
322 {
323 let (tx, rx) = futures::channel::mpsc::unbounded();
324 let task_handle = self.spawn_abortable(f(rx));
325 UnboundedCommunicationTask::new(task_handle, tx)
326 }
327
328 pub fn spawn_unbounded_coroutine_with_receiver_and_context<T, F, C, Fut>(
331 &'scope self,
332 context: C,
333 mut f: F,
334 ) -> UnboundedCommunicationTask<T>
335 where
336 F: FnMut(C, UnboundedReceiver<T>) -> Fut,
337 Fut: Future<Output = ()> + Send + 'scope,
338 {
339 let (tx, rx) = futures::channel::mpsc::unbounded();
340 let task_handle = self.spawn_abortable(f(context, rx));
341 UnboundedCommunicationTask::new(task_handle, tx)
342 }
343
344 pub fn spawn_timeout<F>(
350 &'scope self,
351 duration: std::time::Duration,
352 f: F,
353 ) -> ScopedJoinHandle<Result<F::Output, TimeoutError>>
354 where
355 F: Future + Send + 'scope,
356 F::Output: Send + 'scope,
357 {
358 self.spawn(Timeout::from_future(f, duration).map_err(|_| TimeoutError))
359 }
360
361 pub fn spawn_delay<F>(
363 &'scope self,
364 duration: std::time::Duration,
365 f: F,
366 ) -> ScopedJoinHandle<F::Output>
367 where
368 F: Future + Send + 'scope,
369 F::Output: Send + 'scope,
370 {
371 self.spawn(async move {
372 let _ = Timeout::from_future(futures::future::pending::<()>(), duration).await;
373 f.await
374 })
375 }
376
377 pub fn spawn_abortable_timeout<F>(
383 &'scope self,
384 duration: std::time::Duration,
385 f: F,
386 ) -> AbortableJoinHandle<Result<F::Output, TimeoutError>>
387 where
388 F: Future + Send + 'scope,
389 F::Output: Send + 'scope,
390 {
391 self.spawn_abortable(Timeout::from_future(f, duration).map_err(|_| TimeoutError))
392 }
393
394 pub fn spawn_abortable_delay<F>(
396 &'scope self,
397 duration: std::time::Duration,
398 f: F,
399 ) -> AbortableJoinHandle<F::Output>
400 where
401 F: Future + Send + 'scope,
402 F::Output: Send + 'scope,
403 {
404 self.spawn_abortable(async move {
405 let _ = Timeout::from_future(futures::future::pending::<()>(), duration).await;
406 f.await
407 })
408 }
409}
410
411fn drive_scope<'scope>(
414 active: &mut FuturesUnordered<BoxFuture<'scope, ()>>,
415 state: &ScopeState<'scope>,
416 cx: &mut Context<'_>,
417) -> (bool, bool) {
418 let mut made_progress = false;
419 loop {
420 state.waker.register(cx.waker());
421
422 let incoming = std::mem::take(&mut *state.inbox.lock());
425 active.extend(incoming);
426 match active.poll_next_unpin(cx) {
427 Poll::Ready(Some(())) => made_progress = true,
428 Poll::Ready(None) => {
429 state.waker.register(cx.waker());
430 if state.inbox.lock().is_empty() {
431 return (made_progress, true);
432 }
433 }
434 Poll::Pending => {
435 state.waker.register(cx.waker());
436 if state.inbox.lock().is_empty() {
437 return (made_progress, false);
438 }
439 }
440 }
441 }
442}
443
444pub struct ScopedJoinHandle<T> {
455 rx: oneshot::Receiver<Result<T, JoinError>>,
456}
457
458impl<T> Future for ScopedJoinHandle<T> {
459 type Output = Result<T, JoinError>;
460
461 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
462 match Pin::new(&mut self.rx).poll(cx) {
463 Poll::Ready(Ok(result)) => Poll::Ready(result),
464 Poll::Ready(Err(_)) => Poll::Ready(Err(JoinError::Cancelled)),
465 Poll::Pending => Poll::Pending,
466 }
467 }
468}
469
470pub async fn scope<'env, F, T>(f: F) -> T
496where
497 F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
498{
499 let mut scope = Scope::new();
502 let state = Arc::new(ScopeState {
503 inbox: Mutex::new(Vec::new()),
504 waker: AtomicWaker::new(),
505 });
506 scope.state = Arc::downgrade(&state);
507 let mut active = FuturesUnordered::new();
511
512 let result = {
513 let user_fut = f(&scope);
514 let mut user_fut = std::pin::pin!(user_fut);
515
516 poll_fn(|cx| {
517 loop {
518 if let Poll::Ready(r) = user_fut.as_mut().poll(cx) {
519 return Poll::Ready(r);
520 }
521 let (made_progress, _empty) = drive_scope(&mut active, &state, cx);
522 if !made_progress {
523 return Poll::Pending;
524 }
525 }
526 })
527 .await
528 };
529
530 poll_fn(|cx| {
533 let (_made_progress, empty) = drive_scope(&mut active, &state, cx);
534 if empty {
535 Poll::Ready(())
536 } else {
537 Poll::Pending
538 }
539 })
540 .await;
541
542 result
543}
544
545pub struct ScopeExecutor<'scope, E> {
556 inner: &'scope E,
557 task_handles: Mutex<Vec<AbortableJoinHandle<()>>>,
558 _scope: PhantomData<&'scope mut &'scope ()>,
559}
560
561impl<'scope, E> ScopeExecutor<'scope, E> {
562 fn new(inner: &'scope E) -> Self {
563 Self {
564 inner,
565 task_handles: Mutex::new(Vec::new()),
566 _scope: PhantomData,
567 }
568 }
569
570 fn abort_all(&self) {
572 for handle in self.task_handles.lock().iter() {
573 handle.abort();
574 }
575 }
576}
577
578impl<E> ScopeExecutor<'_, E>
579where
580 E: Executor,
581{
582 fn spawn_tracked<F, T>(&self, future: F) -> JoinHandle<T>
583 where
584 F: Future<Output = Result<T, JoinError>> + Send + 'static,
585 T: Send + 'static,
586 {
587 let (abort_handle, abort_registration) = AbortHandle::new_pair();
588 let (tx, rx) = oneshot::channel();
589 let finished = Arc::new(AtomicBool::new(false));
590 let completion = CompletionGuard::new(finished.clone());
591 let wrapped = async move {
592 let _completion = completion;
593 let result = abortable_result(future, abort_registration)
594 .await
595 .and_then(|result| result);
596 let _ = tx.send(result);
597 };
598
599 let task_handle = self.inner.spawn_abortable(wrapped);
602 self.task_handles.lock().push(task_handle);
603
604 JoinHandle {
605 inner: InnerJoinHandle::CustomHandle {
606 inner: Optional::new(rx),
607 handle: abort_handle,
608 finished,
609 },
610 }
611 }
612}
613
614impl<E> Drop for ScopeExecutor<'_, E> {
615 fn drop(&mut self) {
616 self.abort_all();
617 }
618}
619
620impl<'scope, E> Executor for ScopeExecutor<'scope, E>
621where
622 E: Executor,
623{
624 fn runtime_type(&self) -> Option<&'static str> {
625 self.inner.runtime_type()
626 }
627
628 fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
629 where
630 F: Future + Send + 'static,
631 F::Output: Send + 'static,
632 {
633 self.spawn_tracked(async move { Ok(future.await) })
634 }
635}
636
637impl<E> ExecutorBlocking for ScopeExecutor<'_, E>
638where
639 E: ExecutorBlocking,
640{
641 fn spawn_blocking<F, R>(&self, f: F) -> JoinHandle<R>
642 where
643 F: FnOnce() -> R + Send + 'static,
644 R: Send + 'static,
645 {
646 let blocking_handle = self.inner.spawn_blocking_abortable(f);
647 self.spawn_tracked(blocking_handle)
651 }
652}
653
654impl<E> ExecutorTimeout for ScopeExecutor<'_, E> where E: Executor {}
655
656pub async fn executor_scope<'scope, E, F, T>(executor: &'scope E, f: F) -> T
684where
685 E: Executor,
686 F: AsyncFnOnce(&ScopeExecutor<'scope, E>) -> T,
687{
688 let scope_exec = ScopeExecutor::new(executor);
689 let result = f(&scope_exec).await;
690
691 let handles: Vec<_> = scope_exec.task_handles.lock().drain(..).collect();
693 for handle in handles {
694 let _ = handle.await;
695 }
696
697 result
698}
699
700#[cfg(test)]
701mod tests {
702 use super::*;
703 #[cfg(feature = "tokio")]
704 use futures_timer::Delay;
705 #[cfg(feature = "tokio")]
706 use std::time::Duration;
707
708 #[tokio::test]
709 async fn borrows_stack_data() {
710 let data = vec![1, 2, 3, 4];
711 let data = &data;
712 let sum = scope(async |s: &Scope<'_, '_>| {
713 let a = s.spawn(async move { data[0] + data[1] });
714 let b = s.spawn(async move { data[2] + data[3] });
715 a.await.unwrap() + b.await.unwrap()
716 })
717 .await;
718 assert_eq!(sum, 10);
719 }
720
721 #[tokio::test]
722 async fn drains_unawaited_tasks() {
723 use std::sync::atomic::{AtomicUsize, Ordering};
724 let counter = AtomicUsize::new(0);
725 let counter_ref = &counter;
726 scope(async |s: &Scope<'_, '_>| {
727 for _ in 0..8 {
728 s.spawn(async move {
729 counter_ref.fetch_add(1, Ordering::SeqCst);
730 });
731 }
732 })
733 .await;
734 assert_eq!(counter.load(Ordering::SeqCst), 8);
735 }
736
737 #[tokio::test]
738 async fn returns_closure_value() {
739 let v: i32 = scope(async |_s: &Scope<'_, '_>| 42).await;
740 assert_eq!(v, 42);
741 }
742
743 #[tokio::test]
744 async fn join_handle_yields_output() {
745 let out = scope(async |s: &Scope<'_, '_>| {
746 let h = s.spawn(async { "hello" });
747 h.await.unwrap()
748 })
749 .await;
750 assert_eq!(out, "hello");
751 }
752
753 #[cfg(panic = "unwind")]
754 #[tokio::test]
755 async fn join_handle_reports_task_panic() {
756 let result = scope(async |s: &Scope<'_, '_>| {
757 s.spawn(async { panic!("expected scoped task panic") })
758 .await
759 })
760 .await;
761
762 assert!(matches!(result, Err(JoinError::Panicked)));
763 }
764
765 #[cfg(panic = "unwind")]
766 #[tokio::test]
767 async fn unawaited_task_panic_does_not_stop_other_tasks() {
768 let completed = AtomicBool::new(false);
769
770 scope(async |s: &Scope<'_, '_>| {
771 s.spawn(async { panic!("expected unawaited scoped task panic") });
772 s.spawn(async {
773 completed.store(true, std::sync::atomic::Ordering::SeqCst);
774 });
775 })
776 .await;
777
778 assert!(completed.load(std::sync::atomic::Ordering::SeqCst));
779 }
780
781 #[tokio::test]
782 async fn abortable_handle_reports_completion_without_being_polled() {
783 scope(async |s: &Scope<'_, '_>| {
784 let handle = s.spawn_abortable(async {});
785
786 crate::task::yield_now().await;
789
790 assert!(handle.is_finished());
791 })
792 .await;
793 }
794
795 #[test]
796 fn pushing_task_wakes_scope_driver() {
797 use std::sync::atomic::{AtomicUsize, Ordering};
798 use std::task::{Wake, Waker};
799
800 struct WakeCounter(AtomicUsize);
801
802 impl Wake for WakeCounter {
803 fn wake(self: Arc<Self>) {
804 self.0.fetch_add(1, Ordering::SeqCst);
805 }
806
807 fn wake_by_ref(self: &Arc<Self>) {
808 self.0.fetch_add(1, Ordering::SeqCst);
809 }
810 }
811
812 let mut scope = Scope::new();
813 let state = Arc::new(ScopeState {
814 inbox: Mutex::new(Vec::new()),
815 waker: AtomicWaker::new(),
816 });
817 scope.state = Arc::downgrade(&state);
818
819 let wake_counter = Arc::new(WakeCounter(AtomicUsize::new(0)));
820 let waker = Waker::from(wake_counter.clone());
821 state.waker.register(&waker);
822
823 let scope_ref = &scope;
824 scope.push(
825 async move {
826 scope_ref.push(async {}.boxed());
829 }
830 .boxed(),
831 );
832
833 assert_eq!(state.inbox.lock().len(), 1);
834 assert_eq!(wake_counter.0.load(Ordering::SeqCst), 1);
835
836 let mut active = FuturesUnordered::new();
837 let mut context = Context::from_waker(&waker);
838 let (_, empty) = drive_scope(&mut active, &state, &mut context);
839 assert!(empty);
840 assert_eq!(wake_counter.0.load(Ordering::SeqCst), 2);
841
842 scope.push(async {}.boxed());
845 assert_eq!(wake_counter.0.load(Ordering::SeqCst), 3);
846
847 let (_, empty) = drive_scope(&mut active, &state, &mut context);
848 assert!(empty);
849
850 let state_ref = Arc::downgrade(&state);
851 scope.push(
852 poll_fn(move |_cx| {
853 state_ref.upgrade().unwrap().waker.wake();
857 Poll::<()>::Pending
858 })
859 .boxed(),
860 );
861 assert_eq!(wake_counter.0.load(Ordering::SeqCst), 4);
862
863 let (_, empty) = drive_scope(&mut active, &state, &mut context);
864 assert!(!empty);
865 let wakes_after_pending = wake_counter.0.load(Ordering::SeqCst);
866 assert!(wakes_after_pending > 4);
867
868 scope.push(async {}.boxed());
870 assert_eq!(
871 wake_counter.0.load(Ordering::SeqCst),
872 wakes_after_pending + 1
873 );
874 }
875
876 #[tokio::test]
877 async fn many_concurrent_tasks_complete() {
878 use std::sync::atomic::{AtomicUsize, Ordering};
879 let counter = AtomicUsize::new(0);
880 let counter_ref = &counter;
881 let total: usize = scope(async |s: &Scope<'_, '_>| {
882 let handles: Vec<_> = (0..32)
883 .map(|i| {
884 s.spawn(async move {
885 counter_ref.fetch_add(1, Ordering::SeqCst);
886 i
887 })
888 })
889 .collect();
890 let mut sum = 0usize;
891 for h in handles {
892 sum += h.await.unwrap();
893 }
894 sum
895 })
896 .await;
897 assert_eq!(total, (0..32).sum());
898 assert_eq!(counter.load(Ordering::SeqCst), 32);
899 }
900
901 #[tokio::test]
902 async fn child_task_can_spawn_nested_task() {
903 let result = scope(async |s: &Scope<'_, '_>| {
904 let outer = s.spawn(async move {
905 let inner = s.spawn(async { 41usize });
906 inner.await.unwrap() + 1
907 });
908 outer.await.unwrap()
909 })
910 .await;
911
912 assert_eq!(result, 42);
913 }
914
915 #[tokio::test]
916 async fn drains_unawaited_nested_task() {
917 use std::sync::atomic::{AtomicBool, Ordering};
918
919 let nested_ran = AtomicBool::new(false);
920 let nested_ran_ref = &nested_ran;
921
922 scope(async |s: &Scope<'_, '_>| {
923 s.dispatch(async move {
924 s.dispatch(async move {
925 nested_ran_ref.store(true, Ordering::SeqCst);
926 });
927 });
928 })
929 .await;
930
931 assert!(nested_ran.load(Ordering::SeqCst));
932 }
933
934 #[cfg(feature = "tokio")]
935 #[tokio::test]
936 async fn executor_scope_runs_tasks() {
937 use crate::rt::tokio::TokioExecutor;
938 let executor = TokioExecutor;
939 let total = executor
940 .executor_scope(async |s| {
941 let a = s.spawn(async { 1 + 2 });
942 let b = s.spawn(async { 3 + 4 });
943 a.await.unwrap() + b.await.unwrap()
944 })
945 .await;
946 assert_eq!(total, 10);
947 }
948
949 #[cfg(feature = "tokio")]
950 #[tokio::test]
951 async fn executor_scope_supports_timeouts() {
952 use crate::rt::tokio::TokioExecutor;
953 use futures::future::pending;
954
955 let executor = TokioExecutor;
956 executor
957 .executor_scope(async |s| {
958 let timeout = s.spawn_timeout(Duration::from_millis(10), pending::<()>());
959 assert!(matches!(timeout.await, Ok(Err(TimeoutError))));
960
961 let abortable_timeout =
962 s.spawn_abortable_timeout(Duration::from_millis(10), pending::<()>());
963 assert!(matches!(abortable_timeout.await, Ok(Err(TimeoutError))));
964 })
965 .await;
966 }
967
968 #[cfg(feature = "tokio")]
969 #[tokio::test]
970 async fn executor_scope_supports_blocking_tasks() {
971 use crate::rt::tokio::TokioExecutor;
972
973 let executor = TokioExecutor;
974 executor
975 .executor_scope(async |s| {
976 assert_eq!(s.spawn_blocking(|| 42).await.unwrap(), 42);
977
978 let panicked = s
979 .spawn_blocking(|| -> () { panic!("deliberate blocking task panic") })
980 .await;
981 assert!(matches!(panicked, Err(JoinError::Panicked)));
982 })
983 .await;
984 }
985
986 #[cfg(feature = "tokio")]
987 #[tokio::test]
988 async fn executor_scope_drains_unawaited_blocking_tasks() {
989 use crate::rt::tokio::TokioExecutor;
990 use std::sync::Arc;
991 use std::sync::atomic::{AtomicBool, Ordering};
992
993 let executor = TokioExecutor;
994 let completed = Arc::new(AtomicBool::new(false));
995 let task_completed = completed.clone();
996
997 executor
998 .executor_scope(async move |s| {
999 let _handle = s.spawn_blocking(move || {
1000 std::thread::sleep(Duration::from_millis(25));
1001 task_completed.store(true, Ordering::SeqCst);
1002 });
1003 })
1004 .await;
1005
1006 assert!(completed.load(Ordering::SeqCst));
1007 }
1008
1009 #[cfg(feature = "tokio")]
1010 #[tokio::test(flavor = "current_thread")]
1011 async fn executor_scope_blocking_abort_is_reported() {
1012 use crate::rt::tokio::TokioExecutor;
1013 use futures::future::{Either, select};
1014
1015 let executor = TokioExecutor;
1016 executor
1017 .executor_scope(async |s| {
1018 let (started_tx, started_rx) = oneshot::channel();
1019 let (release_tx, release_rx) = std::sync::mpsc::channel();
1020 let handle = s.spawn_blocking(move || {
1021 let _ = started_tx.send(());
1022 let _ = release_rx.recv();
1023 });
1024
1025 started_rx.await.unwrap();
1026 handle.abort();
1027
1028 let handle = Box::pin(handle);
1029 let result = match select(handle, Delay::new(Duration::from_secs(1))).await {
1030 Either::Left((result, _)) => result,
1031 Either::Right((_, handle)) => {
1032 release_tx.send(()).unwrap();
1033 let _ = handle.await;
1034 panic!("aborting the blocking handle did not cancel its monitor");
1035 }
1036 };
1037
1038 release_tx.send(()).unwrap();
1039 assert!(matches!(result, Err(JoinError::Aborted)));
1040 })
1041 .await;
1042 }
1043
1044 #[cfg(feature = "tokio")]
1045 #[tokio::test(flavor = "current_thread")]
1046 async fn executor_scope_handle_reports_completion_without_being_polled() {
1047 use crate::rt::tokio::TokioExecutor;
1048
1049 let executor = TokioExecutor;
1050 executor
1051 .executor_scope(async |s| {
1052 let (completed_tx, completed_rx) = oneshot::channel();
1053 let handle = s.spawn(async move {
1054 let _ = completed_tx.send(());
1055 });
1056
1057 completed_rx.await.unwrap();
1058
1059 assert!(handle.is_finished());
1062 })
1063 .await;
1064 }
1065
1066 #[tokio::test]
1067 async fn scope_spawn_coroutine_receives_messages() {
1068 use std::sync::atomic::{AtomicUsize, Ordering};
1069 let total = AtomicUsize::new(0);
1070 let total_ref = &total;
1071
1072 scope(async |s: &Scope<'_, '_>| {
1073 let mut task = s.spawn_coroutine(|value| async move {
1074 total_ref.fetch_add(value, Ordering::SeqCst);
1075 });
1076 for v in [1usize, 2, 3, 4] {
1077 task.send(v).await.unwrap();
1078 }
1079 drop(task); })
1081 .await;
1082
1083 assert_eq!(total.load(Ordering::SeqCst), 10);
1084 }
1085
1086 #[tokio::test]
1087 async fn scope_receiver_coroutine_receives_messages() {
1088 use std::sync::atomic::{AtomicUsize, Ordering};
1089 let total = AtomicUsize::new(0);
1090 let total_ref = &total;
1091
1092 scope(async |s: &Scope<'_, '_>| {
1093 let mut task = s.spawn_coroutine_with_receiver(|mut rx| async move {
1094 while let Some(value) = rx.next().await {
1095 total_ref.fetch_add(value, Ordering::SeqCst);
1096 }
1097 });
1098 for value in [1usize, 2, 3, 4] {
1099 task.send(value).await.unwrap();
1100 }
1101 drop(task);
1102 })
1103 .await;
1104
1105 assert_eq!(total.load(Ordering::SeqCst), 10);
1106 }
1107
1108 #[tokio::test]
1109 async fn scope_coroutine_api_matches_executor() {
1110 use futures::future::ready;
1111
1112 scope(async |s: &Scope<'_, '_>| {
1113 let task = s.spawn_coroutine_with_buffer(2, |_value: usize| ready(()));
1114 drop(task);
1115
1116 let task = s.spawn_unbounded_coroutine(|_value: usize| ready(()));
1117 drop(task);
1118
1119 let task =
1120 s.spawn_coroutine_with_context(0usize, |context: &mut usize, value: usize| {
1121 *context += value;
1122 ready(())
1123 });
1124 drop(task);
1125
1126 let task = s.spawn_coroutine_with_buffer_and_context(
1127 0usize,
1128 2,
1129 |context: &mut usize, value: usize| {
1130 *context += value;
1131 ready(())
1132 },
1133 );
1134 drop(task);
1135
1136 let task = s.spawn_unbounded_coroutine_with_context(
1137 0usize,
1138 |context: &mut usize, value: usize| {
1139 *context += value;
1140 ready(())
1141 },
1142 );
1143 drop(task);
1144
1145 let task =
1146 s.spawn_coroutine_with_receiver_and_buffer(2, |_rx: Receiver<usize>| async {});
1147 drop(task);
1148
1149 let task = s.spawn_coroutine_with_receiver_and_context(
1150 0usize,
1151 |_context, _rx: Receiver<usize>| async {},
1152 );
1153 drop(task);
1154
1155 let task = s.spawn_coroutine_with_receiver_buffer_and_context(
1156 0usize,
1157 2,
1158 |_context, _rx: Receiver<usize>| async {},
1159 );
1160 drop(task);
1161
1162 let task =
1163 s.spawn_unbounded_coroutine_with_receiver(|_rx: UnboundedReceiver<usize>| async {});
1164 drop(task);
1165
1166 let task = s.spawn_unbounded_coroutine_with_receiver_and_context(
1167 0usize,
1168 |_context, _rx: UnboundedReceiver<usize>| async {},
1169 );
1170 drop(task);
1171 })
1172 .await;
1173 }
1174
1175 #[tokio::test]
1176 async fn scope_dispatch_runs_fire_and_forget() {
1177 use std::sync::atomic::{AtomicBool, Ordering};
1178 let flag = AtomicBool::new(false);
1179 let flag_ref = &flag;
1180
1181 scope(async |s: &Scope<'_, '_>| {
1182 s.dispatch(async move {
1183 flag_ref.store(true, Ordering::SeqCst);
1184 });
1185 })
1186 .await;
1187
1188 assert!(flag.load(Ordering::SeqCst));
1189 }
1190
1191 #[cfg(feature = "tokio")]
1192 #[tokio::test]
1193 async fn executor_scope_drains_unawaited_tasks() {
1194 use crate::rt::tokio::TokioExecutor;
1195 use std::sync::Arc;
1196 use std::sync::atomic::{AtomicBool, Ordering};
1197
1198 let executor = TokioExecutor;
1199 let flag = Arc::new(AtomicBool::new(false));
1200 let flag_clone = flag.clone();
1201
1202 executor
1203 .executor_scope(async move |s| {
1204 let _h = s.spawn(async move {
1208 Delay::new(Duration::from_millis(50)).await;
1209 flag_clone.store(true, Ordering::SeqCst);
1210 });
1211 })
1212 .await;
1213
1214 assert!(
1215 flag.load(Ordering::SeqCst),
1216 "unawaited task should have completed before executor_scope returned"
1217 );
1218 }
1219
1220 #[cfg(feature = "tokio")]
1221 #[tokio::test]
1222 async fn executor_scope_swallows_task_panic() {
1223 use crate::rt::tokio::TokioExecutor;
1224 use std::sync::Arc;
1225 use std::sync::atomic::{AtomicUsize, Ordering};
1226
1227 let executor = TokioExecutor;
1228 let sibling_done = Arc::new(AtomicUsize::new(0));
1229 let sibling_done_clone = sibling_done.clone();
1230
1231 let result = executor
1232 .executor_scope(async move |s| {
1233 let _panicker = s.spawn(async {
1236 panic!("deliberate test panic");
1237 });
1238 let _sibling = s.spawn(async move {
1241 sibling_done_clone.fetch_add(1, Ordering::SeqCst);
1242 });
1243 42usize
1244 })
1245 .await;
1246
1247 assert_eq!(result, 42);
1248 assert_eq!(sibling_done.load(Ordering::SeqCst), 1);
1249 }
1250
1251 #[cfg(feature = "tokio")]
1252 #[tokio::test]
1253 async fn executor_scope_aborts_on_external_cancel() {
1254 use crate::rt::tokio::TokioExecutor;
1255 use futures::future::Either;
1256 use std::sync::Arc;
1257 use std::sync::atomic::{AtomicBool, Ordering};
1258
1259 let executor = TokioExecutor;
1260 let flag = Arc::new(AtomicBool::new(false));
1261 let flag_clone = flag.clone();
1262
1263 {
1264 let scope_fut = executor.executor_scope(async move |s| {
1265 let _h = s.spawn(async move {
1266 Delay::new(Duration::from_millis(200)).await;
1267 flag_clone.store(true, Ordering::SeqCst);
1268 });
1269 futures::future::pending::<()>().await;
1270 });
1271
1272 let scope_fut = std::pin::pin!(scope_fut);
1273 let timer = std::pin::pin!(Delay::new(Duration::from_millis(30)));
1274 let result = futures::future::select(scope_fut, timer).await;
1275 assert!(
1276 matches!(result, Either::Right(_)),
1277 "timer should have won the race"
1278 );
1279 }
1280
1281 Delay::new(Duration::from_millis(300)).await;
1283 assert!(
1284 !flag.load(Ordering::SeqCst),
1285 "task should have been aborted by scope drop"
1286 );
1287 }
1288
1289 #[cfg(feature = "tokio")]
1290 #[tokio::test]
1291 async fn executor_scope_aborts_when_cancelled_during_drain() {
1292 use crate::rt::tokio::TokioExecutor;
1293 use futures::future::{Either, pending, select};
1294
1295 let executor = TokioExecutor;
1296 let (started_tx, started_rx) = oneshot::channel();
1297 let (held_tx, held_rx) = oneshot::channel::<()>();
1298
1299 let scope_fut = Box::pin(executor.executor_scope(async move |s| {
1300 let _handle = s.spawn(async move {
1301 let _held_until_task_drop = held_tx;
1302 let _ = started_tx.send(());
1303 pending::<()>().await;
1304 });
1305 }));
1306
1307 let scope_fut = match select(scope_fut, started_rx).await {
1308 Either::Right((Ok(()), scope_fut)) => scope_fut,
1309 Either::Left(_) => panic!("scope unexpectedly completed"),
1310 Either::Right((Err(_), _)) => panic!("child task never started"),
1311 };
1312
1313 drop(scope_fut);
1314
1315 match select(held_rx, Delay::new(Duration::from_secs(1))).await {
1316 Either::Left((Err(_), _)) => {}
1317 Either::Left((Ok(_), _)) => unreachable!("child never sends a value"),
1318 Either::Right(_) => panic!("child remained detached after scope cancellation"),
1319 }
1320 }
1321}