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.
43pub trait IServiceResolver: Send + Sync {
44    fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>>;
45    fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>>;
46
47    /// TypeId 直查(默认 `None`,`ServiceProvider` 等覆盖为 O(1) 直查)。
48    ///
49    /// 外部实现者若需优化可覆盖;不覆盖则 [`Self::get`] / [`Self::try_get`]
50    /// 等默认实现 fallback 到 [`Self::get_any`] 字符串路径。
51    fn get_by_type_id(&self, _tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
52        None
53    }
54    /// TypeId 直查 keyed 版本(默认 `None`)。
55    fn get_keyed_by_type_id(
56        &self,
57        _tid: TypeId,
58        _key: &str,
59    ) -> Option<Arc<dyn Any + Send + Sync>> {
60        None
61    }
62
63    /// Type-erased polymorphic resolution: return all registered instances
64    /// (default + keyed) of the given type.
65    ///
66    /// Used by `Vec<Arc<T>>` field injection (`#[inject]` on `Vec<Arc<T>>`)
67    /// to collect all implementations — equivalent to C# MEDI
68    /// `IEnumerable<IFoo>` constructor injection.
69    ///
70    /// Default empty `Vec` keeps external implementors backward-compatible.
71    fn get_all_any(&self, _key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
72        Vec::new()
73    }
74
75    /// Return an `Arc<ServiceProvider>` for on-demand service resolution.
76    ///
77    /// Used by `#[inject(provider)]` to give a service access to the DI container
78    /// so it can resolve scoped/owned instances on-demand (e.g., per-request
79    /// `DbContext` in a web handler).
80    ///
81    /// Returns `None` if the resolver is not backed by a `ServiceProvider`
82    /// (e.g., `ValidationResolver` during build-time validation).
83    ///
84    /// Default `None` keeps external implementors backward-compatible.
85    fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
86        None
87    }
88
89    /// Resolve a service by type (concrete or `dyn Trait`).
90    /// Returns `Err(RdiError::ServiceNotFound)` if not registered.
91    ///
92    /// 优先走 `get_by_type_id`(O(1) TypeId 直查),未覆盖时 fallback
93    /// 到 `get_any` 字符串路径。
94    fn get<T: ?Sized + Sync + Send + 'static>(&self) -> Result<Arc<T>, RdiError>
95    where
96        Self: Sized,
97    {
98        let type_name = std::any::type_name::<T>();
99        let tid = TypeId::of::<T>();
100        self.get_by_type_id(tid)
101            .or_else(|| self.get_any(type_name))
102            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
103            .ok_or_else(|| RdiError::not_found(type_name, None))
104    }
105
106    /// Resolve a service by type, returning `None` if not registered.
107    fn try_get<T: ?Sized + Sync + Send + 'static>(&self) -> Option<Arc<T>>
108    where
109        Self: Sized,
110    {
111        let type_name = std::any::type_name::<T>();
112        let tid = TypeId::of::<T>();
113        self.get_by_type_id(tid)
114            .or_else(|| self.get_any(type_name))
115            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
116    }
117
118    /// Resolve a keyed service by type and key. Returns `Err` if not found.
119    fn get_keyed<T: ?Sized + Sync + Send + 'static>(&self, variant: &str) -> Result<Arc<T>, RdiError>
120    where
121        Self: Sized,
122    {
123        let type_name = std::any::type_name::<T>();
124        let tid = TypeId::of::<T>();
125        self.get_keyed_by_type_id(tid, variant)
126            .or_else(|| self.get_keyed_any(type_name, variant))
127            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
128            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))
129    }
130
131    /// Resolve a keyed service by type and key, returning `None` if not found.
132    fn try_get_keyed<T: ?Sized + Sync + Send + 'static>(&self, variant: &str) -> Option<Arc<T>>
133    where
134        Self: Sized,
135    {
136        let type_name = std::any::type_name::<T>();
137        let tid = TypeId::of::<T>();
138        self.get_keyed_by_type_id(tid, variant)
139            .or_else(|| self.get_keyed_any(type_name, variant))
140            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
141    }
142
143    /// Resolve all registered instances of `T` (default + keyed).
144    ///
145    /// Equivalent to C# MEDI `GetServices<T>()`. Types implementing `IServiceResolver`
146    /// get this for free via `get_all_any`; types with an inherent `get_all<T>`
147    /// method (e.g. `ServiceProvider`, `Scope`) use that instead — Rust's method
148    /// resolution gives inherent methods priority over trait methods.
149    fn get_all<T: ?Sized + Sync + Send + 'static>(&self) -> Vec<Arc<T>>
150    where
151        Self: Sized,
152    {
153        self.get_all_any(std::any::type_name::<T>())
154            .into_iter()
155            .filter_map(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
156            .collect()
157    }
158
159    /// Type-erased owned resolution: bypass cache, call factory fresh, return
160    /// `Arc<dyn Any + Send + Sync>` (concrete `Arc<Arc<T>>`).
161    ///
162    /// - Singleton → `None` (shared singleton cannot be owned).
163    /// - Scoped/Transient → factory invoked directly (no cache read/write),
164    ///   caller downcasts + `Arc::try_unwrap` to obtain owned `T`.
165    ///
166    /// Default `None` keeps external implementors backward-compatible.
167    fn get_owned_any(&self, _key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
168        None
169    }
170    fn get_keyed_owned_any(
171        &self,
172        _key: &str,
173        _variant: &str,
174    ) -> Option<Arc<dyn Any + Send + Sync>> {
175        None
176    }
177
178    /// Resolve owned `T` (bypass cache, fresh each call).
179    /// Returns `Err` if not registered or the service is Singleton.
180    fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError>
181    where
182        Self: Sized,
183    {
184        let type_name = std::any::type_name::<T>();
185        let arc_any = self
186            .get_owned_any(type_name)
187            .ok_or_else(|| RdiError::not_found(type_name, None))?;
188        let arc_t: Arc<T> = arc_any
189            .downcast::<Arc<T>>()
190            .ok()
191            .map(|d| Arc::clone(&*d))
192            .ok_or_else(|| RdiError::not_found(type_name, None))?;
193        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
194    }
195
196    /// Resolve owned `T`, returning `None` if not registered or Singleton.
197    fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T>
198    where
199        Self: Sized,
200    {
201        let arc_any = self.get_owned_any(std::any::type_name::<T>())?;
202        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
203        Arc::try_unwrap(arc_t).ok()
204    }
205
206    /// Resolve owned keyed `T`.
207    /// Returns `Err` if not found or Singleton.
208    fn get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Result<T, RdiError>
209    where
210        Self: Sized,
211    {
212        let type_name = std::any::type_name::<T>();
213        let arc_any = self
214            .get_keyed_owned_any(type_name, variant)
215            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))?;
216        let arc_t: Arc<T> = arc_any
217            .downcast::<Arc<T>>()
218            .ok()
219            .map(|d| Arc::clone(&*d))
220            .ok_or_else(|| RdiError::keyed_not_found(type_name, variant, None))?;
221        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
222    }
223
224    /// Resolve owned keyed `T`, returning `None` if not found or Singleton.
225    fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Option<T>
226    where
227        Self: Sized,
228    {
229        let arc_any = self.get_keyed_owned_any(std::any::type_name::<T>(), variant)?;
230        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
231        Arc::try_unwrap(arc_t).ok()
232    }
233}
234
235pub struct ServiceEntry {
236    pub cache_key: usize,
237    pub key: Option<String>,
238    pub type_name: &'static str, // kept for IServiceResolver string-based resolution
239    pub factory: ServiceFactory,
240    pub async_factory: Option<AsyncServiceFactory>,
241    pub lifetime: ServiceLifetime,
242}
243
244pub type ServiceFactory =
245    Arc<dyn Fn(&dyn IServiceResolver) -> Arc<dyn Any + Send + Sync> + Send + Sync>;
246
247/// Async variant of [`ServiceFactory`] — for services that require async
248/// initialization (e.g., database connections, remote config loading).
249///
250/// Used with [`ServiceCollection::build_async`](crate::collection::ServiceCollection::build_async).
251/// The factory receives an `Arc<ServiceProvider>` (instead of `&dyn IServiceResolver`)
252/// because async closures cannot borrow from the caller's stack frame.
253pub type AsyncServiceFactory = Arc<
254    dyn Fn(Arc<ServiceProvider>) -> Pin<Box<dyn Future<Output = Arc<dyn Any + Send + Sync>> + Send>>
255        + Send
256        + Sync,
257>;