nautilus_common/factories/
client.rs1use std::{any::Any, cell::RefCell, fmt::Debug, rc::Rc};
25
26use ahash::AHashMap;
27
28use crate::{
29 cache::Cache,
30 clients::{DataClient, ExecutionClient},
31 clock::Clock,
32};
33
34pub trait ClientConfig: Debug {
39 fn as_any(&self) -> &dyn Any;
41}
42
43pub trait DataClientFactory: Debug {
48 fn create(
54 &self,
55 name: &str,
56 config: &dyn ClientConfig,
57 cache: Rc<RefCell<Cache>>,
58 clock: Rc<RefCell<dyn Clock>>,
59 ) -> anyhow::Result<Box<dyn DataClient>>;
60
61 fn name(&self) -> &str;
63
64 fn config_type(&self) -> &str;
66}
67
68pub trait ExecutionClientFactory: Debug {
73 fn create(
79 &self,
80 name: &str,
81 config: &dyn ClientConfig,
82 cache: Rc<RefCell<Cache>>,
83 ) -> anyhow::Result<Box<dyn ExecutionClient>>;
84
85 fn name(&self) -> &str;
87
88 fn config_type(&self) -> &str;
90}
91
92#[derive(Debug, Default)]
97pub struct DataClientFactoryRegistry {
98 factories: AHashMap<String, Box<dyn DataClientFactory>>,
99}
100
101impl DataClientFactoryRegistry {
102 #[must_use]
104 pub fn new() -> Self {
105 Self {
106 factories: AHashMap::new(),
107 }
108 }
109
110 pub fn register(
116 &mut self,
117 name: String,
118 factory: Box<dyn DataClientFactory>,
119 ) -> anyhow::Result<()> {
120 if self.factories.contains_key(&name) {
121 anyhow::bail!("Data client factory '{name}' is already registered");
122 }
123
124 self.factories.insert(name, factory);
125 Ok(())
126 }
127
128 #[must_use]
134 pub fn get(&self, name: &str) -> Option<&dyn DataClientFactory> {
135 self.factories.get(name).map(std::convert::AsRef::as_ref)
136 }
137
138 #[must_use]
140 pub fn names(&self) -> Vec<&String> {
141 self.factories.keys().collect()
142 }
143
144 #[must_use]
146 pub fn contains(&self, name: &str) -> bool {
147 self.factories.contains_key(name)
148 }
149}
150
151#[derive(Debug, Default)]
156pub struct ExecutionClientFactoryRegistry {
157 factories: AHashMap<String, Box<dyn ExecutionClientFactory>>,
158}
159
160impl ExecutionClientFactoryRegistry {
161 #[must_use]
163 pub fn new() -> Self {
164 Self {
165 factories: AHashMap::new(),
166 }
167 }
168
169 pub fn register(
175 &mut self,
176 name: String,
177 factory: Box<dyn ExecutionClientFactory>,
178 ) -> anyhow::Result<()> {
179 if self.factories.contains_key(&name) {
180 anyhow::bail!("Execution client factory '{name}' is already registered");
181 }
182
183 self.factories.insert(name, factory);
184 Ok(())
185 }
186
187 #[must_use]
189 pub fn get(&self, name: &str) -> Option<&dyn ExecutionClientFactory> {
190 self.factories.get(name).map(std::convert::AsRef::as_ref)
191 }
192
193 #[must_use]
195 pub fn names(&self) -> Vec<&String> {
196 self.factories.keys().collect()
197 }
198
199 #[must_use]
201 pub fn contains(&self, name: &str) -> bool {
202 self.factories.contains_key(name)
203 }
204}
205
206#[allow(dead_code)]
207#[cfg(test)]
208mod tests {
209 use std::any::Any;
210
211 use rstest::*;
212
213 use super::*;
214
215 #[derive(Debug)]
216 struct MockConfig {
217 #[allow(dead_code)]
218 value: String,
219 }
220
221 impl ClientConfig for MockConfig {
222 fn as_any(&self) -> &dyn Any {
223 self
224 }
225 }
226
227 #[derive(Debug)]
228 struct MockDataClientFactory;
229
230 impl DataClientFactory for MockDataClientFactory {
231 fn create(
232 &self,
233 _name: &str,
234 _config: &dyn ClientConfig,
235 _cache: Rc<RefCell<Cache>>,
236 _clock: Rc<RefCell<dyn Clock>>,
237 ) -> anyhow::Result<Box<dyn DataClient>> {
238 Err(anyhow::anyhow!("Mock factory - not implemented"))
239 }
240
241 fn name(&self) -> &'static str {
242 "mock"
243 }
244
245 fn config_type(&self) -> &'static str {
246 "MockConfig"
247 }
248 }
249
250 #[rstest]
251 fn test_data_client_factory_registry() {
252 let mut registry = DataClientFactoryRegistry::new();
253
254 assert!(registry.names().is_empty());
255 assert!(!registry.contains("mock"));
256 assert!(registry.get("mock").is_none());
257
258 let factory = Box::new(MockDataClientFactory);
259 registry.register("mock".to_string(), factory).unwrap();
260
261 assert_eq!(registry.names().len(), 1);
262 assert!(registry.contains("mock"));
263 assert!(registry.get("mock").is_some());
264
265 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());
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());
284 assert!(!registry.contains("mock"));
285 assert!(registry.get("mock").is_none());
286 }
287}