1use std::{
19 collections::{BTreeMap, BinaryHeap},
20 ops::Deref,
21 sync::Arc,
22};
23
24use nautilus_core::{
25 AtomicTime, DurationNanos, UUID4, UnixNanos, correctness::check_predicate_true,
26 string::formatting::Separable,
27};
28use ustr::Ustr;
29
30use super::{
31 CallbackRegistry, Clock, replace_existing_timer, validate_and_prepare_schedule,
32 validate_and_prepare_time_alert, validate_and_prepare_timer,
33};
34use crate::timer::{
35 ScheduledTimeEvent, TimeEvent, TimeEventCallback, TimeEventHandler, TimerInterval,
36 TimerSchedule, VirtualTimer, create_valid_interval,
37};
38
39#[derive(Debug)]
48pub struct VirtualClock {
49 time: AtomicTime,
50 timers: BTreeMap<Ustr, VirtualTimer>,
51 pub(super) timer_queue: BinaryHeap<ScheduledTimeEvent>,
52 callbacks: CallbackRegistry,
53}
54
55impl VirtualClock {
56 #[must_use]
58 pub fn new() -> Self {
59 Self {
60 time: AtomicTime::new(false, UnixNanos::default()),
61 timers: BTreeMap::new(),
62 timer_queue: BinaryHeap::new(),
63 callbacks: CallbackRegistry::new(),
64 }
65 }
66
67 pub fn advance_time(&mut self, to_time_ns: UnixNanos, set_time: bool) -> Vec<TimeEvent> {
81 const WARN_TIME_EVENTS_THRESHOLD: usize = 1_000_000;
82
83 let from_time_ns = self.time.get_time_ns();
84
85 assert!(
86 to_time_ns >= from_time_ns,
87 "Invariant: time must be non-decreasing, `to_time_ns` {to_time_ns} < `from_time_ns` {from_time_ns}"
88 );
89
90 if set_time {
91 self.time.set_time(to_time_ns);
92 }
93
94 let mut events: Vec<TimeEvent> = Vec::new();
95
96 while self
97 .timer_queue
98 .peek()
99 .is_some_and(|entry| entry.0.ts_event <= to_time_ns)
100 {
101 let entry = self
102 .timer_queue
103 .pop()
104 .expect("timer queue peeked Some but pop returned None");
105
106 let Some((event, next_event)) = self.advance_timer_from_entry(&entry.0) else {
107 continue;
108 };
109
110 events.push(event);
111
112 if let Some(next_event) = next_event {
113 self.timer_queue.push(next_event);
114 }
115 }
116
117 self.compact_timer_queue_if_needed();
118
119 if events.len() >= WARN_TIME_EVENTS_THRESHOLD {
120 log::warn!(
121 "Allocated {} time events during clock advancement from {} to {}, \
122 consider stopping the timer between large time ranges with no data points",
123 events.len().separate_with_commas(),
124 from_time_ns,
125 to_time_ns
126 );
127 }
128
129 events.sort_by(|a, b| {
130 a.ts_event
131 .cmp(&b.ts_event)
132 .then_with(|| a.name.cmp(&b.name))
133 });
134
135 events
136 }
137
138 #[must_use]
146 pub fn match_handlers(&self, events: Vec<TimeEvent>) -> Vec<TimeEventHandler> {
147 events
148 .into_iter()
149 .map(|event| self.callbacks.get_handler(event))
150 .collect()
151 }
152
153 fn replace_existing_timer_if_needed(&mut self, name: &Ustr) {
154 replace_existing_timer(&mut self.timers, name);
155 self.compact_timer_queue_if_needed();
156 }
157
158 fn insert_timer(&mut self, timer: VirtualTimer) {
159 self.timer_queue.push(Self::scheduled_event(&timer));
160 self.timers.insert(timer.name, timer);
161 self.compact_timer_queue_if_needed();
162 }
163
164 fn advance_timer_from_entry(
165 &mut self,
166 entry: &TimeEvent,
167 ) -> Option<(TimeEvent, Option<ScheduledTimeEvent>)> {
168 let timer = self.timers.get_mut(&entry.name)?;
169 if timer.next_time_ns() != entry.ts_event {
170 return None;
171 }
172
173 let Some((event, _)) = timer.next() else {
174 self.timers.remove(&entry.name);
175 return None;
176 };
177
178 let next_entry = if timer.is_expired() {
179 self.timers.remove(&entry.name);
180 None
181 } else {
182 Some(Self::scheduled_event(timer))
183 };
184
185 Some((event, next_entry))
186 }
187
188 fn compact_timer_queue_if_needed(&mut self) {
189 if self.timer_queue.len() > self.timers.len().saturating_mul(2) {
190 self.compact_timer_queue();
191 }
192 }
193
194 fn compact_timer_queue(&mut self) {
195 self.timer_queue = self.timers.values().map(Self::scheduled_event).collect();
196 }
197
198 fn scheduled_event(timer: &VirtualTimer) -> ScheduledTimeEvent {
199 ScheduledTimeEvent::new(TimeEvent::new(
200 timer.name,
201 UUID4::new(),
202 timer.next_time_ns(),
203 timer.next_time_ns(),
204 ))
205 }
206 fn register_timer(
207 &mut self,
208 name: Ustr,
209 interval: TimerInterval,
210 start_time_ns: UnixNanos,
211 stop_time_ns: Option<UnixNanos>,
212 callback: Option<TimeEventCallback>,
213 fire_immediately: bool,
214 ) -> anyhow::Result<()> {
215 check_predicate_true(
216 callback.is_some() | self.callbacks.has_any_callback(&name),
217 "No callbacks provided",
218 )?;
219
220 self.replace_existing_timer_if_needed(&name);
221 if let Some(callback) = callback {
222 self.callbacks.register_callback(name, callback);
223 }
224
225 let timer = VirtualTimer::new(
226 name,
227 interval,
228 start_time_ns,
229 stop_time_ns,
230 fire_immediately,
231 );
232 self.insert_timer(timer);
233
234 Ok(())
235 }
236}
237
238impl Default for VirtualClock {
239 fn default() -> Self {
241 Self::new()
242 }
243}
244
245impl Deref for VirtualClock {
246 type Target = AtomicTime;
247
248 fn deref(&self) -> &Self::Target {
249 &self.time
250 }
251}
252
253impl Clock for VirtualClock {
254 fn timestamp_ns(&self) -> UnixNanos {
255 self.time.get_time_ns()
256 }
257
258 fn timestamp_us(&self) -> u64 {
259 self.time.get_time_us()
260 }
261
262 fn timestamp_ms(&self) -> u64 {
263 self.time.get_time_ms()
264 }
265
266 fn timestamp(&self) -> f64 {
267 self.time.get_time()
268 }
269
270 fn timer_names(&self) -> Vec<&str> {
271 self.timers
272 .iter()
273 .filter(|(_, timer)| !timer.is_expired())
274 .map(|(k, _)| k.as_str())
275 .collect()
276 }
277
278 fn timer_count(&self) -> usize {
279 self.timers
280 .iter()
281 .filter(|(_, timer)| !timer.is_expired())
282 .count()
283 }
284
285 fn timer_exists(&self, name: &Ustr) -> bool {
286 self.timers
287 .get(name)
288 .is_some_and(|timer| !timer.is_expired())
289 }
290
291 fn register_default_handler(&mut self, callback: TimeEventCallback) {
292 self.callbacks.register_default_handler(callback);
293 }
294
295 fn cancel_default_handler(&mut self) {
296 self.callbacks.cancel_default_handler();
297 }
298
299 fn cancel_callbacks(&mut self) {
300 self.callbacks.clear();
301 }
302
303 fn set_time_alert_ns(
304 &mut self,
305 name: &str,
306 alert_time_ns: UnixNanos,
307 callback: Option<TimeEventCallback>,
308 allow_past: Option<bool>,
309 ) -> anyhow::Result<()> {
310 let ts_now = self.get_time_ns();
311 let (name, alert_time_ns) =
312 validate_and_prepare_time_alert(name, alert_time_ns, allow_past, ts_now)?;
313
314 check_predicate_true(
315 callback.is_some() | self.callbacks.has_any_callback(&name),
316 "No callbacks provided",
317 )?;
318
319 self.replace_existing_timer_if_needed(&name);
320
321 if let Some(callback) = callback {
322 self.callbacks.register_callback(name, callback);
323 }
324
325 let interval_ns = create_valid_interval(alert_time_ns - ts_now);
327 let fire_immediately = alert_time_ns == ts_now;
328
329 let timer = VirtualTimer::new(
330 name,
331 interval_ns,
332 ts_now,
333 Some(alert_time_ns),
334 fire_immediately,
335 );
336 self.insert_timer(timer);
337
338 Ok(())
339 }
340
341 fn set_timer_ns(
342 &mut self,
343 name: &str,
344 interval_ns: DurationNanos,
345 start_time_ns: Option<UnixNanos>,
346 stop_time_ns: Option<UnixNanos>,
347 callback: Option<TimeEventCallback>,
348 allow_past: Option<bool>,
349 fire_immediately: Option<bool>,
350 ) -> anyhow::Result<()> {
351 let (name, start_time_ns, stop_time_ns, _, fire_immediately) = validate_and_prepare_timer(
352 name,
353 interval_ns,
354 start_time_ns,
355 stop_time_ns,
356 allow_past,
357 fire_immediately,
358 self.get_time_ns(),
359 )?;
360 self.register_timer(
361 name,
362 TimerInterval::Fixed(create_valid_interval(interval_ns)),
363 start_time_ns,
364 stop_time_ns,
365 callback,
366 fire_immediately,
367 )
368 }
369
370 fn set_timer_schedule(
371 &mut self,
372 name: &str,
373 schedule: Arc<dyn TimerSchedule>,
374 stop_time_ns: Option<UnixNanos>,
375 callback: Option<TimeEventCallback>,
376 allow_past: Option<bool>,
377 fire_immediately: Option<bool>,
378 ) -> anyhow::Result<()> {
379 let start_time_ns = schedule.start_time_ns();
380 let interval = TimerInterval::Schedule(schedule);
381 let (name, start_time_ns, stop_time_ns, _, fire_immediately) =
382 validate_and_prepare_schedule(
383 name,
384 &interval,
385 Some(start_time_ns),
386 stop_time_ns,
387 allow_past,
388 fire_immediately,
389 self.get_time_ns(),
390 )?;
391 self.register_timer(
392 name,
393 interval,
394 start_time_ns,
395 stop_time_ns,
396 callback,
397 fire_immediately,
398 )
399 }
400
401 fn next_time_ns(&self, name: &str) -> Option<UnixNanos> {
402 self.timers
403 .get(&Ustr::from(name))
404 .filter(|timer| !timer.is_expired())
405 .map(VirtualTimer::next_time_ns)
406 }
407
408 fn cancel_timer(&mut self, name: &str) {
409 let timer = self.timers.remove(&Ustr::from(name));
410 if let Some(mut timer) = timer {
411 timer.cancel();
412 }
413
414 self.compact_timer_queue_if_needed();
415 }
416
417 fn cancel_timers(&mut self) {
418 for timer in &mut self.timers.values_mut() {
419 timer.cancel();
420 }
421
422 self.timers.clear();
423 self.timer_queue.clear();
424 }
425
426 fn reset(&mut self) {
427 self.time = AtomicTime::new(false, UnixNanos::default());
428 self.timers = BTreeMap::new();
429 self.timer_queue = BinaryHeap::new();
430 self.callbacks.clear();
431 }
432}