use crate::config::{AppConfig, DatabaseConnection};
use parking_lot::RwLock;
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, OnceLock};
type ServiceInstance = Arc<dyn Any + Send + Sync>;
type ScopeInstances = HashMap<TypeId, ServiceInstance>;
static APP: OnceLock<App> = OnceLock::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lifetime {
Singleton,
Transient,
Scoped,
}
pub use sz_rust_middleware_facade::ScopeId;
type ServiceFactory = Arc<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>;
#[derive(Clone)]
struct ServiceBinding {
factory: ServiceFactory,
lifetime: Lifetime,
}
type ContextBindingFactory = Arc<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>;
type ContextBindingMap = HashMap<(TypeId, TypeId), ContextBindingFactory>;
pub struct Container {
bindings: RwLock<HashMap<TypeId, ServiceBinding>>,
instances: RwLock<HashMap<TypeId, ServiceInstance>>,
scoped_instances: RwLock<HashMap<ScopeId, ScopeInstances>>,
aliases: RwLock<HashMap<String, TypeId>>,
tags: RwLock<HashMap<String, Vec<TypeId>>>,
context_bindings: RwLock<ContextBindingMap>,
constructing: RwLock<Vec<(&'static str, TypeId)>>,
}
impl Container {
pub fn new() -> Self {
Self {
bindings: RwLock::new(HashMap::new()),
instances: RwLock::new(HashMap::new()),
scoped_instances: RwLock::new(HashMap::new()),
aliases: RwLock::new(HashMap::new()),
tags: RwLock::new(HashMap::new()),
context_bindings: RwLock::new(HashMap::new()),
constructing: RwLock::new(Vec::new()),
}
}
pub fn bind<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
let type_id = TypeId::of::<T>();
let binding = ServiceBinding {
factory: Arc::new(move || Box::new(factory())),
lifetime: Lifetime::Transient,
};
self.bindings.write().insert(type_id, binding);
}
pub fn singleton<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
let type_id = TypeId::of::<T>();
let binding = ServiceBinding {
factory: Arc::new(move || Box::new(factory())),
lifetime: Lifetime::Singleton,
};
self.bindings.write().insert(type_id, binding);
}
pub fn scoped<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
let type_id = TypeId::of::<T>();
let binding = ServiceBinding {
factory: Arc::new(move || Box::new(factory())),
lifetime: Lifetime::Scoped,
};
self.bindings.write().insert(type_id, binding);
}
pub fn instance<T>(&self, instance: T)
where
T: Send + Sync + 'static,
{
let type_id = TypeId::of::<T>();
let arc: Arc<dyn Any + Send + Sync> = Arc::new(instance);
self.instances.write().insert(type_id, arc);
self.bindings.write().insert(
type_id,
ServiceBinding {
factory: Arc::new(|| {
panic!("instance() 绑定的服务不应调用工厂 — 这是内部不变量违反")
}),
lifetime: Lifetime::Singleton,
},
);
}
pub fn alias<T: 'static>(&self, name: impl Into<String>) {
let type_id = TypeId::of::<T>();
self.aliases.write().insert(name.into(), type_id);
}
pub fn resolve_alias(&self, name: &str) -> Option<TypeId> {
self.aliases.read().get(name).copied()
}
pub fn is_alias(&self, name: &str) -> bool {
self.aliases.read().contains_key(name)
}
pub fn debug_aliases(&self) -> Vec<String> {
self.aliases.read().keys().cloned().collect()
}
#[inline]
pub fn make<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
self.make_with_scope::<T>(0)
}
pub fn make_with_scope<T: Send + Sync + 'static>(&self, scope_id: ScopeId) -> Option<Arc<T>> {
let type_id = TypeId::of::<T>();
if let Some(cached) = self.instances.read().get(&type_id) {
return Arc::downcast::<T>(cached.clone()).ok();
}
if scope_id != 0 {
let scoped = self.scoped_instances.read();
if let Some(scope_map) = scoped.get(&scope_id) {
if let Some(cached) = scope_map.get(&type_id) {
return Arc::downcast::<T>(cached.clone()).ok();
}
}
}
let guard = self.bindings.read();
let binding = guard.get(&type_id)?.clone();
drop(guard);
let type_name = std::any::type_name::<T>();
let instance = self.check_and_call_factory(type_id, type_name, &binding.factory)?;
match binding.lifetime {
Lifetime::Singleton => {
let arc: Arc<dyn Any + Send + Sync> = Arc::from(instance);
self.instances.write().insert(type_id, arc.clone());
Arc::downcast::<T>(arc).ok()
}
Lifetime::Scoped => {
let arc: Arc<dyn Any + Send + Sync> = Arc::from(instance);
self.scoped_instances
.write()
.entry(scope_id)
.or_default()
.insert(type_id, arc.clone());
Arc::downcast::<T>(arc).ok()
}
Lifetime::Transient => {
Arc::downcast::<T>(Arc::from(instance)).ok()
}
}
}
pub fn clear_scope(&self, scope_id: ScopeId) {
self.scoped_instances.write().remove(&scope_id);
}
pub fn has<T: 'static>(&self) -> bool {
let type_id = TypeId::of::<T>();
self.bindings.read().contains_key(&type_id)
}
pub fn forget<T: 'static>(&self) {
let type_id = TypeId::of::<T>();
self.bindings.write().remove(&type_id);
self.instances.write().remove(&type_id);
let mut scoped = self.scoped_instances.write();
for scope_map in scoped.values_mut() {
scope_map.remove(&type_id);
}
}
pub fn clear(&self) {
self.bindings.write().clear();
self.instances.write().clear();
self.scoped_instances.write().clear();
self.aliases.write().clear();
self.tags.write().clear();
self.context_bindings.write().clear();
self.constructing.write().clear();
}
pub fn constructing_depth(&self) -> usize {
self.constructing.read().len()
}
pub fn count(&self) -> usize {
self.bindings.read().len()
}
pub fn alias_count(&self) -> usize {
self.aliases.read().len()
}
pub fn active_scope_count(&self) -> usize {
self.scoped_instances.read().len()
}
pub fn tag<T: 'static>(&self, tag: impl Into<String>) {
let type_id = TypeId::of::<T>();
let tag_name = tag.into();
self.tags.write().entry(tag_name).or_default().push(type_id);
}
pub fn tagged<T: Send + Sync + 'static>(&self, tag: &str) -> Vec<Arc<T>> {
let type_ids = match self.tags.read().get(tag) {
Some(ids) => ids.clone(),
None => return Vec::new(),
};
let target_type_id = TypeId::of::<T>();
type_ids
.into_iter()
.filter(|id| *id == target_type_id)
.filter_map(|_| self.make::<T>())
.collect()
}
pub fn tagged_type_ids(&self, tag: &str) -> Vec<TypeId> {
self.tags.read().get(tag).cloned().unwrap_or_default()
}
pub fn tag_names(&self) -> Vec<String> {
self.tags.read().keys().cloned().collect()
}
pub fn tag_count(&self, tag: &str) -> usize {
self.tags.read().get(tag).map(|ids| ids.len()).unwrap_or(0)
}
pub fn forget_tag(&self, tag: &str) {
self.tags.write().remove(tag);
}
pub fn bind_contextual<Consumer: 'static, T: Send + Sync + 'static, F>(&self, factory: F)
where
F: Fn() -> T + Send + Sync + 'static,
{
let key = (TypeId::of::<Consumer>(), TypeId::of::<T>());
let arc_factory: Arc<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync> =
Arc::new(move || Box::new(factory()));
self.context_bindings.write().insert(key, arc_factory);
}
pub fn make_for<T: Send + Sync + 'static, Consumer: 'static>(&self) -> Option<Arc<T>> {
let key = (TypeId::of::<Consumer>(), TypeId::of::<T>());
let factory = {
let guard = self.context_bindings.read();
guard.get(&key).cloned()
};
if let Some(factory) = factory {
let type_id = TypeId::of::<T>();
let type_name = std::any::type_name::<T>();
let instance = self.check_and_call_factory(type_id, type_name, &factory);
instance.and_then(|inst| Arc::downcast::<T>(Arc::from(inst)).ok())
} else {
self.make::<T>()
}
}
fn check_and_call_factory(
&self,
type_id: TypeId,
type_name: &'static str,
factory: &ServiceFactory,
) -> Option<Box<dyn Any + Send + Sync>> {
{
let constructing = self.constructing.read();
if constructing.iter().any(|(_, tid)| *tid == type_id) {
let chain: Vec<&str> = constructing
.iter()
.skip_while(|(_, tid)| *tid != type_id)
.map(|(name, _)| *name)
.chain(std::iter::once(type_name))
.collect();
drop(constructing);
panic!("DI 容器检测到循环依赖: {}", chain.join(" -> "));
}
}
self.constructing.write().push((type_name, type_id));
let instance = factory();
self.constructing.write().pop();
Some(instance)
}
pub fn has_contextual<Consumer: 'static, T: 'static>(&self) -> bool {
let key = (TypeId::of::<Consumer>(), TypeId::of::<T>());
self.context_bindings.read().contains_key(&key)
}
pub fn contextual_count(&self) -> usize {
self.context_bindings.read().len()
}
pub fn forget_contextual<Consumer: 'static, T: 'static>(&self) {
let key = (TypeId::of::<Consumer>(), TypeId::of::<T>());
self.context_bindings.write().remove(&key);
}
pub fn call_method<R, P, F, C>(&self, resolver: C, callback: F) -> R
where
F: FnOnce(P) -> R,
C: FnOnce(&Self) -> P,
{
let params = resolver(self);
callback(params)
}
pub fn invoke<R, F>(&self, callback: F) -> R
where
F: FnOnce(&Self) -> R,
{
callback(self)
}
#[inline]
pub fn make_or_panic<T: Send + Sync + 'static>(&self) -> Arc<T> {
match self.make::<T>() {
Some(instance) => instance,
None => panic!(
"无法解析服务: {} — 请确保已通过 bind/singleton/scoped 注册",
std::any::type_name::<T>()
),
}
}
}
impl Default for Container {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for Container {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Container")
.field("bindings_count", &self.bindings.read().len())
.field("instances_count", &self.instances.read().len())
.field("scoped_scope_count", &self.scoped_instances.read().len())
.field("aliases_count", &self.aliases.read().len())
.finish()
}
}
pub struct App {
config: AppConfig,
db_connections: HashMap<String, DatabaseConnection>,
cache: RwLock<Option<String>>,
log: RwLock<Option<String>>,
container: Container,
}
impl App {
pub fn new(config: AppConfig) -> App {
let db_connections = config.database.connections.clone();
App {
config,
db_connections,
cache: RwLock::new(None),
log: RwLock::new(None),
container: Container::new(),
}
}
pub fn init(config: AppConfig) -> &'static App {
APP.get_or_init(|| App::new(config))
}
pub fn global() -> Option<&'static App> {
APP.get()
}
pub fn config(&self) -> &AppConfig {
&self.config
}
pub fn db_connection(&self, name: &str) -> Option<&DatabaseConnection> {
self.db_connections.get(name)
}
pub fn db_connection_names(&self) -> Vec<&str> {
self.db_connections.keys().map(|s| s.as_str()).collect()
}
pub fn default_db_connection(&self) -> Option<&DatabaseConnection> {
self.db_connection(&self.config.database.default)
}
pub fn set_cache(&self, cache: impl Into<String>) {
let mut guard = self.cache.write();
*guard = Some(cache.into());
}
pub fn cache(&self) -> Option<String> {
self.cache.read().clone()
}
pub fn set_log(&self, log: impl Into<String>) {
let mut guard = self.log.write();
*guard = Some(log.into());
}
pub fn log(&self) -> Option<String> {
self.log.read().clone()
}
pub fn container(&self) -> &Container {
&self.container
}
pub fn bind<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
self.container.bind(factory);
}
pub fn singleton<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
self.container.singleton(factory);
}
pub fn scoped<T, F>(&self, factory: F)
where
T: Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
self.container.scoped(factory);
}
pub fn instance<T>(&self, instance: T)
where
T: Send + Sync + 'static,
{
self.container.instance(instance);
}
pub fn alias<T: 'static>(&self, name: impl Into<String>) {
self.container.alias::<T>(name);
}
#[inline]
pub fn make<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
if let Some(scope_id) = crate::middleware::request_scope::current_scope_id() {
self.container.make_with_scope::<T>(scope_id)
} else {
self.container.make::<T>()
}
}
#[inline]
pub fn make_with_scope<T: Send + Sync + 'static>(&self, scope_id: ScopeId) -> Option<Arc<T>> {
self.container.make_with_scope::<T>(scope_id)
}
pub fn clear_scope(&self, scope_id: ScopeId) {
self.container.clear_scope(scope_id);
}
pub fn has_service<T: 'static>(&self) -> bool {
self.container.has::<T>()
}
}
impl std::fmt::Debug for App {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("App")
.field("config", &self.config)
.field(
"db_connections",
&self.db_connections.keys().collect::<Vec<_>>(),
)
.field("cache", &self.cache.read().is_some())
.field("log", &self.log.read().is_some())
.field("container", &self.container)
.finish()
}
}
#[cfg(test)]
mod tests;