use std::pin::Pin;
use std::task::{Context, Poll, Waker};
use std::time::Duration;
use super::Clock;
use super::timers::TimerKey;
#[derive(Debug)]
pub struct Delay {
current_timer: Option<TimerKey>,
clock: Clock,
duration: Duration,
}
impl Delay {
#[must_use]
pub fn new(clock: &Clock, duration: Duration) -> Self {
Self {
duration,
current_timer: None,
clock: clock.clone(),
}
}
fn register_timer(&mut self, waker: &Waker) -> Poll<()> {
let when = self.clock.instant().checked_add(self.duration);
if let Some(when) = when {
self.current_timer = Some(self.clock.register_timer(when, waker.clone()));
} else {
self.duration = Duration::MAX;
self.current_timer = None;
}
Poll::Pending
}
}
impl Future for Delay {
type Output = ();
#[cfg_attr(test, mutants::skip)] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
match this.current_timer {
None if this.duration == Duration::MAX => Poll::Pending,
None if this.duration == Duration::ZERO => Poll::Ready(()),
None => this.register_timer(cx.waker()),
Some(key) if key.tick() <= this.clock.instant() => {
this.current_timer = None;
this.clock.unregister_timer(key);
Poll::Ready(())
}
Some(_) => Poll::Pending,
}
}
}
impl Drop for Delay {
fn drop(&mut self) {
if let Some(key) = self.current_timer {
self.clock.unregister_timer(key);
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use std::thread;
use super::*;
use crate::ClockControl;
#[test]
fn assert_types() {
static_assertions::assert_impl_all!(Delay: Send, Sync);
}
#[cfg_attr(miri, ignore)]
#[tokio::test]
async fn delay_ok() {
let clock = Clock::new_tokio();
let now = std::time::Instant::now();
Delay::new(&clock, Duration::from_millis(5)).await;
assert!(now.elapsed() >= Duration::from_millis(5));
}
#[test]
fn delay_with_control() {
let control = ClockControl::new();
let clock = control.to_clock();
let mut delay = Delay::new(&clock, Duration::from_millis(1));
assert_eq!(poll_delay(&mut delay), Poll::Pending);
thread::sleep(Duration::from_millis(1));
assert_eq!(poll_delay(&mut delay), Poll::Pending);
let len = control.timers_len();
control.advance(Duration::from_millis(2));
assert_eq!(control.timers_len(), len - 1);
assert_eq!(poll_delay(&mut delay), Poll::Ready(()));
}
#[test]
fn delay_zero() {
let clock = Clock::new_system_frozen();
let mut delay = Delay::new(&clock, Duration::ZERO);
assert_eq!(poll_delay(&mut delay), Poll::Ready(()));
}
#[test]
fn delay_max() {
let clock = Clock::new_system_frozen();
let result = poll_delay(&mut Delay::new(&clock, Duration::MAX));
assert_eq!(result, Poll::Pending);
}
#[test]
fn delay_zero_ensure_timer_not_registered() {
let clock = Clock::new_system_frozen();
assert!(Delay::new(&clock, Duration::ZERO).current_timer.is_none());
}
#[test]
fn delay_max_ensure_timer_not_registered() {
let clock = Clock::new_system_frozen();
assert!(Delay::new(&clock, Duration::MAX).current_timer.is_none());
}
#[test]
fn delay_close_to_max_ensure_timer_not_registered() {
let clock = Clock::new_system_frozen();
let mut delay = Delay::new(&clock, Duration::MAX.saturating_sub(Duration::from_millis(1)));
assert_eq!(poll_delay(&mut delay), Poll::Pending);
assert_eq!(delay.duration, Duration::MAX);
assert!(delay.current_timer.is_none());
}
#[test]
fn ready_without_advancing_timers_ensure_timer_unregistered() {
let clock = Clock::new_system_frozen();
let period = Duration::from_millis(1);
let mut delay = Delay::new(&clock, period);
assert_eq!(poll_delay(&mut delay), Poll::Pending);
assert_eq!(clock.clock_state().timers_len(), 1);
thread::sleep(period);
assert_eq!(poll_delay(&mut delay), Poll::Ready(()));
assert_eq!(delay.current_timer, None);
assert_eq!(clock.clock_state().timers_len(), 0);
}
#[test]
fn drop_delay_unregisters_timer() {
let clock = Clock::new_system_frozen();
let period = Duration::from_millis(1);
{
let mut delay = Delay::new(&clock, period);
assert_eq!(poll_delay(&mut delay), Poll::Pending);
assert_eq!(clock.clock_state().timers_len(), 1);
}
assert_eq!(clock.clock_state().timers_len(), 0);
}
fn poll_delay(delay: &mut Delay) -> Poll<()> {
let mut cx = Context::from_waker(Waker::noop());
let delay = std::pin::pin!(delay);
delay.poll(&mut cx)
}
}