diff options
Diffstat (limited to 'third_party/rust/tokio/src/time/delay.rs')
-rw-r--r-- | third_party/rust/tokio/src/time/delay.rs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/third_party/rust/tokio/src/time/delay.rs b/third_party/rust/tokio/src/time/delay.rs new file mode 100644 index 0000000000..8088c9955c --- /dev/null +++ b/third_party/rust/tokio/src/time/delay.rs @@ -0,0 +1,99 @@ +use crate::time::driver::Registration; +use crate::time::{Duration, Instant}; + +use std::future::Future; +use std::pin::Pin; +use std::task::{self, Poll}; + +/// Waits until `deadline` is reached. +/// +/// No work is performed while awaiting on the delay to complete. The delay +/// operates at millisecond granularity and should not be used for tasks that +/// require high-resolution timers. +/// +/// # Cancellation +/// +/// Canceling a delay is done by dropping the returned future. No additional +/// cleanup work is required. +pub fn delay_until(deadline: Instant) -> Delay { + let registration = Registration::new(deadline, Duration::from_millis(0)); + Delay { registration } +} + +/// Waits until `duration` has elapsed. +/// +/// Equivalent to `delay_until(Instant::now() + duration)`. An asynchronous +/// analog to `std::thread::sleep`. +/// +/// No work is performed while awaiting on the delay to complete. The delay +/// operates at millisecond granularity and should not be used for tasks that +/// require high-resolution timers. +/// +/// # Cancellation +/// +/// Canceling a delay is done by dropping the returned future. No additional +/// cleanup work is required. +pub fn delay_for(duration: Duration) -> Delay { + delay_until(Instant::now() + duration) +} + +/// Future returned by [`delay_until`](delay_until) and +/// [`delay_for`](delay_for). +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Delay { + /// The link between the `Delay` instance and the timer that drives it. + /// + /// This also stores the `deadline` value. + registration: Registration, +} + +impl Delay { + pub(crate) fn new_timeout(deadline: Instant, duration: Duration) -> Delay { + let registration = Registration::new(deadline, duration); + Delay { registration } + } + + /// Returns the instant at which the future will complete. + pub fn deadline(&self) -> Instant { + self.registration.deadline() + } + + /// Returns `true` if the `Delay` has elapsed + /// + /// A `Delay` is elapsed when the requested duration has elapsed. + pub fn is_elapsed(&self) -> bool { + self.registration.is_elapsed() + } + + /// Resets the `Delay` instance to a new deadline. + /// + /// Calling this function allows changing the instant at which the `Delay` + /// future completes without having to create new associated state. + /// + /// This function can be called both before and after the future has + /// completed. + pub fn reset(&mut self, deadline: Instant) { + self.registration.reset(deadline); + } +} + +impl Future for Delay { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { + // `poll_elapsed` can return an error in two cases: + // + // - AtCapacity: this is a pathlogical case where far too many + // delays have been scheduled. + // - Shutdown: No timer has been setup, which is a mis-use error. + // + // Both cases are extremely rare, and pretty accurately fit into + // "logic errors", so we just panic in this case. A user couldn't + // really do much better if we passed the error onwards. + match ready!(self.registration.poll_elapsed(cx)) { + Ok(()) => Poll::Ready(()), + Err(e) => panic!("timer error: {}", e), + } + } +} |