agnostic_lite/wasm/
sleep.rs1use core::{
2 future::Future,
3 pin::Pin,
4 task::{Context, Poll},
5 time::Duration,
6};
7use std::time::Instant;
8use wasm::Delay;
9
10use crate::time::{AsyncLocalSleep, AsyncLocalSleepExt};
11
12pin_project_lite::pin_project! {
13 #[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "wasm"))))]
15 pub struct WasmSleep {
16 #[pin]
17 pub(crate) sleep: Delay,
18 pub(crate) ddl: Instant,
19 pub(crate) duration: Duration,
20 }
21}
22
23impl Future for WasmSleep {
24 type Output = Instant;
25
26 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
27 let ddl = self.ddl;
28 self.project().sleep.poll(cx).map(|_| ddl)
29 }
30}
31
32impl AsyncLocalSleep for WasmSleep {
33 type Instant = Instant;
34
35 fn reset(self: Pin<&mut Self>, deadline: Instant) {
36 let mut this = self.project();
37 let ddl = deadline - Instant::now();
38 this.sleep.reset(ddl);
39 *this.ddl = deadline;
40 }
41}
42
43impl AsyncLocalSleepExt for WasmSleep {
44 fn sleep_local(after: Duration) -> Self
45 where
46 Self: Sized,
47 {
48 Self {
49 ddl: Instant::now() + after,
50 sleep: Delay::new(after),
51 duration: after,
52 }
53 }
54
55 fn sleep_local_until(deadline: Instant) -> Self
56 where
57 Self: Sized,
58 {
59 let duration = deadline - Instant::now();
60 Self {
61 sleep: Delay::new(duration),
62 ddl: deadline,
63 duration,
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::WasmSleep;
71 use crate::time::{AsyncSleep, AsyncSleepExt};
72 use core::pin::Pin;
73 use std::time::{Duration, Instant};
74
75 const ORIGINAL: Duration = Duration::from_secs(1);
76 const RESET: Duration = Duration::from_secs(2);
77 const BOUND: Duration = Duration::from_millis(10);
78
79 #[test]
80 fn test_wasm_sleep() {
81 futures::executor::block_on(async {
82 let start = Instant::now();
83 let sleep = WasmSleep::sleep(ORIGINAL);
84 let ins = sleep.await;
85 assert!(ins >= start + ORIGINAL);
86 let elapsed = start.elapsed();
87 assert!(elapsed >= ORIGINAL && elapsed < ORIGINAL + BOUND);
88 });
89 }
90
91 #[test]
92 fn test_wasm_sleep_until() {
93 futures::executor::block_on(async {
94 let start = Instant::now();
95 let sleep = WasmSleep::sleep_until(start + ORIGINAL);
96 let ins = sleep.await;
97 assert!(ins >= start + ORIGINAL);
98 let elapsed = start.elapsed();
99 assert!(elapsed >= ORIGINAL && elapsed < ORIGINAL + BOUND);
100 });
101 }
102
103 #[test]
104 fn test_wasm_sleep_reset() {
105 futures::executor::block_on(async {
106 let start = Instant::now();
107 let mut sleep = WasmSleep::sleep(ORIGINAL);
108 let pin = Pin::new(&mut sleep);
109 pin.reset(Instant::now() + RESET);
110 let ins = sleep.await;
111 assert!(ins >= start + RESET);
112 let elapsed = start.elapsed();
113 assert!(elapsed >= RESET && elapsed < RESET + BOUND);
114 });
115 }
116
117 #[test]
118 fn test_wasm_sleep_reset2() {
119 futures::executor::block_on(async {
120 let start = Instant::now();
121 let mut sleep = WasmSleep::sleep_until(start + ORIGINAL);
122 let pin = Pin::new(&mut sleep);
123 pin.reset(Instant::now() + RESET);
124 let ins = sleep.await;
125 assert!(ins >= start + RESET);
126 let elapsed = start.elapsed();
127 assert!(elapsed >= RESET && elapsed < RESET + BOUND);
128 });
129 }
130}