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