use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock, RwLock};
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_c<T: Any + Send + Sync + Clone>(&self, key: &str) -> Option<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 arc = Arc::new(
*boxed
.downcast::<T>()
.expect("类型不匹配:注册和解析的类型不一致"),
);
*guard = Some(arc);
}
guard.as_ref().map(|arc| {
arc.downcast_ref::<T>()
.expect("类型转换失败")
.clone()
})
}
Entry::Factory { .. } => 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 { .. }))
}
}
#[derive(Debug, Clone)]
struct Database {
id: u64,
}
impl Database {
fn new() -> Self {
println!(">>> Database::new() 被调用了!");
Self { id: rand::random() }
}
}
#[derive(Debug, Clone)]
struct Logger;
impl Logger {
fn new() -> Self {
println!(">>> Logger::new() 被调用了!");
Self
}
}
fn main() {
let mut container = Container::new();
container.register("db", Database::new);
container.register_singleton("logger", Logger::new);
println!("--- 第一次 get db ---");
let db1 = container.get::<Database>("db").unwrap();
println!("db1: {:?}\n", db1);
println!("--- 第二次 get db ---");
let db2 = container.get::<Database>("db").unwrap();
println!("db2: {:?}\n", db2);
println!("--- 第一次 get logger ---");
let log1 = container.get_singleton::<Logger>("logger").unwrap();
println!("log1: {:?}\n", log1);
println!("--- 第二次 get logger ---");
let log2 = container.get_singleton::<Logger>("logger").unwrap();
println!("log2: {:?}\n", log2);
println!("db1 == db2 ? {}", db1.id == db2.id); println!("log1 == log2 ? {}", std::ptr::eq(&log1, &log2)); }
pub struct Reg {
pub name: &'static str,
pub apply: fn(&mut crate::rudi::dicontainer::dicontainer::Container),
}
inventory::collect!(Reg);
pub fn bootstrap(container: &mut crate::rudi::dicontainer::dicontainer::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::dicontainer::Reg {
name: $key,
apply: |c: &mut $crate::rudi::dicontainer::dicontainer::Container| {
c.register_singleton($key, $factory);
},
}
}
};
}
#[macro_export]
macro_rules! register_transient {
($key:expr, $type:ty, $factory:expr) => {
inventory::submit! {
$crate::rudi::dicontainer::dicontainer::Reg {
name: $key,
apply: |c: &mut $crate::rudi::dicontainer::dicontainer::Container| {
c.register($key, $factory);
},
}
}
};
}