1use crate::timestamp::Timestamp;
4use crate::timestamp::TimestampDelta;
5use std::fmt;
6
7pub trait Clock: Send + Sync {
9 fn now(&self) -> Timestamp;
10 fn clone_box(&self) -> Box<dyn Clock>;
11}
12
13#[derive(Clone, Debug)]
15pub struct SystemClock;
16
17impl Clock for SystemClock {
18 fn now(&self) -> Timestamp {
19 Timestamp::from(chrono::Utc::now())
21 }
22 fn clone_box(&self) -> Box<dyn Clock> {
23 Box::new(self.clone())
24 }
25}
26
27use std::sync::{Arc, Mutex};
28
29#[derive(Clone, Debug, Default)]
31pub struct ManualClock {
32 current_time: Arc<Mutex<Timestamp>>,
33}
34
35impl ManualClock {
36 pub fn new() -> Self {
37 let zero_time = Timestamp::zero();
38 Self {
39 current_time: Arc::new(Mutex::new(zero_time)),
40 }
41 }
42
43 pub fn advance_by(&self, duration: TimestampDelta) {
44 assert!(duration > TimestampDelta::zero());
45 let mut time = self.current_time.lock().unwrap();
46 *time = *time + duration;
47 }
48
49 pub fn advance_to(&self, time: Timestamp) {
50 let mut current_time = self.current_time.lock().unwrap();
51 *current_time = time;
52 }
53}
54
55impl Clock for ManualClock {
56 fn now(&self) -> Timestamp {
57 *self.current_time.lock().unwrap()
58 }
59
60 fn clone_box(&self) -> Box<dyn Clock> {
61 Box::new(self.clone())
62 }
63}
64
65#[cfg(test)]
66pub mod tests {
67 use super::*;
68
69 #[test]
70 fn advance_time_in_mocked_time_provider() {
71 struct Component {
72 times: Vec<Timestamp>,
73 provider: Box<dyn Clock>,
74 }
75
76 impl Component {
77 fn new(provider: Box<dyn Clock>) -> Self {
78 Self {
79 times: Vec::new(),
80 provider,
81 }
82 }
83 fn append_now(&mut self) {
84 self.times.push(self.provider.now());
85 }
86 }
87
88 let clock = ManualClock::new();
89 let mut a = Component::new(clock.clone_box());
90 let mut b = Component::new(clock.clone_box());
91
92 a.append_now(); clock.advance_by(TimestampDelta::from_secs(1)); a.append_now(); b.append_now(); clock.advance_by(TimestampDelta::from_secs(2)); a.append_now(); clock.advance_by(TimestampDelta::from_secs(1)); a.append_now(); b.append_now(); assert_eq!(
103 a.times.iter().map(|t| t.as_secs()).collect::<Vec<_>>(),
104 vec![0, 1, 3, 4]
105 );
106 assert_eq!(
107 b.times.iter().map(|t| t.as_secs()).collect::<Vec<_>>(),
108 vec![1, 4]
109 );
110 }
111
112 #[test]
113 fn advance_time_across_threads_simplified() {
114 use std::sync::{mpsc::sync_channel, Arc, Barrier};
115
116 let clock = ManualClock::new();
117 let worker_count = 4;
118 let steps = 4;
119
120 let barrier = Arc::new(Barrier::new(worker_count + 1));
123 let (sender, receiver) = sync_channel(worker_count);
124 for _ in 0..worker_count {
125 let clock = clock.clone_box();
126 let barrier = barrier.clone();
127 let sender = sender.clone();
128
129 std::thread::spawn(move || {
130 let mut times = Vec::with_capacity(steps);
131 for _ in 0..steps {
132 barrier.wait(); times.push(clock.now()); barrier.wait(); }
136 sender.send(times).unwrap();
137 });
138 }
139
140 for _ in 0..steps {
141 clock.advance_by(TimestampDelta::from_secs(1));
142 barrier.wait(); barrier.wait(); }
145
146 let results: Vec<Vec<Timestamp>> = (0..worker_count)
148 .map(|_| receiver.recv().unwrap().into_iter().collect())
149 .collect();
150
151 for res in results {
152 assert_eq!(
153 res,
154 (1..steps + 1)
155 .map(|i| Timestamp::from_secs(i as i64))
156 .collect::<Vec<_>>(),
157 "All thread components should show consistent time steps"
158 );
159 }
160 }
161}
162
163pub struct Stopwatch {
165 clock: Box<dyn Clock>,
166 start_time: Timestamp,
167}
168
169impl fmt::Debug for Stopwatch {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.debug_struct("Stopwatch")
172 .field("clock", &self.clock.now()) .field("start_time", &self.start_time)
174 .finish()
175 }
176}
177
178impl Stopwatch {
179 pub fn new(clock: Box<dyn Clock>) -> Self {
180 Self {
181 start_time: clock.now(),
182 clock,
183 }
184 }
185
186 pub fn elapsed(&self) -> TimestampDelta {
187 self.clock.now() - self.start_time
188 }
189
190 pub fn reset(&mut self) {
191 self.start_time = self.clock.now();
192 }
193}
194
195#[derive(Debug)]
197pub struct Timer {
198 stopwatch: Stopwatch,
199 delay: TimestampDelta,
200}
201
202impl Timer {
203 pub fn new(clock: Box<dyn Clock>, delay: TimestampDelta) -> Self {
204 Self {
205 delay,
206 stopwatch: Stopwatch::new(clock),
207 }
208 }
209
210 pub fn is_timeout(&self) -> bool {
211 self.stopwatch.elapsed() >= self.delay
212 }
213
214 pub fn elapsed(&self) -> TimestampDelta {
215 self.stopwatch.elapsed()
216 }
217
218 pub fn reset(&mut self) {
219 self.stopwatch.reset();
220 }
221}