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 ) -> anyhow::Result<Box<dyn ExecutionClient>>;
75
76 fn name(&self) -> &str;
78
79 fn config_type(&self) -> &str;
81}
82
83#[derive(Debug, Default)]
88pub struct DataClientFactoryRegistry {
89 factories: AHashMap<String, Box<dyn DataClientFactory>>,
90}
91
92impl DataClientFactoryRegistry {
93 #[must_use]
95 pub fn new() -> Self {
96 Self {
97 factories: AHashMap::new(),
98 }
99 }
100
101 pub fn register(
107 &mut self,
108 name: String,
109 factory: Box<dyn DataClientFactory>,
110 ) -> anyhow::Result<()> {
111 if self.factories.contains_key(&name) {
112 anyhow::bail!("Data client factory '{name}' is already registered");
113 }
114
115 self.factories.insert(name, factory);
116 Ok(())
117 }
118
119 #[must_use]
125 pub fn get(&self, name: &str) -> Option<&dyn DataClientFactory> {
126 self.factories.get(name).map(std::convert::AsRef::as_ref)
127 }
128
129 #[must_use]
131 pub fn names(&self) -> Vec<&String> {
132 self.factories.keys().collect()
133 }
134
135 #[must_use]
137 pub fn contains(&self, name: &str) -> bool {
138 self.factories.contains_key(name)
139 }
140}
141
142#[derive(Debug, Default)]
147pub struct ExecutionClientFactoryRegistry {
148 factories: AHashMap<String, Box<dyn ExecutionClientFactory>>,
149}
150
151impl ExecutionClientFactoryRegistry {
152 #[must_use]
154 pub fn new() -> Self {
155 Self {
156 factories: AHashMap::new(),
157 }
158 }
159
160 pub fn register(
166 &mut self,
167 name: String,
168 factory: Box<dyn ExecutionClientFactory>,
169 ) -> anyhow::Result<()> {
170 if self.factories.contains_key(&name) {
171 anyhow::bail!("Execution client factory '{name}' is already registered");
172 }
173
174 self.factories.insert(name, factory);
175 Ok(())
176 }
177
178 #[must_use]
180 pub fn get(&self, name: &str) -> Option<&dyn ExecutionClientFactory> {
181 self.factories.get(name).map(std::convert::AsRef::as_ref)
182 }
183
184 #[must_use]
186 pub fn names(&self) -> Vec<&String> {
187 self.factories.keys().collect()
188 }
189
190 #[must_use]
192 pub fn contains(&self, name: &str) -> bool {
193 self.factories.contains_key(name)
194 }
195}
196
197#[allow(dead_code)]
198#[cfg(test)]
199mod tests {
200 use std::any::Any;
201
202 use rstest::*;
203
204 use super::*;
205
206 #[derive(Debug)]
208 struct MockConfig {
209 #[allow(dead_code)]
210 value: String,
211 }
212
213 impl ClientConfig for MockConfig {
214 fn as_any(&self) -> &dyn Any {
215 self
216 }
217 }
218
219 #[derive(Debug)]
221 struct MockDataClientFactory;
222
223 impl DataClientFactory for MockDataClientFactory {
224 fn create(
225 &self,
226 _name: &str,
227 _config: &dyn ClientConfig,
228 _cache: Rc<RefCell<Cache>>,
229 _clock: Rc<RefCell<dyn Clock>>,
230 ) -> anyhow::Result<Box<dyn DataClient>> {
231 Err(anyhow::anyhow!("Mock factory - not implemented"))
233 }
234
235 fn name(&self) -> &'static str {
236 "mock"
237 }
238
239 fn config_type(&self) -> &'static str {
240 "MockConfig"
241 }
242 }
243
244 #[rstest]
245 fn test_data_client_factory_registry() {
246 let mut registry = DataClientFactoryRegistry::new();
247
248 assert!(registry.names().is_empty());
250 assert!(!registry.contains("mock"));
251 assert!(registry.get("mock").is_none());
252
253 let factory = Box::new(MockDataClientFactory);
255 registry.register("mock".to_string(), factory).unwrap();
256
257 assert_eq!(registry.names().len(), 1);
259 assert!(registry.contains("mock"));
260 assert!(registry.get("mock").is_some());
261
262 let factory2 = Box::new(MockDataClientFactory);
264 let result = registry.register("mock".to_string(), factory2);
265 assert!(result.is_err());
266 }
267
268 #[rstest]
269 fn test_empty_data_client_factory_registry() {
270 let registry = DataClientFactoryRegistry::new();
271
272 assert!(registry.names().is_empty());
274 assert!(!registry.contains("mock"));
275 assert!(registry.get("mock").is_none());
276 }
277
278 #[rstest]
279 fn test_empty_execution_client_factory_registry() {
280 let registry = ExecutionClientFactoryRegistry::new();
281
282 assert!(registry.names().is_empty());
284 assert!(!registry.contains("mock"));
285 assert!(registry.get("mock").is_none());
286 }
287}