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