1#[cfg(not(target_arch = "wasm32"))]
8pub use tokio::task::{spawn, spawn_blocking, yield_now, JoinError, JoinHandle};
9
10#[cfg(not(target_arch = "wasm32"))]
11pub mod time {
12 pub use tokio::time::*;
13}
14
15#[cfg(target_arch = "wasm32")]
16pub use wasm::*;
17
18pub fn can_spawn() -> bool {
22 #[cfg(not(target_arch = "wasm32"))]
23 {
24 tokio::runtime::Handle::try_current().is_ok()
25 }
26 #[cfg(target_arch = "wasm32")]
27 {
28 true
29 }
30}
31
32#[cfg(target_arch = "wasm32")]
33mod wasm {
34 use futures_util::future::{AbortHandle, Abortable};
35 use std::future::Future;
36 use std::pin::Pin;
37 use std::sync::atomic::{AtomicBool, Ordering};
38 use std::sync::Arc;
39 use std::task::{Context, Poll};
40
41 pub mod time {
42 pub use std::time::Duration;
43 pub use wasmtimer::std::Instant;
44 pub use wasmtimer::tokio::{
45 interval, interval_at, sleep, sleep_until, Interval, MissedTickBehavior, Sleep, Timeout,
46 };
47
48 pub fn timeout<F: std::future::IntoFuture>(d: Duration, f: F) -> Timeout<F::IntoFuture> {
50 wasmtimer::tokio::timeout(d, f.into_future())
51 }
52
53 pub fn timeout_at<F: std::future::IntoFuture>(at: Instant, f: F) -> Timeout<F::IntoFuture> {
54 wasmtimer::tokio::timeout_at(at, f.into_future())
55 }
56 pub mod error {
57 pub use wasmtimer::tokio::error::Elapsed;
58 }
59 }
60
61 #[derive(Debug)]
62 pub struct JoinError;
63
64 impl JoinError {
65 pub fn is_cancelled(&self) -> bool { true }
66 pub fn is_panic(&self) -> bool { false }
67 }
68
69 impl std::fmt::Display for JoinError {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 f.write_str("task was cancelled")
72 }
73 }
74
75 impl std::error::Error for JoinError {}
76
77 pub struct JoinHandle<T> {
78 rx: tokio::sync::oneshot::Receiver<T>,
79 abort: AbortHandle,
80 done: Arc<AtomicBool>,
81 }
82
83 impl<T> JoinHandle<T> {
84 pub fn abort(&self) { self.abort.abort(); }
85 pub fn is_finished(&self) -> bool { self.done.load(Ordering::Relaxed) || self.abort.is_aborted() }
86 }
87
88 impl<T> Future for JoinHandle<T> {
89 type Output = Result<T, JoinError>;
90 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
91 Pin::new(&mut self.rx).poll(cx).map(|r| r.map_err(|_| JoinError))
92 }
93 }
94
95 pub fn spawn<F>(fut: F) -> JoinHandle<F::Output>
96 where
97 F: Future + 'static,
98 F::Output: 'static,
99 {
100 let (tx, rx) = tokio::sync::oneshot::channel();
101 let (abort, reg) = AbortHandle::new_pair();
102 let done = Arc::new(AtomicBool::new(false));
103 let flag = done.clone();
104 wasm_bindgen_futures::spawn_local(async move {
105 if let Ok(v) = Abortable::new(fut, reg).await {
106 let _ = tx.send(v);
107 }
108 flag.store(true, Ordering::Relaxed);
109 });
110 JoinHandle { rx, abort, done }
111 }
112
113 pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
115 where
116 F: FnOnce() -> R + 'static,
117 R: 'static,
118 {
119 spawn(async move { f() })
120 }
121
122 pub async fn yield_now() {
123 struct YieldNow(bool);
124 impl Future for YieldNow {
125 type Output = ();
126 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
127 if self.0 {
128 return Poll::Ready(());
129 }
130 self.0 = true;
131 cx.waker().wake_by_ref();
132 Poll::Pending
133 }
134 }
135 YieldNow(false).await
136 }
137}
138
139#[cfg(not(target_arch = "wasm32"))]
142pub trait MaybeSend: Send {}
143#[cfg(not(target_arch = "wasm32"))]
144impl<T: Send + ?Sized> MaybeSend for T {}
145
146#[cfg(target_arch = "wasm32")]
147pub trait MaybeSend {}
148#[cfg(target_arch = "wasm32")]
149impl<T: ?Sized> MaybeSend for T {}
150
151pub use web_time as time_std;