Skip to main content

async_rs/implementors/
async_global_executor.rs

1//! async-global-executor implementation of async runtime definition traits
2
3use crate::{traits::Executor, util::Task};
4use std::future::Future;
5
6use task::AGETask;
7
8#[cfg(feature = "async-io")]
9use crate::{AsyncIO, Runtime, util::RuntimeParts};
10
11/// Type alias for the async-global-executor runtime
12#[cfg(feature = "async-io")]
13pub type AGERuntime = Runtime<RuntimeParts<AsyncGlobalExecutor, AsyncIO>>;
14
15#[cfg(feature = "async-io")]
16impl AGERuntime {
17    /// Create a new AGERuntime
18    #[must_use]
19    pub fn async_global_executor() -> Self {
20        Self::new(RuntimeParts::new(AsyncGlobalExecutor, AsyncIO))
21    }
22}
23
24/// Dummy object implementing executor common interfaces on top of async-global-executor
25#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
26pub struct AsyncGlobalExecutor;
27
28impl Executor for AsyncGlobalExecutor {
29    type Task<T: Send + 'static> = AGETask<T>;
30
31    fn block_on<T, F: Future<Output = T>>(&self, f: F) -> T {
32        async_global_executor::block_on(f)
33    }
34
35    fn spawn<T: Send + 'static, F: Future<Output = T> + Send + 'static>(
36        &self,
37        f: F,
38    ) -> Task<Self::Task<T>> {
39        AGETask(Some(async_global_executor::spawn(f))).into()
40    }
41
42    fn spawn_blocking<T: Send + 'static, F: FnOnce() -> T + Send + 'static>(
43        &self,
44        f: F,
45    ) -> Task<Self::Task<T>> {
46        AGETask(Some(async_global_executor::spawn_blocking(f))).into()
47    }
48}
49
50mod task {
51    use crate::util::TaskImpl;
52    use async_trait::async_trait;
53    use std::{
54        future::Future,
55        pin::Pin,
56        task::{Context, Poll},
57    };
58
59    /// An async-global-executor task
60    #[derive(Debug)]
61    pub struct AGETask<T: Send + 'static>(pub(super) Option<async_global_executor::Task<T>>);
62
63    #[async_trait]
64    impl<T: Send + 'static> TaskImpl for AGETask<T> {
65        async fn cancel(&mut self) -> Option<T> {
66            self.0.take()?.cancel().await
67        }
68
69        fn detach(&mut self) {
70            if let Some(task) = self.0.take() {
71                task.detach();
72            }
73        }
74    }
75
76    impl<T: Send + 'static> Future for AGETask<T> {
77        type Output = T;
78
79        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
80            // async-task propagates a panicking task on its own; all we have to add is not
81            // stalling forever once the task has been taken away by cancel or detach.
82            let task = self
83                .0
84                .as_mut()
85                .expect("Task polled after it was canceled or completed");
86            Pin::new(task).poll(cx)
87        }
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn auto_traits() {
97        use crate::util::test::*;
98        #[cfg(feature = "async-io")]
99        let runtime = Runtime::async_global_executor();
100        #[cfg(not(feature = "async-io"))]
101        let runtime = AsyncGlobalExecutor;
102        assert_send(&runtime);
103        assert_sync(&runtime);
104        assert_clone(&runtime);
105    }
106}