use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex };
pub enum Entry {
Factory(Box<dyn Fn() -> Box<dyn Any> + Send + Sync>),
Singleton {
factory: Box<dyn Fn() -> Box<dyn Any> + Send + Sync>,
instance: Mutex<Option<Arc<dyn Any + Send + Sync>>>,
},
}
pub struct Container {
pub items: HashMap<String, Entry>,
}
impl Container {
pub fn new() -> Self {
Self {
items: HashMap::new(),
}
}
pub fn register<F, T>(&mut self, key: &str, factory: F)
where
F: Fn() -> T + Send + Sync + 'static,
T: Any + Send + Sync + 'static,
{
self.items.insert(
key.to_string(),
Entry::Factory(Box::new(move || Box::new(factory()) as Box<dyn Any>)),
);
}
pub fn register_singleton<F, T>(&mut self, key: &str, factory: F)
where
F: Fn() -> T + Send + Sync + 'static,
T: Any + Send + Sync + 'static,
{
self.items.insert(
key.to_string(),
Entry::Singleton {
factory: Box::new(move || Box::new(factory()) as Box<dyn Any>),
instance: Mutex::new(None),
},
);
}
pub fn get<T: Any + Clone>(&self, key: &str) -> Option<T> {
let entry = self.items.get(key)?;
match entry {
Entry::Factory(factory) => {
let boxed = factory();
boxed.downcast_ref::<T>().cloned()
}
Entry::Singleton { .. } => {
None
}
}
}
pub fn get_singleton<T: Any + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
let entry = self.items.get(key)?;
match entry {
Entry::Singleton { factory, instance } => {
let mut guard = instance.lock().ok()?;
if guard.is_none() {
let boxed = factory();
let val = *boxed.downcast::<T>()
.expect("类型不匹配:注册和解析的类型不一致");
*guard = Some(Arc::new(val) as Arc<dyn Any + Send + Sync>);
}
guard.as_ref().map(|arc_any| {
arc_any.clone().downcast::<T>()
.expect("单例内部类型转换失败")
})
}
Entry::Factory { .. } => None,
}
}
pub fn get_bean<T: Any + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
let entry = self.items.get(key)?;
match entry {
Entry::Factory(factory) => {
let boxed = factory();
let val = *boxed.downcast::<T>().ok()?;
Some(Arc::new(val))
}
Entry::Singleton { factory, instance } => {
let mut guard = instance.lock().ok()?;
if guard.is_none() {
let val = *factory().downcast::<T>().ok()?;
*guard = Some(Arc::new(val) as Arc<dyn Any + Send + Sync>);
}
guard.as_ref()?.clone().downcast::<T>().ok()
}
}
}
pub fn is_singleton(&self, key: &str) -> bool {
matches!(self.items.get(key), Some(Entry::Singleton { .. }))
}
}
pub struct Reg {
pub name: &'static str,
pub apply: fn(&mut crate::rudi::dicontainer::container::Container),
}
inventory::collect!(Reg);
pub fn bootstrap(container: &mut crate::rudi::dicontainer::container::Container) {
for reg in inventory::iter::<Reg> {
(reg.apply)(container);
}
}
#[macro_export]
macro_rules! register_singleton {
($key:expr, $type:ty, $factory:expr) => {
inventory::submit! {
$crate::rudi::dicontainer::container::Reg {
name: $key,
apply: |c: &mut $crate::rudi::dicontainer::container::Container| {
c.register_singleton($key, $factory);
},
}
}
};
}
#[macro_export]
macro_rules! register_transient {
($key:expr, $type:ty, $factory:expr) => {
inventory::submit! {
$crate::rudi::dicontainer::container::Reg {
name: $key,
apply: |c: &mut $crate::rudi::dicontainer::container::Container| {
c.register($key, $factory);
},
}
}
};
}