use std::sync::{Arc, Mutex};
use std::task::Waker;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use crate::state::ClockState;
use crate::timers::{TimerKey, Timers};
use crate::{Clock, thread_aware_move};
#[derive(Clone, Default)]
pub struct ClockControl {
state: Arc<Mutex<State>>,
}
impl std::fmt::Debug for ClockControl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug = f.debug_struct("ClockControl");
let time = self.system_time();
match time.duration_since(UNIX_EPOCH) {
Ok(duration) => debug.field("UNIX offset", &duration),
Err(_) => debug.field("UNIX offset", &"negative"),
};
debug.field("timers", &self.timers_len()).finish_non_exhaustive()
}
}
thread_aware_move!(ClockControl);
impl ClockControl {
#[must_use]
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(State::default())),
}
}
#[must_use]
pub fn new_at(time: impl Into<SystemTime>) -> Self {
let this = Self::new();
this.set_time(time.into());
this
}
#[must_use]
pub fn to_clock(&self) -> Clock {
Clock::new(ClockState::ClockControl(self.clone()))
}
#[must_use]
pub fn auto_advance(self, duration: Duration) -> Self {
self.with_state(|v| v.auto_advance = duration);
self
}
#[must_use]
pub fn auto_advance_limit(self, limit: Duration) -> Self {
self.with_state(|v| {
v.auto_advance_total_max = Some(limit);
});
self
}
#[must_use]
pub fn auto_advance_timers(self, enabled: bool) -> Self {
self.with_state(|v| v.auto_advance_timers = enabled);
self
}
pub fn advance_millis(&self, millis: u64) {
self.advance(Duration::from_millis(millis));
}
pub fn advance(&self, duration: Duration) {
self.with_state(|v| v.advance(duration, TimeFlow::Forward));
}
#[expect(
clippy::missing_panics_doc,
reason = "we are handling cases where the timestamp is either in future or past and the resulting duration is always positive"
)]
pub fn set_time(&self, timestamp: impl Into<SystemTime>) {
let now = self.system_time();
let timestamp = timestamp.into();
match timestamp.duration_since(now) {
Ok(duration) => {
self.with_state(|v| v.advance(duration, TimeFlow::Forward));
}
Err(_e) => {
let duration = now.duration_since(timestamp).expect("the resulting duration must be positive here");
self.with_state(|v| v.advance(duration, TimeFlow::Backward));
}
}
}
pub(super) fn system_time(&self) -> SystemTime {
self.with_state(State::now)
}
pub(super) fn instant(&self) -> Instant {
self.with_state(State::instant_now)
}
pub(super) fn register_timer(&self, when: Instant, waker: Waker) -> TimerKey {
let key = self.with_state(|s| s.timers.register(when, waker));
self.with_state(State::evaluate_timers);
key
}
pub(super) fn unregister_timer(&self, key: TimerKey) {
self.with_state(|s| s.timers.unregister(key));
}
pub(super) fn next_timer(&self) -> Option<Instant> {
self.with_state(|s| s.timers.next_timer())
}
pub(super) fn timers_len(&self) -> usize {
self.with_state(|s| s.timers.len())
}
fn with_state<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut State) -> R,
{
f(&mut self.state.lock().expect("acquiring lock must always succeed"))
}
pub(crate) fn is_unique(&self) -> bool {
Arc::strong_count(&self.state) == 1
}
}
impl From<ClockControl> for Clock {
fn from(control: ClockControl) -> Self {
control.to_clock()
}
}
impl From<&ClockControl> for Clock {
fn from(control: &ClockControl) -> Self {
control.to_clock()
}
}
#[derive(Debug)]
struct State {
instant: Instant,
system_time: SystemTime,
timers: Timers,
auto_advance: Duration,
auto_advance_total: Duration,
auto_advance_timers: bool,
auto_advance_total_max: Option<Duration>,
}
impl Default for State {
fn default() -> Self {
Self {
instant: Instant::now(),
system_time: SystemTime::UNIX_EPOCH,
timers: Timers::default(),
auto_advance: Duration::ZERO,
auto_advance_timers: false,
auto_advance_total: Duration::ZERO,
auto_advance_total_max: None,
}
}
}
impl State {
fn auto_advance(&mut self, duration: Option<Duration>) {
let auto_advance = self.get_next_auto_advance_duration(duration.unwrap_or(self.auto_advance));
self.auto_advance_total = self.auto_advance_total.saturating_add(auto_advance);
self.advance(auto_advance, TimeFlow::Forward);
}
fn get_next_auto_advance_duration(&self, hint: Duration) -> Duration {
if let Some(max) = self.auto_advance_total_max {
let remaining = max.saturating_sub(self.auto_advance_total);
hint.min(remaining)
} else {
hint
}
}
#[cfg_attr(test, mutants::skip)] fn advance(&mut self, duration: Duration, flow: TimeFlow) {
self.advance_time(duration, flow);
self.evaluate_timers();
}
fn evaluate_timers(&mut self) {
self.timers.advance_timers(self.instant);
if !self.auto_advance_timers {
return;
}
while let Some(next_timer) = self.timers.next_timer() {
let time_to_next_timer = next_timer.saturating_duration_since(self.instant);
let advance = self.get_next_auto_advance_duration(time_to_next_timer);
if advance == Duration::ZERO {
break;
}
self.advance(advance, TimeFlow::Forward);
self.auto_advance_total = self.auto_advance_total.saturating_add(advance);
}
}
fn advance_time(&mut self, duration: Duration, flow: TimeFlow) {
if duration == Duration::ZERO {
return;
}
match flow {
TimeFlow::Forward => {
self.instant = self.instant.checked_add(duration).expect(OUTSIDE_RANGE_MESSAGE);
self.system_time = self.system_time.checked_add(duration).expect(OUTSIDE_RANGE_MESSAGE);
self.timers.advance_timers(self.instant);
}
TimeFlow::Backward => {
self.instant = self.instant.checked_sub(duration).expect(OUTSIDE_RANGE_MESSAGE);
self.system_time = self.system_time.checked_sub(duration).expect(OUTSIDE_RANGE_MESSAGE);
}
}
}
fn now(&mut self) -> SystemTime {
let time = self.system_time;
self.auto_advance(None);
time
}
fn instant_now(&mut self) -> Instant {
let time = self.instant;
self.auto_advance(None);
time
}
}
#[derive(Debug, Copy, Clone)]
enum TimeFlow {
Forward,
Backward,
}
static OUTSIDE_RANGE_MESSAGE: &str =
"moving the clock outside of the supported time range is not possible: [1970-01-01T00:00:00Z, 9999-12-30T22:00:00.9999999Z]";
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::fmt::UnixSeconds;
#[test]
fn assert_types() {
static_assertions::assert_impl_all!(ClockControl: Send, Sync);
}
#[test]
fn defaults_ok() {
let control = ClockControl::new();
assert_eq!(control.with_state(|s| s.auto_advance), Duration::ZERO);
assert_eq!(control.system_time(), SystemTime::UNIX_EPOCH);
}
#[test]
fn auto_advance_ok() {
let duration = Duration::from_secs(1);
let control = ClockControl::new().auto_advance(duration);
let clock = control.to_clock();
assert_eq!(control.with_state(|s| s.auto_advance), duration);
let now = clock.system_time();
assert_eq!(clock.system_time().duration_since(now).unwrap(), duration);
let watch = clock.stopwatch();
assert_eq!(watch.elapsed(), duration);
}
#[test]
fn advance_ok() {
let control = ClockControl::new();
let clock = control.to_clock();
let now = clock.system_time();
() = control.advance(Duration::from_secs(1));
assert_eq!(clock.system_time().duration_since(now).unwrap(), Duration::from_secs(1));
}
#[test]
fn set_time_ok() {
let control = ClockControl::new();
let clock = control.to_clock();
let now = clock.system_time();
control.set_time(now.checked_add(Duration::from_secs(1)).unwrap());
assert_eq!(clock.system_time().duration_since(now).unwrap(), Duration::from_secs(1));
}
#[test]
fn set_time_past_ok() {
let control = ClockControl::new();
let clock = control.to_clock();
let now = clock.system_time();
control.set_time(now.checked_add(Duration::from_secs(10)).unwrap());
let now1 = clock.system_time();
let instant_now1 = clock.instant();
() = control.set_time(now1.checked_sub(Duration::from_secs(5)).unwrap());
let now2 = clock.system_time();
let instant_now2 = clock.instant();
assert_eq!(now1.duration_since(now2).unwrap(), Duration::from_secs(5));
assert_eq!(instant_now1.checked_duration_since(instant_now2).unwrap(), Duration::from_secs(5));
}
#[test]
fn advance_millis_ok() {
let control = ClockControl::new();
let clock = control.to_clock();
let now = clock.system_time();
() = control.advance_millis(123);
assert_eq!(clock.system_time().duration_since(now).unwrap(), Duration::from_millis(123));
}
#[test]
fn register_timer_ok() {
let control = ClockControl::new();
let key = control.register_timer(Instant::now(), Waker::noop().clone());
assert_eq!(control.timers_len(), 1);
control.unregister_timer(key);
assert_eq!(control.timers_len(), 0);
}
#[test]
fn next_timer_ok() {
let control = ClockControl::new();
assert_eq!(control.next_timer(), None);
let key = control.register_timer(Instant::now(), Waker::noop().clone());
assert_eq!(control.next_timer().unwrap(), key.tick());
}
#[test]
fn unregister_timer_ok() {
let control = ClockControl::new();
let key = control.register_timer(Instant::now(), Waker::noop().clone());
control.unregister_timer(key);
assert_eq!(control.timers_len(), 0);
}
#[test]
fn auto_advance_timers() {
let control = ClockControl::new().auto_advance_timers(true);
let clock = control.to_clock();
let now = clock.system_time();
control.register_timer(clock.instant() + Duration::from_secs(100), Waker::noop().clone());
assert_eq!(clock.system_time().duration_since(now).unwrap(), Duration::from_secs(100));
}
#[test]
fn advance_ensure_timers_advanced() {
let control = ClockControl::new();
let clock = control.to_clock();
control.register_timer(clock.instant() + Duration::from_secs(1), Waker::noop().clone());
control.advance(Duration::from_secs(1));
assert_eq!(control.timers_len(), 0);
}
#[test]
fn auto_advance_limit() {
let control = ClockControl::new()
.auto_advance(Duration::from_millis(550))
.auto_advance_limit(Duration::from_secs(2));
let clock = control.to_clock();
let anchor = clock.system_time();
assert_eq!(clock.system_time().duration_since(anchor).unwrap(), Duration::from_millis(550));
assert_eq!(clock.system_time().duration_since(anchor).unwrap(), Duration::from_millis(1100));
assert_eq!(clock.system_time().duration_since(anchor).unwrap(), Duration::from_millis(1650));
assert_eq!(clock.system_time().duration_since(anchor).unwrap(), Duration::from_secs(2));
assert_eq!(clock.system_time().duration_since(anchor).unwrap(), Duration::from_secs(2));
}
#[test]
fn new_at_with_system_time_ok() {
let system_time = SystemTime::UNIX_EPOCH + Duration::from_secs(222);
let control = ClockControl::new_at(system_time);
let clock = control.to_clock();
assert_eq!(clock.system_time(), system_time);
}
#[test]
fn new_at_with_timestamp_ok() {
let timestamp: SystemTime = UnixSeconds::from_secs(222).unwrap().into();
let control = ClockControl::new_at(timestamp);
let clock = control.to_clock();
assert_eq!(clock.system_time(), timestamp);
}
#[test]
fn auto_advance_timers_no_stack_overflow() {
let control = ClockControl::new().auto_advance_timers(true);
let clock = control.to_clock();
let start_instant = clock.instant();
let target_time = start_instant + Duration::from_secs(100);
for _ in 0..100 {
control.register_timer(target_time, Waker::noop().clone());
}
assert_eq!(clock.instant().saturating_duration_since(start_instant), Duration::from_secs(100));
assert_eq!(control.timers_len(), 0);
}
#[test]
fn auto_advance_timers_many_sequential_no_stack_overflow() {
let control = ClockControl::new().auto_advance_timers(true);
let clock = control.to_clock();
let start_instant = clock.instant();
for i in 1..=1000 {
control.register_timer(start_instant + Duration::from_millis(i), Waker::noop().clone());
}
assert_eq!(control.timers_len(), 0);
assert!(clock.instant().saturating_duration_since(start_instant) >= Duration::from_millis(1));
}
#[test]
fn from_clock_control_ok() {
let control = ClockControl::default();
control.advance_millis(12345);
let clock_1 = Clock::from(control.clone());
let clock_2 = Clock::from(&control);
assert_eq!(clock_1.system_time(), SystemTime::UNIX_EPOCH + Duration::from_millis(12345));
assert_eq!(clock_1.system_time(), clock_2.system_time());
}
#[test]
fn auto_advance_timers_stops_at_limit() {
let control = ClockControl::new()
.auto_advance_timers(true)
.auto_advance(Duration::from_secs(1))
.auto_advance_limit(Duration::from_secs(1));
let clock = control.to_clock();
let start_instant = clock.instant();
control.register_timer(start_instant + Duration::from_secs(2), Waker::noop().clone());
let current_instant = clock.instant();
assert_eq!(current_instant.saturating_duration_since(start_instant), Duration::from_secs(1));
assert_eq!(control.timers_len(), 1);
}
#[test]
#[cfg_attr(miri, ignore)]
fn debug_ok() {
let system = SystemTime::UNIX_EPOCH + Duration::from_secs(123);
let control = ClockControl::new_at(system);
let future = control.instant() + Duration::from_secs(100);
control.register_timer(future, Waker::noop().clone());
insta::assert_debug_snapshot!(control);
}
#[test]
#[cfg_attr(miri, ignore)]
fn debug_negative_offset_ok() {
let system = SystemTime::UNIX_EPOCH - Duration::from_secs(123);
let control = ClockControl::new_at(system);
insta::assert_debug_snapshot!(control);
}
}