pub mod scopes;
pub mod comp;
use std::any::{Any, TypeId};
use std::sync::Arc;
use dashmap::DashMap;
use crate::{CompRef, ComponentDescriptor, ComponentMeta, Scope, COMPONENT_REGISTRY};
pub struct BuildContext {
store: DashMap<TypeId, CompRef>,
}
impl crate::BuildContext {
pub fn new() -> Self {
Self {
store: DashMap::new(),
}
}
pub fn register_factory<T: Any + Send + Sync + 'static>(
&mut self,
scope: Scope,
factory: fn(&mut crate::BuildContext) -> Box<T>,
) {
match scope {
Scope::Singleton => {
let instance: Arc<T> = Arc::new(*factory(self));
self.store
.insert(TypeId::of::<T>(), CompRef::Cached(instance));
}
Scope::Prototype => {
let factory_fn = factory;
let closure = move |ctx: &mut crate::BuildContext| -> Arc<dyn Any + Send + Sync> {
let boxed: Box<T> = (factory_fn)(ctx);
Arc::new(*boxed) as Arc<dyn Any + Send + Sync>
};
self.store
.insert(TypeId::of::<T>(), CompRef::Factory(Arc::new(closure)));
}
}
}
pub fn register_factory_boxed(
&mut self,
type_id: TypeId,
scope: Scope,
factory: fn(&mut crate::BuildContext) -> Box<dyn Any + Send + Sync>,
) {
match scope {
Scope::Singleton => {
let instance: Box<dyn Any + Send + Sync> = factory(self);
let arc: Arc<dyn Any + Send + Sync> = Arc::from(instance);
self.store.insert(type_id, CompRef::Cached(arc));
}
Scope::Prototype => {
let factory_fn = factory;
let closure = move |ctx: &mut crate::BuildContext| -> Arc<dyn Any + Send + Sync> {
let boxed: Box<dyn Any + Send + Sync> = (factory_fn)(ctx);
Arc::from(boxed)
};
self.store
.insert(type_id, CompRef::Factory(Arc::new(closure)));
}
}
}
pub fn inject<T: Any + Send + Sync + 'static + ComponentDescriptor>(&mut self) -> Arc<T> {
let tid = TypeId::of::<T>();
let scope = <T as ComponentDescriptor>::SCOPE;
match scope {
Scope::Singleton => self.inject_singleton::<T>(tid),
Scope::Prototype => self.inject_prototype::<T>(tid),
}
}
fn inject_singleton<T: Any + Send + Sync + 'static>(&self, tid: TypeId) -> Arc<T> {
self.store
.get(&tid)
.map(|entry| match &*entry {
CompRef::Cached(any_arc) => any_arc.clone(),
CompRef::Factory(_) => {
panic!(
"[di] inject_singleton::<{}> 错误:组件注册为 Prototype",
std::any::type_name::<T>()
)
}
})
.unwrap_or_else(|| {
panic!(
"[di] inject::<{}> 未找到,请确认 app!{{}} 中包含该组件",
std::any::type_name::<T>()
)
})
.downcast::<T>()
.unwrap_or_else(|_| {
panic!(
"[di] inject singleton downcast 失败:{}",
std::any::type_name::<T>()
)
})
}
fn inject_prototype<T: Any + Send + Sync + 'static>(&mut self, tid: TypeId) -> Arc<T> {
let factory_arc = self
.store
.get(&tid)
.map(|entry| match &*entry {
CompRef::Factory(f) => Some(f.clone()),
_ => None,
})
.flatten()
.unwrap_or_else(|| panic!("[di] inject::<{}> 未找到", std::any::type_name::<T>()));
factory_arc(self)
.downcast::<T>()
.unwrap_or_else(|_| panic!("[di] downcast 失败:{}", std::any::type_name::<T>()))
}
pub fn get_arc<T: Any + Send + Sync + 'static + ComponentDescriptor>(&mut self) -> Arc<T> {
self.inject::<T>()
}
pub fn take<T: Any + Send + Sync + 'static>(&mut self) -> T {
let entry = self
.store
.remove(&TypeId::of::<T>())
.unwrap_or_else(|| panic!("[di] take::<{}> 未找到", std::any::type_name::<T>()))
.1;
match entry {
CompRef::Cached(any_arc) => {
let arc_t: Arc<T> = any_arc.downcast::<T>().unwrap_or_else(|_| {
panic!("[di] take downcast 失败:{}", std::any::type_name::<T>())
});
Arc::try_unwrap(arc_t).unwrap_or_else(|_| {
panic!(
"[di] take::<{}> 失败:仍有其他强引用(Arc 计数 > 1)",
std::any::type_name::<T>()
)
})
}
_ => {
panic!(
"[di] take::<{}> 只能用于单例组件",
std::any::type_name::<T>()
)
}
}
}
#[inline]
pub fn len(&self) -> usize {
self.store.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.store.is_empty()
}
pub fn debug_registry() {
for meta in COMPONENT_REGISTRY.iter() {
let dep_names: Vec<&str> = meta.deps.iter().map(|dep_fn| {
COMPONENT_REGISTRY.iter()
.find(|m| (m.type_id)() == dep_fn())
.map(|m| m.name)
.unwrap_or("unknown")
}).collect();
println!(
" {:20} scope={:?} deps=[{}]",
meta.name,
meta.scope,
dep_names.join(", ")
);
}
}
fn init(&mut self) {
let mut metas: Vec<&ComponentMeta> = COMPONENT_REGISTRY
.iter()
.filter(|m| m.async_init_fn.is_some())
.collect();
metas.sort_by_key(|m| (m.init_sort_fn)());
for meta in metas {
if let Some(init_fn) = meta.init_fn {
init_fn(self);
}
}
}
async fn async_init(&mut self) {
let mut metas: Vec<&ComponentMeta> = COMPONENT_REGISTRY
.iter()
.filter(|m| m.async_init_fn.is_some())
.collect();
metas.sort_by_key(|m| (m.init_sort_fn)());
for meta in metas {
if let Some(async_init_fn) = meta.async_init_fn {
async_init_fn(self).await;
}
}
}
pub async fn run(&mut self){
self.init();
self.async_init().await
}
}
impl Default for crate::BuildContext {
fn default() -> Self {
Self::new()
}
}