1use crate::{BackendConfig, BackendFactory, BackendVersion, CanBackend, CanError, CanResult};
7use indexmap::IndexMap;
8use std::sync::{Arc, OnceLock, RwLock};
9
10#[derive(Debug, Clone)]
26pub struct BackendInfo {
27 pub name: String,
29
30 pub version: BackendVersion,
32}
33
34pub struct BackendRegistry {
61 factories: RwLock<IndexMap<String, Arc<dyn BackendFactory>>>,
62}
63
64impl BackendRegistry {
65 #[must_use]
75 pub fn new() -> Self {
76 Self {
77 factories: RwLock::new(IndexMap::new()),
78 }
79 }
80
81 pub fn global() -> Arc<Self> {
94 static INSTANCE: OnceLock<Arc<BackendRegistry>> = OnceLock::new();
95 INSTANCE.get_or_init(|| Arc::new(Self::new())).clone()
96 }
97
98 pub fn register(&self, factory: Arc<dyn BackendFactory>) -> CanResult<()> {
120 let name = factory.name().to_string();
121 let mut factories = self.factories.write().map_err(|e| CanError::Other {
122 message: format!("Failed to acquire write lock: {e}"),
123 })?;
124
125 if factories.contains_key(&name) {
126 return Err(CanError::BackendAlreadyRegistered { name: name.clone() });
127 }
128
129 factories.insert(name, factory);
130 Ok(())
131 }
132
133 pub fn unregister(&self, name: &str) -> CanResult<()> {
151 let mut factories = self.factories.write().map_err(|e| CanError::Other {
152 message: format!("Failed to acquire write lock: {e}"),
153 })?;
154
155 if factories.shift_remove(name).is_none() {
156 return Err(CanError::BackendNotFound {
157 name: name.to_string(),
158 });
159 }
160
161 Ok(())
162 }
163
164 pub fn create(&self, name: &str, config: &BackendConfig) -> CanResult<Box<dyn CanBackend>> {
192 let factories = self.factories.read().map_err(|e| CanError::Other {
193 message: format!("Failed to acquire read lock: {e}"),
194 })?;
195
196 let factory = factories
197 .get(name)
198 .ok_or_else(|| CanError::BackendNotFound {
199 name: name.to_string(),
200 })?;
201
202 factory.create(config)
203 }
204
205 pub fn list_backends(&self) -> Vec<String> {
224 let factories = self.factories.read().unwrap();
225 factories.keys().cloned().collect()
227 }
228
229 pub fn get_backend_info(&self, name: &str) -> CanResult<BackendInfo> {
248 let factories = self.factories.read().map_err(|e| CanError::Other {
249 message: format!("Failed to acquire read lock: {e}"),
250 })?;
251
252 let factory = factories
253 .get(name)
254 .ok_or_else(|| CanError::BackendNotFound {
255 name: name.to_string(),
256 })?;
257
258 Ok(BackendInfo {
259 name: factory.name().to_string(),
260 version: factory.version(),
261 })
262 }
263
264 #[must_use]
286 pub fn is_registered(&self, name: &str) -> bool {
287 let factories = self.factories.read().unwrap();
288 factories.contains_key(name)
289 }
290}
291
292impl Default for BackendRegistry {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 use crate::{CanMessage, HardwareCapability};
302
303 struct MockBackend;
305
306 impl CanBackend for MockBackend {
307 fn initialize(&mut self, _config: &BackendConfig) -> CanResult<()> {
308 Ok(())
309 }
310
311 fn close(&mut self) -> CanResult<()> {
312 Ok(())
313 }
314
315 fn get_capability(&self) -> CanResult<HardwareCapability> {
316 Ok(HardwareCapability::new(
317 2,
318 true,
319 8_000_000,
320 vec![125_000, 250_000, 500_000, 1_000_000],
321 16,
322 crate::TimestampPrecision::Microsecond,
323 ))
324 }
325
326 fn send_message(&mut self, _message: &CanMessage) -> CanResult<()> {
327 Ok(())
328 }
329
330 fn receive_message(&mut self) -> CanResult<Option<CanMessage>> {
331 Ok(None)
332 }
333
334 fn open_channel(&mut self, _channel: u8) -> CanResult<()> {
335 Ok(())
336 }
337
338 fn close_channel(&mut self, _channel: u8) -> CanResult<()> {
339 Ok(())
340 }
341
342 fn version(&self) -> BackendVersion {
343 BackendVersion::new(0, 1, 0)
344 }
345
346 fn name(&self) -> &'static str {
347 "mock"
348 }
349 }
350
351 struct MockBackendFactory;
352
353 impl BackendFactory for MockBackendFactory {
354 fn create(&self, _config: &BackendConfig) -> CanResult<Box<dyn CanBackend>> {
355 Ok(Box::new(MockBackend))
356 }
357
358 fn name(&self) -> &'static str {
359 "mock"
360 }
361
362 fn version(&self) -> BackendVersion {
363 BackendVersion::new(0, 1, 0)
364 }
365 }
366
367 #[test]
368 fn test_registry_new() {
369 let registry = BackendRegistry::new();
370 assert_eq!(registry.list_backends().len(), 0);
371 }
372
373 #[test]
374 fn test_registry_register() {
375 let registry = BackendRegistry::new();
376 let factory = Arc::new(MockBackendFactory);
377
378 assert!(registry.register(factory).is_ok());
379 assert_eq!(registry.list_backends().len(), 1);
380 assert!(registry.is_registered("mock"));
381 }
382
383 #[test]
384 fn test_registry_register_duplicate() {
385 let registry = BackendRegistry::new();
386 let factory1 = Arc::new(MockBackendFactory);
387 let factory2 = Arc::new(MockBackendFactory);
388
389 assert!(registry.register(factory1).is_ok());
390 assert!(registry.register(factory2).is_err());
391 }
392
393 #[test]
394 fn test_registry_unregister() {
395 let registry = BackendRegistry::new();
396 let factory = Arc::new(MockBackendFactory);
397
398 registry.register(factory).unwrap();
399 assert!(registry.is_registered("mock"));
400
401 assert!(registry.unregister("mock").is_ok());
402 assert!(!registry.is_registered("mock"));
403 }
404
405 #[test]
406 fn test_registry_unregister_not_found() {
407 let registry = BackendRegistry::new();
408 assert!(registry.unregister("nonexistent").is_err());
409 }
410
411 #[test]
412 fn test_registry_create() {
413 let registry = BackendRegistry::new();
414 let factory = Arc::new(MockBackendFactory);
415 let config = BackendConfig::new("mock");
416
417 registry.register(factory).unwrap();
418
419 let backend = registry.create("mock", &config);
420 assert!(backend.is_ok());
421 }
422
423 #[test]
424 fn test_registry_create_not_found() {
425 let registry = BackendRegistry::new();
426 let config = BackendConfig::new("mock");
427
428 let result = registry.create("nonexistent", &config);
429 assert!(result.is_err());
430 }
431
432 #[test]
433 fn test_registry_list_backends() {
434 let registry = BackendRegistry::new();
435 let factory = Arc::new(MockBackendFactory);
436
437 registry.register(factory).unwrap();
438
439 let backends = registry.list_backends();
440 assert_eq!(backends.len(), 1);
441 assert!(backends.contains(&"mock".to_string()));
442 }
443
444 #[test]
445 fn test_registry_get_backend_info() {
446 let registry = BackendRegistry::new();
447 let factory = Arc::new(MockBackendFactory);
448
449 registry.register(factory).unwrap();
450
451 let info = registry.get_backend_info("mock").unwrap();
452 assert_eq!(info.name, "mock");
453 assert_eq!(info.version.major(), 0);
454 assert_eq!(info.version.minor(), 1);
455 assert_eq!(info.version.patch(), 0);
456 }
457
458 #[test]
459 fn test_registry_global() {
460 let registry1 = BackendRegistry::global();
461 let registry2 = BackendRegistry::global();
462
463 assert!(Arc::ptr_eq(®istry1, ®istry2));
465 }
466
467 #[test]
468 fn test_registration_order() {
469 struct TestFactory(&'static str);
471 impl BackendFactory for TestFactory {
472 fn create(&self, _config: &BackendConfig) -> CanResult<Box<dyn CanBackend>> {
473 Ok(Box::new(MockBackend))
474 }
475 fn name(&self) -> &str {
476 self.0
477 }
478 fn version(&self) -> BackendVersion {
479 BackendVersion::new(0, 1, 0)
480 }
481 }
482
483 let registry = BackendRegistry::new();
484
485 registry
487 .register(Arc::new(TestFactory("backend_a")))
488 .unwrap();
489 registry
490 .register(Arc::new(TestFactory("backend_b")))
491 .unwrap();
492 registry
493 .register(Arc::new(TestFactory("backend_c")))
494 .unwrap();
495
496 let backends = registry.list_backends();
498 assert_eq!(backends, vec!["backend_a", "backend_b", "backend_c"]);
499 }
500
501 #[test]
502 fn test_duplicate_registration_error_type() {
503 let registry = BackendRegistry::new();
504 let factory1 = Arc::new(MockBackendFactory);
505 let factory2 = Arc::new(MockBackendFactory);
506
507 registry.register(factory1).unwrap();
508
509 let result = registry.register(factory2);
510 assert!(result.is_err());
511
512 match result.unwrap_err() {
514 CanError::BackendAlreadyRegistered { name } => {
515 assert_eq!(name, "mock");
516 }
517 other => panic!("Expected BackendAlreadyRegistered, got {other:?}"),
518 }
519 }
520}