Skip to main content

rust_dix/
entry.rs

1use crate::error::RdiError;
2use crate::provider::ServiceProvider;
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::future::Future;
6use std::pin::Pin;
7use std::sync::Arc;
8
9/// Service lifetime enum — defines how instances are cached.
10///
11/// - `Transient`: new instance every resolution (never cached)
12/// - `Scoped`: one instance per scope (cached within the scope)
13/// - `Singleton`: one instance shared across all scopes (cached globally)
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum ServiceLifetime {
16    Transient,
17    Scoped,
18    Singleton,
19}
20
21/// Service descriptor holds registration metadata for a service.
22///
23/// Created during `ServiceCollection` building and passed to `ServiceStore`
24/// to create `ServiceEntry`.
25#[derive(Clone)]
26pub struct ServiceDescriptor {
27    pub type_id: TypeId,
28    pub type_name: &'static str,
29    pub key: Option<String>,
30    pub factory: ServiceFactory,
31    pub async_factory: Option<AsyncServiceFactory>,
32    pub lifetime: ServiceLifetime,
33}
34
35/// ServiceStore is the root registry — maps `TypeId` to all `ServiceEntry` entries.
36///
37/// Multiple entries per type exist when keyed variants are registered.
38pub type ServiceStore = HashMap<TypeId, Vec<ServiceEntry>>;
39
40/// Service resolver trait — the core DI resolution interface.
41///
42/// Provides both type-erased and generic resolution methods.
43///
44/// # Panic contract of `Option`-returning lookups
45///
46/// [`Self::get_any`], [`Self::get_keyed_any`], [`Self::get_by_type_id`] and
47/// [`Self::get_keyed_by_type_id`] return `Option` because they answer "found or
48/// not". For a *registered* service that must not be resolved at this point
49/// (root scope validation under `validate_scopes`, a disposed provider/scope,
50/// circular dependency) implementations panic with a **typed [`RdiError`]**
51/// payload instead of returning `None`, so required-resolution APIs
52/// ([`Self::get`], `ServiceProvider::get`, …) can catch it and surface a precise
53/// `Err`. Constructor injection relies on this to propagate the real cause
54/// through user factories.
55///
56/// Infallible probing must use [`Self::try_get_any_result`] /
57/// [`Self::try_get_keyed_any_result`] (or `try_get` / `try_get_keyed`), which
58/// map such failures to `None`/`Err` without panicking.
59pub trait IServiceResolver: Send + Sync {
60    fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>>;
61    fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>>;
62
63    /// TypeId 直查(默认 `None`,`ServiceProvider` 等覆盖为 O(1) 直查)。
64    ///
65    /// 外部实现者若需优化可覆盖;不覆盖则 [`Self::get`] 默认实现 fallback
66    /// 到 [`Self::get_any`] 字符串路径。
67    ///
68    /// 覆盖实现须遵循 trait 级 panic 契约(注册但当前不可解析 → typed
69    /// [`RdiError`] payload panic,供 required API 捕获;可选探测请用
70    /// [`Self::try_get_any_result`])。
71    fn get_by_type_id(&self, _tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
72        None
73    }
74    /// TypeId 直查 keyed 版本(默认 `None`)。
75    ///
76    /// 覆盖实现须遵循 trait 级 panic 契约(见 [`Self::get_by_type_id`])。
77    fn get_keyed_by_type_id(&self, _tid: TypeId, _key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
78        None
79    }
80
81    /// Type-erased polymorphic resolution: return all **unkeyed** registered
82    /// instances of the given type, in registration order.
83    ///
84    /// Equivalent to C# MEDI `GetServices<T>()` / `IEnumerable<IFoo>`
85    /// constructor injection, which also excludes keyed services.
86    /// Keyed implementations are enumerated with [`Self::get_all_keyed_any`].
87    ///
88    /// Default empty `Vec` keeps external implementors backward-compatible.
89    fn get_all_any(&self, _key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
90        Vec::new()
91    }
92
93    /// Type-erased polymorphic resolution over **keyed** registrations only
94    /// (MEDI `GetKeyedServices<T>(KeyedService.AnyKey)`).
95    ///
96    /// Default empty `Vec` keeps external implementors backward-compatible.
97    fn get_all_keyed_any(&self, _key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
98        Vec::new()
99    }
100
101    /// Error-reporting variant of [`Self::get_all_any`], used by the inject
102    /// macros for `Vec<Arc<T>>` fields.
103    ///
104    /// Containers that can fail (scope validation, disposal, factory errors)
105    /// override it so constructor injection surfaces a typed [`RdiError`]
106    /// instead of silently returning a partial/empty list. The default keeps
107    /// external implementors source-compatible.
108    fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
109        Ok(self.get_all_any(key))
110    }
111
112    /// Return an `Arc<ServiceProvider>` for on-demand service resolution.
113    ///
114    /// Used by `#[inject(provider)]` to give a service access to the DI container
115    /// so it can resolve scoped/owned instances on-demand (e.g., per-request
116    /// `DbContext` in a web handler, or per-tick scopes in a singleton worker).
117    ///
118    /// Available during `build()` as well: validation executes singleton
119    /// factories against the real provider, so `#[inject(provider)]` works in
120    /// eagerly built singletons too.
121    ///
122    /// Returns `None` only for resolvers not backed by a `ServiceProvider`.
123    ///
124    /// Default `None` keeps external implementors backward-compatible.
125    fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
126        None
127    }
128
129    /// Resolve a service by type (concrete or `dyn Trait`).
130    /// Returns `Err(RdiError::ServiceNotFound)` if not registered.
131    ///
132    /// 优先走 `get_by_type_id`(O(1) TypeId 直查),未覆盖时 fallback
133    /// 到 `get_any` 字符串路径。
134    fn get<T: ?Sized + Sync + Send + 'static>(&self) -> Result<Arc<T>, RdiError>
135    where
136        Self: Sized,
137    {
138        let type_name = std::any::type_name::<T>();
139        let tid = TypeId::of::<T>();
140        self.get_by_type_id(tid)
141            .or_else(|| self.get_any(type_name))
142            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
143            .ok_or_else(|| RdiError::not_found(type_name, None))
144    }
145
146    /// Resolve a service by type, returning `None` if it is not registered or
147    /// not resolvable at this point (e.g. a scoped service under root scope
148    /// validation, or a disposed provider/scope).
149    ///
150    /// Uses [`Self::try_get_any_result`]; containers override it with an
151    /// infallible lookup so `try_get` never panics for framework-level failures.
152    fn try_get<T: ?Sized + Sync + Send + 'static>(&self) -> Option<Arc<T>>
153    where
154        Self: Sized,
155    {
156        let type_name = std::any::type_name::<T>();
157        self.try_get_any_result(type_name)
158            .ok()
159            .flatten()
160            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
161    }
162
163    /// Fallible, type-erased lookup used by [`Self::try_get`].
164    ///
165    /// Default implementation delegates to [`Self::get_any`] (so external
166    /// resolvers keep working); containers that can fail override it so
167    /// infallible lookups can distinguish "absent" from "resolution error"
168    /// without panicking.
169    fn try_get_any_result(
170        &self,
171        key: &str,
172    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
173        Ok(self.get_any(key))
174    }
175
176    /// Resolve a keyed service by type and key. Returns `Err` if not found.
177    fn get_keyed<T: ?Sized + Sync + Send + 'static>(
178        &self,
179        variant: &str,
180    ) -> Result<Arc<T>, RdiError>
181    where
182        Self: Sized,
183    {
184        let type_name = std::any::type_name::<T>();
185        let tid = TypeId::of::<T>();
186        self.get_keyed_by_type_id(tid, variant)
187            .or_else(|| self.get_keyed_any(type_name, variant))
188            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
189            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))
190    }
191
192    /// Resolve a keyed service by type and key, returning `None` if not found or
193    /// not resolvable at this point (e.g. root scope validation, disposed
194    /// provider/scope). Never panics for framework-level failures.
195    fn try_get_keyed<T: ?Sized + Sync + Send + 'static>(&self, variant: &str) -> Option<Arc<T>>
196    where
197        Self: Sized,
198    {
199        let type_name = std::any::type_name::<T>();
200        self.try_get_keyed_any_result(type_name, variant)
201            .ok()
202            .flatten()
203            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
204    }
205
206    /// Fallible, type-erased keyed lookup used by [`Self::try_get_keyed`].
207    ///
208    /// Default implementation delegates to [`Self::get_keyed_any`]; containers
209    /// override it to return `None`/`Err` without panicking.
210    fn try_get_keyed_any_result(
211        &self,
212        key: &str,
213        variant: &str,
214    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
215        Ok(self.get_keyed_any(key, variant))
216    }
217
218    /// Resolve all **unkeyed** registered instances of `T`, in registration
219    /// order.
220    ///
221    /// Equivalent to C# MEDI `GetServices<T>()` (which also excludes keyed
222    /// services). Types implementing `IServiceResolver` get this for free via
223    /// `get_all_any`; types with an inherent `get_all<T>` method (e.g.
224    /// `ServiceProvider`, `Scope`) use that instead — Rust's method resolution
225    /// gives inherent methods priority over trait methods.
226    fn get_all<T: ?Sized + Sync + Send + 'static>(&self) -> Vec<Arc<T>>
227    where
228        Self: Sized,
229    {
230        self.get_all_any(std::any::type_name::<T>())
231            .into_iter()
232            .filter_map(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
233            .collect()
234    }
235
236    /// Type-erased owned resolution: bypass cache, call factory fresh, return
237    /// `Arc<dyn Any + Send + Sync>` (concrete `Arc<Arc<T>>`).
238    ///
239    /// - Singleton → `None` (shared singleton cannot be owned).
240    /// - Scoped/Transient → factory invoked directly (no cache read/write),
241    ///   caller downcasts + `Arc::try_unwrap` to obtain owned `T`.
242    ///
243    /// Default `None` keeps external implementors backward-compatible.
244    fn get_owned_any(&self, _key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
245        None
246    }
247    fn get_keyed_owned_any(
248        &self,
249        _key: &str,
250        _variant: &str,
251    ) -> Option<Arc<dyn Any + Send + Sync>> {
252        None
253    }
254
255    /// Resolve owned `T` (bypass cache, fresh each call).
256    /// Returns `Err` if not registered or the service is Singleton.
257    fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError>
258    where
259        Self: Sized,
260    {
261        let type_name = std::any::type_name::<T>();
262        let arc_any = self
263            .get_owned_any(type_name)
264            .ok_or_else(|| RdiError::not_found(type_name, None))?;
265        let arc_t: Arc<T> = arc_any
266            .downcast::<Arc<T>>()
267            .ok()
268            .map(|d| Arc::clone(&*d))
269            .ok_or_else(|| RdiError::not_found(type_name, None))?;
270        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
271    }
272
273    /// Resolve owned `T`, returning `None` if not registered or Singleton.
274    fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T>
275    where
276        Self: Sized,
277    {
278        let arc_any = self.get_owned_any(std::any::type_name::<T>())?;
279        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
280        Arc::try_unwrap(arc_t).ok()
281    }
282
283    /// Resolve owned keyed `T`.
284    /// Returns `Err` if not found or Singleton.
285    fn get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Result<T, RdiError>
286    where
287        Self: Sized,
288    {
289        let type_name = std::any::type_name::<T>();
290        let arc_any = self
291            .get_keyed_owned_any(type_name, variant)
292            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))?;
293        let arc_t: Arc<T> = arc_any
294            .downcast::<Arc<T>>()
295            .ok()
296            .map(|d| Arc::clone(&*d))
297            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))?;
298        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
299    }
300
301    /// Resolve owned keyed `T`, returning `None` if not found or Singleton.
302    fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Option<T>
303    where
304        Self: Sized,
305    {
306        let arc_any = self.get_keyed_owned_any(std::any::type_name::<T>(), variant)?;
307        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
308        Arc::try_unwrap(arc_t).ok()
309    }
310}
311
312pub struct ServiceEntry {
313    pub cache_key: usize,
314    pub key: Option<String>,
315    pub type_name: &'static str, // kept for IServiceResolver string-based resolution
316    pub factory: ServiceFactory,
317    pub async_factory: Option<AsyncServiceFactory>,
318    pub lifetime: ServiceLifetime,
319}
320
321pub type ServiceFactory =
322    Arc<dyn Fn(&dyn IServiceResolver) -> Arc<dyn Any + Send + Sync> + Send + Sync>;
323
324/// Async variant of [`ServiceFactory`] — for services that require async
325/// initialization (e.g., database connections, remote config loading).
326///
327/// Used with [`ServiceCollection::build_async`](crate::collection::ServiceCollection::build_async).
328/// The factory receives an `Arc<ServiceProvider>` (instead of `&dyn IServiceResolver`)
329/// because async closures cannot borrow from the caller's stack frame.
330pub type AsyncServiceFactory = Arc<
331    dyn Fn(Arc<ServiceProvider>) -> Pin<Box<dyn Future<Output = Arc<dyn Any + Send + Sync>> + Send>>
332        + Send
333        + Sync,
334>;