clock_kit/lib.rs
1//! `clock-kit` — the estate's precision time substrate (L1).
2//!
3//! clock-kit answers three questions `std` leaves unresolved: **how expensive
4//! is reading the clock** ([`Clock::source`]), **how much do we trust it**
5//! ([`SyncQuality`]), and **how do we test against it deterministically**
6//! ([`MockClock`]). It is the time source for latency-critical paths — feed
7//! handlers, matching threads, latency measurement.
8//!
9//! # Design
10//!
11//! - **Guarantee grades.** [`Timestamp::mono`] never regresses within a
12//! process — enforced by a process-wide floor, not by trust in the
13//! underlying source (G1). [`SyncQuality`] is an advisory hint, never a
14//! guarantee (G2). [`MockClock`] never consults the OS: time moves only
15//! when the test moves it (G3).
16//! - **Wall and monotonic are separate.** [`Timestamp`] carries both with
17//! independent rules; the only cross-derivation is the explicitly lossy
18//! [`Timestamp::mono_from_wall_lossy`] (REQ-CLK-002).
19//! - **Cheap reads behind calibration.** With the `tsc` feature, `x86_64` reads
20//! `rdtsc` and aarch64 reads `cntvct_el0`, converted through a calibrated
21//! multiply-shift (no division on the read path); if calibration or the
22//! invariant-counter check fails, [`CalibratedClock`] transparently falls
23//! back to `Instant` / `CLOCK_MONOTONIC` (REQ-CLK-003).
24//! - **PTP detection, not participation.** With the `ptp` feature,
25//! [`detect_sync_quality`] classifies the host's sync state by looking at
26//! `/sys/class/ptp` and probing `CLOCK_TAI`. It runs no daemon and touches
27//! nothing (REQ-CLK-004).
28//! - **Allocation-free latency statistics.** [`LatencyRing`] is a
29//! fixed-capacity, sliding-window ring of `u64` nanos; [`stats`]
30//! is exact over the current window with zero heap allocation (REQ-CLK-006).
31//!
32//! # chronoshift bridge
33//!
34//! The estate keeps **one time idiom**: chronoshift (L0) owns time
35//! *abstraction*, clock-kit owns time *precision and cost*. With the
36//! `chronoshift` feature, every `chronoshift::Clock` is automatically a
37//! [`Clock`] (blanket impl): its `now_ns()` is bridged into a full
38//! [`Timestamp`] with the monotonic floor applied. clock-kit does not mint a
39//! rival trait — its [`Clock`] extends the idiom with quality and source
40//! observability.
41//!
42//! # Feature flags
43//!
44//! | Feature | Default | Description |
45//! |---|---|---|
46//! | `std` | yes | `SystemTime`-backed wall time, `Instant` monotonic reads |
47//! | `libc` | no | `clock_gettime(2)` wall/monotonic reads for `no_std` hosts |
48//! | `tsc` | no | Hardware-counter reads behind calibration (`x86_64/aarch64`) |
49//! | `ptp` | no | Sync-quality detection (`/sys/class/ptp` + `CLOCK_TAI`); implies `std` |
50//! | `chronoshift` | no | Blanket `Clock` impl for every `chronoshift::Clock` |
51//!
52//! # `no_std` posture
53//!
54//! Core-only (no `std`, no `libc`): [`Timestamp`], [`WallTime`], [`Clock`],
55//! [`MockClock`], and [`LatencyRing`] build with `--no-default-features` —
56//! pure `core`. Wall reads need `std` or `libc`. The critical-section
57//! fallback for targets without 64-bit atomics follows the chronoshift
58//! convention: the final binary provides the `critical-section` impl.
59//!
60//! # Example
61//!
62//! ```
63//! use clock_kit::{Clock, ClockSource, MockClock, SyncQuality};
64//! use std::time::Duration;
65//!
66//! let clock = MockClock::start_at(1_000, 1_000);
67//! clock.advance(Duration::from_millis(5));
68//! let t = clock.now();
69//! assert_eq!(t.mono, 5_001_000);
70//!
71//! // Deterministic: the OS is never consulted.
72//! assert_eq!(clock.source(), ClockSource::Mock);
73//! assert_eq!(clock.quality(), SyncQuality::Fallback);
74//! ```
75//!
76//! [`stats`]: LatencyRing::stats
77//! [`CalibratedClock`]: crate::calibrated::CalibratedClock
78//! [`detect_sync_quality`]: crate::ptp::detect_sync_quality
79
80#![cfg_attr(not(feature = "std"), no_std)]
81
82#[forbid(unsafe_code)]
83pub mod clock;
84#[forbid(unsafe_code)]
85pub mod mock;
86#[forbid(unsafe_code)]
87pub mod monotonic;
88#[cfg(feature = "ptp")]
89#[forbid(unsafe_code)]
90pub mod ptp;
91#[forbid(unsafe_code)]
92pub mod quality;
93#[forbid(unsafe_code)]
94pub mod ring;
95#[cfg(any(feature = "std", feature = "libc"))]
96#[forbid(unsafe_code)]
97pub mod system;
98#[forbid(unsafe_code)]
99pub mod timestamp;
100
101// The crate's only unsafe: counter reads + clock_gettime FFI wrappers.
102#[cfg(any(feature = "std", feature = "libc"))]
103#[forbid(unsafe_code)]
104pub mod calibrated;
105#[allow(unsafe_code)]
106mod low;
107
108pub use clock::Clock;
109pub use mock::MockClock;
110pub use monotonic::mono_floor;
111pub use quality::{ClockSource, SyncQuality};
112pub use ring::{IntervalStats, LatencyRing};
113pub use timestamp::{Timestamp, WallTime};
114
115#[cfg(feature = "chronoshift")]
116pub use chronoshift;
117// Raw counter reads are public API per the spec sketch (REQ-CLK-003) —
118// convert through `calibrated::Calibration` before interpreting as time.
119#[cfg(any(feature = "std", feature = "libc"))]
120pub use calibrated::{calibrate, CalError, CalMethod, CalibratedClock, Calibration};
121#[cfg(all(feature = "tsc", any(target_arch = "x86_64", target_arch = "aarch64")))]
122pub use low::counter;
123#[cfg(feature = "ptp")]
124pub use ptp::{
125 classify_sync_quality, detect_sync_quality, detect_sync_quality_in, tai_offset_coherent,
126 tai_offset_ns,
127};
128#[cfg(any(feature = "std", feature = "libc"))]
129pub use system::SystemClock;