clawft_kernel/
mesh_clock.rs1use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::Arc;
10use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17pub struct MonoTime {
18 nanos: u64,
19}
20
21impl MonoTime {
22 pub const fn from_nanos(nanos: u64) -> Self {
24 Self { nanos }
25 }
26
27 pub const fn as_nanos(self) -> u64 {
29 self.nanos
30 }
31
32 pub fn duration_since(self, earlier: Self) -> Duration {
34 Duration::from_nanos(self.nanos.saturating_sub(earlier.nanos))
35 }
36
37 pub fn elapsed_since(self, earlier: Self) -> Duration {
39 self.duration_since(earlier)
40 }
41}
42
43pub trait Clock: Send + Sync + 'static {
54 fn now(&self) -> MonoTime;
56
57 fn unix_time_us(&self) -> u64;
59}
60
61#[derive(Debug, Clone, Copy, Default)]
63pub struct RealClock;
64
65impl RealClock {
66 pub const fn new() -> Self {
68 Self
69 }
70
71 pub fn shared() -> Arc<dyn Clock> {
73 Arc::new(Self)
74 }
75}
76
77impl Clock for RealClock {
78 fn now(&self) -> MonoTime {
79 static ORIGIN: std::sync::OnceLock<Instant> = std::sync::OnceLock::new();
81 let origin = ORIGIN.get_or_init(Instant::now);
82 MonoTime::from_nanos(origin.elapsed().as_nanos() as u64)
83 }
84
85 fn unix_time_us(&self) -> u64 {
86 SystemTime::now()
87 .duration_since(UNIX_EPOCH)
88 .unwrap_or_default()
89 .as_micros() as u64
90 }
91}
92
93#[derive(Debug, Clone)]
97pub struct MockClock {
98 mono_nanos: Arc<AtomicU64>,
99 unix_us: Arc<AtomicU64>,
100}
101
102impl MockClock {
103 pub fn new() -> Self {
105 Self {
106 mono_nanos: Arc::new(AtomicU64::new(0)),
107 unix_us: Arc::new(AtomicU64::new(0)),
108 }
109 }
110
111 pub fn with_unix_us(unix_us: u64) -> Self {
113 Self {
114 mono_nanos: Arc::new(AtomicU64::new(0)),
115 unix_us: Arc::new(AtomicU64::new(unix_us)),
116 }
117 }
118
119 pub fn advance(&self, duration: Duration) {
121 let nanos = duration.as_nanos() as u64;
122 let us = duration.as_micros() as u64;
123 self.mono_nanos.fetch_add(nanos, Ordering::SeqCst);
124 self.unix_us.fetch_add(us, Ordering::SeqCst);
125 }
126
127 pub fn set_mono_nanos(&self, nanos: u64) {
129 self.mono_nanos.store(nanos, Ordering::SeqCst);
130 }
131
132 pub fn set_unix_us(&self, us: u64) {
134 self.unix_us.store(us, Ordering::SeqCst);
135 }
136
137 pub fn shared(self) -> Arc<dyn Clock> {
139 Arc::new(self)
140 }
141}
142
143impl Default for MockClock {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149impl Clock for MockClock {
150 fn now(&self) -> MonoTime {
151 MonoTime::from_nanos(self.mono_nanos.load(Ordering::SeqCst))
152 }
153
154 fn unix_time_us(&self) -> u64 {
155 self.unix_us.load(Ordering::SeqCst)
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn mono_time_duration_since_saturating() {
165 let a = MonoTime::from_nanos(1_000);
166 let b = MonoTime::from_nanos(3_000);
167 assert_eq!(b.duration_since(a), Duration::from_nanos(2_000));
168 assert_eq!(a.duration_since(b), Duration::from_nanos(0));
169 }
170
171 #[test]
172 fn mock_clock_advance() {
173 let clock = MockClock::new();
174 assert_eq!(clock.now().as_nanos(), 0);
175 assert_eq!(clock.unix_time_us(), 0);
176 clock.advance(Duration::from_millis(500));
177 assert_eq!(clock.now().as_nanos(), 500_000_000);
178 assert_eq!(clock.unix_time_us(), 500_000);
179 }
180
181 #[test]
182 fn real_clock_unix_plausible() {
183 let t = RealClock.unix_time_us();
184 assert!(t > 1_577_836_800_000_000);
186 assert!(t < 2_524_608_000_000_000);
187 }
188
189 #[test]
190 fn real_clock_mono_advances() {
191 let c = RealClock;
192 let a = c.now();
193 let b = c.now();
194 assert!(b >= a);
195 }
196}