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
8pub trait ScopeFactory: Send + Sync {
23 fn create_scope(&self) -> Scope;
26}
27
28pub(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
52pub(crate) fn builtin_scope_factory(provider: Weak<ServiceProvider>) -> Arc<dyn ScopeFactory> {
54 Arc::new(BuiltinScopeFactory::new(provider))
55}
56
57pub(crate) fn builtin_scope_factory_any(factory: Arc<dyn ScopeFactory>) -> AnyService {
60 Arc::new(factory) as AnyService
61}
62
63pub 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 pub fn scope_provider(&self) -> &Arc<ServiceProvider> {
97 &self.scope_provider
98 }
99
100 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 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 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 pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
143 self.scope_provider.get_owned::<T>()
144 }
145
146 pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
148 self.scope_provider.try_get_owned::<T>()
149 }
150
151 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 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 pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
169 self.scope_provider.get_all::<T>()
170 }
171
172 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 pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
179 self.scope_provider.is_registered::<T>()
180 }
181
182 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 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 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 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 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 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 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 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 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 assert!(matches!(
369 provider.get::<ScopedCore>(),
370 Err(crate::error::RdiError::ScopedFromRootProvider { .. })
371 ));
372
373 assert_eq!(
375 CORE_CALLS.load(Ordering::SeqCst),
376 2,
377 "ScopedCore 工厂应执行 2 次(两个子 scope 各一次)"
378 );
379 }
380}