use crate::{FutureObj, LocalFutureObj}; use core::fmt; /// The `Spawn` trait allows for pushing futures onto an executor that will /// run them to completion. pub trait Spawn { /// Spawns a future that will be run to completion. /// /// # Errors /// /// The executor may be unable to spawn tasks. Spawn errors should /// represent relatively rare scenarios, such as the executor /// having been shut down so that it is no longer able to accept /// tasks. fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>; /// Determines whether the executor is able to spawn new tasks. /// /// This method will return `Ok` when the executor is *likely* /// (but not guaranteed) to accept a subsequent spawn attempt. /// Likewise, an `Err` return means that `spawn` is likely, but /// not guaranteed, to yield an error. #[inline] fn status(&self) -> Result<(), SpawnError> { Ok(()) } } /// The `LocalSpawn` is similar to [`Spawn`], but allows spawning futures /// that don't implement `Send`. pub trait LocalSpawn { /// Spawns a future that will be run to completion. /// /// # Errors /// /// The executor may be unable to spawn tasks. Spawn errors should /// represent relatively rare scenarios, such as the executor /// having been shut down so that it is no longer able to accept /// tasks. fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>; /// Determines whether the executor is able to spawn new tasks. /// /// This method will return `Ok` when the executor is *likely* /// (but not guaranteed) to accept a subsequent spawn attempt. /// Likewise, an `Err` return means that `spawn` is likely, but /// not guaranteed, to yield an error. #[inline] fn status_local(&self) -> Result<(), SpawnError> { Ok(()) } } /// An error that occurred during spawning. pub struct SpawnError { _priv: (), } impl fmt::Debug for SpawnError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("SpawnError").field(&"shutdown").finish() } } impl fmt::Display for SpawnError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Executor is shutdown") } } #[cfg(feature = "std")] impl std::error::Error for SpawnError {} impl SpawnError { /// Spawning failed because the executor has been shut down. pub fn shutdown() -> Self { Self { _priv: () } } /// Check whether spawning failed to the executor being shut down. pub fn is_shutdown(&self) -> bool { true } } impl Spawn for &Sp { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { Sp::spawn_obj(self, future) } fn status(&self) -> Result<(), SpawnError> { Sp::status(self) } } impl Spawn for &mut Sp { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { Sp::spawn_obj(self, future) } fn status(&self) -> Result<(), SpawnError> { Sp::status(self) } } impl LocalSpawn for &Sp { fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { Sp::spawn_local_obj(self, future) } fn status_local(&self) -> Result<(), SpawnError> { Sp::status_local(self) } } impl LocalSpawn for &mut Sp { fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { Sp::spawn_local_obj(self, future) } fn status_local(&self) -> Result<(), SpawnError> { Sp::status_local(self) } } #[cfg(feature = "alloc")] mod if_alloc { use super::*; use alloc::{boxed::Box, rc::Rc}; impl Spawn for Box { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_obj(future) } fn status(&self) -> Result<(), SpawnError> { (**self).status() } } impl LocalSpawn for Box { fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_local_obj(future) } fn status_local(&self) -> Result<(), SpawnError> { (**self).status_local() } } impl Spawn for Rc { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_obj(future) } fn status(&self) -> Result<(), SpawnError> { (**self).status() } } impl LocalSpawn for Rc { fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_local_obj(future) } fn status_local(&self) -> Result<(), SpawnError> { (**self).status_local() } } #[cfg(not(futures_no_atomic_cas))] impl Spawn for alloc::sync::Arc { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_obj(future) } fn status(&self) -> Result<(), SpawnError> { (**self).status() } } #[cfg(not(futures_no_atomic_cas))] impl LocalSpawn for alloc::sync::Arc { fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { (**self).spawn_local_obj(future) } fn status_local(&self) -> Result<(), SpawnError> { (**self).status_local() } } }