clock_kit/quality.rs
1//! Sync-quality classification and clock-source identity — REQ-CLK-004.
2
3/// Advisory classification of the host's time synchronization.
4///
5/// A **hint** read at clock construction/discovery time — never a guarantee
6/// (G2): a [`SyncQuality::Ptp`]-labelled source may be in holdover.
7/// Consumers use it to decide whether derived timestamps may be correlated
8/// across machines, never for correctness. REQ-CLK-004.
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub enum SyncQuality {
11 /// PTP device present **and** coherent `CLOCK_TAI` offset. Still only a
12 /// hint: the source may be in holdover.
13 Ptp,
14 /// Disciplined by a network sync stack (NTP markers, or a coherent TAI
15 /// offset without a PTP device).
16 Ntp,
17 /// Nothing trustworthy detected — fail-closed to distrust.
18 #[default]
19 Fallback,
20}
21
22impl SyncQuality {
23 /// Stable machine-readable name (`"ptp" | "ntp" | "fallback"`).
24 #[must_use]
25 pub const fn as_str(&self) -> &'static str {
26 match self {
27 Self::Ptp => "ptp",
28 Self::Ntp => "ntp",
29 Self::Fallback => "fallback",
30 }
31 }
32}
33
34/// Which underlying source a [`Clock`](crate::Clock) is actually reading.
35///
36/// Observable per REQ-CLK-003: read cost and source used must be
37/// discoverable — e.g. a `CalibratedClock` that fell back reports the
38/// fallback, never the counter it failed to use.
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub enum ClockSource {
41 /// `x86_64` `rdtsc` behind a calibrated multiply-shift.
42 Tsc,
43 /// aarch64 `cntvct_el0` behind a calibrated multiply-shift.
44 Cntvct,
45 /// `std::time::Instant` (the calibrated-clock fallback under `std`).
46 Instant,
47 /// `clock_gettime(CLOCK_MONOTONIC)` via libc (`no_std` hosts, and the
48 /// calibrated-clock fallback under the `libc` feature).
49 LibcMono,
50 /// Deterministic test clock — the OS is never consulted.
51 Mock,
52 /// Bridged `chronoshift::Clock` (the `chronoshift` feature).
53 External,
54}
55
56impl ClockSource {
57 /// Stable machine-readable name.
58 #[must_use]
59 pub const fn as_str(&self) -> &'static str {
60 match self {
61 Self::Tsc => "tsc",
62 Self::Cntvct => "cntvct",
63 Self::Instant => "instant",
64 Self::LibcMono => "libc-mono",
65 Self::Mock => "mock",
66 Self::External => "external",
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::{ClockSource, SyncQuality};
74
75 /// Stable names for machine-readable surfaces (logs, metrics labels).
76 #[test]
77 fn names_are_stable() {
78 assert_eq!(SyncQuality::Ptp.as_str(), "ptp");
79 assert_eq!(SyncQuality::Ntp.as_str(), "ntp");
80 assert_eq!(SyncQuality::Fallback.as_str(), "fallback");
81 assert_eq!(ClockSource::Tsc.as_str(), "tsc");
82 assert_eq!(ClockSource::Cntvct.as_str(), "cntvct");
83 assert_eq!(ClockSource::Instant.as_str(), "instant");
84 assert_eq!(ClockSource::LibcMono.as_str(), "libc-mono");
85 assert_eq!(ClockSource::Mock.as_str(), "mock");
86 assert_eq!(ClockSource::External.as_str(), "external");
87 // Default is fail-closed.
88 assert_eq!(SyncQuality::default(), SyncQuality::Fallback);
89 }
90}