#[cfg(not(target_arch = "wasm32"))]
pub use tokio::task::{spawn, spawn_blocking, yield_now, JoinError, JoinHandle};
#[cfg(not(target_arch = "wasm32"))]
pub mod time {
pub use tokio::time::*;
}
#[cfg(target_arch = "wasm32")]
pub use wasm::*;
pub fn can_spawn() -> bool {
#[cfg(not(target_arch = "wasm32"))]
{
tokio::runtime::Handle::try_current().is_ok()
}
#[cfg(target_arch = "wasm32")]
{
true
}
}
#[cfg(target_arch = "wasm32")]
mod wasm {
use futures_util::future::{AbortHandle, Abortable};
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::task::{Context, Poll};
pub mod time {
pub use std::time::Duration;
pub use wasmtimer::std::Instant;
pub use wasmtimer::tokio::{
interval, interval_at, sleep, sleep_until, Interval, MissedTickBehavior, Sleep, Timeout,
};
pub fn timeout<F: std::future::IntoFuture>(d: Duration, f: F) -> Timeout<F::IntoFuture> {
wasmtimer::tokio::timeout(d, f.into_future())
}
pub fn timeout_at<F: std::future::IntoFuture>(at: Instant, f: F) -> Timeout<F::IntoFuture> {
wasmtimer::tokio::timeout_at(at, f.into_future())
}
pub mod error {
pub use wasmtimer::tokio::error::Elapsed;
}
}
#[derive(Debug)]
pub struct JoinError;
impl JoinError {
pub fn is_cancelled(&self) -> bool { true }
pub fn is_panic(&self) -> bool { false }
}
impl std::fmt::Display for JoinError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("task was cancelled")
}
}
impl std::error::Error for JoinError {}
pub struct JoinHandle<T> {
rx: tokio::sync::oneshot::Receiver<T>,
abort: AbortHandle,
done: Arc<AtomicBool>,
}
impl<T> JoinHandle<T> {
pub fn abort(&self) { self.abort.abort(); }
pub fn is_finished(&self) -> bool { self.done.load(Ordering::Relaxed) || self.abort.is_aborted() }
}
impl<T> Future for JoinHandle<T> {
type Output = Result<T, JoinError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.rx).poll(cx).map(|r| r.map_err(|_| JoinError))
}
}
pub fn spawn<F>(fut: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
let (tx, rx) = tokio::sync::oneshot::channel();
let (abort, reg) = AbortHandle::new_pair();
let done = Arc::new(AtomicBool::new(false));
let flag = done.clone();
wasm_bindgen_futures::spawn_local(async move {
if let Ok(v) = Abortable::new(fut, reg).await {
let _ = tx.send(v);
}
flag.store(true, Ordering::Relaxed);
});
JoinHandle { rx, abort, done }
}
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
where
F: FnOnce() -> R + 'static,
R: 'static,
{
spawn(async move { f() })
}
pub async fn yield_now() {
struct YieldNow(bool);
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
return Poll::Ready(());
}
self.0 = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
YieldNow(false).await
}
}
#[cfg(not(target_arch = "wasm32"))]
pub trait MaybeSend: Send {}
#[cfg(not(target_arch = "wasm32"))]
impl<T: Send + ?Sized> MaybeSend for T {}
#[cfg(target_arch = "wasm32")]
pub trait MaybeSend {}
#[cfg(target_arch = "wasm32")]
impl<T: ?Sized> MaybeSend for T {}
pub use web_time as time_std;