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 and blocking tasks on top of an executor
25pub trait FullExecutor: Executor + BlockingExecutor {}
26
27/// A common interface for spawning futures on top of an executor
28pub trait Executor {
29    /// Block on a future until completion
30    fn block_on(&self, f: Pin<Box<dyn Future<Output = ()>>>);
31
32    /// Spawn a future and return a handle to track its completion.
33    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Box<dyn Task>;
34
35    /// Spawn a non-Send future on the current thread and return a handle to track its completion.
36    fn spawn_local(
37        &self,
38        f: Pin<Box<dyn Future<Output = ()>>>,
39    ) -> Result<Box<dyn Task>, LocalExecutorError> {
40        Err(LocalExecutorError(f))
41    }
42}
43
44/// A common interface for spawning blocking tasks on top of an executor
45#[async_trait]
46pub trait BlockingExecutor {
47    /// Convert a blocking task into a future, spawning it on a decicated thread pool
48    async fn spawn_blocking(&self, f: Box<dyn FnOnce() + Send + 'static>);
49}
50
51impl<E: Deref + Sync> FullExecutor for E where E::Target: FullExecutor + Sync {}
52
53impl<E: Deref + Sync> Executor for E
54where
55    E::Target: Executor + Sync,
56{
57    fn block_on(&self, f: Pin<Box<dyn Future<Output = ()>>>) {
58        self.deref().block_on(f)
59    }
60
61    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Box<dyn Task> {
62        self.deref().spawn(f)
63    }
64
65    fn spawn_local(
66        &self,
67        f: Pin<Box<dyn Future<Output = ()>>>,
68    ) -> Result<Box<dyn Task>, LocalExecutorError> {
69        self.deref().spawn_local(f)
70    }
71}
72
73#[async_trait]
74impl<E: Deref + Sync> BlockingExecutor for E
75where
76    E::Target: BlockingExecutor + Sync,
77{
78    async fn spawn_blocking(&self, f: Box<dyn FnOnce() + Send + 'static>) {
79        self.deref().spawn_blocking(f).await
80    }
81}
82
83/// A common interface to wait for a Task completion, let it run n the background or cancel it.
84#[async_trait(?Send)]
85pub trait Task: Future<Output = ()> {
86    /// Cancels the task and waits for it to stop running.
87    ///
88    /// Returns the task's output if it was completed just before it got canceled, or None if it
89    /// didn't complete.
90    async fn cancel(self: Box<Self>) -> Option<()>;
91}