nautilus_system/
factories.rs1use std::{any::Any, cell::RefCell, fmt::Debug, rc::Rc};
17
18use ahash::AHashMap;
19use nautilus_common::{
20 cache::Cache,
21 clients::{DataClient, ExecutionClient},
22 clock::Clock,
23};
24
25pub trait ClientConfig: Debug {
30 fn as_any(&self) -> &dyn Any;
32}
33
34pub trait DataClientFactory: Debug {
39 fn create(
45 &self,
46 name: &str,
47 config: &dyn ClientConfig,
48 cache: Rc<RefCell<Cache>>,
49 clock: Rc<RefCell<dyn Clock>>,
50 ) -> anyhow::Result<Box<dyn DataClient>>;
51
52 fn name(&self) -> &str;
54
55 fn config_type(&self) -> &str;
57}
58
59pub trait ExecutionClientFactory: Debug {
64 fn create(
70 &self,
71 name: &str,
72 config: &dyn ClientConfig,
73 cache: Rc<RefCell<Cache>>,
74 clock: Rc<RefCell<dyn Clock>>,
75 ) -> anyhow::Result<Box<dyn ExecutionClient>>;
76
77 fn name(&self) -> &str;
79
80 fn config_type(&self) -> &str;
82}
83
84#[derive(Debug, Default)]
89pub struct DataClientFactoryRegistry {
90 factories: AHashMap<String, Box<dyn DataClientFactory>>,
91}
92
93impl DataClientFactoryRegistry {
94 #[must_use]
96 pub fn new() -> Self {
97 Self {
98 factories: AHashMap::new(),
99 }
100 }
101
102 pub fn register(
108 &mut self,
109 name: String,
110 factory: Box<dyn DataClientFactory>,
111 ) -> anyhow::Result<()> {
112 if self.factories.contains_key(&name) {
113 anyhow::bail!("Data client factory '{name}' is already registered");
114 }
115
116 self.factories.insert(name, factory);
117 Ok(())
118 }
119
120 #[must_use]
126 pub fn get(&self, name: &str) -> Option<&dyn DataClientFactory> {
127 self.factories.get(name).map(std::convert::AsRef::as_ref)
128 }
129
130 #[must_use]
132 pub fn names(&self) -> Vec<&String> {
133 self.factories.keys().collect()
134 }
135
136 #[must_use]
138 pub fn contains(&self, name: &str) -> bool {
139 self.factories.contains_key(name)
140 }
141}
142
143#[derive(Debug, Default)]
148pub struct ExecutionClientFactoryRegistry {
149 factories: AHashMap<String, Box<dyn ExecutionClientFactory>>,
150}
151
152impl ExecutionClientFactoryRegistry {
153 #[must_use]
155 pub fn new() -> Self {
156 Self {
157 factories: AHashMap::new(),
158 }
159 }
160
161 pub fn register(
167 &mut self,
168 name: String,
169 factory: Box<dyn ExecutionClientFactory>,
170 ) -> anyhow::Result<()> {
171 if self.factories.contains_key(&name) {
172 anyhow::bail!("Execution client factory '{name}' is already registered");
173 }
174
175 self.factories.insert(name, factory);
176 Ok(())
177 }
178
179 #[must_use]
181 pub fn get(&self, name: &str) -> Option<&dyn ExecutionClientFactory> {
182 self.factories.get(name).map(std::convert::AsRef::as_ref)
183 }
184
185 #[must_use]
187 pub fn names(&self) -> Vec<&String> {
188 self.factories.keys().collect()
189 }
190
191 #[must_use]
193 pub fn contains(&self, name: &str) -> bool {
194 self.factories.contains_key(name)
195 }
196}
197
198#[allow(dead_code)]
199#[cfg(test)]
200mod tests {
201 use std::any::Any;
202
203 use rstest::*;
204
205 use super::*;
206
207 #[derive(Debug)]
209 struct MockConfig {
210 #[allow(dead_code)]
211 value: String,
212 }
213
214 impl ClientConfig for MockConfig {
215 fn as_any(&self) -> &dyn Any {
216 self
217 }
218 }
219
220 #[derive(Debug)]
222 struct MockDataClientFactory;
223
224 impl DataClientFactory for MockDataClientFactory {
225 fn create(
226 &self,
227 _name: &str,
228 _config: &dyn ClientConfig,
229 _cache: Rc<RefCell<Cache>>,
230 _clock: Rc<RefCell<dyn Clock>>,
231 ) -> anyhow::Result<Box<dyn DataClient>> {
232 Err(anyhow::anyhow!("Mock factory - not implemented"))
234 }
235
236 fn name(&self) -> &'static str {
237 "mock"
238 }
239
240 fn config_type(&self) -> &'static str {
241 "MockConfig"
242 }
243 }
244
245 #[rstest]
246 fn test_data_client_factory_registry() {
247 let mut registry = DataClientFactoryRegistry::new();
248
249 assert!(registry.names().is_empty());
251 assert!(!registry.contains("mock"));
252 assert!(registry.get("mock").is_none());
253
254 let factory = Box::new(MockDataClientFactory);
256 registry.register("mock".to_string(), factory).unwrap();
257
258 assert_eq!(registry.names().len(), 1);
260 assert!(registry.contains("mock"));
261 assert!(registry.get("mock").is_some());
262
263 let factory2 = Box::new(MockDataClientFactory);
265 let result = registry.register("mock".to_string(), factory2);
266 assert!(result.is_err());
267 }
268
269 #[rstest]
270 fn test_empty_data_client_factory_registry() {
271 let registry = DataClientFactoryRegistry::new();
272
273 assert!(registry.names().is_empty());
275 assert!(!registry.contains("mock"));
276 assert!(registry.get("mock").is_none());
277 }
278
279 #[rstest]
280 fn test_empty_execution_client_factory_registry() {
281 let registry = ExecutionClientFactoryRegistry::new();
282
283 assert!(registry.names().is_empty());
285 assert!(!registry.contains("mock"));
286 assert!(registry.get("mock").is_none());
287 }
288}