executor.rs

  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> + 'static,
 81        R: Send + 'static,
 82    {
 83        let (runnable, task) = async_task::spawn(
 84            {
 85                let this = self.clone();
 86                async move {
 87                    let task = this.spawn_on_main_local(func());
 88                    task.await
 89                }
 90            },
 91            {
 92                let dispatcher = self.dispatcher.clone();
 93                move |runnable| dispatcher.dispatch_on_main_thread(runnable)
 94            },
 95        );
 96        runnable.schedule();
 97        Task::Spawned(task)
 98    }
 99
100    /// Enqueues the given closure to be run on the application's event loop. Must
101    /// be called on the main thread.
102    pub fn spawn_on_main_local<R>(&self, future: impl Future<Output = R> + 'static) -> Task<R>
103    where
104        R: 'static,
105    {
106        assert!(
107            self.dispatcher.is_main_thread(),
108            "must be called on main thread"
109        );
110
111        let dispatcher = self.dispatcher.clone();
112        let (runnable, task) = async_task::spawn_local(future, move |runnable| {
113            dispatcher.dispatch_on_main_thread(runnable)
114        });
115        runnable.schedule();
116        Task::Spawned(task)
117    }
118
119    pub fn is_main_thread(&self) -> bool {
120        self.dispatcher.is_main_thread()
121    }
122}