1use std::sync::Arc;
4use std::time::{Instant, SystemTime, UNIX_EPOCH};
5
6pub type SharedClock = Arc<dyn Clock>;
8
9pub trait Clock: Send + Sync {
14 fn monotonic_millis(&self) -> u64;
16
17 fn epoch_seconds(&self) -> u64;
19}
20
21#[derive(Debug)]
23pub struct SystemClock {
24 started_at: Instant,
25}
26
27impl Default for SystemClock {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl SystemClock {
34 #[must_use]
36 pub fn new() -> Self {
37 Self {
38 started_at: Instant::now(),
39 }
40 }
41}
42
43impl Clock for SystemClock {
44 fn monotonic_millis(&self) -> u64 {
45 u64::try_from(self.started_at.elapsed().as_millis()).unwrap_or(u64::MAX)
46 }
47
48 fn epoch_seconds(&self) -> u64 {
49 SystemTime::now()
50 .duration_since(UNIX_EPOCH)
51 .ok()
52 .map_or(0, |duration| duration.as_secs())
53 }
54}
55
56#[derive(Debug, Clone)]
58pub struct FixedClock {
59 epoch_seconds: u64,
60 monotonic_millis: u64,
61}
62
63impl FixedClock {
64 #[must_use]
66 pub const fn new(epoch_seconds: u64, monotonic_millis: u64) -> Self {
67 Self {
68 epoch_seconds,
69 monotonic_millis,
70 }
71 }
72}
73
74impl Clock for FixedClock {
75 fn monotonic_millis(&self) -> u64 {
76 self.monotonic_millis
77 }
78
79 fn epoch_seconds(&self) -> u64 {
80 self.epoch_seconds
81 }
82}
83
84#[must_use]
86pub fn system_clock() -> SharedClock {
87 Arc::new(SystemClock::new())
88}
89
90#[cfg(test)]
91mod tests {
92 use super::{Clock, FixedClock};
93
94 #[test]
95 fn fixed_clock_returns_injected_values() {
96 let clock = FixedClock::new(1_700_000_000, 42);
97
98 assert_eq!(clock.epoch_seconds(), 1_700_000_000);
99 assert_eq!(clock.monotonic_millis(), 42);
100 }
101}