use std::any::TypeId; use ahash::AHashMap; #[derive(Debug, PartialEq, Eq, Hash)] struct DIContainerBindingKey { type_id: TypeId, name: Option<&'static str>, } pub struct DIContainerBindingMap where Provider: 'static + ?Sized, { bindings: AHashMap>, } impl DIContainerBindingMap where Provider: 'static + ?Sized, { pub fn new() -> Self { Self { bindings: AHashMap::new(), } } #[allow(clippy::borrowed_box)] pub fn get(&self, name: Option<&'static str>) -> Option<&Box> where Interface: 'static + ?Sized, { let interface_typeid = TypeId::of::(); self.bindings.get(&DIContainerBindingKey { type_id: interface_typeid, name, }) } pub fn set(&mut self, name: Option<&'static str>, provider: Box) where Interface: 'static + ?Sized, { let interface_typeid = TypeId::of::(); self.bindings.insert( DIContainerBindingKey { type_id: interface_typeid, name, }, provider, ); } pub fn remove( &mut self, name: Option<&'static str>, ) -> Option> where Interface: 'static + ?Sized, { let interface_typeid = TypeId::of::(); self.bindings.remove(&DIContainerBindingKey { type_id: interface_typeid, name, }) } pub fn has(&self, name: Option<&'static str>) -> bool where Interface: 'static + ?Sized, { let interface_typeid = TypeId::of::(); self.bindings.contains_key(&DIContainerBindingKey { type_id: interface_typeid, name, }) } /// Only used by tests in the `di_container` module. #[cfg(test)] pub fn count(&self) -> usize { self.bindings.len() } } #[cfg(test)] mod tests { use super::*; mod subjects { pub trait SomeProvider { fn get_id(&self) -> u8; } pub struct SomeProviderImpl { pub id: u8, } impl SomeProvider for SomeProviderImpl { fn get_id(&self) -> u8 { self.id } } } #[test] fn can_get() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: None, }, Box::new(subjects::SomeProviderImpl { id: 20 }), ); assert!(binding_map .get::(None) .map_or_else(|| false, |provider| provider.get_id() == 20)); } #[test] fn can_get_with_name() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: Some("hello"), }, Box::new(subjects::SomeProviderImpl { id: 11 }), ); assert!(binding_map .get::(Some("hello")) .map_or_else(|| false, |provider| provider.get_id() == 11)); assert!(binding_map.get::(None).is_none()); } #[test] fn can_set() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map .set::(None, Box::new(subjects::SomeProviderImpl { id: 65 })); let expected_key = &DIContainerBindingKey { type_id: TypeId::of::(), name: None, }; assert!(binding_map.bindings.contains_key(expected_key)); assert_eq!(binding_map.bindings[expected_key].get_id(), 65); } #[test] fn can_set_with_name() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map.set::( Some("special"), Box::new(subjects::SomeProviderImpl { id: 3 }), ); let expected_key = &DIContainerBindingKey { type_id: TypeId::of::(), name: Some("special"), }; assert!(binding_map.bindings.contains_key(expected_key)); assert_eq!(binding_map.bindings[expected_key].get_id(), 3); } #[test] fn can_remove() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: None, }, Box::new(subjects::SomeProviderImpl { id: 103 }), ); binding_map.remove::(None); let expected_key = &DIContainerBindingKey { type_id: TypeId::of::(), name: None, }; assert!(!binding_map.bindings.contains_key(expected_key)); } #[test] fn can_remove_with_name() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: Some("cool"), }, Box::new(subjects::SomeProviderImpl { id: 42 }), ); binding_map.remove::(Some("cool")); let expected_key = &DIContainerBindingKey { type_id: TypeId::of::(), name: Some("cool"), }; assert!(!binding_map.bindings.contains_key(expected_key)); } #[test] fn can_get_has() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); assert!(!binding_map.has::(None)); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: None, }, Box::new(subjects::SomeProviderImpl { id: 103 }), ); assert!(binding_map.has::(None)); } #[test] fn can_get_has_with_name() { type Interface = (); let mut binding_map = DIContainerBindingMap::::new(); assert!(!binding_map.has::(Some("awesome"))); binding_map.bindings.insert( DIContainerBindingKey { type_id: TypeId::of::(), name: Some("awesome"), }, Box::new(subjects::SomeProviderImpl { id: 101 }), ); assert!(binding_map.has::(Some("awesome"))); } }