use futures::future::BoxFuture;
#[cfg(not(feature = "wasm"))]
use futures::task::FutureObj;
#[cfg(feature = "wasm")]
use futures::task::LocalFutureObj;
use std::{future::Future, sync::OnceLock, time::Duration};
use tracing::Span;
#[cfg(feature = "wasm")]
mod wasm;
#[cfg(feature = "tokio-runtime")]
mod tokio;
static GLOBAL_ASYNC_MANAGER: OnceLock<Box<dyn AsyncManager>> = OnceLock::new();
pub fn set_global_async_manager(manager: Box<dyn AsyncManager>) {
GLOBAL_ASYNC_MANAGER
.set(manager)
.expect("Global async manager can only be set once.");
}
fn get_default_async_manager() -> Box<dyn AsyncManager> {
cfg_if::cfg_if! {
if #[cfg(feature = "wasm")] {
return Box::new(wasm::WasmBindgenAsyncManager::default());
} else if #[cfg(feature = "tokio-runtime")] {
return Box::new(tokio::TokioAsyncManager::default());
} else {
unimplemented!(
"No async runtime configured. Enable the `tokio-runtime` or `wasm` feature, \
or call `set_global_async_manager` before performing async operations."
);
}
}
}
fn get_global_async_manager() -> &'static dyn AsyncManager {
GLOBAL_ASYNC_MANAGER
.get_or_init(|| get_default_async_manager())
.as_ref()
}
pub trait AsyncManager: std::fmt::Debug + Send + Sync {
#[cfg(not(feature = "wasm"))]
fn spawn(&self, future: FutureObj<'static, ()>, span: Span);
#[cfg(feature = "wasm")]
fn spawn(&self, future: LocalFutureObj<'static, ()>, span: Span);
fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()>;
}
#[cfg(not(feature = "wasm"))]
pub fn spawn<F>(future: F, span: Span)
where
F: Future<Output = ()> + Send + 'static,
{
get_global_async_manager().spawn(FutureObj::new(Box::new(future)), span);
}
#[cfg(feature = "wasm")]
pub fn spawn<F>(future: F, span: Span)
where
F: Future<Output = ()> + 'static,
{
get_global_async_manager().spawn(LocalFutureObj::new(Box::new(future)), span);
}
pub async fn sleep(duration: Duration) {
get_global_async_manager().sleep(duration).await;
}
#[macro_export]
macro_rules! spawn {
($future:expr) => {
$crate::util::async_manager::spawn(
$future,
tracing::span!(tracing::Level::INFO, "Buttplug Async Task"),
)
};
($name:expr, $future:expr) => {
$crate::util::async_manager::spawn($future, tracing::span!(tracing::Level::INFO, $name))
};
}