Skip to main content

rust_dix/
scope.rs

1use crate::cache::AnyService;
2use crate::entry::IServiceResolver;
3use crate::error::RdiError;
4use crate::provider::ServiceProvider;
5use std::any::{Any, TypeId};
6use std::sync::{Arc, Weak};
7
8/// 工厂 trait:创建独立 scope。可注入 singleton 服务按需创建 scope。
9///
10/// 典型场景:后台 worker singleton 需要按请求创建独立 scope,
11/// 在 scope 内解析 Scoped 服务(如 request-scoped DbContext)。
12///
13/// built provider 内置此服务:`provider.get::<dyn ScopeFactory>()` 以及
14/// `#[inject] Arc<dyn ScopeFactory>` 字段都可用,无需手动注册,eager
15/// singleton 与懒解析服务一致。显式 `singleton::<dyn ScopeFactory>(...)`
16/// 注册仍然优先(覆盖内置实现)。
17///
18/// 内置实现持有 provider 的 [`Weak`] 引用,因此 singleton 持有它不会形成
19/// `容器 → singleton → 容器` 的 `Arc` 环;容器必须先于其创建的服务存活
20/// (`create_scope` 在 provider 已释放时会 panic,与 MEDI 的容器生命周期
21/// 约定一致)。若需要强引用语义,可自行注册实现。
22pub trait ScopeFactory: Send + Sync {
23    /// 创建一个独立 scope,共享 root 的 store/singleton_cache/named,
24    /// 独立 scoped 缓存和 disposables。
25    fn create_scope(&self) -> Scope;
26}
27
28/// 内置 [`ScopeFactory`] 实现:按需 upgrade provider 的弱引用。
29///
30/// 使用 `Weak` 而非 `Arc` 是有意设计:singleton 会持有该工厂,强引用会形成
31/// `ServiceProvider::singleton_cache → singleton → ServiceProvider` 的引用环,
32/// 导致容器在外部句柄释放后仍无法回收。
33pub(crate) struct BuiltinScopeFactory {
34    provider: Weak<ServiceProvider>,
35}
36
37impl BuiltinScopeFactory {
38    pub(crate) fn new(provider: Weak<ServiceProvider>) -> Self {
39        Self { provider }
40    }
41}
42
43impl ScopeFactory for BuiltinScopeFactory {
44    fn create_scope(&self) -> Scope {
45        self.provider.upgrade().map(Scope::new).expect(
46            "ScopeFactory::create_scope: ServiceProvider has been dropped; \
47                 the DI container must outlive services created from it",
48        )
49    }
50}
51
52/// Create the built-in `dyn ScopeFactory` singleton for a provider.
53pub(crate) fn builtin_scope_factory(provider: Weak<ServiceProvider>) -> Arc<dyn ScopeFactory> {
54    Arc::new(BuiltinScopeFactory::new(provider))
55}
56
57/// Wrap a scope factory in the `Arc<Arc<T>>`-style storage format used by
58/// [`IServiceResolver`] (`Arc::new(Arc<dyn T>)`).
59pub(crate) fn builtin_scope_factory_any(factory: Arc<dyn ScopeFactory>) -> AnyService {
60    Arc::new(factory) as AnyService
61}
62
63/// A scoped service provider — created via [`ServiceProvider::scope`].
64///
65/// 内部持有一个 scope 范围的 `ServiceProvider`(由 `ServiceProvider::new_scope` 派生),
66/// 共享 root 的 store/singleton_cache/named,独立 scoped 缓存。
67///
68/// 所有解析方法委托给内嵌的 `scope_provider`,确保:
69/// - Scoped 服务在 scope 内缓存复用。
70/// - Transient 依赖通过 `scope_provider` 解析,正确绑定到当前 scope(MEDI 语义)。
71/// - `#[inject(provider)]` 字段拿到的是 scope 范围的 provider,经该字段解析 Scoped
72///   服务命中 scope 缓存——不泄漏到 root。
73///
74/// # 资源释放
75///
76/// [`Scope::dispose`](以及 `Drop` 安全网)会按 **创建逆序** 释放该 scope 创建的
77/// Scoped 实例(实例的 `Drop` 在最后一个引用释放时运行),并按注册逆序执行
78/// [`ServiceProvider::register_disposable`] 注册的清理闭包。释放后 scope 解析返回
79/// [`RdiError::ScopeDisposed`]。
80pub struct Scope {
81    scope_provider: Arc<ServiceProvider>,
82}
83
84impl Scope {
85    pub(crate) fn new(parent: Arc<ServiceProvider>) -> Self {
86        Self {
87            scope_provider: ServiceProvider::new_scope(&parent),
88        }
89    }
90
91    /// Returns the scope-local `ServiceProvider` backing this scope.
92    ///
93    /// Exposed for advanced use cases (e.g. passing the scope provider to
94    /// `ServiceProviderWrapper`). Most callers should use [`Self::get`] /
95    /// [`Self::get_owned`] directly.
96    pub fn scope_provider(&self) -> &Arc<ServiceProvider> {
97        &self.scope_provider
98    }
99
100    /// Dispose the scope: release scoped instances in reverse creation order,
101    /// then run `register_disposable` cleanups in reverse registration order.
102    ///
103    /// Idempotent; also called by `Drop`. After disposal, resolution through
104    /// this scope returns [`RdiError::ScopeDisposed`] (or `None`/empty for
105    /// infallible lookups).
106    pub fn dispose(&self) {
107        self.scope_provider.dispose();
108    }
109
110    pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
111        self.scope_provider.get::<T>()
112    }
113
114    pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
115        self.scope_provider.get_optional::<T>()
116    }
117
118    pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
119        &self,
120        key: impl Into<crate::key::ServiceKey>,
121    ) -> Result<Arc<T>, RdiError> {
122        self.scope_provider.get_keyed::<T>(key)
123    }
124
125    /// Resolve an async service (transient or scoped) within this scope.
126    pub fn get_async<T: ?Sized + Send + Sync + 'static>(
127        &self,
128    ) -> impl std::future::Future<Output = Result<Arc<T>, RdiError>> + Send + '_ {
129        self.scope_provider.get_async::<T>()
130    }
131
132    /// Resolve an async keyed service within this scope.
133    pub fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
134        &self,
135        key: impl Into<crate::key::ServiceKey> + Send,
136    ) -> impl std::future::Future<Output = Result<Arc<T>, RdiError>> + Send + '_ {
137        self.scope_provider.get_keyed_async::<T>(key)
138    }
139
140    /// Resolve owned `T` within this scope (bypass cache, fresh each call).
141    /// Returns `Err` if not registered or the service is Singleton.
142    pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
143        self.scope_provider.get_owned::<T>()
144    }
145
146    /// Resolve owned `T`, returning `None` if not registered or Singleton.
147    pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
148        self.scope_provider.try_get_owned::<T>()
149    }
150
151    /// Resolve owned keyed `T`.
152    /// Returns `Err` if not found or Singleton.
153    pub fn get_keyed_owned<T: Send + Sync + 'static>(
154        &self,
155        key: impl Into<crate::key::ServiceKey>,
156    ) -> Result<T, RdiError> {
157        self.scope_provider.get_keyed_owned::<T>(key)
158    }
159
160    /// Resolve owned keyed `T`, returning `None` if not found or Singleton.
161    pub fn try_get_keyed_owned<T: Send + Sync + 'static>(
162        &self,
163        key: impl Into<crate::key::ServiceKey>,
164    ) -> Option<T> {
165        self.scope_provider.try_get_keyed_owned::<T>(key)
166    }
167    /// Return all **unkeyed** registered instances (MEDI `GetServices<T>()`).
168    pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
169        self.scope_provider.get_all::<T>()
170    }
171
172    /// Return all **keyed** registered instances (MEDI `GetKeyedServices<T>()`).
173    pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
174        self.scope_provider.get_all_keyed::<T>()
175    }
176
177    /// Whether `T` has a resolvable registration (MEDI `IServiceProviderIsService`).
178    pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
179        self.scope_provider.is_registered::<T>()
180    }
181
182    /// Whether `T` has a registration under `key`.
183    /// Whether `T` has a registration under `key` (exact or `AnyKey` fallback).
184    pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(
185        &self,
186        key: impl Into<crate::key::ServiceKey>,
187    ) -> bool {
188        self.scope_provider.is_registered_keyed::<T>(key)
189    }
190
191    /// Create an [`AsyncFactoryContext`](crate::AsyncFactoryContext) bound to
192    /// the current async resolution chain (for detached task propagation).
193    pub fn async_context(&self) -> Option<crate::AsyncFactoryContext> {
194        self.scope_provider.async_context()
195    }
196
197    pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
198        self.scope_provider.get_named_any(name)
199    }
200
201    /// Register a named service (for [`IProvider`](crate::bridge::IProvider) trait).
202    pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
203        self.scope_provider.rdi_register_named(name, service);
204    }
205
206    /// Remove a named service (for [`IProvider`](crate::bridge::IProvider) trait).
207    pub fn rdi_remove_named(&self, name: &str) {
208        self.scope_provider.rdi_remove_named(name);
209    }
210}
211
212impl Drop for Scope {
213    fn drop(&mut self) {
214        self.dispose();
215    }
216}
217
218impl IServiceResolver for Scope {
219    fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
220        self.scope_provider.get_any(key)
221    }
222    fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
223        self.scope_provider.get_keyed_any(key, variant)
224    }
225    fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
226        self.scope_provider.get_by_type_id(tid)
227    }
228    fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
229        self.scope_provider.get_keyed_by_type_id(tid, key)
230    }
231    fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
232        self.scope_provider.get_all_any(key)
233    }
234    fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
235        self.scope_provider.get_all_keyed_any(key)
236    }
237    fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
238        self.scope_provider.get_all_any_result(key)
239    }
240    fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
241        self.scope_provider.get_owned_any(key)
242    }
243    fn try_get_any_result(
244        &self,
245        key: &str,
246    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
247        self.scope_provider.try_get_any_result(key)
248    }
249    fn try_get_keyed_any_result(
250        &self,
251        key: &str,
252        variant: &str,
253    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
254        self.scope_provider.try_get_keyed_any_result(key, variant)
255    }
256    fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
257        self.scope_provider.get_keyed_owned_any(key, variant)
258    }
259    fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
260        // 返回 scope 范围的 provider(不是 root),符合 MEDI 语义:
261        // 在 scope 内解析的服务经 #[inject(provider)] 拿到此 provider,
262        // 后续 get::<ScopedX>() 命中 scope 自己的 scoped 缓存。
263        Some(Arc::clone(&self.scope_provider))
264    }
265}
266
267#[cfg(test)]
268mod tests {
269    use super::*;
270    use crate::collection::ServiceCollection;
271    use std::sync::atomic::{AtomicU64, Ordering};
272    #[derive(Debug, PartialEq)]
273    struct Sd(u64);
274    #[test]
275    fn scoped_cached_per_scope() {
276        static NXT: AtomicU64 = AtomicU64::new(0);
277        let p = ServiceCollection::new()
278            .scoped(|_| Arc::new(Sd(NXT.fetch_add(1, Ordering::SeqCst))))
279            .build()
280            .unwrap();
281        let s1 = p.scope();
282        let a = s1.get::<Sd>().unwrap();
283        let b = s1.get::<Sd>().unwrap();
284        assert_eq!(a.0, b.0);
285        let s2 = p.scope();
286        let c = s2.get::<Sd>().unwrap();
287        assert_ne!(a.0, c.0);
288    }
289
290    #[test]
291    fn disposed_scope_rejects_resolution() {
292        let p = ServiceCollection::new()
293            .scoped(|_| Arc::new(Sd(1)))
294            .build()
295            .unwrap();
296        let scope = p.scope();
297        assert!(scope.get::<Sd>().is_ok());
298        scope.dispose();
299        assert!(matches!(
300            scope.get::<Sd>(),
301            Err(crate::error::RdiError::ScopeDisposed)
302        ));
303        assert!(scope.get_optional::<Sd>().is_none());
304    }
305
306    #[test]
307    fn nested_transient_chain_scoped_binds_to_child_scope() {
308        // 边界场景:双层嵌套 Transient 依赖链 → Scoped
309        //   OuterTransient → MidTransient → ScopedCore
310        // 验证最内层 ScopedCore 在子 scope 内解析(scope.scoped_cache),
311        // 不回退到根 root_scoped_cache。
312        // 严格性:任一层 Transient 若错误用 self.parent 解析依赖,
313        // ScopedCore 都会泄漏到根,三 scope 序号会塌缩为相同值。
314        static CORE_CALLS: AtomicU64 = AtomicU64::new(0);
315
316        struct ScopedCore(u64);
317        struct MidTransient {
318            core: Arc<ScopedCore>,
319        }
320        struct OuterTransient {
321            mid: Arc<MidTransient>,
322        }
323
324        let provider = ServiceCollection::new()
325            .scoped(|_| {
326                let n = CORE_CALLS.fetch_add(1, Ordering::SeqCst);
327                Arc::new(ScopedCore(n))
328            })
329            .transient(|r| {
330                let any = r.get_any(std::any::type_name::<ScopedCore>()).unwrap();
331                let outer = any.downcast::<Arc<ScopedCore>>().unwrap();
332                let core: Arc<ScopedCore> = Arc::clone(&*outer);
333                Arc::new(MidTransient { core })
334            })
335            .transient(|r| {
336                let any = r.get_any(std::any::type_name::<MidTransient>()).unwrap();
337                let outer = any.downcast::<Arc<MidTransient>>().unwrap();
338                let mid: Arc<MidTransient> = Arc::clone(&*outer);
339                Arc::new(OuterTransient { mid })
340            })
341            .build()
342            .unwrap();
343
344        // scope1:首次解析 OuterTransient,ScopedCore 工厂执行(序号 0)。
345        let scope1 = provider.scope();
346        let o1: Arc<OuterTransient> = scope1.get().unwrap();
347        assert_eq!(o1.mid.core.0, 0, "scope1 的 ScopedCore 应为序号 0");
348
349        // scope1 内再次解析:OuterTransient/MidTransient 每次新建(Transient),
350        // 但 ScopedCore 应复用 scope1 的 scoped 缓存(序号仍 0)。
351        let o1b: Arc<OuterTransient> = scope1.get().unwrap();
352        assert_eq!(o1b.mid.core.0, 0, "scope1 应复用同一 ScopedCore");
353        assert!(
354            Arc::ptr_eq(&o1.mid.core, &o1b.mid.core),
355            "scope1 内 ScopedCore 必须复用"
356        );
357
358        // scope2:独立子 scope,ScopedCore 工厂再次执行(序号 1)。
359        let scope2 = provider.scope();
360        let o2: Arc<OuterTransient> = scope2.get().unwrap();
361        assert_eq!(o2.mid.core.0, 1, "scope2 的 ScopedCore 应为序号 1");
362        assert!(
363            !Arc::ptr_eq(&o1.mid.core, &o2.mid.core),
364            "不同 scope 的 ScopedCore 必须独立"
365        );
366
367        // 严格 scope 校验(0.8 默认):root 不允许解析 Scoped 服务。
368        assert!(matches!(
369            provider.get::<ScopedCore>(),
370            Err(crate::error::RdiError::ScopedFromRootProvider { .. })
371        ));
372
373        // 全程工厂只执行 2 次(scope1、scope2 各一次)。
374        assert_eq!(
375            CORE_CALLS.load(Ordering::SeqCst),
376            2,
377            "ScopedCore 工厂应执行 2 次(两个子 scope 各一次)"
378        );
379    }
380}