nautilus_system/
factories.rs1use std::{any::Any, cell::RefCell, fmt::Debug, rc::Rc};
17
18use ahash::AHashMap;
19use nautilus_common::{cache::Cache, clock::Clock};
20use nautilus_data::client::DataClient;
21use nautilus_execution::client::ExecutionClient;
22
23pub trait ClientConfig: Debug {
28 fn as_any(&self) -> &dyn Any;
30}
31
32pub trait DataClientFactory: Debug {
37 fn create(
43 &self,
44 name: &str,
45 config: &dyn ClientConfig,
46 cache: Rc<RefCell<Cache>>,
47 clock: Rc<RefCell<dyn Clock>>,
48 ) -> anyhow::Result<Box<dyn DataClient>>;
49
50 fn name(&self) -> &str;
52
53 fn config_type(&self) -> &str;
55}
56
57pub trait ExecutionClientFactory: Debug {
62 fn create(
68 &self,
69 name: &str,
70 config: &dyn ClientConfig,
71 cache: Rc<RefCell<Cache>>,
72 clock: Rc<RefCell<dyn Clock>>,
73 ) -> anyhow::Result<Box<dyn ExecutionClient>>;
74
75 fn name(&self) -> &str;
77
78 fn config_type(&self) -> &str;
80}
81
82#[derive(Debug, Default)]
87pub struct DataClientFactoryRegistry {
88 factories: AHashMap<String, Box<dyn DataClientFactory>>,
89}
90
91impl DataClientFactoryRegistry {
92 #[must_use]
94 pub fn new() -> Self {
95 Self {
96 factories: AHashMap::new(),
97 }
98 }
99
100 pub fn register(
106 &mut self,
107 name: String,
108 factory: Box<dyn DataClientFactory>,
109 ) -> anyhow::Result<()> {
110 if self.factories.contains_key(&name) {
111 anyhow::bail!("Data client factory '{name}' is already registered");
112 }
113
114 self.factories.insert(name, factory);
115 Ok(())
116 }
117
118 #[must_use]
124 pub fn get(&self, name: &str) -> Option<&dyn DataClientFactory> {
125 self.factories.get(name).map(std::convert::AsRef::as_ref)
126 }
127
128 #[must_use]
130 pub fn names(&self) -> Vec<&String> {
131 self.factories.keys().collect()
132 }
133
134 #[must_use]
136 pub fn contains(&self, name: &str) -> bool {
137 self.factories.contains_key(name)
138 }
139}
140
141#[derive(Debug, Default)]
146pub struct ExecutionClientFactoryRegistry {
147 factories: AHashMap<String, Box<dyn ExecutionClientFactory>>,
148}
149
150impl ExecutionClientFactoryRegistry {
151 #[must_use]
153 pub fn new() -> Self {
154 Self {
155 factories: AHashMap::new(),
156 }
157 }
158
159 pub fn register(
165 &mut self,
166 name: String,
167 factory: Box<dyn ExecutionClientFactory>,
168 ) -> anyhow::Result<()> {
169 if self.factories.contains_key(&name) {
170 anyhow::bail!("Execution client factory '{name}' is already registered");
171 }
172
173 self.factories.insert(name, factory);
174 Ok(())
175 }
176
177 #[must_use]
179 pub fn get(&self, name: &str) -> Option<&dyn ExecutionClientFactory> {
180 self.factories.get(name).map(std::convert::AsRef::as_ref)
181 }
182
183 #[must_use]
185 pub fn names(&self) -> Vec<&String> {
186 self.factories.keys().collect()
187 }
188
189 #[must_use]
191 pub fn contains(&self, name: &str) -> bool {
192 self.factories.contains_key(name)
193 }
194}
195
196#[allow(dead_code)]
197#[cfg(test)]
198mod tests {
199 use std::any::Any;
200
201 use rstest::*;
202
203 use super::*;
204
205 #[derive(Debug)]
207 struct MockConfig {
208 #[allow(dead_code)]
209 value: String,
210 }
211
212 impl ClientConfig for MockConfig {
213 fn as_any(&self) -> &dyn Any {
214 self
215 }
216 }
217
218 #[derive(Debug)]
220 struct MockDataClientFactory;
221
222 impl DataClientFactory for MockDataClientFactory {
223 fn create(
224 &self,
225 _name: &str,
226 _config: &dyn ClientConfig,
227 _cache: Rc<RefCell<Cache>>,
228 _clock: Rc<RefCell<dyn Clock>>,
229 ) -> anyhow::Result<Box<dyn DataClient>> {
230 Err(anyhow::anyhow!("Mock factory - not implemented"))
232 }
233
234 fn name(&self) -> &'static str {
235 "mock"
236 }
237
238 fn config_type(&self) -> &'static str {
239 "MockConfig"
240 }
241 }
242
243 #[rstest]
244 fn test_data_client_factory_registry() {
245 let mut registry = DataClientFactoryRegistry::new();
246
247 assert!(registry.names().is_empty());
249 assert!(!registry.contains("mock"));
250 assert!(registry.get("mock").is_none());
251
252 let factory = Box::new(MockDataClientFactory);
254 registry.register("mock".to_string(), factory).unwrap();
255
256 assert_eq!(registry.names().len(), 1);
258 assert!(registry.contains("mock"));
259 assert!(registry.get("mock").is_some());
260
261 let factory2 = Box::new(MockDataClientFactory);
263 let result = registry.register("mock".to_string(), factory2);
264 assert!(result.is_err());
265 }
266
267 #[rstest]
268 fn test_empty_data_client_factory_registry() {
269 let registry = DataClientFactoryRegistry::new();
270
271 assert!(registry.names().is_empty());
273 assert!(!registry.contains("mock"));
274 assert!(registry.get("mock").is_none());
275 }
276
277 #[rstest]
278 fn test_empty_execution_client_factory_registry() {
279 let registry = ExecutionClientFactoryRegistry::new();
280
281 assert!(registry.names().is_empty());
283 assert!(!registry.contains("mock"));
284 assert!(registry.get("mock").is_none());
285 }
286}