1use crate::PlatformDispatcher;
2use smol::prelude::*;
3use std::{
4 pin::Pin,
5 sync::Arc,
6 task::{Context, Poll},
7};
8
9#[derive(Clone)]
10pub struct Executor {
11 dispatcher: Arc<dyn PlatformDispatcher>,
12}
13
14#[must_use]
15pub enum Task<T> {
16 Ready(Option<T>),
17 Spawned(async_task::Task<T>),
18}
19
20impl<T> Task<T> {
21 pub fn ready(val: T) -> Self {
22 Task::Ready(Some(val))
23 }
24
25 pub fn detach(self) {
26 match self {
27 Task::Ready(_) => {}
28 Task::Spawned(task) => task.detach(),
29 }
30 }
31}
32
33impl<T> Future for Task<T> {
34 type Output = T;
35
36 fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
37 match unsafe { self.get_unchecked_mut() } {
38 Task::Ready(val) => Poll::Ready(val.take().unwrap()),
39 Task::Spawned(task) => task.poll(cx),
40 }
41 }
42}
43
44impl Executor {
45 pub fn new(dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
46 Self { dispatcher }
47 }
48
49 /// Enqueues the given closure to be run on any thread. The closure returns
50 /// a future which will be run to completion on any available thread.
51 pub fn spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
52 where
53 R: Send + 'static,
54 {
55 let dispatcher = self.dispatcher.clone();
56 let (runnable, task) =
57 async_task::spawn(future, move |runnable| dispatcher.dispatch(runnable));
58 runnable.schedule();
59 Task::Spawned(task)
60 }
61
62 /// Enqueues the given closure to run on the application's event loop.
63 /// Returns the result asynchronously.
64 pub fn run_on_main<F, R>(&self, func: F) -> Task<R>
65 where
66 F: FnOnce() -> R + Send + 'static,
67 R: Send + 'static,
68 {
69 if self.dispatcher.is_main_thread() {
70 Task::ready(func())
71 } else {
72 self.spawn_on_main(move || async move { func() })
73 }
74 }
75
76 /// Enqueues the given closure to be run on the application's event loop. The
77 /// closure returns a future which will be run to completion on the main thread.
78 pub fn spawn_on_main<F, R>(&self, func: impl FnOnce() -> F + Send + 'static) -> Task<R>
79 where
80 F: Future<Output = R> + Send + 'static,
81 R: Send + 'static,
82 {
83 let dispatcher = self.dispatcher.clone();
84 let (runnable, task) = async_task::spawn(async move { func().await }, move |runnable| {
85 dispatcher.dispatch_on_main_thread(runnable)
86 });
87 runnable.schedule();
88 Task::Spawned(task)
89 }
90
91 /// Enqueues the given closure to be run on the application's event loop. Must
92 /// be called on the main thread.
93 pub fn spawn_on_main_local<R>(&self, future: impl Future<Output = R> + 'static) -> Task<R>
94 where
95 R: 'static,
96 {
97 assert!(
98 self.dispatcher.is_main_thread(),
99 "must be called on main thread"
100 );
101
102 let dispatcher = self.dispatcher.clone();
103 let (runnable, task) = async_task::spawn_local(future, move |runnable| {
104 dispatcher.dispatch_on_main_thread(runnable)
105 });
106 runnable.schedule();
107 Task::Spawned(task)
108 }
109
110 pub fn is_main_thread(&self) -> bool {
111 self.dispatcher.is_main_thread()
112 }
113}