proxima_clock/lib.rs
1//! Hardware-clock source polymorphism, expressed as [`proxima_primitives`]
2//! pipes instead of a bespoke clock trait — principle 5 ("source
3//! polymorphism", today applied to the reactor's readiness sources)
4//! applied to time.
5//!
6//! # Why this is a pipe, not a trait
7//!
8//! A monotonic tick source — a `read_volatile` on a memory-mapped
9//! register, `mrs CNTVCT_EL0`, `rdtsc`, a DMA'd timestamp a device writes
10//! into memory — takes nothing and produces a reading. That is exactly
11//! [`proxima_primitives::pipe::primitives::Pipe`]'s source shape (`In =
12//! (), Out = Ticks`), already in the workspace, already `no_std` +
13//! no-alloc, already box-free. Binding a new hardware backend is
14//! "implement `Pipe` for your type" — zero edits to this crate, and not
15//! even this crate's own trait: it is the workspace's general pipe
16//! algebra, the same one the reactor's readiness sources, HTTP handlers,
17//! and codec frame pipelines already speak.
18//!
19//! This crate therefore does **not** define a `MonotonicClock` or
20//! `Sleeper` capability trait. Both shapes were checked against the
21//! binary rule ("can this be expressed with a pipe? If yes, it does not
22//! get a type") by writing the composition, not by arguing about it:
23//!
24//! - A tick source is `Pipe<In = (), Out = Ticks, Err = Infallible>` —
25//! the source form from `Pipe`'s own module doc's "four forms" table.
26//! - A sleeper is `Pipe<In = Ticks, Out = (), Err = Infallible>` whose
27//! future genuinely pends until the deadline — the sink form, mirrored.
28//! Any type implementing this shape, with a future that registers a
29//! real waker (a timer interrupt, `prime`'s timer wheel), is a sleeper;
30//! there is nothing else to implement. This crate ships no reference
31//! sleeper — a correct one needs an interrupt or a runtime's timer
32//! wheel, which is a runtime-tier concern, not a leaf crate's.
33//! - Converting ticks to wall-clock time is `Pipe<In = Ticks, Out =
34//! UnixNanos, Err = Infallible>` — [`anchor::ToUnixNanos`], composed
35//! with a source via `.and_then`. There is no `WallClock<C>` wrapper
36//! type: the transform stage IS the monotonic-to-wall-clock bridge.
37//! - Arbitrating between redundant tick sources (a GPS PPS signal, a PTP
38//! grandmaster, a local oscillator, each potentially going stale) is
39//! [`proxima_primitives::pipe::fan_in::FanIn`] — see
40//! `tests/fan_in_multi_source.rs` for a worked example. No bespoke
41//! arbitration machinery needed.
42//!
43//! What this crate *does* provide: two domain value types
44//! ([`ticks::Ticks`], [`unix_nanos::UnixNanos`]) so a caller cannot
45//! accidentally mix tick-domain and wall-clock-domain arithmetic, and two
46//! small stateful cells ([`coarse::TickCell`], [`anchor::AnchorCell`])
47//! that a hardware-facing `Pipe` impl or the wall-clock bridge can hold —
48//! plain data-and-synchronization types, not a parallel API to `Pipe`.
49//!
50//! # Tiers
51//!
52//! - **Bare `no_std` + no-alloc floor**: [`ticks`], [`unix_nanos`],
53//! [`coarse`], [`anchor`] — zero `alloc::`, zero `Box`/`Vec`/`Arc`/
54//! `String`. `--no-default-features` both builds for
55//! `thumbv7m-none-eabi` and RUNS the crate's unit tests; only the tests
56//! that genuinely need threads or an allocator are `std`-gated.
57//! - **`std` feature (on by default)**: no extra surface of its own — it
58//! turns off `no_std` and admits the thread- and `format!`-using tests.
59//! - **`config` feature (std, opt-in)**: `config` — the principle-4
60//! config + fluent-builder surface for [`anchor::AnchorCell`]'s initial
61//! `(ticks, unix_nanos)` pair. `conflaguration` is std-only, so this
62//! lives at the std composition boundary; the no-alloc core never
63//! depends on it.
64#![cfg_attr(not(feature = "std"), no_std)]
65#![warn(clippy::pedantic)]
66
67pub mod anchor;
68pub mod coarse;
69#[cfg(feature = "config")]
70pub mod config;
71mod seq_u64s;
72pub mod ticks;
73pub mod unix_nanos;