Skip to main content

tx_di_core/
store.rs

1//! Store — 类型擦除的组件存储
2//!
3//! 底层是 `DashMap<TypeId, CompRef>`,运行期解析依赖。
4//! 对外提供类型安全的 `inject::<T>()` 接口。
5
6use std::any::{Any, TypeId};
7use std::sync::Arc;
8
9use dashmap::DashMap;
10
11use crate::component::Component;
12use crate::error::{AppError, DiErr};
13
14/// 存储单元:
15/// - `Factory(Arc<dyn Fn>)` → 存工厂闭包,prototype 每次注入时调用
16/// - `Cached(Arc<dyn Any>)` → 已实例化的单例(擦除类型)
17#[derive(Clone)]
18pub enum CompRef {
19    /// 工厂闭包:Prototype 作用域,每次注入调用
20    Factory(Arc<dyn Fn(&Store) -> Arc<dyn Any + Send + Sync> + Send + Sync>),
21    /// 已缓存的实例:Singleton 作用域
22    Cached(Arc<dyn Any + Send + Sync>),
23}
24
25/// 组件存储 — 类型安全的注入入口
26pub struct Store {
27    inner: DashMap<TypeId, CompRef>,
28    /// trait 实现的映射表(trait TypeId → 实现列表),由 BuildContext 在构建时填充
29    pub(crate) trait_impls: TraitImplMap,
30}
31
32impl Store {
33    /// 创建空 Store
34    pub fn new() -> Self {
35        Store {
36            inner: DashMap::new(),
37            trait_impls: DashMap::new(),
38        }
39    }
40
41    /// 从 DashMap 创建 Store(trait_impls 为空,需后续填充)
42    pub fn from_dashmap(inner: DashMap<TypeId, CompRef>) -> Self {
43        Store {
44            inner,
45            trait_impls: DashMap::new(),
46        }
47    }
48
49    /// 获取内部 DashMap 的引用
50    pub fn inner(&self) -> &DashMap<TypeId, CompRef> {
51        &self.inner
52    }
53
54    /// 获取内部 DashMap 的所有权(消耗 self)
55    pub fn into_inner(self) -> DashMap<TypeId, CompRef> {
56        self.inner
57    }
58
59    /// 注册缓存实例(Singleton)
60    pub fn insert_cached<T: Any + Send + Sync>(&self, value: T) {
61        self.inner
62            .insert(TypeId::of::<T>(), CompRef::Cached(Arc::new(value)));
63    }
64
65    /// 注册已 Arc 包装的缓存实例
66    pub fn insert_arc<T: Any + Send + Sync>(&self, arc: Arc<T>) {
67        self.inner
68            .insert(TypeId::of::<T>(), CompRef::Cached(arc as Arc<dyn Any + Send + Sync>));
69    }
70
71    /// 注册工厂闭包(Prototype)
72    ///
73    /// 每次注入时调用工厂,构造新实例。
74    /// `T` 为组件类型,`TypeId` 通过 `TypeId::of::<T>()` 自动获取。
75    pub fn insert_factory<T: Any + Send + Sync, F>(&self, factory: F)
76    where
77        F: Fn(&Store) -> Arc<T> + Send + Sync + 'static,
78    {
79        let type_id = TypeId::of::<T>();
80        self.inner.insert(type_id, CompRef::Factory(Arc::new(move |store| {
81            factory(store) as Arc<dyn Any + Send + Sync>
82        })));
83    }
84
85    /// 注入组件实例(类型安全)
86    ///
87    /// - Singleton:返回缓存的 `Arc<T>`
88    /// - Prototype:调用工厂闭包,每次构造新实例
89    ///
90    /// # Panics
91    ///
92    /// 组件未注册时 panic(编程错误,不是运行时错误)。
93    pub fn inject<T: Component>(&self) -> Result<Arc<T>, AppError> {
94        let tid = TypeId::of::<T>();
95        let type_name = std::any::type_name::<T>();
96
97        match self.inner.get(&tid) {
98            Some(entry) => {
99                let any_arc = match &*entry {
100                    CompRef::Cached(arc) => arc.clone(),
101                    CompRef::Factory(f) => f(self),
102                };
103                any_arc.downcast::<T>().map_err(|bad_arc| {
104                    let actual = (&*bad_arc).type_id();
105                    AppError::with_context(
106                        DiErr::InjectError,
107                        format!(
108                            "downcast 失败: 期望 `{}`, 实际 TypeId={:?}",
109                            type_name, actual
110                        ),
111                    )
112                })
113            }
114            None => {
115                let count = self.inner.len();
116                Err(AppError::with_context(
117                    DiErr::InjectError,
118                    format!(
119                        "组件 `{}` (TypeId={:?}) 未注册。\n\
120                         请确认:\n\
121                         1. 该结构体已标注 #[derive(Component)]\n\
122                         2. 所在 crate 已在 Cargo.toml 中引入\n\
123                         当前已注册 {} 个组件",
124                        type_name, tid, count
125                    ),
126                ))
127            }
128        }
129    }
130
131    /// 注入组件实例(类型安全)— 直接返回 Arc<T>,失败时 panic
132    ///
133    /// 这是 `inject()` 的便捷版本,用于不需要错误处理的场景。
134    pub fn inject_or_panic<T: Component>(&self) -> Arc<T> {
135        match self.inject::<T>() {
136            Ok(arc) => arc,
137            Err(e) => panic!("{}", e),
138        }
139    }
140
141    /// 尝试注入,失败返回 None
142    pub fn try_inject<T: Component>(&self) -> Option<Arc<T>> {
143        self.inject::<T>().ok()
144    }
145
146    /// 检查组件是否已注册
147    pub fn contains<T: Any + Send + Sync>(&self) -> bool {
148        self.inner.contains_key(&TypeId::of::<T>())
149    }
150
151    /// 已注册组件数量
152    pub fn len(&self) -> usize {
153        self.inner.len()
154    }
155
156    /// 是否为空
157    pub fn is_empty(&self) -> bool {
158        self.inner.is_empty()
159    }
160}
161
162impl Default for Store {
163    fn default() -> Self {
164        Self::new()
165    }
166}
167
168// ── 全局注入函数(兼容宏生成的代码)──────────────────────────────────────
169
170/// 从 Store 中注入依赖(类型安全版本)
171///
172/// 供宏生成的 `build` 方法调用。
173///
174/// # Panics
175///
176/// 组件未注册时 panic,附带已注册组件列表辅助排查。
177pub fn inject_from_store<T: Component>(store: &Store) -> Arc<T> {
178    store.inject_or_panic::<T>()
179}
180
181// ── Trait Object 注入 ─────────────────────────────────────────────────────
182
183/// trait 实现条目:记录某个 trait 的一个具体实现
184#[derive(Clone, Copy)]
185pub struct TraitImplEntry {
186    /// 具体类型的 TypeId
187    pub concrete_tid: fn() -> TypeId,
188    /// 将具体实例 (Arc<dyn Any + Send + Sync>) 转型为 trait object
189    /// 返回的 Arc<dyn Any + Send + Sync> 内部是 Arc<dyn Trait>
190    pub upcast: fn(Arc<dyn Any + Send + Sync>) -> Arc<dyn Any + Send + Sync>,
191}
192
193/// trait TypeId → 实现列表的映射表类型
194pub type TraitImplMap = DashMap<TypeId, Vec<TraitImplEntry>>;
195
196/// 从 Store 中注入 trait object(返回第一个实现)
197///
198/// 通过 `store.trait_impls` 查找 trait 的具体实现。
199///
200/// # Panics
201///
202/// trait 无实现时 panic。
203pub fn inject_trait_from_store<T: ?Sized + Any + Send + Sync + 'static>(
204    store: &Store,
205) -> Arc<T> {
206    let tid = TypeId::of::<T>();
207    let type_name = std::any::type_name::<T>();
208
209    store
210        .trait_impls
211        .get(&tid)
212        .and_then(|entries| entries.first().cloned())
213        .map(|entry| {
214            let concrete = store
215                .inner()
216                .get(&(entry.concrete_tid)())
217                .map(|r| match &*r {
218                    CompRef::Cached(any_arc) => any_arc.clone(),
219                    CompRef::Factory(f) => f(store),
220                })
221                .unwrap_or_else(|| {
222                    panic!(
223                        "[di] trait `{}` 的具体实现未注册到 store",
224                        type_name
225                    )
226                });
227            let trait_any = (entry.upcast)(concrete);
228            trait_any
229                .downcast_ref::<Arc<T>>()
230                .expect("[di] trait upcast 类型不匹配")
231                .clone()
232        })
233        .unwrap_or_else(|| {
234            panic!(
235                "[di] 注入失败: trait `{}` 无任何实现。\n\
236                 请确认:\n\
237                 1. 实现该 trait 的结构体已标注 #[component(as_trait = dyn Trait)]\n\
238                 2. 所在 crate 已在 Cargo.toml 中引入",
239                type_name
240            )
241        })
242}
243
244/// 从 Store 中注入 trait object 的所有实现
245pub fn inject_all_traits_from_store<T: ?Sized + Any + Send + Sync + 'static>(
246    store: &Store,
247) -> Vec<Arc<T>> {
248    let tid = TypeId::of::<T>();
249
250    store
251        .trait_impls
252        .get(&tid)
253        .map(|entries| {
254            entries
255                .iter()
256                .map(|entry| {
257                    let concrete = store
258                        .inner()
259                        .get(&(entry.concrete_tid)())
260                        .map(|r| match &*r {
261                            CompRef::Cached(any_arc) => any_arc.clone(),
262                            CompRef::Factory(f) => f(store),
263                        })
264                        .expect("[di] trait 具体实现未注册到 store");
265                    let trait_any = (entry.upcast)(concrete);
266                    trait_any
267                        .downcast_ref::<Arc<T>>()
268                        .expect("[di] trait upcast 类型不匹配")
269                        .clone()
270                })
271                .collect()
272        })
273        .unwrap_or_default()
274}