nautilus_system/
clock_factory.rs1use std::{
19 cell::{OnceCell, RefCell},
20 fmt::Debug,
21 rc::Rc,
22};
23
24use nautilus_common::{
25 clock::{Clock, TestClock},
26 enums::Environment,
27};
28
29#[derive(Clone)]
34pub struct ClockFactory {
35 clock: Rc<OnceCell<Rc<RefCell<dyn Clock>>>>,
36 create_clock: Rc<dyn Fn() -> Rc<RefCell<dyn Clock>>>,
37}
38
39impl ClockFactory {
40 #[must_use]
42 pub fn new<F>(factory: F) -> Self
43 where
44 F: Fn() -> Rc<RefCell<dyn Clock>> + 'static,
45 {
46 Self {
47 clock: Rc::new(OnceCell::new()),
48 create_clock: Rc::new(factory),
49 }
50 }
51
52 #[must_use]
54 pub fn test_default() -> Self {
55 Self::for_environment(Environment::Backtest)
56 }
57
58 #[must_use]
60 pub fn for_environment(environment: Environment) -> Self {
61 match environment {
62 Environment::Backtest => Self::new(|| Rc::new(RefCell::new(TestClock::new()))),
63 Environment::Live | Environment::Sandbox => Self::live_default(),
64 }
65 }
66
67 #[must_use]
69 pub fn clock(&self) -> Rc<RefCell<dyn Clock>> {
70 self.clock.get_or_init(|| (self.create_clock)()).clone()
71 }
72
73 #[must_use]
75 pub fn create_component_clock(&self) -> Rc<RefCell<dyn Clock>> {
76 (self.create_clock)()
77 }
78
79 #[cfg(feature = "live")]
80 fn live_default() -> Self {
81 Self::new(|| {
82 Rc::new(RefCell::new(
83 nautilus_common::live::clock::LiveClock::default(), ))
85 })
86 }
87
88 #[cfg(not(feature = "live"))]
89 fn live_default() -> Self {
90 Self::new(|| {
91 panic!(
92 "Live/Sandbox environment requires the 'live' feature to be enabled. \
93 Build with `--features live` or supply a clock factory."
94 )
95 })
96 }
97}
98
99impl Debug for ClockFactory {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 f.debug_struct(stringify!(ClockFactory))
102 .finish_non_exhaustive()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use std::cell::Cell;
109
110 use rstest::rstest;
111
112 use super::*;
113
114 #[rstest]
115 fn test_clock_memoizes_primary_clock() {
116 let calls = Rc::new(Cell::new(0usize));
117 let calls_in_factory = calls.clone();
118 let factory = ClockFactory::new(move || {
119 calls_in_factory.set(calls_in_factory.get() + 1);
120 Rc::new(RefCell::new(TestClock::new()))
121 });
122
123 let first = factory.clock();
124 let second = factory.clock();
125
126 assert_eq!(calls.get(), 1);
127 assert!(Rc::ptr_eq(&first, &second));
128 }
129
130 #[rstest]
131 fn test_create_component_clock_returns_distinct_clocks() {
132 let factory = ClockFactory::test_default();
133
134 let first = factory.create_component_clock();
135 let second = factory.create_component_clock();
136
137 assert!(!Rc::ptr_eq(&first, &second));
138 }
139
140 #[rstest]
141 fn test_for_environment_backtest_uses_test_clock() {
142 let factory = ClockFactory::for_environment(Environment::Backtest);
143 let clock = factory.clock();
144
145 assert!(clock.borrow_mut().as_any_mut().is::<TestClock>());
146 }
147
148 #[rstest]
149 fn test_default_uses_test_clock() {
150 let factory = ClockFactory::test_default();
151 let clock = factory.clock();
152
153 assert!(clock.borrow_mut().as_any_mut().is::<TestClock>());
154 }
155}