v0.3.0 — The Mockable Clock
Pre-release
Pre-release
v0.3.0 — The Mockable Clock
The headline feature of clock-lib lands in this release: a Clock trait with two implementations — SystemClock for production and ManualClock for tests — so timing-driven code becomes deterministically testable without ever calling thread::sleep.
Highlights
Clocktrait. ASend + Syncsource of time exposingnow() -> Monotonicandwall() -> Wall. Take it as a dependency anywhere your code reads the clock; substitute it in tests.SystemClock. Zero-sized,Copy,const-constructible. Forwards directly to the OS readings already in the crate — nothing extra to pay over the free functions.ManualClock. Lock-free advance via anAtomicU64offset. The clock never moves on its own. Tests advance it forward in arbitrary increments and observe the timing-driven behavior exactly.- Blanket impls.
Clockis implemented forArc<C>and&CwhereC: Clock, so shared ownership and borrowed access work without re-implementing the trait. - TTL test pattern, no sleep. The classic "is this expired?" check now takes 8 lines and zero milliseconds of real wall-clock time:
use clock_lib::{Clock, ManualClock, Monotonic};
use std::time::Duration;
fn expired<C: Clock>(clock: &C, stamp: Monotonic, ttl: Duration) -> bool {
clock.now().duration_since(stamp) >= ttl
}
let clock = ManualClock::new();
let stamp = clock.now();
assert!(!expired(&clock, stamp, Duration::from_secs(60)));
clock.advance(Duration::from_secs(60));
assert!(expired(&clock, stamp, Duration::from_secs(60)));What's New
Added
Clocktrait withnowandwallmethods (Send + Sync).SystemClockstruct (Copy,const-constructible).ManualClockstruct withnew,advance, andoffsetmethods backed by an atomic offset.- Blanket
Clockimpls forArc<C: Clock>and&C: Clock. - Integration tests covering: zero-advance idempotence, exact-advance semantics on both monotonic and wall, offset accumulation, the sleep-free TTL pattern,
Arc<ManualClock>dispatch, andArc<dyn Clock>trait-object usage. - Doctests on every public item in the new module.
Changed
MonotonicandWallfields are nowpub(crate)(internal change — field access remains forbidden outside the crate, butManualClockcan construct synthetic readings).
Compatibility
- MSRV: Rust 1.85 (unchanged)
- Edition: 2024 (unchanged)
- Public API: strictly additive. All 0.2.x code continues to compile unchanged.
Upgrading From 0.2.x
[dependencies]
clock-lib = "0.3"No code changes required. To adopt the mockable clock pattern, take a C: Clock (or &dyn Clock, or Arc<dyn Clock>) as a dependency wherever you call clock_lib::now() today, and pass SystemClock in production. Your tests can then swap to ManualClock and drop every thread::sleep.
What's Next
- 0.4.0 — performance verification. Criterion benchmarks for reading latency on both
SystemClockandManualClock, with committed baselines proving zero overhead over rawstd::time. - 0.5.0 —
no_stdhardening and the 1.0 release candidate.
Full Changelog: v0.2.1...v0.3.0