executor_trait/
lib.rs

1//! A collection of traits to define a common interface across executors
2
3#![forbid(unsafe_code)]
4#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
5#![no_std]
6extern crate alloc;
7
8use alloc::boxed::Box;
9use async_trait::async_trait;
10use core::{fmt, future::Future, ops::Deref, pin::Pin};
11
12/// An error to notify that the current executor doesn't support spawning local tasks.
13/// Holds the task that we tried to spawn.
14pub struct LocalExecutorError(pub Pin<Box<dyn Future<Output = ()>>>);
15
16impl fmt::Debug for LocalExecutorError {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.debug_tuple("LocalExecutorError")
19            .field(&"Future")
20            .finish()
21    }
22}
23
24/// A common interface for spawning futures on top of an executor
25#[async_trait]
26pub trait Executor {
27    /// Block on a future until completion
28    fn block_on(&self, f: Pin<Box<dyn Future<Output = ()>>>);
29
30    /// Spawn a future and return a handle to track its completion.
31    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Box<dyn Task>;
32
33    /// Spawn a non-Send future on the current thread and return a handle to track its completion.
34    fn spawn_local(
35        &self,
36        f: Pin<Box<dyn Future<Output = ()>>>,
37    ) -> Result<Box<dyn Task>, LocalExecutorError> {
38        Err(LocalExecutorError(f))
39    }
40
41    /// Convert a blocking task into a future, spawning it on a decicated thread pool
42    async fn spawn_blocking(&self, f: Box<dyn FnOnce() + Send + 'static>);
43}
44
45#[async_trait]
46impl<E: Deref + Sync> Executor for E
47where
48    E::Target: Executor + Sync,
49{
50    fn block_on(&self, f: Pin<Box<dyn Future<Output = ()>>>) {
51        self.deref().block_on(f)
52    }
53
54    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Box<dyn Task> {
55        self.deref().spawn(f)
56    }
57
58    fn spawn_local(
59        &self,
60        f: Pin<Box<dyn Future<Output = ()>>>,
61    ) -> Result<Box<dyn Task>, LocalExecutorError> {
62        self.deref().spawn_local(f)
63    }
64
65    async fn spawn_blocking(&self, f: Box<dyn FnOnce() + Send + 'static>) {
66        self.deref().spawn_blocking(f).await
67    }
68}
69
70/// A common interface to wait for a Task completion, let it run n the background or cancel it.
71#[async_trait(?Send)]
72pub trait Task: Future<Output = ()> {
73    /// Cancels the task and waits for it to stop running.
74    ///
75    /// Returns the task's output if it was completed just before it got canceled, or None if it
76    /// didn't complete.
77    async fn cancel(self: Box<Self>) -> Option<()>;
78}