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}