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