use std::fmt::{self, Debug};
use thread_aware::ThreadAware;
use crate::custom::{CustomSpawner, SpawnCustom};
use crate::handle::{JoinHandle, JoinHandleInner};
#[derive(Clone, ThreadAware)]
#[must_use]
pub struct Spawner(SpawnerKind);
#[derive(Clone, ThreadAware)]
enum SpawnerKind {
#[cfg(feature = "tokio")]
Tokio(#[thread_aware(skip)] Option<::tokio::runtime::Handle>),
Custom(CustomSpawner),
}
impl Spawner {
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub fn new_tokio() -> Self {
Self(SpawnerKind::Tokio(None))
}
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub fn new_tokio_with_handle(handle: ::tokio::runtime::Handle) -> Self {
Self(SpawnerKind::Tokio(Some(handle)))
}
pub fn new_custom<T>(name: &'static str, custom: T) -> Self
where
T: SpawnCustom + Clone,
{
Self(SpawnerKind::Custom(CustomSpawner::new(name, custom)))
}
pub fn spawn<T: Send + 'static>(&self, work: impl Future<Output = T> + Send + 'static) -> JoinHandle<T> {
match &self.0 {
#[cfg(feature = "tokio")]
SpawnerKind::Tokio(handle) => {
let jh = match handle {
Some(h) => h.spawn(work),
None => ::tokio::spawn(work),
};
JoinHandle(JoinHandleInner::Tokio(jh))
}
SpawnerKind::Custom(c) => JoinHandle(JoinHandleInner::Custom(c.spawn(work))),
}
}
pub fn spawn_anywhere<T, D, F>(&self, data: D, f: fn(D) -> F) -> JoinHandle<T>
where
T: Send + 'static,
D: ThreadAware + 'static,
F: Future<Output = T> + Send + 'static,
{
match &self.0 {
#[cfg(feature = "tokio")]
SpawnerKind::Tokio(handle) => {
let jh = match handle {
Some(h) => h.spawn(f(data)),
None => ::tokio::spawn(f(data)),
};
JoinHandle(JoinHandleInner::Tokio(jh))
}
SpawnerKind::Custom(c) => JoinHandle(JoinHandleInner::Custom(c.spawn_anywhere(data, f))),
}
}
}
impl Debug for Spawner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
#[cfg(feature = "tokio")]
SpawnerKind::Tokio(None) => f.debug_tuple("Spawner").field(&"tokio").finish(),
#[cfg(feature = "tokio")]
SpawnerKind::Tokio(Some(_)) => f.debug_tuple("Spawner").field(&"tokio(handle)").finish(),
SpawnerKind::Custom(c) => f.debug_tuple("Spawner").field(c).finish(),
}
}
}