use std::any::TypeId;
use ahash::AHashMap;
use crate::di_container::BindingOptions;
pub struct DIContainerBindingStorage<Provider>
where
Provider: 'static + ?Sized,
{
inner: AHashMap<BindingId<'static>, Box<Provider>>,
}
impl<Provider> DIContainerBindingStorage<Provider>
where
Provider: 'static + ?Sized,
{
pub fn new() -> Self
{
Self {
inner: AHashMap::new(),
}
}
#[allow(clippy::borrowed_box)]
pub fn get<'this, Interface>(
&'this self,
options: BindingOptions<'this>,
) -> Option<&'this Box<Provider>>
where
Interface: 'static + ?Sized,
{
self.inner.get(&BindingId::new::<Interface>(options))
}
pub fn set<Interface>(
&mut self,
options: BindingOptions<'static>,
provider: Box<Provider>,
) where
Interface: 'static + ?Sized,
{
self.inner
.insert(BindingId::new::<Interface>(options), provider);
}
pub fn remove<Interface>(
&mut self,
options: BindingOptions<'static>,
) -> Option<Box<Provider>>
where
Interface: 'static + ?Sized,
{
self.inner.remove(&BindingId::new::<Interface>(options))
}
pub fn has<Interface>(&self, options: BindingOptions) -> bool
where
Interface: 'static + ?Sized,
{
self.inner
.contains_key(&BindingId::new::<Interface>(options))
}
}
impl<Provider> Default for DIContainerBindingStorage<Provider>
where
Provider: 'static + ?Sized,
{
fn default() -> Self
{
Self::new()
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
struct BindingId<'opts>
{
type_id: TypeId,
options: BindingOptions<'opts>,
}
impl<'opts> BindingId<'opts>
{
fn new<Interface>(options: BindingOptions<'opts>) -> Self
where
Interface: ?Sized + 'static,
{
Self {
type_id: TypeId::of::<Interface>(),
options,
}
}
}
#[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 =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new()),
Box::new(subjects::SomeProviderImpl { id: 20 }),
);
assert!(binding_map
.get::<Interface>(BindingOptions::new())
.map_or_else(|| false, |provider| provider.get_id() == 20));
}
#[test]
fn can_get_with_name()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new().name("hello")),
Box::new(subjects::SomeProviderImpl { id: 11 }),
);
assert!(binding_map
.get::<Interface>(BindingOptions::new().name("hello"))
.map_or_else(|| false, |provider| provider.get_id() == 11));
assert!(binding_map
.get::<Interface>(BindingOptions::new())
.is_none());
}
#[test]
fn can_set()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.set::<Interface>(
BindingOptions::new(),
Box::new(subjects::SomeProviderImpl { id: 65 }),
);
let expected_key = BindingId::new::<Interface>(BindingOptions::new());
assert!(binding_map.inner.contains_key(&expected_key));
assert_eq!(binding_map.inner[&expected_key].get_id(), 65);
}
#[test]
fn can_set_with_name()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.set::<Interface>(
BindingOptions::new().name("special"),
Box::new(subjects::SomeProviderImpl { id: 3 }),
);
let expected_key =
BindingId::new::<Interface>(BindingOptions::new().name("special"));
assert!(binding_map.inner.contains_key(&expected_key));
assert_eq!(binding_map.inner[&expected_key].get_id(), 3);
}
#[test]
fn can_remove()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new()),
Box::new(subjects::SomeProviderImpl { id: 103 }),
);
binding_map.remove::<Interface>(BindingOptions::new());
assert!(!binding_map
.inner
.contains_key(&BindingId::new::<Interface>(BindingOptions::new())));
}
#[test]
fn can_remove_with_name()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new().name("cool")),
Box::new(subjects::SomeProviderImpl { id: 42 }),
);
binding_map.remove::<Interface>(BindingOptions::new().name("cool"));
assert!(
!binding_map.inner.contains_key(&BindingId::new::<Interface>(
BindingOptions::new().name("cool")
))
);
}
#[test]
fn can_get_has()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
assert!(!binding_map.has::<Interface>(BindingOptions::new()));
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new()),
Box::new(subjects::SomeProviderImpl { id: 103 }),
);
assert!(binding_map.has::<Interface>(BindingOptions::new()));
}
#[test]
fn can_get_has_with_name()
{
type Interface = ();
let mut binding_map =
DIContainerBindingStorage::<dyn subjects::SomeProvider>::new();
assert!(!binding_map.has::<Interface>(BindingOptions::new().name("awesome")));
binding_map.inner.insert(
BindingId::new::<Interface>(BindingOptions::new().name("awesome")),
Box::new(subjects::SomeProviderImpl { id: 101 }),
);
assert!(binding_map.has::<Interface>(BindingOptions::new().name("awesome")));
}
}