1use std::fmt::Debug;
6use std::sync::Arc;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10pub trait Clock: Send + Sync + 'static + Debug {
11 fn now(&self) -> u64;
12}
13
14#[derive(Debug, Default)]
15pub struct SystemClock;
16
17impl Clock for SystemClock {
18 fn now(&self) -> u64 {
19 SystemTime::now()
20 .duration_since(UNIX_EPOCH)
21 .unwrap_or_default()
22 .as_secs()
23 }
24}
25
26impl<T: Clock> Clock for Arc<T> {
27 fn now(&self) -> u64 {
28 T::now(&**self)
29 }
30}
31
32#[derive(Debug)]
33pub struct ManualClock {
34 now: AtomicU64,
35}
36
37impl ManualClock {
38 pub fn new(init_unix: u64) -> Self {
39 Self {
40 now: AtomicU64::new(init_unix),
41 }
42 }
43
44 pub fn set(&self, unix: u64) {
45 self.now.store(unix, Ordering::Relaxed);
46 }
47
48 pub fn advance(&self, secs: u64) {
49 self.now.fetch_add(secs, Ordering::Relaxed);
50 }
51}
52
53impl Clock for ManualClock {
54 fn now(&self) -> u64 {
55 self.now.load(Ordering::Relaxed)
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn manual_clock_new_returns_initial_time() {
65 let c = ManualClock::new(0);
66 assert_eq!(c.now(), 0);
67 }
68
69 #[test]
70 fn manual_clock_set_overwrites_time() {
71 let c = ManualClock::new(10);
72
73 c.set(999);
74 assert_eq!(c.now(), 999);
75
76 c.set(0);
77 assert_eq!(c.now(), 0);
78 }
79
80 #[test]
81 fn manual_clock_advance_increases_time() {
82 let c = ManualClock::new(100);
83
84 c.advance(5);
85 assert_eq!(c.now(), 105);
86
87 c.advance(10);
88 assert_eq!(c.now(), 115);
89 }
90
91 #[test]
92 fn manual_clock_advance_zero_is_noop() {
93 let c = ManualClock::new(42);
94 c.advance(0);
95 assert_eq!(c.now(), 42);
96 }
97
98 #[test]
99 fn system_clock_now_is_non_decreasing() {
100 let c = SystemClock::default();
101
102 let t1 = c.now();
103 let t2 = c.now();
104
105 assert!(t2 >= t1, "expected t2 >= t1, got t1={t1}, t2={t2}");
106 }
107
108 #[test]
109 fn arc_clock_delegates_to_inner_clock() {
110 let c: Arc<ManualClock> = Arc::new(ManualClock::new(7));
111 assert_eq!(c.now(), 7);
112 }
113
114 #[test]
115 fn clock_trait_objects_work_for_manual_clock() {
116 let c: Box<dyn Clock> = Box::new(ManualClock::new(7));
117 assert_eq!(c.now(), 7);
118 }
119}