1cfg_time!(
2 mod after;
3 mod delay;
4 mod interval;
5 mod sleep;
6 mod timeout;
7
8 pub use after::*;
9 pub use delay::*;
10 pub use interval::*;
11 pub use sleep::*;
12 pub use timeout::*;
13
14 use std::time::{Duration, Instant};
15);
16
17use core::{
18 future::Future,
19 pin::Pin,
20 task::{Context, Poll},
21};
22
23use wasm::channel::*;
24
25use super::handle::JoinError;
26use crate::{AsyncBlockingSpawner, AsyncLocalSpawner, AsyncSpawner, Yielder};
27
28pub struct JoinHandle<F> {
30 pub(crate) stop_tx: oneshot::Sender<bool>,
31 pub(crate) rx: oneshot::Receiver<F>,
32}
33
34impl<F> Future for JoinHandle<F> {
35 type Output = Result<F, JoinError>;
36
37 fn poll(
38 mut self: core::pin::Pin<&mut Self>,
39 cx: &mut core::task::Context<'_>,
40 ) -> core::task::Poll<Self::Output> {
41 core::pin::Pin::new(&mut self.rx)
42 .poll(cx)
43 .map(|res| res.map_err(|_| JoinError::new()))
44 }
45}
46
47impl<F> JoinHandle<F> {
48 #[inline]
50 pub fn detach(self) {
51 let _ = self.stop_tx.send(false);
52 }
53
54 #[inline]
56 pub fn cancel(self) {
57 let _ = self.stop_tx.send(true);
58 }
59}
60
61impl<O> super::JoinHandle<O> for JoinHandle<O> {
62 type JoinError = JoinError;
63
64 fn detach(self) {
65 Self::detach(self)
66 }
67
68 fn abort(self) {
69 self.cancel();
70 }
71}
72
73impl<O> super::LocalJoinHandle<O> for JoinHandle<O> {
74 type JoinError = JoinError;
75
76 fn detach(self) {
77 Self::detach(self)
78 }
79}
80
81#[derive(Debug, Clone, Copy)]
85pub struct WasmSpawner;
86
87impl AsyncSpawner for WasmSpawner {
88 type JoinHandle<F>
89 = JoinHandle<F>
90 where
91 F: Send + 'static;
92
93 fn spawn<F>(future: F) -> Self::JoinHandle<F::Output>
94 where
95 F::Output: Send + 'static,
96 F: core::future::Future + Send + 'static,
97 {
98 <Self as super::AsyncLocalSpawner>::spawn_local(future)
99 }
100}
101
102impl AsyncLocalSpawner for WasmSpawner {
103 type JoinHandle<F>
104 = JoinHandle<F>
105 where
106 F: 'static;
107
108 fn spawn_local<F>(future: F) -> Self::JoinHandle<F::Output>
109 where
110 F::Output: 'static,
111 F: core::future::Future + 'static,
112 {
113 use futures_util::FutureExt;
114
115 let (tx, rx) = oneshot::channel();
116 let (stop_tx, stop_rx) = oneshot::channel();
117 wasm::spawn_local(async {
118 futures_util::pin_mut!(future);
119
120 futures_util::select! {
121 sig = stop_rx.fuse() => {
122 match sig {
123 Ok(true) => {
124 },
126 Ok(false) | Err(_) => {
127 let _ = future.await;
128 },
129 }
130 },
131 future = (&mut future).fuse() => {
132 let _ = tx.send(future);
133 }
134 }
135 });
136 JoinHandle { stop_tx, rx }
137 }
138}
139
140impl AsyncBlockingSpawner for WasmSpawner {
141 type JoinHandle<R>
142 = JoinHandle<R>
143 where
144 R: Send + 'static;
145
146 fn spawn_blocking<F, R>(_: F) -> Self::JoinHandle<R>
147 where
148 F: FnOnce() -> R + Send + 'static,
149 R: Send + 'static,
150 {
151 panic!("wasm-bindgen-futures does not support blocking tasks")
152 }
153}
154
155impl Yielder for WasmSpawner {
156 async fn yield_now() {
157 YieldNow(false).await
158 }
159
160 async fn yield_now_local() {
161 YieldNow(false).await
162 }
163}
164
165#[derive(Debug)]
167#[must_use = "futures do nothing unless you `.await` or poll them"]
168struct YieldNow(bool);
169
170impl Future for YieldNow {
171 type Output = ();
172
173 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
174 if !self.0 {
175 self.0 = true;
176 cx.waker().wake_by_ref();
177 Poll::Pending
178 } else {
179 Poll::Ready(())
180 }
181 }
182}
183
184#[derive(Debug, Clone, Copy)]
188pub struct WasmRuntime;
189
190impl core::fmt::Display for WasmRuntime {
191 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192 write!(f, "wasm-bindgen-futures")
193 }
194}
195
196impl super::LocalRuntimeLite for WasmRuntime {
197 type LocalSpawner = WasmSpawner;
198 type BlockingSpawner = WasmSpawner;
199
200 cfg_time!(
201 type Instant = Instant;
202
203 type LocalInterval = WasmInterval;
204
205 type LocalSleep = WasmSleep;
206
207 type LocalDelay<F>
208 = WasmDelay<F>
209 where
210 F: Future;
211
212 type LocalTimeout<F>
213 = WasmTimeout<F>
214 where
215 F: Future;
216 );
217
218 fn new() -> Self {
219 Self
220 }
221
222 fn name() -> &'static str {
223 "wasm-bindgen-futures"
224 }
225
226 fn fqname() -> &'static str {
227 "wasm-bindgen-futures"
228 }
229
230 fn block_on<F: Future>(_f: F) -> F::Output {
231 panic!("LocalRuntimeLite::block_on is not supported on wasm")
232 }
233
234 cfg_time!(
235 fn interval_local(interval: Duration) -> Self::LocalInterval {
236 use crate::time::AsyncIntervalExt;
237
238 WasmInterval::interval(interval)
239 }
240
241 fn interval_local_at(start: Instant, period: Duration) -> Self::LocalInterval {
242 use crate::time::AsyncIntervalExt;
243
244 WasmInterval::interval_at(start, period)
245 }
246
247 fn sleep_local(duration: Duration) -> Self::LocalSleep {
248 use crate::time::AsyncSleepExt;
249
250 WasmSleep::sleep(duration)
251 }
252
253 fn sleep_local_until(instant: Instant) -> Self::LocalSleep {
254 use crate::time::AsyncSleepExt;
255
256 WasmSleep::sleep_until(instant)
257 }
258
259 fn delay_local<F>(duration: Duration, fut: F) -> Self::LocalDelay<F>
260 where
261 F: Future,
262 {
263 use crate::time::AsyncLocalDelayExt;
264
265 <WasmDelay<F> as AsyncLocalDelayExt<F>>::delay(duration, fut)
266 }
267
268 fn delay_local_at<F>(deadline: Instant, fut: F) -> Self::LocalDelay<F>
269 where
270 F: Future,
271 {
272 use crate::time::AsyncLocalDelayExt;
273
274 <WasmDelay<F> as AsyncLocalDelayExt<F>>::delay_at(deadline, fut)
275 }
276
277 fn timeout_local<F>(duration: Duration, future: F) -> Self::LocalTimeout<F>
278 where
279 F: Future,
280 {
281 use crate::time::AsyncLocalTimeout;
282
283 <WasmTimeout<F> as AsyncLocalTimeout<F>>::timeout_local(duration, future)
284 }
285
286 fn timeout_local_at<F>(deadline: Instant, future: F) -> Self::LocalTimeout<F>
287 where
288 F: Future,
289 {
290 use crate::time::AsyncLocalTimeout;
291
292 <WasmTimeout<F> as AsyncLocalTimeout<F>>::timeout_local_at(deadline, future)
293 }
294 );
295}
296
297impl super::RuntimeLite for WasmRuntime {
298 type Spawner = WasmSpawner;
299
300 cfg_time!(
301 type AfterSpawner = WasmSpawner;
302
303 type Interval = WasmInterval;
304
305 type Sleep = WasmSleep;
306
307 type Delay<F>
308 = WasmDelay<F>
309 where
310 F: Future + Send;
311
312 type Timeout<F>
313 = WasmTimeout<F>
314 where
315 F: Future + Send;
316 );
317
318 async fn yield_now() {
319 YieldNow(false).await
320 }
321
322 cfg_time!(
323 fn interval(interval: Duration) -> Self::Interval {
324 use crate::time::AsyncIntervalExt;
325
326 WasmInterval::interval(interval)
327 }
328
329 fn interval_at(start: Instant, period: Duration) -> Self::Interval {
330 use crate::time::AsyncIntervalExt;
331
332 WasmInterval::interval_at(start, period)
333 }
334
335 fn sleep(duration: Duration) -> Self::Sleep {
336 use crate::time::AsyncSleepExt;
337
338 WasmSleep::sleep(duration)
339 }
340
341 fn sleep_until(instant: Instant) -> Self::Sleep {
342 use crate::time::AsyncSleepExt;
343
344 WasmSleep::sleep_until(instant)
345 }
346
347 fn delay<F>(duration: Duration, fut: F) -> Self::Delay<F>
348 where
349 F: Future + Send,
350 {
351 use crate::time::AsyncDelayExt;
352
353 <WasmDelay<F> as AsyncDelayExt<F>>::delay(duration, fut)
354 }
355
356 fn delay_at<F>(deadline: Instant, fut: F) -> Self::Delay<F>
357 where
358 F: Future + Send,
359 {
360 use crate::time::AsyncDelayExt;
361
362 <WasmDelay<F> as AsyncDelayExt<F>>::delay_at(deadline, fut)
363 }
364
365 fn timeout<F>(duration: Duration, future: F) -> Self::Timeout<F>
366 where
367 F: Future + Send,
368 {
369 use crate::time::AsyncTimeout;
370
371 <WasmTimeout<F> as AsyncTimeout<F>>::timeout(duration, future)
372 }
373
374 fn timeout_at<F>(deadline: Instant, future: F) -> Self::Timeout<F>
375 where
376 F: Future + Send,
377 {
378 use crate::time::AsyncTimeout;
379
380 <WasmTimeout<F> as AsyncTimeout<F>>::timeout_at(deadline, future)
381 }
382 );
383}