nautilus_system/
factories.rs1use std::{any::Any, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
17
18use nautilus_common::{cache::Cache, clock::Clock};
19use posei_trader::client::DataClient;
20use nautilus_execution::client::ExecutionClient;
21
22pub trait ClientConfig: Send + Sync + std::fmt::Debug {
27 fn as_any(&self) -> &dyn Any;
29}
30
31pub trait DataClientFactory: Send + Sync + Debug {
36 fn create(
42 &self,
43 name: &str,
44 config: &dyn ClientConfig,
45 cache: Rc<RefCell<Cache>>,
46 clock: Rc<RefCell<dyn Clock>>,
47 ) -> anyhow::Result<Box<dyn DataClient>>;
48
49 fn name(&self) -> &str;
51
52 fn config_type(&self) -> &str;
54}
55
56pub trait ExecutionClientFactory: Send + Sync + std::fmt::Debug {
61 fn create(
67 &self,
68 name: &str,
69 config: &dyn ClientConfig,
70 cache: Rc<RefCell<Cache>>,
71 clock: Rc<RefCell<dyn Clock>>,
72 ) -> anyhow::Result<Box<dyn ExecutionClient>>;
73
74 fn name(&self) -> &str;
76
77 fn config_type(&self) -> &str;
79}
80
81#[derive(Debug, Default)]
86pub struct DataClientFactoryRegistry {
87 factories: std::collections::HashMap<String, Box<dyn DataClientFactory>>,
88}
89
90impl DataClientFactoryRegistry {
91 #[must_use]
93 pub fn new() -> Self {
94 Self {
95 factories: std::collections::HashMap::new(),
96 }
97 }
98
99 pub fn register(
105 &mut self,
106 name: String,
107 factory: Box<dyn DataClientFactory>,
108 ) -> anyhow::Result<()> {
109 if self.factories.contains_key(&name) {
110 anyhow::bail!("Data client factory '{name}' is already registered");
111 }
112
113 self.factories.insert(name, factory);
114 Ok(())
115 }
116
117 #[must_use]
123 pub fn get(&self, name: &str) -> Option<&dyn DataClientFactory> {
124 self.factories.get(name).map(std::convert::AsRef::as_ref)
125 }
126
127 #[must_use]
129 pub fn names(&self) -> Vec<&String> {
130 self.factories.keys().collect()
131 }
132
133 #[must_use]
135 pub fn contains(&self, name: &str) -> bool {
136 self.factories.contains_key(name)
137 }
138}
139
140#[derive(Debug, Default)]
145pub struct ExecutionClientFactoryRegistry {
146 factories: HashMap<String, Box<dyn ExecutionClientFactory>>,
147}
148
149impl ExecutionClientFactoryRegistry {
150 #[must_use]
152 pub fn new() -> Self {
153 Self {
154 factories: std::collections::HashMap::new(),
155 }
156 }
157
158 pub fn register(
164 &mut self,
165 name: String,
166 factory: Box<dyn ExecutionClientFactory>,
167 ) -> anyhow::Result<()> {
168 if self.factories.contains_key(&name) {
169 anyhow::bail!("Execution client factory '{name}' is already registered");
170 }
171
172 self.factories.insert(name, factory);
173 Ok(())
174 }
175
176 #[must_use]
178 pub fn get(&self, name: &str) -> Option<&dyn ExecutionClientFactory> {
179 self.factories.get(name).map(std::convert::AsRef::as_ref)
180 }
181
182 #[must_use]
184 pub fn names(&self) -> Vec<&String> {
185 self.factories.keys().collect()
186 }
187
188 #[must_use]
190 pub fn contains(&self, name: &str) -> bool {
191 self.factories.contains_key(name)
192 }
193}
194
195#[allow(dead_code)]
200#[cfg(test)]
201mod tests {
202 use std::any::Any;
203
204 use rstest::*;
205
206 use super::*;
207
208 #[derive(Debug)]
210 struct MockConfig {
211 #[allow(dead_code)]
212 value: String,
213 }
214
215 impl ClientConfig for MockConfig {
216 fn as_any(&self) -> &dyn Any {
217 self
218 }
219 }
220
221 #[derive(Debug)]
223 struct MockDataClientFactory;
224
225 impl DataClientFactory for MockDataClientFactory {
226 fn create(
227 &self,
228 _name: &str,
229 _config: &dyn ClientConfig,
230 _cache: Rc<RefCell<Cache>>,
231 _clock: Rc<RefCell<dyn Clock>>,
232 ) -> anyhow::Result<Box<dyn DataClient>> {
233 Err(anyhow::anyhow!("Mock factory - not implemented"))
235 }
236
237 fn name(&self) -> &'static str {
238 "mock"
239 }
240
241 fn config_type(&self) -> &'static str {
242 "MockConfig"
243 }
244 }
245
246 #[rstest]
247 fn test_data_client_factory_registry() {
248 let mut registry = DataClientFactoryRegistry::new();
249
250 assert!(registry.names().is_empty());
252 assert!(!registry.contains("mock"));
253 assert!(registry.get("mock").is_none());
254
255 let factory = Box::new(MockDataClientFactory);
257 registry.register("mock".to_string(), factory).unwrap();
258
259 assert_eq!(registry.names().len(), 1);
261 assert!(registry.contains("mock"));
262 assert!(registry.get("mock").is_some());
263
264 let factory2 = Box::new(MockDataClientFactory);
266 let result = registry.register("mock".to_string(), factory2);
267 assert!(result.is_err());
268 }
269
270 #[rstest]
271 fn test_empty_data_client_factory_registry() {
272 let registry = DataClientFactoryRegistry::new();
273
274 assert!(registry.names().is_empty());
276 assert!(!registry.contains("mock"));
277 assert!(registry.get("mock").is_none());
278 }
279
280 #[rstest]
281 fn test_empty_execution_client_factory_registry() {
282 let registry = ExecutionClientFactoryRegistry::new();
283
284 assert!(registry.names().is_empty());
286 assert!(!registry.contains("mock"));
287 assert!(registry.get("mock").is_none());
288 }
289}