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(RdiError::ServiceNotFound { ty: type_name, context: 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(RdiError::KeyedServiceNotFound {
129                key: variant.to_string(),
130                ty: type_name,
131            })
132    }
133
134    /// Resolve a keyed service by type and key, returning `None` if not found.
135    fn try_get_keyed<T: ?Sized + Sync + Send + 'static>(&self, variant: &str) -> Option<Arc<T>>
136    where
137        Self: Sized,
138    {
139        let type_name = std::any::type_name::<T>();
140        let tid = TypeId::of::<T>();
141        self.get_keyed_by_type_id(tid, variant)
142            .or_else(|| self.get_keyed_any(type_name, variant))
143            .and_then(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
144    }
145
146    /// Resolve all registered instances of `T` (default + keyed).
147    ///
148    /// Equivalent to C# MEDI `GetServices<T>()`. Types implementing `IServiceResolver`
149    /// get this for free via `get_all_any`; types with an inherent `get_all<T>`
150    /// method (e.g. `ServiceProvider`, `Scope`) use that instead — Rust's method
151    /// resolution gives inherent methods priority over trait methods.
152    fn get_all<T: ?Sized + Sync + Send + 'static>(&self) -> Vec<Arc<T>>
153    where
154        Self: Sized,
155    {
156        self.get_all_any(std::any::type_name::<T>())
157            .into_iter()
158            .filter_map(|a| a.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d)))
159            .collect()
160    }
161
162    /// Type-erased owned resolution: bypass cache, call factory fresh, return
163    /// `Arc<dyn Any + Send + Sync>` (concrete `Arc<Arc<T>>`).
164    ///
165    /// - Singleton → `None` (shared singleton cannot be owned).
166    /// - Scoped/Transient → factory invoked directly (no cache read/write),
167    ///   caller downcasts + `Arc::try_unwrap` to obtain owned `T`.
168    ///
169    /// Default `None` keeps external implementors backward-compatible.
170    fn get_owned_any(&self, _key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
171        None
172    }
173    fn get_keyed_owned_any(
174        &self,
175        _key: &str,
176        _variant: &str,
177    ) -> Option<Arc<dyn Any + Send + Sync>> {
178        None
179    }
180
181    /// Resolve owned `T` (bypass cache, fresh each call).
182    /// Returns `Err` if not registered or the service is Singleton.
183    fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError>
184    where
185        Self: Sized,
186    {
187        let type_name = std::any::type_name::<T>();
188        let arc_any = self
189            .get_owned_any(type_name)
190            .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })?;
191        let arc_t: Arc<T> = arc_any
192            .downcast::<Arc<T>>()
193            .ok()
194            .map(|d| Arc::clone(&*d))
195            .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })?;
196        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
197    }
198
199    /// Resolve owned `T`, returning `None` if not registered or Singleton.
200    fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T>
201    where
202        Self: Sized,
203    {
204        let arc_any = self.get_owned_any(std::any::type_name::<T>())?;
205        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
206        Arc::try_unwrap(arc_t).ok()
207    }
208
209    /// Resolve owned keyed `T`.
210    /// Returns `Err` if not found or Singleton.
211    fn get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Result<T, RdiError>
212    where
213        Self: Sized,
214    {
215        let type_name = std::any::type_name::<T>();
216        let arc_any = self
217            .get_keyed_owned_any(type_name, variant)
218            .ok_or(RdiError::KeyedServiceNotFound {
219                key: variant.to_string(),
220                ty: type_name,
221            })?;
222        let arc_t: Arc<T> = arc_any
223            .downcast::<Arc<T>>()
224            .ok()
225            .map(|d| Arc::clone(&*d))
226            .ok_or(RdiError::KeyedServiceNotFound {
227                key: variant.to_string(),
228                ty: type_name,
229            })?;
230        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
231    }
232
233    /// Resolve owned keyed `T`, returning `None` if not found or Singleton.
234    fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, variant: &str) -> Option<T>
235    where
236        Self: Sized,
237    {
238        let arc_any = self.get_keyed_owned_any(std::any::type_name::<T>(), variant)?;
239        let arc_t: Arc<T> = arc_any.downcast::<Arc<T>>().ok().map(|d| Arc::clone(&*d))?;
240        Arc::try_unwrap(arc_t).ok()
241    }
242}
243
244pub struct ServiceEntry {
245    pub cache_key: usize,
246    pub key: Option<String>,
247    pub type_name: &'static str, // kept for IServiceResolver string-based resolution
248    pub factory: ServiceFactory,
249    pub async_factory: Option<AsyncServiceFactory>,
250    pub lifetime: ServiceLifetime,
251}
252
253pub type ServiceFactory =
254    Arc<dyn Fn(&dyn IServiceResolver) -> Arc<dyn Any + Send + Sync> + Send + Sync>;
255
256/// Async variant of [`ServiceFactory`] — for services that require async
257/// initialization (e.g., database connections, remote config loading).
258///
259/// Used with [`ServiceCollection::build_async`](crate::collection::ServiceCollection::build_async).
260/// The factory receives an `Arc<ServiceProvider>` (instead of `&dyn IServiceResolver`)
261/// because async closures cannot borrow from the caller's stack frame.
262pub type AsyncServiceFactory = Arc<
263    dyn Fn(Arc<ServiceProvider>) -> Pin<Box<dyn Future<Output = Arc<dyn Any + Send + Sync>> + Send>>
264        + Send
265        + Sync,
266>;