js_utils/
sleep.rs

1//! Sleeping.
2
3use futures::{Future, FutureExt};
4use std::{
5    pin::Pin,
6    task::{Context, Poll},
7    time::Duration,
8};
9use zduny_wasm_timer::Delay;
10pub use zduny_wasm_timer::Instant;
11
12/// Waits until `duration` has elapsed.
13///
14/// An asynchronous analog to [`std::thread::sleep`].
15#[must_use]
16pub fn sleep(duration: Duration) -> Sleep {
17    sleep_until(Instant::now() + duration)
18}
19
20/// Waits until `deadline` is reached.
21#[must_use]
22pub fn sleep_until(deadline: Instant) -> Sleep {
23    Sleep {
24        deadline,
25        delay: Delay::new_at(deadline),
26    }
27}
28
29/// Future returned by [`sleep`] and [`sleep_until`].
30#[derive(Debug)]
31pub struct Sleep {
32    deadline: Instant,
33    delay: Delay,
34}
35
36impl Sleep {
37    /// Returns the instant at which the future will complete.
38    pub fn deadline(&self) -> Instant {
39        self.deadline
40    }
41
42    /// Returns `true` if `Sleep` has elapsed.
43    ///
44    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
45    pub fn is_elapsed(&self) -> bool {
46        Instant::now() > self.deadline
47    }
48
49    /// Resets the `Sleep` instance to a new deadline.
50    ///
51    /// Calling this function allows changing the instant at which the `Sleep`
52    /// future completes without having to create new associated state.
53    ///
54    /// This function can be called both before and after the future has
55    /// completed.
56    pub fn reset(&mut self, deadline: Instant) {
57        self.delay.reset_at(deadline);
58    }
59}
60
61impl Future for Sleep {
62    type Output = ();
63
64    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
65        match self.delay.poll_unpin(cx) {
66            Poll::Ready(_) => Poll::Ready(()),
67            Poll::Pending => Poll::Pending,
68        }
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use std::time::Duration;
75    use wasm_bindgen_test::wasm_bindgen_test;
76
77    use crate::{sleep, sleep::Instant};
78
79    #[wasm_bindgen_test]
80    async fn test_sleep() {
81        let current = Instant::now();
82        sleep(Duration::from_secs(1)).await;
83        let difference = Instant::now() - current;
84        assert!(difference.as_secs_f64() >= 1.0)
85    }
86}