1pub mod arc;
2pub mod error;
3#[cfg(feature = "fs")]
4pub mod fs;
5pub mod global;
6#[cfg(all(
7 feature = "net",
8 not(target_arch = "wasm32"),
9 any(feature = "tokio", feature = "smol", feature = "compio")
10))]
11pub mod net;
12pub mod rt;
13pub mod task;
14pub mod tracker;
15
16#[cfg(feature = "either")]
17pub mod either;
18pub mod rc;
19pub mod scoped;
20
21use std::fmt::{Debug, Formatter};
22use std::panic::AssertUnwindSafe;
23use std::sync::atomic::{AtomicBool, Ordering};
24
25pub use crate::error::JoinError;
26pub use crate::error::TimeoutError;
27pub use crate::scoped::{Scope, ScopeExecutor, ScopedJoinHandle};
28#[cfg(all(
29 feature = "macros",
30 feature = "compio",
31 not(any(feature = "tokio", feature = "smol", target_arch = "wasm32"))
32))]
33#[doc(inline)]
34pub use async_rt_macros::{main_compio as main, test_compio as test};
35#[cfg(all(
36 feature = "macros",
37 not(any(
38 feature = "tokio",
39 feature = "smol",
40 feature = "compio",
41 feature = "threadpool",
42 feature = "lite"
43 )),
44 not(target_arch = "wasm32")
45))]
46#[doc(inline)]
47pub use async_rt_macros::{main_fail as main, test_fail as test};
48#[cfg(all(
49 feature = "macros",
50 feature = "lite",
51 not(any(
52 feature = "tokio",
53 feature = "smol",
54 feature = "compio",
55 feature = "threadpool",
56 target_arch = "wasm32"
57 ))
58))]
59#[doc(inline)]
60pub use async_rt_macros::{main_lite as main, test_lite as test};
61#[cfg(all(
62 feature = "macros",
63 feature = "smol",
64 not(any(feature = "tokio", target_arch = "wasm32"))
65))]
66#[doc(inline)]
67pub use async_rt_macros::{main_smol as main, test_smol as test};
68#[cfg(all(
69 feature = "macros",
70 feature = "threadpool",
71 not(any(
72 feature = "tokio",
73 feature = "smol",
74 feature = "compio",
75 target_arch = "wasm32"
76 ))
77))]
78#[doc(inline)]
79pub use async_rt_macros::{main_threadpool as main, test_threadpool as test};
80#[cfg(all(feature = "macros", feature = "tokio", not(target_arch = "wasm32")))]
81#[doc(inline)]
82pub use async_rt_macros::{main_tokio as main, test_tokio as test};
83#[cfg(all(feature = "macros", target_arch = "wasm32"))]
84#[doc(inline)]
85pub use async_rt_macros::{main_wasm_fail as main, test_wasm_fail as test};
86use futures::channel::mpsc::{Receiver, UnboundedReceiver};
87use futures::future::{AbortHandle, AbortRegistration, Abortable};
88use futures::task::AtomicWaker;
89use futures::{FutureExt, SinkExt, StreamExt, TryFutureExt};
90use futures_timeout::Timeout;
91#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
92use parking_lot::Mutex;
93use pollable_map::optional::Optional;
94use std::future::Future;
95use std::pin::Pin;
96use std::sync::Arc;
97use std::task::{Context, Poll};
98
99#[cfg(feature = "macros")]
100extern crate self as async_rt;
101
102#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
103type BoxCancelFuture<T> = Pin<Box<dyn Future<Output = Option<T>> + Send + 'static>>;
104
105#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
106type StartCompioCancel<T> = fn(&Mutex<InnerCompioHandle<T>>, &AtomicBool);
107
108#[cfg_attr(feature = "tokio", allow(dead_code))]
109pub(crate) struct CompletionGuard {
110 finished: Arc<AtomicBool>,
111}
112
113impl CompletionGuard {
114 #[cfg_attr(feature = "tokio", allow(dead_code))]
115 pub(crate) fn new(finished: Arc<AtomicBool>) -> Self {
116 Self { finished }
117 }
118}
119
120impl Drop for CompletionGuard {
121 fn drop(&mut self) {
122 self.finished.store(true, Ordering::Release);
123 }
124}
125
126pub(crate) async fn abortable_result<F>(
127 future: F,
128 abort_registration: AbortRegistration,
129) -> Result<F::Output, JoinError>
130where
131 F: Future,
132{
133 let future = AssertUnwindSafe(future).catch_unwind();
134
135 match Abortable::new(future, abort_registration).await {
136 Ok(Ok(value)) => Ok(value),
137 Ok(Err(_)) => Err(JoinError::Panicked),
138 Err(_) => Err(JoinError::Aborted),
139 }
140}
141
142pub struct JoinHandle<T> {
154 inner: InnerJoinHandle<T>,
155}
156
157impl<T> Debug for JoinHandle<T> {
158 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("JoinHandle").finish()
160 }
161}
162
163#[derive(Default)]
164enum InnerJoinHandle<T> {
165 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
166 TokioHandle {
167 handle: Optional<::tokio::task::JoinHandle<T>>,
168 abort_requested: AtomicBool,
169 },
170 #[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
171 CompioHandle {
172 handle: Mutex<InnerCompioHandle<T>>,
173 abort_requested: AtomicBool,
174 start_cancel: StartCompioCancel<T>,
175 },
176 #[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
177 SmolHandle { handle: SmolTask<T> },
178 #[allow(dead_code)]
179 CustomHandle {
180 inner: Optional<futures::channel::oneshot::Receiver<Result<T, JoinError>>>,
181 handle: AbortHandle,
182 finished: Arc<AtomicBool>,
183 },
184 #[default]
185 Empty,
186}
187
188#[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
189struct SmolTask<T> {
190 inner: Optional<::async_task::FallibleTask<Result<T, JoinError>>>,
191 abort_handle: AbortHandle,
192}
193
194#[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
195impl<T> SmolTask<T> {
196 fn new(task: ::smol::Task<Result<T, JoinError>>, abort_handle: AbortHandle) -> Self {
197 Self {
198 inner: Optional::new(task.fallible()),
199 abort_handle,
200 }
201 }
202
203 fn abort(&self) {
204 self.abort_handle.abort();
205 }
206
207 fn is_finished(&self) -> bool {
208 self.inner
209 .as_ref()
210 .map(|task| task.is_finished())
211 .unwrap_or(true)
212 }
213}
214
215#[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
216impl<T> Drop for SmolTask<T> {
217 fn drop(&mut self) {
218 if let Some(task) = self.inner.take() {
219 task.detach();
220 }
221 }
222}
223
224#[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
225impl<T> Future for SmolTask<T> {
226 type Output = Result<T, JoinError>;
227
228 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
229 match futures::ready!(Pin::new(&mut self.inner).poll(cx)) {
230 Some(result) => Poll::Ready(result),
231 None => Poll::Ready(Err(JoinError::Cancelled)),
232 }
233 }
234}
235
236#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
237enum InnerCompioHandle<T> {
238 Running(Option<::compio::runtime::JoinHandle<T>>),
239 Cancelling(CompioCancel<T>),
240 Ready(Option<Option<T>>),
241}
242
243#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
244impl<T> Unpin for InnerCompioHandle<T> {}
245
246#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
247struct CompioCancelWake {
248 outer: AtomicWaker,
249}
250
251#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
252impl futures::task::ArcWake for CompioCancelWake {
253 fn wake_by_ref(arc_self: &Arc<Self>) {
254 arc_self.outer.wake();
255 }
256}
257
258#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
259struct CompioCancel<T> {
260 future: BoxCancelFuture<T>,
261 wake: Arc<CompioCancelWake>,
262}
263
264#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
265impl<T> CompioCancel<T> {
266 fn new(future: BoxCancelFuture<T>) -> Self {
267 Self {
268 future,
269 wake: Arc::new(CompioCancelWake {
270 outer: AtomicWaker::new(),
271 }),
272 }
273 }
274
275 fn poll_inner(&mut self) -> Poll<Option<T>> {
276 let waker = futures::task::waker(self.wake.clone());
277 let mut cx = Context::from_waker(&waker);
278 self.future.as_mut().poll(&mut cx)
279 }
280}
281
282#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
283impl<T> Future for CompioCancel<T> {
284 type Output = Option<T>;
285
286 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
287 self.wake.outer.register(cx.waker());
288 self.poll_inner()
289 }
290}
291
292#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
296impl<T> Drop for InnerCompioHandle<T> {
297 fn drop(&mut self) {
298 if let InnerCompioHandle::Running(handle) = self {
299 let Some(handle) = handle.take() else {
300 return;
301 };
302 handle.detach();
303 }
304 }
305}
306
307#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
308impl<T> Future for InnerCompioHandle<T> {
309 type Output = Result<Option<T>, JoinError>;
310 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
311 let this = &mut *self;
312
313 match this {
314 InnerCompioHandle::Running(handle) => {
315 let Some(mut handle) = handle.take() else {
316 return Poll::Ready(Ok(None));
317 };
318 match Pin::new(&mut handle).poll(cx) {
319 Poll::Ready(result) => Poll::Ready(result.map(Some).map_err(JoinError::from)),
320 Poll::Pending => {
321 *this = InnerCompioHandle::Running(Some(handle));
322 Poll::Pending
323 }
324 }
325 }
326 InnerCompioHandle::Cancelling(future) => match Pin::new(future).poll(cx) {
327 Poll::Ready(result) => {
328 *this = InnerCompioHandle::Ready(None);
329 Poll::Ready(Ok(result))
330 }
331 Poll::Pending => Poll::Pending,
332 },
333 InnerCompioHandle::Ready(result) => match result.take() {
334 Some(result) => Poll::Ready(Ok(result)),
335 None => Poll::Ready(Err(JoinError::Empty)),
336 },
337 }
338 }
339}
340
341#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
342fn start_compio_cancel<T: Send + 'static>(
343 state: &Mutex<InnerCompioHandle<T>>,
344 requested: &AtomicBool,
345) {
346 let mut state = state.lock();
347
348 let InnerCompioHandle::Running(slot) = &mut *state else {
349 return;
350 };
351 let Some(handle) = slot.take() else {
352 return;
353 };
354
355 requested.store(true, Ordering::Release);
356
357 let future: BoxCancelFuture<T> = Box::pin(handle.cancel());
358 let mut future = CompioCancel::new(future);
359 *state = match future.poll_inner() {
360 Poll::Ready(result) => InnerCompioHandle::Ready(Some(result)),
361 Poll::Pending => InnerCompioHandle::Cancelling(future),
362 };
363}
364
365#[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
366impl<T> InnerCompioHandle<T> {
367 fn is_finished(&mut self) -> bool {
368 match self {
369 InnerCompioHandle::Running(handle) => {
370 handle.as_ref().map(|h| h.is_finished()).unwrap_or(true)
371 }
372 InnerCompioHandle::Cancelling(future) => match future.poll_inner() {
373 Poll::Ready(result) => {
374 *self = InnerCompioHandle::Ready(Some(result));
375 true
376 }
377 Poll::Pending => false,
378 },
379 InnerCompioHandle::Ready(_) => true,
380 }
381 }
382}
383
384impl<T> InnerJoinHandle<T> {
385 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
386 fn tokio(handle: ::tokio::task::JoinHandle<T>) -> Self {
387 Self::TokioHandle {
388 handle: Optional::new(handle),
389 abort_requested: AtomicBool::new(false),
390 }
391 }
392
393 #[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
394 fn compio(handle: ::compio::runtime::JoinHandle<T>) -> Self
395 where
396 T: Send + 'static,
397 {
398 Self::CompioHandle {
399 handle: Mutex::new(InnerCompioHandle::Running(Some(handle))),
400 abort_requested: AtomicBool::new(false),
401 start_cancel: start_compio_cancel::<T>,
402 }
403 }
404
405 #[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
406 fn smol(handle: ::smol::Task<Result<T, JoinError>>, abort_handle: AbortHandle) -> Self {
407 Self::SmolHandle {
408 handle: SmolTask::new(handle, abort_handle),
409 }
410 }
411}
412
413impl<T> JoinHandle<T> {
414 pub fn empty() -> Self {
416 JoinHandle {
417 inner: InnerJoinHandle::Empty,
418 }
419 }
420}
421
422impl<T> JoinHandle<T> {
423 pub fn abort(&self) {
429 match &self.inner {
430 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
431 InnerJoinHandle::TokioHandle {
432 handle,
433 abort_requested,
434 } => {
435 if let Some(handle) = handle.as_ref() {
436 abort_requested.store(true, Ordering::Release);
437 handle.abort();
438 }
439 }
440 #[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
441 InnerJoinHandle::CompioHandle {
442 handle,
443 abort_requested,
444 start_cancel,
445 } => {
446 start_cancel(handle, abort_requested);
447 }
448 #[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
449 InnerJoinHandle::SmolHandle { handle } => handle.abort(),
450 InnerJoinHandle::CustomHandle { handle, .. } => handle.abort(),
451 InnerJoinHandle::Empty => {}
452 }
453 }
454
455 pub fn is_finished(&self) -> bool {
460 match &self.inner {
461 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
462 InnerJoinHandle::TokioHandle { handle, .. } => {
463 handle.as_ref().map(|h| h.is_finished()).unwrap_or(true)
464 }
465 #[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
466 InnerJoinHandle::CompioHandle { handle, .. } => handle.lock().is_finished(),
467 #[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
468 InnerJoinHandle::SmolHandle { handle } => handle.is_finished(),
469 InnerJoinHandle::CustomHandle {
470 inner, finished, ..
471 } => finished.load(Ordering::Acquire) || inner.is_none(),
472 InnerJoinHandle::Empty => true,
473 }
474 }
475
476 pub fn replace(&mut self, mut handle: JoinHandle<T>) {
485 self.inner = std::mem::take(&mut handle.inner);
486 }
487
488 pub fn replace_in_place(&mut self, handle: &mut JoinHandle<T>) {
498 self.inner = std::mem::take(&mut handle.inner);
499 }
500}
501
502impl<T> Future for JoinHandle<T> {
503 type Output = Result<T, JoinError>;
504 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
505 let inner = &mut self.inner;
506 match inner {
507 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
508 InnerJoinHandle::TokioHandle {
509 handle,
510 abort_requested,
511 } => {
512 let fut = futures::ready!(Pin::new(handle).poll(cx));
513
514 match fut {
515 Ok(val) => Poll::Ready(Ok(val)),
516 Err(e) if e.is_cancelled() && abort_requested.load(Ordering::Acquire) => {
517 Poll::Ready(Err(JoinError::Aborted))
518 }
519 Err(e) => Poll::Ready(Err(e.into())),
520 }
521 }
522 #[cfg(all(feature = "compio", not(target_arch = "wasm32")))]
523 InnerJoinHandle::CompioHandle {
524 handle,
525 abort_requested,
526 ..
527 } => {
528 let handle = &mut *handle.lock();
529 let fut = futures::ready!(Pin::new(handle).poll(cx));
530
531 match fut {
532 Ok(Some(val)) => Poll::Ready(Ok(val)),
533 Ok(None) if abort_requested.load(Ordering::Acquire) => {
534 Poll::Ready(Err(JoinError::Aborted))
535 }
536 Ok(None) => Poll::Ready(Err(JoinError::Empty)),
537 Err(_) if abort_requested.load(Ordering::Acquire) => {
538 Poll::Ready(Err(JoinError::Aborted))
539 }
540 Err(e) => Poll::Ready(Err(e)),
541 }
542 }
543 #[cfg(all(feature = "smol", not(target_arch = "wasm32")))]
544 InnerJoinHandle::SmolHandle { handle } => Pin::new(handle).poll(cx),
545 InnerJoinHandle::CustomHandle { inner, .. } => {
546 let fut = futures::ready!(Pin::new(inner).poll(cx));
547 match fut {
548 Ok(result) => Poll::Ready(result),
549 Err(_) => Poll::Ready(Err(JoinError::Cancelled)),
550 }
551 }
552 InnerJoinHandle::Empty => Poll::Ready(Err(JoinError::Empty)),
553 }
554 }
555}
556
557#[derive(Clone)]
560pub struct AbortableJoinHandle<T> {
561 handle: Arc<InnerHandle<T>>,
562}
563
564impl<T> Debug for AbortableJoinHandle<T> {
565 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
566 f.debug_struct("AbortableJoinHandle").finish()
567 }
568}
569
570impl<T> From<JoinHandle<T>> for AbortableJoinHandle<T> {
571 fn from(handle: JoinHandle<T>) -> Self {
572 AbortableJoinHandle {
573 handle: Arc::new(InnerHandle {
574 inner: parking_lot::Mutex::new(handle),
575 waker: AtomicWaker::new(),
576 }),
577 }
578 }
579}
580
581impl<T> AbortableJoinHandle<T> {
582 pub fn empty() -> Self {
584 Self {
585 handle: Arc::new(InnerHandle {
586 inner: parking_lot::Mutex::new(JoinHandle::empty()),
587 waker: AtomicWaker::new(),
588 }),
589 }
590 }
591}
592
593impl<T> AbortableJoinHandle<T> {
594 pub fn abort(&self) {
596 self.handle.inner.lock().abort();
597 self.handle.wake();
598 }
599
600 pub fn is_finished(&self) -> bool {
602 self.handle.inner.lock().is_finished()
603 }
604
605 pub fn replace(&self, other: AbortableJoinHandle<T>) {
612 if Arc::ptr_eq(&self.handle, &other.handle) {
613 return;
614 }
615
616 let replacement = {
617 let mut source = other.handle.inner.lock();
618 std::mem::replace(&mut *source, JoinHandle::empty())
619 };
620
621 other.handle.wake();
622
623 let previous = {
624 let mut destination = self.handle.inner.lock();
625 std::mem::replace(&mut *destination, replacement)
626 };
627
628 drop(previous);
629
630 self.handle.wake();
631 }
632}
633
634struct InnerHandle<T> {
635 pub inner: parking_lot::Mutex<JoinHandle<T>>,
636 pub waker: AtomicWaker,
637}
638
639impl<T> Drop for InnerHandle<T> {
640 fn drop(&mut self) {
641 self.inner.lock().abort();
642 }
643}
644
645impl<T> InnerHandle<T> {
646 pub fn wake(&self) {
647 self.waker.wake();
648 }
649}
650
651impl<T> Future for AbortableJoinHandle<T> {
652 type Output = Result<T, JoinError>;
653 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
654 self.handle.waker.register(cx.waker());
655 let inner = &mut *self.handle.inner.lock();
656 Pin::new(inner).poll(cx)
657 }
658}
659
660pub struct CommunicationTask<T> {
662 _task_handle: AbortableJoinHandle<()>,
663 _channel_tx: futures::channel::mpsc::Sender<T>,
664}
665
666impl<T> Clone for CommunicationTask<T> {
667 fn clone(&self) -> Self {
668 CommunicationTask {
669 _task_handle: self._task_handle.clone(),
670 _channel_tx: self._channel_tx.clone(),
671 }
672 }
673}
674
675impl<T> Debug for CommunicationTask<T> {
676 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
677 f.debug_struct("CommunicationTask").finish()
678 }
679}
680
681impl<T> CommunicationTask<T> {
682 pub(crate) fn new(
683 task_handle: AbortableJoinHandle<()>,
684 channel_tx: futures::channel::mpsc::Sender<T>,
685 ) -> Self {
686 Self {
687 _task_handle: task_handle,
688 _channel_tx: channel_tx,
689 }
690 }
691
692 pub async fn send(&mut self, data: T) -> std::io::Result<()> {
694 self._channel_tx
695 .send(data)
696 .await
697 .map_err(std::io::Error::other)
698 }
699
700 pub fn try_send(&mut self, data: T) -> std::io::Result<()> {
702 self._channel_tx
703 .try_send(data)
704 .map_err(|e| std::io::Error::other(e.to_string()))
705 }
706
707 pub fn abort(mut self) {
709 self._channel_tx.close_channel();
710 self._task_handle.abort();
711 }
712
713 pub fn is_active(&self) -> bool {
715 !self._task_handle.is_finished() && !self._channel_tx.is_closed()
716 }
717}
718
719pub struct UnboundedCommunicationTask<T> {
721 _task_handle: AbortableJoinHandle<()>,
722 _channel_tx: futures::channel::mpsc::UnboundedSender<T>,
723}
724
725impl<T> Clone for UnboundedCommunicationTask<T> {
726 fn clone(&self) -> Self {
727 UnboundedCommunicationTask {
728 _task_handle: self._task_handle.clone(),
729 _channel_tx: self._channel_tx.clone(),
730 }
731 }
732}
733
734impl<T> Debug for UnboundedCommunicationTask<T> {
735 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
736 f.debug_struct("UnboundedCommunicationTask").finish()
737 }
738}
739
740impl<T> UnboundedCommunicationTask<T> {
741 pub(crate) fn new(
742 task_handle: AbortableJoinHandle<()>,
743 channel_tx: futures::channel::mpsc::UnboundedSender<T>,
744 ) -> Self {
745 Self {
746 _task_handle: task_handle,
747 _channel_tx: channel_tx,
748 }
749 }
750
751 pub fn send(&mut self, data: T) -> std::io::Result<()> {
753 self._channel_tx
754 .unbounded_send(data)
755 .map_err(|e| std::io::Error::other(e.to_string()))
756 }
757
758 pub fn abort(self) {
760 self._channel_tx.close_channel();
761 self._task_handle.abort();
762 }
763
764 pub fn is_active(&self) -> bool {
766 !self._task_handle.is_finished() && !self._channel_tx.is_closed()
767 }
768}
769
770pub trait Executor {
771 fn runtime_type(&self) -> Option<&'static str> {
773 None
774 }
775
776 fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
778 where
779 F: Future + Send + 'static,
780 F::Output: Send + 'static;
781
782 fn spawn_abortable<F>(&self, future: F) -> AbortableJoinHandle<F::Output>
788 where
789 F: Future + Send + 'static,
790 F::Output: Send + 'static,
791 {
792 let handle = self.spawn(future);
793 handle.into()
794 }
795
796 fn dispatch<F>(&self, future: F)
799 where
800 F: Future + Send + 'static,
801 F::Output: Send + 'static,
802 {
803 self.spawn(future);
804 }
805
806 fn spawn_coroutine<T, F, Fut>(&self, f: F) -> CommunicationTask<T>
810 where
811 F: FnMut(T) -> Fut + Send + 'static,
812 Fut: Future<Output = ()> + Send + 'static,
813 T: Send + 'static,
814 {
815 Self::spawn_coroutine_with_buffer(self, 1, f)
816 }
817
818 fn spawn_coroutine_with_buffer<T, F, Fut>(
822 &self,
823 buffer: usize,
824 mut f: F,
825 ) -> CommunicationTask<T>
826 where
827 F: FnMut(T) -> Fut + Send + 'static,
828 Fut: Future<Output = ()> + Send + 'static,
829 T: Send + 'static,
830 {
831 let (tx, mut rx) = futures::channel::mpsc::channel(buffer);
832 let _task_handle = self.spawn_abortable(async move {
833 while let Some(msg) = rx.next().await {
834 f(msg).await;
835 }
836 });
837 CommunicationTask {
838 _task_handle,
839 _channel_tx: tx,
840 }
841 }
842
843 fn spawn_unbounded_coroutine<T, F, Fut>(&self, mut f: F) -> UnboundedCommunicationTask<T>
847 where
848 F: FnMut(T) -> Fut + Send + 'static,
849 Fut: Future<Output = ()> + Send + 'static,
850 T: Send + 'static,
851 {
852 let (tx, mut rx) = futures::channel::mpsc::unbounded();
853 let _task_handle = self.spawn_abortable(async move {
854 while let Some(msg) = rx.next().await {
855 f(msg).await;
856 }
857 });
858 UnboundedCommunicationTask {
859 _task_handle,
860 _channel_tx: tx,
861 }
862 }
863
864 fn spawn_coroutine_with_context<T, C, F, Fut>(&self, context: C, f: F) -> CommunicationTask<T>
872 where
873 F: FnMut(&mut C, T) -> Fut + Send + 'static,
874 Fut: Future<Output = ()> + Send + 'static,
875 C: Send + 'static,
876 T: Send + 'static,
877 {
878 Self::spawn_coroutine_with_buffer_and_context(self, context, 1, f)
879 }
880
881 fn spawn_coroutine_with_buffer_and_context<T, C, F, Fut>(
885 &self,
886 context: C,
887 buffer: usize,
888 mut f: F,
889 ) -> CommunicationTask<T>
890 where
891 F: FnMut(&mut C, T) -> Fut + Send + 'static,
892 Fut: Future<Output = ()> + Send + 'static,
893 C: Send + 'static,
894 T: Send + 'static,
895 {
896 let (tx, mut rx) = futures::channel::mpsc::channel(buffer);
897 let _task_handle = self.spawn_abortable(async move {
898 let mut context = context;
899 while let Some(msg) = rx.next().await {
900 f(&mut context, msg).await;
901 }
902 });
903 CommunicationTask {
904 _task_handle,
905 _channel_tx: tx,
906 }
907 }
908
909 fn spawn_unbounded_coroutine_with_context<T, C, F, Fut>(
913 &self,
914 context: C,
915 mut f: F,
916 ) -> UnboundedCommunicationTask<T>
917 where
918 F: FnMut(&mut C, T) -> Fut + Send + 'static,
919 Fut: Future<Output = ()> + Send + 'static,
920 C: Send + 'static,
921 T: Send + 'static,
922 {
923 let (tx, mut rx) = futures::channel::mpsc::unbounded();
924 let _task_handle = self.spawn_abortable(async move {
925 let mut context = context;
926 while let Some(msg) = rx.next().await {
927 f(&mut context, msg).await;
928 }
929 });
930 UnboundedCommunicationTask {
931 _task_handle,
932 _channel_tx: tx,
933 }
934 }
935
936 fn spawn_coroutine_with_receiver<T, F, Fut>(&self, f: F) -> CommunicationTask<T>
940 where
941 F: FnMut(Receiver<T>) -> Fut,
942 Fut: Future<Output = ()> + Send + 'static,
943 {
944 Self::spawn_coroutine_with_receiver_and_buffer(self, 1, f)
945 }
946
947 fn spawn_coroutine_with_receiver_and_buffer<T, F, Fut>(
951 &self,
952 buffer: usize,
953 mut f: F,
954 ) -> CommunicationTask<T>
955 where
956 F: FnMut(Receiver<T>) -> Fut,
957 Fut: Future<Output = ()> + Send + 'static,
958 {
959 let (tx, rx) = futures::channel::mpsc::channel(buffer);
960 let fut = f(rx);
961 let _task_handle = self.spawn_abortable(fut);
962 CommunicationTask {
963 _task_handle,
964 _channel_tx: tx,
965 }
966 }
967
968 fn spawn_coroutine_with_receiver_and_context<T, F, C, Fut>(
972 &self,
973 context: C,
974 f: F,
975 ) -> CommunicationTask<T>
976 where
977 F: FnMut(C, Receiver<T>) -> Fut,
978 Fut: Future<Output = ()> + Send + 'static,
979 {
980 Self::spawn_coroutine_with_receiver_buffer_and_context(self, context, 1, f)
981 }
982
983 fn spawn_coroutine_with_receiver_buffer_and_context<T, F, C, Fut>(
987 &self,
988 context: C,
989 buffer: usize,
990 mut f: F,
991 ) -> CommunicationTask<T>
992 where
993 F: FnMut(C, Receiver<T>) -> Fut,
994 Fut: Future<Output = ()> + Send + 'static,
995 {
996 let (tx, rx) = futures::channel::mpsc::channel(buffer);
997 let fut = f(context, rx);
998 let _task_handle = self.spawn_abortable(fut);
999 CommunicationTask {
1000 _task_handle,
1001 _channel_tx: tx,
1002 }
1003 }
1004
1005 fn spawn_unbounded_coroutine_with_receiver<T, F, Fut>(
1009 &self,
1010 mut f: F,
1011 ) -> UnboundedCommunicationTask<T>
1012 where
1013 F: FnMut(UnboundedReceiver<T>) -> Fut,
1014 Fut: Future<Output = ()> + Send + 'static,
1015 {
1016 let (tx, rx) = futures::channel::mpsc::unbounded();
1017 let fut = f(rx);
1018 let _task_handle = self.spawn_abortable(fut);
1019 UnboundedCommunicationTask {
1020 _task_handle,
1021 _channel_tx: tx,
1022 }
1023 }
1024
1025 fn spawn_unbounded_coroutine_with_receiver_and_context<T, F, C, Fut>(
1029 &self,
1030 context: C,
1031 mut f: F,
1032 ) -> UnboundedCommunicationTask<T>
1033 where
1034 F: FnMut(C, UnboundedReceiver<T>) -> Fut,
1035 Fut: Future<Output = ()> + Send + 'static,
1036 {
1037 let (tx, rx) = futures::channel::mpsc::unbounded();
1038 let fut = f(context, rx);
1039 let _task_handle = self.spawn_abortable(fut);
1040 UnboundedCommunicationTask {
1041 _task_handle,
1042 _channel_tx: tx,
1043 }
1044 }
1045
1046 fn scope<'env, F, T>(&self, f: F) -> impl Future<Output = T>
1076 where
1077 F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
1078 {
1079 scoped::scope(f)
1080 }
1081
1082 fn executor_scope<'scope, F, T>(&'scope self, f: F) -> impl Future<Output = T>
1109 where
1110 Self: Sized,
1111 F: AsyncFnOnce(&ScopeExecutor<'scope, Self>) -> T,
1112 {
1113 scoped::executor_scope(self, f)
1114 }
1115}
1116
1117pub trait ExecutorBlocking: Executor {
1118 fn spawn_blocking<F, R>(&self, f: F) -> JoinHandle<R>
1124 where
1125 F: FnOnce() -> R + Send + 'static,
1126 R: Send + 'static;
1127
1128 fn spawn_blocking_abortable<F, R>(&self, f: F) -> AbortableJoinHandle<R>
1135 where
1136 F: FnOnce() -> R + Send + 'static,
1137 R: Send + 'static,
1138 {
1139 let handle = self.spawn_blocking(f);
1140 handle.into()
1141 }
1142}
1143
1144pub trait ExecutorTimeout: Executor {
1145 fn spawn_timeout<F>(
1151 &self,
1152 duration: std::time::Duration,
1153 f: F,
1154 ) -> JoinHandle<Result<F::Output, TimeoutError>>
1155 where
1156 F: Future + Send + 'static,
1157 F::Output: Send + 'static,
1158 {
1159 self.spawn(Timeout::from_future(f, duration).map_err(|_| TimeoutError))
1160 }
1161
1162 fn spawn_delay<F>(&self, duration: std::time::Duration, f: F) -> JoinHandle<F::Output>
1164 where
1165 F: Future + Send + 'static,
1166 F::Output: Send + 'static,
1167 {
1168 self.spawn(async move {
1169 let _ = Timeout::from_future(futures::future::pending::<()>(), duration).await;
1170 f.await
1171 })
1172 }
1173
1174 fn spawn_abortable_timeout<F>(
1180 &self,
1181 duration: std::time::Duration,
1182 f: F,
1183 ) -> AbortableJoinHandle<Result<F::Output, TimeoutError>>
1184 where
1185 F: Future + Send + 'static,
1186 F::Output: Send + 'static,
1187 {
1188 self.spawn_abortable(Timeout::from_future(f, duration).map_err(|_| TimeoutError))
1189 }
1190
1191 fn spawn_abortable_delay<F>(
1193 &self,
1194 duration: std::time::Duration,
1195 f: F,
1196 ) -> AbortableJoinHandle<F::Output>
1197 where
1198 F: Future + Send + 'static,
1199 F::Output: Send + 'static,
1200 {
1201 self.spawn_abortable(async move {
1202 let _ = Timeout::from_future(futures::future::pending::<()>(), duration).await;
1203 f.await
1204 })
1205 }
1206}
1207
1208pub trait ExecutorBlockOn: Executor {
1209 fn block_on<F: Future>(&self, future: F) -> F::Output;
1213}
1214
1215#[cfg(test)]
1216mod tests {
1217 use crate::CompletionGuard;
1218 use crate::error::JoinError;
1219 use crate::{Executor, ExecutorBlocking, InnerJoinHandle, JoinHandle};
1220 use futures::future::AbortHandle;
1221 use pollable_map::optional::Optional;
1222 use std::future::Future;
1223 use std::sync::Arc;
1224 use std::sync::atomic::AtomicBool;
1225
1226 async fn task(tx: futures::channel::oneshot::Sender<()>) {
1227 futures_timer::Delay::new(std::time::Duration::from_secs(5)).await;
1228 let _ = tx.send(());
1229 unreachable!();
1230 }
1231
1232 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
1233 #[tokio::test]
1234 async fn replacing_handle_wakes_pending_clone() {
1235 use futures::task::{ArcWake, waker_ref};
1236 use std::pin::Pin;
1237 use std::sync::atomic::{AtomicUsize, Ordering};
1238 use std::task::Context;
1239
1240 struct WakeCounter(AtomicUsize);
1241
1242 impl ArcWake for WakeCounter {
1243 fn wake_by_ref(arc_self: &Arc<Self>) {
1244 arc_self.0.fetch_add(1, Ordering::SeqCst);
1245 }
1246 }
1247
1248 let executor = crate::rt::tokio::TokioExecutor;
1249 let handle = executor.spawn_abortable(futures::future::pending::<usize>());
1250 let mut pending_clone = handle.clone();
1251
1252 let wake_counter = Arc::new(WakeCounter(AtomicUsize::new(0)));
1253 let waker = waker_ref(&wake_counter);
1254 let mut context = Context::from_waker(&waker);
1255
1256 assert!(Pin::new(&mut pending_clone).poll(&mut context).is_pending());
1257 assert_eq!(wake_counter.0.load(Ordering::SeqCst), 0);
1258
1259 let replacement = executor.spawn_abortable(async { 42 });
1260 handle.replace(replacement);
1261
1262 assert!(wake_counter.0.load(Ordering::SeqCst) > 0);
1263 assert_eq!(pending_clone.await.unwrap(), 42);
1264 }
1265
1266 #[test]
1267 fn custom_abortable_task() {
1268 struct FuturesExecutor {
1269 pool: futures::executor::ThreadPool,
1270 }
1271
1272 impl Default for FuturesExecutor {
1273 fn default() -> Self {
1274 Self {
1275 pool: futures::executor::ThreadPool::new().unwrap(),
1276 }
1277 }
1278 }
1279
1280 impl Executor for FuturesExecutor {
1281 fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
1282 where
1283 F: Future + Send + 'static,
1284 F::Output: Send + 'static,
1285 {
1286 let (abort_handle, abort_registration) = AbortHandle::new_pair();
1287 let future = crate::abortable_result(future, abort_registration);
1288 let (tx, rx) = futures::channel::oneshot::channel();
1289
1290 let fin = Arc::new(AtomicBool::new(false));
1291 let finished = fin.clone();
1292 let completion = CompletionGuard::new(fin);
1293 let fut = async move {
1294 let _completion = completion;
1295 let val = future.await;
1296 let _ = tx.send(val);
1297 };
1298
1299 self.pool.spawn_ok(fut);
1300 let inner = InnerJoinHandle::CustomHandle {
1301 inner: Optional::new(rx),
1302 handle: abort_handle,
1303 finished,
1304 };
1305
1306 JoinHandle { inner }
1307 }
1308 }
1309
1310 impl ExecutorBlocking for FuturesExecutor {
1311 fn spawn_blocking<F, R>(&self, _: F) -> JoinHandle<R>
1312 where
1313 F: FnOnce() -> R + Send + 'static,
1314 R: Send + 'static,
1315 {
1316 unimplemented!()
1317 }
1318 }
1319
1320 futures::executor::block_on(async move {
1321 let executor = FuturesExecutor::default();
1322
1323 let (tx, rx) = futures::channel::oneshot::channel::<()>();
1324 let handle = executor.spawn_abortable(task(tx));
1325 drop(handle);
1326 let result = rx.await;
1327 assert!(result.is_err());
1328 });
1329 }
1330
1331 #[test]
1332 fn empty_handle_reports_empty() {
1333 let handle = JoinHandle::<()>::empty();
1334
1335 assert!(matches!(
1336 futures::executor::block_on(handle),
1337 Err(JoinError::Empty)
1338 ));
1339 }
1340
1341 #[test]
1342 fn custom_handle_reports_cancelled_when_sender_dropped() {
1343 let (tx, rx) = futures::channel::oneshot::channel::<Result<(), JoinError>>();
1344 let (abort_handle, _abort_registration) = AbortHandle::new_pair();
1345 let handle = JoinHandle {
1346 inner: InnerJoinHandle::CustomHandle {
1347 inner: Optional::new(rx),
1348 handle: abort_handle,
1349 finished: Arc::new(AtomicBool::new(false)),
1350 },
1351 };
1352
1353 drop(tx);
1357
1358 assert!(matches!(
1359 futures::executor::block_on(handle),
1360 Err(JoinError::Cancelled)
1361 ));
1362 }
1363}