accesskit_unix/
executor.rs

1// Copyright 2024 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6// Derived from zbus.
7// Copyright 2024 Zeeshan Ali Khan.
8// Licensed under the MIT license (found in the LICENSE-MIT file).
9
10#[cfg(not(feature = "tokio"))]
11use async_executor::Executor as AsyncExecutor;
12#[cfg(not(feature = "tokio"))]
13use async_task::Task as AsyncTask;
14#[cfg(feature = "tokio")]
15use std::marker::PhantomData;
16#[cfg(not(feature = "tokio"))]
17use std::sync::Arc;
18use std::{
19    future::Future,
20    pin::Pin,
21    task::{Context, Poll},
22};
23#[cfg(feature = "tokio")]
24use tokio::task::JoinHandle;
25
26/// A wrapper around the underlying runtime/executor.
27///
28/// This is used to run asynchronous tasks internally and allows integration with various runtimes.
29/// See [`crate::Connection::executor`] for an example of integration with external runtimes.
30///
31/// **Note:** You can (and should) completely ignore this type when building with `tokio` feature
32/// enabled.
33#[cfg(not(feature = "tokio"))]
34#[derive(Debug, Clone)]
35pub(crate) struct Executor<'a> {
36    executor: Arc<AsyncExecutor<'a>>,
37}
38#[cfg(feature = "tokio")]
39#[derive(Debug, Clone)]
40pub(crate) struct Executor<'a> {
41    phantom: PhantomData<&'a ()>,
42}
43
44impl Executor<'_> {
45    /// Spawns a task onto the executor.
46    pub(crate) fn spawn<T: Send + 'static>(
47        &self,
48        future: impl Future<Output = T> + Send + 'static,
49        #[allow(unused)] name: &str,
50    ) -> Task<T> {
51        #[cfg(not(feature = "tokio"))]
52        {
53            Task(Some(self.executor.spawn(future)))
54        }
55
56        #[cfg(feature = "tokio")]
57        {
58            Task(Some(tokio::task::spawn(future)))
59        }
60    }
61
62    /// Create a new `Executor`.
63    pub(crate) fn new() -> Self {
64        #[cfg(not(feature = "tokio"))]
65        {
66            Self {
67                executor: Arc::new(AsyncExecutor::new()),
68            }
69        }
70
71        #[cfg(feature = "tokio")]
72        {
73            Self {
74                phantom: PhantomData,
75            }
76        }
77    }
78
79    /// Runs the executor until the given future completes.
80    ///
81    /// With `tokio` feature enabled, it just awaits on the `future`.
82    pub(crate) async fn run<T>(&self, future: impl Future<Output = T>) -> T {
83        #[cfg(not(feature = "tokio"))]
84        {
85            self.executor.run(future).await
86        }
87        #[cfg(feature = "tokio")]
88        {
89            future.await
90        }
91    }
92}
93
94/// A wrapper around the task API of the underlying runtime/executor.
95///
96/// This follows the semantics of `async_task::Task` on drop:
97///
98/// * it will be cancelled, rather than detached. For detaching, use the `detach` method.
99/// * errors from the task cancellation will will be ignored. If you need to know about task errors,
100///   convert the task to a `FallibleTask` using the `fallible` method.
101#[cfg(not(feature = "tokio"))]
102#[derive(Debug)]
103pub(crate) struct Task<T>(Option<AsyncTask<T>>);
104#[cfg(feature = "tokio")]
105#[derive(Debug)]
106pub(crate) struct Task<T>(Option<JoinHandle<T>>);
107
108impl<T> Task<T> {
109    /// Detaches the task to let it keep running in the background.
110    #[allow(unused_mut)]
111    #[allow(unused)]
112    pub(crate) fn detach(mut self) {
113        #[cfg(not(feature = "tokio"))]
114        {
115            self.0.take().expect("async_task::Task is none").detach()
116        }
117
118        #[cfg(feature = "tokio")]
119        {
120            self.0.take().expect("tokio::task::JoinHandle is none");
121        }
122    }
123}
124
125impl<T> Drop for Task<T> {
126    fn drop(&mut self) {
127        #[cfg(feature = "tokio")]
128        {
129            if let Some(join_handle) = self.0.take() {
130                join_handle.abort();
131            }
132        }
133    }
134}
135
136impl<T> Future for Task<T> {
137    type Output = T;
138
139    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
140        #[cfg(not(feature = "tokio"))]
141        {
142            Pin::new(&mut self.get_mut().0.as_mut().expect("async_task::Task is none")).poll(cx)
143        }
144
145        #[cfg(feature = "tokio")]
146        {
147            Pin::new(
148                &mut self
149                    .get_mut()
150                    .0
151                    .as_mut()
152                    .expect("tokio::task::JoinHandle is none"),
153            )
154            .poll(cx)
155            .map(|r| r.expect("tokio::task::JoinHandle error"))
156        }
157    }
158}