agnostic_lite/async_io/
sleep.rs

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