1use std::{collections::BTreeMap, ops::Deref, sync::Arc};
19
20use nautilus_core::{
21 AtomicTime, DurationNanos, UnixNanos, correctness::check_predicate_true,
22 time::get_atomic_clock_realtime,
23};
24use ustr::Ustr;
25
26use super::timer::LiveTimer;
27use crate::{
28 clock::{
29 CallbackRegistry, Clock, replace_existing_timer, validate_and_prepare_schedule,
30 validate_and_prepare_time_alert, validate_and_prepare_timer,
31 },
32 runner::{TimeEventSender, purge_closed_time_event_callbacks, try_get_time_event_sender},
33 timer::{TimeEventCallback, TimerInterval, TimerSchedule, create_valid_interval},
34};
35
36#[derive(Debug)]
44pub struct LiveClock {
45 time: &'static AtomicTime,
46 timers: BTreeMap<Ustr, LiveTimer>,
47 callbacks: CallbackRegistry,
48 sender: Option<Arc<dyn TimeEventSender>>,
49 sender_deferred: bool,
50}
51
52impl LiveClock {
53 #[must_use]
55 pub fn new(sender: Option<Arc<dyn TimeEventSender>>) -> Self {
56 Self {
57 time: get_atomic_clock_realtime(),
58 timers: BTreeMap::new(),
59 callbacks: CallbackRegistry::new(),
60 sender,
61 sender_deferred: false,
62 }
63 }
64
65 fn clear_expired_timers(&mut self) {
66 self.timers.retain(|_, timer| !timer.is_expired());
67 purge_closed_time_event_callbacks();
68 }
69
70 fn replace_existing_timer_if_needed(&mut self, name: &Ustr) {
71 replace_existing_timer(&mut self.timers, name);
72 }
73 fn register_timer(
74 &mut self,
75 name: Ustr,
76 interval: TimerInterval,
77 start_time_ns: UnixNanos,
78 stop_time_ns: Option<UnixNanos>,
79 callback: Option<TimeEventCallback>,
80 fire_immediately: bool,
81 ) -> anyhow::Result<()> {
82 check_predicate_true(
83 callback.is_some() | self.callbacks.has_any_callback(&name),
84 "No callbacks provided",
85 )?;
86
87 self.replace_existing_timer_if_needed(&name);
88 let callback = if let Some(callback) = callback {
89 self.callbacks.register_callback(name, callback.clone());
90 callback
91 } else {
92 self.callbacks
93 .get_callback(&name)
94 .expect("Callback should exist")
95 };
96
97 let sender = self.resolve_time_event_sender();
98
99 let mut timer = LiveTimer::new(
100 name,
101 interval,
102 start_time_ns,
103 stop_time_ns,
104 callback,
105 fire_immediately,
106 sender,
107 );
108 timer.start();
109
110 self.clear_expired_timers();
111 self.timers.insert(name, timer);
112
113 Ok(())
114 }
115}
116
117impl Default for LiveClock {
118 fn default() -> Self {
122 let mut clock = Self::new(try_get_time_event_sender());
123 clock.sender_deferred = clock.sender.is_none();
124 clock
125 }
126}
127
128impl Deref for LiveClock {
129 type Target = AtomicTime;
130
131 fn deref(&self) -> &Self::Target {
132 self.time
133 }
134}
135
136impl Clock for LiveClock {
137 fn timestamp_ns(&self) -> UnixNanos {
138 self.time.get_time_ns()
139 }
140
141 fn timestamp_us(&self) -> u64 {
142 self.time.get_time_us()
143 }
144
145 fn timestamp_ms(&self) -> u64 {
146 self.time.get_time_ms()
147 }
148
149 fn timestamp(&self) -> f64 {
150 self.time.get_time()
151 }
152
153 fn timer_names(&self) -> Vec<&str> {
154 self.timers
155 .iter()
156 .filter(|(_, timer)| !timer.is_expired())
157 .map(|(k, _)| k.as_str())
158 .collect()
159 }
160
161 fn timer_count(&self) -> usize {
162 self.timers
163 .iter()
164 .filter(|(_, timer)| !timer.is_expired())
165 .count()
166 }
167
168 fn timer_exists(&self, name: &Ustr) -> bool {
169 self.timers
170 .get(name)
171 .is_some_and(|timer| !timer.is_expired())
172 }
173
174 fn register_default_handler(&mut self, handler: TimeEventCallback) {
175 self.callbacks.register_default_handler(handler);
176 }
177
178 fn cancel_default_handler(&mut self) {
179 self.callbacks.cancel_default_handler();
180 }
181
182 fn cancel_callbacks(&mut self) {
183 self.callbacks.clear();
184 }
185
186 fn set_time_alert_ns(
187 &mut self,
188 name: &str,
189 alert_time_ns: UnixNanos,
190 callback: Option<TimeEventCallback>,
191 allow_past: Option<bool>,
192 ) -> anyhow::Result<()> {
193 let ts_now = self.get_time_ns();
194 let (name, alert_time_ns) =
195 validate_and_prepare_time_alert(name, alert_time_ns, allow_past, ts_now)?;
196
197 check_predicate_true(
198 callback.is_some() | self.callbacks.has_any_callback(&name),
199 "No callbacks provided",
200 )?;
201
202 self.replace_existing_timer_if_needed(&name);
203
204 let callback = if let Some(callback) = callback {
205 self.callbacks.register_callback(name, callback.clone());
206 callback
207 } else {
208 self.callbacks
209 .get_callback(&name)
210 .expect("Callback should exist")
211 };
212
213 let interval_ns = create_valid_interval(alert_time_ns - ts_now);
215 let fire_immediately = alert_time_ns == ts_now;
216 let sender = self.resolve_time_event_sender();
217
218 let mut timer = LiveTimer::new(
219 name,
220 interval_ns,
221 ts_now,
222 Some(alert_time_ns),
223 callback,
224 fire_immediately,
225 sender,
226 );
227
228 timer.start();
229
230 self.clear_expired_timers();
231 self.timers.insert(name, timer);
232
233 Ok(())
234 }
235
236 fn set_timer_ns(
237 &mut self,
238 name: &str,
239 interval_ns: DurationNanos,
240 start_time_ns: Option<UnixNanos>,
241 stop_time_ns: Option<UnixNanos>,
242 callback: Option<TimeEventCallback>,
243 allow_past: Option<bool>,
244 fire_immediately: Option<bool>,
245 ) -> anyhow::Result<()> {
246 let (name, start_time_ns, stop_time_ns, _, fire_immediately) = validate_and_prepare_timer(
247 name,
248 interval_ns,
249 start_time_ns,
250 stop_time_ns,
251 allow_past,
252 fire_immediately,
253 self.get_time_ns(),
254 )?;
255 self.register_timer(
256 name,
257 TimerInterval::Fixed(create_valid_interval(interval_ns)),
258 start_time_ns,
259 stop_time_ns,
260 callback,
261 fire_immediately,
262 )
263 }
264
265 fn set_timer_schedule(
266 &mut self,
267 name: &str,
268 schedule: Arc<dyn TimerSchedule>,
269 stop_time_ns: Option<UnixNanos>,
270 callback: Option<TimeEventCallback>,
271 allow_past: Option<bool>,
272 fire_immediately: Option<bool>,
273 ) -> anyhow::Result<()> {
274 let start_time_ns = schedule.start_time_ns();
275 let interval = TimerInterval::Schedule(schedule);
276 let (name, start_time_ns, stop_time_ns, _, fire_immediately) =
277 validate_and_prepare_schedule(
278 name,
279 &interval,
280 Some(start_time_ns),
281 stop_time_ns,
282 allow_past,
283 fire_immediately,
284 self.get_time_ns(),
285 )?;
286 self.register_timer(
287 name,
288 interval,
289 start_time_ns,
290 stop_time_ns,
291 callback,
292 fire_immediately,
293 )
294 }
295
296 fn next_time_ns(&self, name: &str) -> Option<UnixNanos> {
297 self.timers
298 .get(&Ustr::from(name))
299 .filter(|timer| !timer.is_expired())
300 .map(LiveTimer::next_time_ns)
301 }
302
303 fn cancel_timer(&mut self, name: &str) {
304 let timer = self.timers.remove(&Ustr::from(name));
305 if let Some(mut timer) = timer {
306 timer.cancel();
307 }
308 }
309
310 fn cancel_timers(&mut self) {
311 for timer in &mut self.timers.values_mut() {
312 timer.cancel();
313 }
314
315 self.timers.clear();
316 }
317
318 fn reset(&mut self) {
319 self.cancel_timers();
320 self.callbacks.clear();
321 }
322}
323
324impl LiveClock {
325 fn resolve_time_event_sender(&mut self) -> Option<Arc<dyn TimeEventSender>> {
326 if self.sender.is_none() && self.sender_deferred {
327 self.sender = try_get_time_event_sender();
328 }
329
330 self.sender.clone()
331 }
332}
333
334#[cfg(test)]
335#[cfg(not(all(feature = "simulation", madsim)))]
336mod tests {
337 use std::{
338 sync::{
339 Arc,
340 atomic::{AtomicBool, Ordering},
341 mpsc,
342 },
343 time::Duration,
344 };
345
346 use nautilus_core::{DurationNanos, UnixNanos, time::get_atomic_clock_realtime};
347 use parking_lot::Mutex;
348 use rstest::rstest;
349 use ustr::Ustr;
350
351 use super::*;
352 use crate::{
353 calendar::CalendarSchedule,
354 clock::Clock,
355 runner::{TimeEventMessage, TimeEventSender, replace_time_event_sender},
356 testing::wait_until,
357 timer::{TimeEvent, TimeEventCallback},
358 };
359
360 #[derive(Debug)]
361 struct CollectingSender {
362 events: Arc<Mutex<Vec<(TimeEvent, UnixNanos)>>>,
363 }
364
365 impl CollectingSender {
366 fn new(events: Arc<Mutex<Vec<(TimeEvent, UnixNanos)>>>) -> Self {
367 Self { events }
368 }
369 }
370
371 impl TimeEventSender for CollectingSender {
372 fn send(&self, message: TimeEventMessage) {
373 let now_ns = get_atomic_clock_realtime().get_time_ns();
374 let event = message.event().clone();
375 message.dispatch();
376 self.events.lock().push((event, now_ns));
377 }
378 }
379
380 #[derive(Debug)]
381 struct PausingCollectingSender {
382 collector: CollectingSender,
383 paused_tx: mpsc::Sender<()>,
384 release_rx: Mutex<mpsc::Receiver<()>>,
385 pause_once: AtomicBool,
386 }
387
388 impl PausingCollectingSender {
389 fn new(
390 events: Arc<Mutex<Vec<(TimeEvent, UnixNanos)>>>,
391 ) -> (Arc<Self>, mpsc::Receiver<()>, mpsc::Sender<()>) {
392 let (paused_tx, paused_rx) = mpsc::channel();
393 let (release_tx, release_rx) = mpsc::channel();
394 let sender = Arc::new(Self {
395 collector: CollectingSender::new(events),
396 paused_tx,
397 release_rx: Mutex::new(release_rx),
398 pause_once: AtomicBool::new(true),
399 });
400 (sender, paused_rx, release_tx)
401 }
402 }
403
404 impl TimeEventSender for PausingCollectingSender {
405 fn send(&self, message: TimeEventMessage) {
406 self.collector.send(message);
407
408 if self.pause_once.swap(false, Ordering::SeqCst) {
409 self.paused_tx.send(()).expect("timer send should pause");
410 self.release_rx
411 .lock()
412 .recv()
413 .expect("timer send should release");
414 }
415 }
416 }
417
418 fn wait_for_events(
419 events: &Arc<Mutex<Vec<(TimeEvent, UnixNanos)>>>,
420 target: usize,
421 timeout: Duration,
422 ) {
423 wait_until(|| events.lock().len() >= target, timeout);
424 }
425
426 #[rstest]
427 fn test_live_clock_timer_replacement_cancels_previous_task() {
428 let events = Arc::new(Mutex::new(Vec::new()));
429 let (sender, paused_rx, release_tx) = PausingCollectingSender::new(Arc::clone(&events));
430
431 let mut clock = LiveClock::new(Some(sender));
432 clock.register_default_handler(TimeEventCallback::from(|_| {}));
433
434 let fast_interval = DurationNanos::from_millis(10);
435 clock
436 .set_timer_ns("replace", fast_interval, None, None, None, None, None)
437 .unwrap();
438
439 paused_rx
440 .recv_timeout(Duration::from_secs(2))
441 .expect("fast timer send should pause");
442 events.lock().clear();
443
444 let slow_interval = DurationNanos::from_millis(30);
445 clock
446 .set_timer_ns("replace", slow_interval, None, None, None, None, None)
447 .unwrap();
448 release_tx.send(()).expect("fast timer send should release");
449
450 wait_for_events(&events, 3, Duration::from_secs(2));
451
452 let snapshot = events.lock().clone();
453 let diffs: Vec<DurationNanos> = snapshot
454 .array_windows()
455 .map(|[a, b]| b.0.ts_event - a.0.ts_event)
456 .collect();
457
458 assert!(!diffs.is_empty());
459 for diff in diffs {
460 assert_eq!(diff, slow_interval);
461 }
462
463 clock.cancel_timers();
464 }
465
466 #[rstest]
467 fn test_live_clock_time_alert_persists_callback() {
468 let events = Arc::new(Mutex::new(Vec::new()));
469 let sender = Arc::new(CollectingSender::new(Arc::clone(&events)));
470
471 let mut clock = LiveClock::new(Some(sender));
472 clock.register_default_handler(TimeEventCallback::from(|_| {}));
473
474 let now = clock.timestamp_ns();
475 let alert_time = now + DurationNanos::from_mins(1);
476
477 clock
478 .set_time_alert_ns("alert-callback", alert_time, None, None)
479 .unwrap();
480
481 assert!(
482 clock
483 .callbacks
484 .has_any_callback(&Ustr::from("alert-callback"))
485 );
486
487 clock.cancel_timers();
488 }
489
490 #[rstest]
491 fn test_default_live_clock_resolves_sender_after_initialization() {
492 std::thread::spawn(|| {
493 let events = Arc::new(Mutex::new(Vec::new()));
494 let sender = Arc::new(CollectingSender::new(Arc::clone(&events)));
495 let mut clock = LiveClock::default();
496 assert!(clock.sender.is_none());
497
498 replace_time_event_sender(sender);
499 let mut explicit_senderless = LiveClock::new(None);
500 assert!(explicit_senderless.resolve_time_event_sender().is_none());
501
502 let alert_time = clock.timestamp_ns();
503 clock
504 .set_time_alert_ns(
505 "late-sender",
506 alert_time,
507 Some(TimeEventCallback::from(|_| {})),
508 None,
509 )
510 .unwrap();
511 wait_for_events(&events, 1, Duration::from_secs(2));
512
513 assert!(clock.sender.is_some());
514 let events = events.lock();
515 assert_eq!(events.len(), 1);
516 assert_eq!(events[0].0.name, Ustr::from("late-sender"));
517 })
518 .join()
519 .expect("live clock sender test thread should join");
520 }
521
522 #[rstest]
523 fn test_live_clock_reset_stops_active_timers() {
524 let events = Arc::new(Mutex::new(Vec::new()));
525 let (sender, paused_rx, release_tx) = PausingCollectingSender::new(Arc::clone(&events));
526
527 let mut clock = LiveClock::new(Some(sender.clone()));
528
529 clock
530 .set_timer_ns(
531 "reset-test",
532 DurationNanos::from_millis(15),
533 None,
534 None,
535 Some(TimeEventCallback::from(|_| {})),
536 None,
537 None,
538 )
539 .unwrap();
540
541 paused_rx
542 .recv_timeout(Duration::from_secs(2))
543 .expect("timer send should pause");
544
545 assert_eq!(events.lock().len(), 1);
546 assert_eq!(clock.timer_count(), 1);
547
548 clock.reset();
549 release_tx.send(()).expect("timer send should release");
550
551 wait_until(|| Arc::strong_count(&sender) == 2, Duration::from_secs(2));
553
554 assert_eq!(events.lock().len(), 1);
555 assert_eq!(clock.timer_count(), 0);
556 assert!(clock.timer_names().is_empty());
557 assert!(!clock.callbacks.has_any_callback(&Ustr::from("reset-test")));
558 }
559
560 #[rstest]
561 fn test_live_clock_timer_exists_consistent_after_expiry() {
562 let events = Arc::new(Mutex::new(Vec::new()));
563 let (sender, paused_rx, release_tx) = PausingCollectingSender::new(Arc::clone(&events));
564
565 let mut clock = LiveClock::new(Some(sender));
566 clock.register_default_handler(TimeEventCallback::from(|_| {}));
567
568 let name = Ustr::from("expiring");
569 let interval_ns = DurationNanos::from_millis(10);
570 let start_time = clock.timestamp_ns();
571 let stop_time = start_time + DurationNanos::from_millis(30);
572
573 clock
574 .set_timer_ns(
575 name.as_str(),
576 interval_ns,
577 Some(start_time),
578 Some(stop_time),
579 None,
580 None,
581 None,
582 )
583 .unwrap();
584
585 paused_rx
586 .recv_timeout(Duration::from_secs(2))
587 .expect("timer send should pause");
588
589 assert!(clock.timer_exists(&name));
590 release_tx.send(()).expect("timer send should release");
591
592 wait_until(|| clock.timer_count() == 0, Duration::from_secs(2));
594
595 assert!(clock.timers.contains_key(&name));
599 assert!(!clock.timer_exists(&name));
600 assert_eq!(clock.timer_count(), 0);
601 assert!(clock.timer_names().is_empty());
602 assert!(clock.next_time_ns(name.as_str()).is_none());
603 }
604
605 #[rstest]
606 fn test_live_clock_failed_set_time_alert_ns_preserves_existing_timer() {
607 let events = Arc::new(Mutex::new(Vec::new()));
608 let sender = Arc::new(CollectingSender::new(Arc::clone(&events)));
609
610 let mut clock = LiveClock::new(Some(sender));
612
613 let now = clock.timestamp_ns();
614 let alert_time = now + DurationNanos::from_mins(1);
615
616 clock
617 .set_time_alert_ns(
618 "alert",
619 alert_time,
620 Some(TimeEventCallback::from(|_| {})),
621 None,
622 )
623 .unwrap();
624 assert_eq!(clock.next_time_ns("alert"), Some(alert_time));
625
626 clock.cancel_callbacks();
628
629 let err = clock
632 .set_time_alert_ns("alert", alert_time + DurationNanos::new(1000), None, None)
633 .unwrap_err();
634 assert!(
635 err.to_string().contains("No callbacks provided"),
636 "unexpected error: {err}"
637 );
638 assert!(clock.timer_exists(&Ustr::from("alert")));
639 assert_eq!(clock.next_time_ns("alert"), Some(alert_time));
640
641 clock.cancel_timers();
642 }
643 #[rstest]
644 fn test_live_clock_registers_deadline_schedule_with_default_callback_and_inclusive_stop() {
645 let events = Arc::new(Mutex::new(Vec::new()));
646 let sender = Arc::new(CollectingSender::new(events.clone()));
647 let mut clock = LiveClock::new(Some(sender));
648 clock.register_default_handler(TimeEventCallback::from(|_| {}));
649 let origin = clock.timestamp_ns();
650 let first = origin + DurationNanos::from_millis(200);
651
652 let schedule = Arc::new(
653 CalendarSchedule::new(
654 &origin.to_datetime_utc().to_zoned(jiff::tz::TimeZone::UTC),
655 jiff::Span::new().milliseconds(200),
656 )
657 .unwrap(),
658 );
659 clock
660 .set_timer_schedule("deadline", schedule, Some(first), None, None, None)
661 .unwrap();
662 assert_eq!(clock.next_time_ns("deadline"), Some(first));
663 wait_until(|| clock.timer_count() == 0, Duration::from_secs(2));
664 let recorded = events.lock();
665 assert_eq!(recorded.len(), 1);
666 assert_eq!(recorded[0].0.name, Ustr::from("deadline"));
667 assert_eq!(recorded[0].0.ts_event, first);
668 assert!(recorded[0].0.ts_init >= first);
669 assert_eq!(clock.next_time_ns("deadline"), None);
670 }
671}