use std::time::Instant;
use crate::runtime::ClockGone;
use crate::state::ClockState;
#[derive(Debug)]
pub struct ClockDriver {
pub(crate) state: ClockState,
}
impl ClockDriver {
pub(super) const fn new(state: ClockState) -> Self {
Self { state }
}
#[cfg_attr(test, mutants::skip)] #[expect(clippy::needless_pass_by_ref_mut, reason = "the mut forces exclusive ownership of the driver")]
pub fn advance_timers(&mut self, now: Instant) -> Result<Option<Instant>, ClockGone> {
let next_timer = match &self.state {
ClockState::System(timers) => timers.try_advance_timers(now),
#[cfg(any(feature = "test-util", test))]
ClockState::ClockControl(control) => control.next_timer(),
};
match next_timer {
Some(next) => Ok(Some(next)),
None if self.state.is_unique() => Err(ClockGone::new()),
None => Ok(None),
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use std::task::{Context, Waker};
use std::time::Duration;
use futures::FutureExt;
use super::*;
use crate::clock_control::ClockControl;
use crate::runtime::InactiveClock;
use crate::state::SynchronizedTimers;
#[test]
fn assert_types() {
static_assertions::assert_impl_all!(ClockDriver: Send, Sync);
static_assertions::assert_not_impl_all!(ClockDriver: Clone);
}
#[test]
fn advance_timers_ok() {
let timers = SynchronizedTimers::new_isolated();
let when = Instant::now();
timers.with_timers::<_, ()>(|timers| {
timers.register(when, Waker::noop().clone());
});
let clock_state = ClockState::System(timers);
let mut driver = ClockDriver::new(clock_state.clone());
_ = driver.advance_timers(Instant::now() - Duration::from_secs(1));
assert_eq!(clock_state.timers_len(), 1);
_ = driver.advance_timers(Instant::now() + Duration::from_secs(1));
assert_eq!(clock_state.timers_len(), 0);
}
#[test]
fn clock_gone_error_reported() {
let (clock, mut driver) = InactiveClock::default().activate();
driver.advance_timers(Instant::now()).unwrap();
drop(clock);
let error = driver.advance_timers(Instant::now()).unwrap_err();
assert_eq!(error.to_string(), "all clock owners have been dropped");
}
#[test]
fn clock_gone_but_timers_left_not_dropped() {
let now = Instant::now();
let (clock, mut driver) = InactiveClock::default().activate();
driver.advance_timers(now).unwrap();
let mut future = Box::pin(clock.delay(Duration::from_secs(1)));
let mut context = Context::from_waker(Waker::noop());
_ = future.poll_unpin(&mut context);
drop(clock);
driver.advance_timers(now).unwrap();
driver.advance_timers(now + Duration::from_secs(123)).unwrap();
_ = future.poll_unpin(&mut context);
drop(future);
driver.advance_timers(now + Duration::from_secs(123)).unwrap_err();
}
#[test]
fn advance_timers_with_clock_control_does_not_advance() {
let control = ClockControl::new();
let clock_state = ClockState::ClockControl(control.clone());
let when = control.instant() + Duration::from_secs(1);
control.register_timer(when, Waker::noop().clone());
let mut driver = ClockDriver::new(clock_state);
let next = driver.advance_timers(control.instant() + Duration::from_secs(2)).unwrap();
assert_eq!(control.timers_len(), 1);
assert_eq!(next, Some(when));
}
}