use std::future::Future;
use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
pub fn spawn<F>(future: F) -> SpawnHandle
where
F: Future<Output = ()> + Send + 'static,
{
SpawnHandle {
handle: tokio::spawn(future),
}
}
#[cfg(target_arch = "wasm32")]
pub fn spawn<F>(future: F) -> SpawnHandle
where
F: Future<Output = ()> + 'static,
{
let (abort_tx, abort_rx) = tokio::sync::oneshot::channel::<()>();
wasm_bindgen_futures::spawn_local(async move {
futures_util::pin_mut!(future);
futures_util::future::select(future, abort_rx).await;
});
SpawnHandle { abort_tx: Some(abort_tx) }
}
#[cfg(not(target_arch = "wasm32"))]
pub struct SpawnHandle {
handle: tokio::task::JoinHandle<()>,
}
#[cfg(not(target_arch = "wasm32"))]
impl SpawnHandle {
pub fn abort(&self) {
self.handle.abort();
}
}
#[cfg(target_arch = "wasm32")]
pub struct SpawnHandle {
abort_tx: Option<tokio::sync::oneshot::Sender<()>>,
}
#[cfg(target_arch = "wasm32")]
impl SpawnHandle {
pub fn abort(&mut self) {
if let Some(tx) = self.abort_tx.take() {
let _ = tx.send(());
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub async fn sleep(duration: Duration) {
tokio::time::sleep(duration).await;
}
#[cfg(target_arch = "wasm32")]
pub async fn sleep(duration: Duration) {
gloo_timers::future::sleep(duration).await;
}
#[derive(Debug, Clone)]
pub struct TimeoutError;
impl std::fmt::Display for TimeoutError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "operation timed out")
}
}
impl std::error::Error for TimeoutError {}
#[cfg(not(target_arch = "wasm32"))]
pub async fn timeout<F, T>(duration: Duration, future: F) -> Result<T, TimeoutError>
where
F: Future<Output = T>,
{
tokio::time::timeout(duration, future)
.await
.map_err(|_| TimeoutError)
}
#[cfg(target_arch = "wasm32")]
pub async fn timeout<F, T>(duration: Duration, future: F) -> Result<T, TimeoutError>
where
F: Future<Output = T>,
{
use futures_util::future::{select, Either};
futures_util::pin_mut!(future);
let sleep = gloo_timers::future::sleep(duration);
futures_util::pin_mut!(sleep);
match select(future, sleep).await {
Either::Left((output, _)) => Ok(output),
Either::Right((_, _)) => Err(TimeoutError),
}
}