kayrx_timer/delay.rs
1use crate::driver::Registration;
2use crate::{Duration, Instant};
3
4use std::future::Future;
5use std::pin::Pin;
6use std::task::{self, Poll};
7
8macro_rules! ready {
9 ($e:expr $(,)?) => {
10 match $e {
11 std::task::Poll::Ready(t) => t,
12 std::task::Poll::Pending => return std::task::Poll::Pending,
13 }
14 };
15}
16
17/// Wait until `deadline` is reached.
18///
19/// No work is performed while awaiting on the delay to complete. The delay
20/// operates at millisecond granularity and should not be used for tasks that
21/// require high-resolution timers.
22///
23/// # Cancellation
24///
25/// Canceling a delay is done by dropping the returned future. No additional
26/// cleanup work is required.
27pub fn delay_until(deadline: Instant) -> Delay {
28 let registration = Registration::new(deadline, Duration::from_millis(0));
29 Delay { registration }
30}
31
32/// Wait until `duration` has elapsed.
33///
34/// Equivalent to `delay_until(Instant::now() + duration)`. An asynchronous
35/// analog to `std::thread::sleep`.
36///
37/// No work is performed while awaiting on the delay to complete. The delay
38/// operates at millisecond granularity and should not be used for tasks that
39/// require high-resolution timers.
40///
41/// # Cancellation
42///
43/// Canceling a delay is done by dropping the returned future. No additional
44/// cleanup work is required.
45pub fn delay_for(duration: Duration) -> Delay {
46 delay_until(Instant::now() + duration)
47}
48
49/// Future returned by [`delay_until`](delay_until) and
50/// [`delay_for`](delay_for).
51#[derive(Debug)]
52#[must_use = "futures do nothing unless you `.await` or poll them"]
53pub struct Delay {
54 /// The link between the `Delay` instance and the timer that drives it.
55 ///
56 /// This also stores the `deadline` value.
57 registration: Registration,
58}
59
60impl Delay {
61 pub(crate) fn new_timeout(deadline: Instant, duration: Duration) -> Delay {
62 let registration = Registration::new(deadline, duration);
63 Delay { registration }
64 }
65
66 /// Returns the instant at which the future will complete.
67 pub fn deadline(&self) -> Instant {
68 self.registration.deadline()
69 }
70
71 /// Returns true if the `Delay` has elapsed
72 ///
73 /// A `Delay` is elapsed when the requested duration has elapsed.
74 pub fn is_elapsed(&self) -> bool {
75 self.registration.is_elapsed()
76 }
77
78 /// Reset the `Delay` instance to a new deadline.
79 ///
80 /// Calling this function allows changing the instant at which the `Delay`
81 /// future completes without having to create new associated state.
82 ///
83 /// This function can be called both before and after the future has
84 /// completed.
85 pub fn reset(&mut self, deadline: Instant) {
86 self.registration.reset(deadline);
87 }
88}
89
90impl Future for Delay {
91 type Output = ();
92
93 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
94 // `poll_elapsed` can return an error in two cases:
95 //
96 // - AtCapacity: this is a pathlogical case where far too many
97 // delays have been scheduled.
98 // - Shutdown: No timer has been setup, which is a mis-use error.
99 //
100 // Both cases are extremely rare, and pretty accurately fit into
101 // "logic errors", so we just panic in this case. A user couldn't
102 // really do much better if we passed the error onwards.
103 match ready!(self.registration.poll_elapsed(cx)) {
104 Ok(()) => Poll::Ready(()),
105 Err(e) => panic!("timer error: {}", e),
106 }
107 }
108}