Now let's take a silly one
1use std::sync::Arc;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::time::{SystemTime, UNIX_EPOCH};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct UnixMicros(u64);
7
8impl UnixMicros {
9 pub const fn new(micros: u64) -> Self {
10 Self(micros)
11 }
12
13 pub const fn get(self) -> u64 {
14 self.0
15 }
16}
17
18pub trait Clock: Send + Sync + 'static {
19 fn now_unix_micros(&self) -> UnixMicros;
20}
21
22impl<T: Clock + ?Sized> Clock for Arc<T> {
23 fn now_unix_micros(&self) -> UnixMicros {
24 (**self).now_unix_micros()
25 }
26}
27
28pub struct SystemClock;
29
30impl Clock for SystemClock {
31 fn now_unix_micros(&self) -> UnixMicros {
32 let micros = SystemTime::now()
33 .duration_since(UNIX_EPOCH)
34 .map(|elapsed| elapsed.as_micros() as u64)
35 .unwrap_or(0);
36 UnixMicros::new(micros)
37 }
38}
39
40pub struct ManualClock {
41 micros: AtomicU64,
42}
43
44impl ManualClock {
45 pub fn new(start: UnixMicros) -> Self {
46 Self {
47 micros: AtomicU64::new(start.get()),
48 }
49 }
50
51 pub fn advance(&self, micros: u64) {
52 self.micros.fetch_add(micros, Ordering::SeqCst);
53 }
54}
55
56impl Clock for ManualClock {
57 fn now_unix_micros(&self) -> UnixMicros {
58 UnixMicros::new(self.micros.load(Ordering::SeqCst))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn manual_clock_advances() {
68 let clock = ManualClock::new(UnixMicros::new(1_000));
69 assert_eq!(clock.now_unix_micros().get(), 1_000);
70 clock.advance(500);
71 assert_eq!(clock.now_unix_micros().get(), 1_500);
72 }
73
74 #[test]
75 fn manual_clock_same_start_same_sequence() {
76 let one = ManualClock::new(UnixMicros::new(1_000));
77 let two = ManualClock::new(UnixMicros::new(1_000));
78 let advances = [10, 250, 7, 1_000];
79 advances.iter().for_each(|&step| {
80 one.advance(step);
81 two.advance(step);
82 assert_eq!(one.now_unix_micros(), two.now_unix_micros());
83 });
84 }
85
86 #[test]
87 fn system_clock_is_after_epoch() {
88 assert!(SystemClock.now_unix_micros().get() > 0);
89 }
90
91 #[test]
92 fn a_shared_clock_advances_through_the_trait_object() {
93 let shared = Arc::new(ManualClock::new(UnixMicros::new(1_000)));
94 let view: Arc<dyn Clock> = Arc::clone(&shared) as Arc<dyn Clock>;
95 assert_eq!(view.now_unix_micros().get(), 1_000);
96 shared.advance(250);
97 assert_eq!(view.now_unix_micros().get(), 1_250);
98 }
99}