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
 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}