clock_kit/clock.rs
1//! The estate time idiom: [`Clock`] — and the chronoshift bridge.
2//!
3//! clock-kit does **not** mint a rival time abstraction (spec §Decisions #1,
4//! recommended resolution): chronoshift (L0) owns time *abstraction*,
5//! clock-kit owns time *precision and cost*. With the `chronoshift` feature
6//! a blanket impl makes every `chronoshift::Clock` a clock-kit [`Clock`],
7//! bridging `now_ns()` into a full [`Timestamp`] with the monotonic floor
8//! applied.
9
10#[cfg(feature = "chronoshift")]
11use crate::monotonic::mono_floor;
12use crate::quality::{ClockSource, SyncQuality};
13use crate::timestamp::Timestamp;
14#[cfg(feature = "chronoshift")]
15use crate::timestamp::WallTime;
16
17/// A time source producing wall+monotonic [`Timestamp`]s.
18///
19/// Object-safe; all implementations enforce REQ-CLK-001 by construction
20/// (`mono` passes through a process-wide floor). Two advisory accessors
21/// make cost and trust observable instead of guessed.
22///
23/// REQ-CLK-001, REQ-CLK-004.
24pub trait Clock {
25 /// Current reading. `t.mono` never decreases across calls within a
26 /// process, even if the underlying source regresses. REQ-CLK-001.
27 fn now(&self) -> Timestamp;
28
29 /// Advisory sync quality of the underlying source (G2 — a hint, never a
30 /// guarantee). REQ-CLK-004.
31 fn quality(&self) -> SyncQuality;
32
33 /// Which underlying source reads are actually served from. REQ-CLK-003.
34 fn source(&self) -> ClockSource;
35}
36
37#[cfg(feature = "chronoshift")]
38impl<T: chronoshift::Clock> Clock for T {
39 fn now(&self) -> Timestamp {
40 let ns = chronoshift::Clock::now_ns(self);
41 // Bridge is lossy at the edges, documented: chronoshift nanos are
42 // i64 (signed, wall scale). Negative (pre-epoch) clamps to 0 for
43 // both fields; monotonic passes through the process-wide floor so
44 // even a regressing bridged source honors REQ-CLK-001.
45 let wall = u64::try_from(ns).unwrap_or(0);
46 Timestamp {
47 wall: WallTime::from_unix_nanos(wall),
48 mono: mono_floor(wall),
49 }
50 }
51
52 fn quality(&self) -> SyncQuality {
53 // The bridge cannot know how the foreign clock is disciplined;
54 // fail-closed to distrust (G2).
55 SyncQuality::Fallback
56 }
57
58 fn source(&self) -> ClockSource {
59 ClockSource::External
60 }
61}