193 lines
5.7 KiB
Rust
193 lines
5.7 KiB
Rust
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<Sp: ?Sized + Spawn> 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<Sp: ?Sized + Spawn> 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<Sp: ?Sized + LocalSpawn> 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<Sp: ?Sized + LocalSpawn> 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<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
|
|
fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
|
|
(**self).spawn_obj(future)
|
|
}
|
|
|
|
fn status(&self) -> Result<(), SpawnError> {
|
|
(**self).status()
|
|
}
|
|
}
|
|
|
|
impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
|
|
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<Sp: ?Sized + Spawn> Spawn for Rc<Sp> {
|
|
fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
|
|
(**self).spawn_obj(future)
|
|
}
|
|
|
|
fn status(&self) -> Result<(), SpawnError> {
|
|
(**self).status()
|
|
}
|
|
}
|
|
|
|
impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Rc<Sp> {
|
|
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<Sp: ?Sized + Spawn> Spawn for alloc::sync::Arc<Sp> {
|
|
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<Sp: ?Sized + LocalSpawn> LocalSpawn for alloc::sync::Arc<Sp> {
|
|
fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
|
|
(**self).spawn_local_obj(future)
|
|
}
|
|
|
|
fn status_local(&self) -> Result<(), SpawnError> {
|
|
(**self).status_local()
|
|
}
|
|
}
|
|
}
|