win_time_sys/clock.rs
1// Copyright (c) 2026 Mike Grier
2//! Clocks: the getters that read now on a timeline ([WT-D-2]).
3//!
4//! [WT-D-2]: https://github.com/MikeGrier/windows-threadpool-sys/blob/main/crates/win-time-sys/DESIGN-NOTES.md#wt-d-2
5
6use crate::timeline::{TimePoint, Timeline};
7
8/// A way to read "now" on one timeline. Several clocks may share a timeline, differing only in
9/// what a reading costs and how fresh it is; their readings compare with each other because they
10/// are points on the same timeline.
11///
12/// `now` takes `&self` ([WT-D-7]), so a clock may carry state -- a test's fake clock, or a value it
13/// reads once and keeps -- and code that is generic over a clock is handed one.
14///
15/// ```
16/// use core::cell::Cell;
17/// use core::num::NonZeroU64;
18/// use win_time_sys::{Clock, TimePoint, Ticks, Timeline};
19///
20/// /// Ticks of one millisecond since some zero.
21/// enum Millis {}
22/// impl Timeline for Millis {
23/// fn ticks_per_second() -> NonZeroU64 { NonZeroU64::new(1_000).unwrap() }
24/// }
25///
26/// /// A fake clock a test advances by hand.
27/// struct Manual(Cell<u64>);
28/// impl Clock for Manual {
29/// type Timeline = Millis;
30/// fn now(&self) -> TimePoint<Millis> { TimePoint::from_ticks(self.0.get()) }
31/// }
32///
33/// fn elapsed<C: Clock>(clock: &C, since: TimePoint<C::Timeline>) -> Ticks<C::Timeline> {
34/// clock.now() - since
35/// }
36///
37/// let clock = Manual(Cell::new(1_000));
38/// let start = clock.now();
39/// clock.0.set(1_250);
40/// assert_eq!(elapsed(&clock, start).to_duration(), Some(core::time::Duration::from_millis(250)));
41/// ```
42///
43/// [WT-D-7]: https://github.com/MikeGrier/windows-threadpool-sys/blob/main/crates/win-time-sys/DESIGN-NOTES.md#wt-d-7
44pub trait Clock {
45 /// The timeline this clock reads.
46 type Timeline: Timeline;
47
48 /// The current point on the timeline.
49 fn now(&self) -> TimePoint<Self::Timeline>;
50}
51
52/// A clock whose readings never decrease: a reading taken after another is at or after it
53/// ([WT-D-9]).
54///
55/// A promise rather than a check. Implementing it is how a clock -- a test's mock included -- says
56/// it keeps the promise, and code that relies on the promise names `Steady` in its bounds, so a
57/// clock that does not make it fails to compile there. It promises direction only: not a rate, not
58/// freshness, and not that two readings differ, which a plain interrupt-time clock does not for a
59/// whole system tick.
60///
61/// The interrupt clocks and the performance clock make it. The system clocks do not, because
62/// setting the time moves them backwards:
63///
64/// ```
65/// use win_time_sys::{InterruptClock, PerformanceClock, Steady};
66///
67/// fn stamps_with<C: Steady>(_: C) {}
68/// stamps_with(InterruptClock);
69/// stamps_with(PerformanceClock);
70/// ```
71///
72/// ```compile_fail,E0277
73/// use win_time_sys::{PreciseSystemClock, Steady};
74///
75/// fn stamps_with<C: Steady>(_: C) {}
76/// stamps_with(PreciseSystemClock);
77/// ```
78///
79/// [WT-D-9]: https://github.com/MikeGrier/windows-threadpool-sys/blob/main/crates/win-time-sys/DESIGN-NOTES.md#wt-d-9
80pub trait Steady: Clock {}