1use crate::cache::{AnyService, LazyCache};
2use crate::entry::{
3 AsyncServiceFactory, IServiceResolver, ServiceEntry, ServiceFactory, ServiceLifetime,
4 ServiceStore,
5};
6use crate::error::RdiError;
7use crate::scope::ScopeFactory;
8use crate::validation::ValidationResolver;
9use std::any::{Any, TypeId};
10use std::cell::{Cell, RefCell};
11use std::collections::HashMap;
12use std::panic::AssertUnwindSafe;
13use std::sync::atomic::{AtomicBool, Ordering};
14use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
15
16thread_local! {
17 static RESOLVING: RefCell<Vec<(usize, &'static str)>> = const { RefCell::new(Vec::new()) };
19 static BUILD_FACTORY_DEPTH: Cell<usize> = const { Cell::new(0) };
25}
26
27pub(crate) struct ResolveGuard;
28
29impl Drop for ResolveGuard {
30 fn drop(&mut self) {
31 RESOLVING.with(|stack| {
32 stack.borrow_mut().pop();
33 });
34 }
35}
36
37pub(crate) struct BuildFactoryGuard;
39
40impl BuildFactoryGuard {
41 pub(crate) fn enter() -> Self {
42 BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get() + 1));
43 Self
44 }
45}
46
47impl Drop for BuildFactoryGuard {
48 fn drop(&mut self) {
49 BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get().saturating_sub(1)));
50 }
51}
52
53fn reject_build_time_provider_resolution(type_name: &'static str) {
58 if BUILD_FACTORY_DEPTH.with(|depth| depth.get()) > 0 {
59 std::panic::panic_any(RdiError::FactoryPanic {
60 service: type_name.to_string(),
61 payload: format!(
62 "resolving services through the injected provider from a build-time constructor \
63 is not supported: store the provider/ScopeFactory and resolve lazily in methods \
64 (attempted to resolve {type_name})"
65 ),
66 });
67 }
68}
69
70pub(crate) fn enter_resolve(
71 cache_key: usize,
72 type_name: &'static str,
73) -> Result<ResolveGuard, RdiError> {
74 RESOLVING.with(|stack| {
75 let mut s = stack.borrow_mut();
76 if s.iter().any(|(k, _)| *k == cache_key) {
77 let mut chain: Vec<&str> = s.iter().map(|(_, n)| *n).collect();
78 chain.push(type_name);
79 return Err(RdiError::CircularDependency(chain.join(" -> ")));
80 }
81 s.push((cache_key, type_name));
82 Ok(ResolveGuard)
83 })
84}
85
86fn check_not_resolving(cache_key: usize, type_name: &'static str) -> Result<(), RdiError> {
92 RESOLVING.with(|stack| {
93 let s = stack.borrow();
94 if s.iter().any(|(k, _)| *k == cache_key) {
95 let mut chain: Vec<&str> = s.iter().map(|(_, n)| *n).collect();
96 chain.push(type_name);
97 return Err(RdiError::CircularDependency(chain.join(" -> ")));
98 }
99 Ok(())
100 })
101}
102
103struct AsyncPollGuard {
104 cache_key: usize,
105 type_name: &'static str,
106}
107
108impl Drop for AsyncPollGuard {
109 fn drop(&mut self) {
110 let _ = self.cache_key;
111 let _ = self.type_name;
112 RESOLVING.with(|stack| {
113 stack.borrow_mut().pop();
114 });
115 }
116}
117
118struct AsyncPollGuardFuture<F> {
127 inner: std::pin::Pin<Box<F>>,
128 cache_key: usize,
129 type_name: &'static str,
130}
131
132impl<F: std::future::Future> std::future::Future for AsyncPollGuardFuture<F> {
133 type Output = F::Output;
134
135 fn poll(
136 self: std::pin::Pin<&mut Self>,
137 cx: &mut std::task::Context<'_>,
138 ) -> std::task::Poll<Self::Output> {
139 let this = self.get_mut();
141 RESOLVING.with(|stack| stack.borrow_mut().push((this.cache_key, this.type_name)));
142 let _guard = AsyncPollGuard {
143 cache_key: this.cache_key,
144 type_name: this.type_name,
145 };
146 this.inner.as_mut().poll(cx)
147 }
148}
149
150fn poll_guard<F: std::future::Future>(
151 cache_key: usize,
152 type_name: &'static str,
153 future: F,
154) -> AsyncPollGuardFuture<F> {
155 AsyncPollGuardFuture {
156 inner: Box::pin(future),
157 cache_key,
158 type_name,
159 }
160}
161
162fn drop_instances_safely(instances: Vec<AnyService>) -> Option<Box<dyn Any + Send>> {
168 let mut first_panic: Option<Box<dyn Any + Send>> = None;
169 for instance in instances {
170 if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(|| drop(instance))) {
171 if first_panic.is_none() {
172 first_panic = Some(payload);
173 }
174 }
175 }
176 first_panic
177}
178
179#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185#[non_exhaustive]
186pub struct ServiceProviderOptions {
187 pub validate_scopes: bool,
204}
205
206impl ServiceProviderOptions {
207 pub fn new() -> Self {
209 Self {
210 validate_scopes: true,
211 }
212 }
213
214 pub fn with_validate_scopes(mut self, validate_scopes: bool) -> Self {
216 self.validate_scopes = validate_scopes;
217 self
218 }
219
220 pub fn lenient() -> Self {
223 Self {
224 validate_scopes: false,
225 }
226 }
227}
228
229impl Default for ServiceProviderOptions {
230 fn default() -> Self {
231 Self::new()
232 }
233}
234
235pub(crate) struct SharedProviderState {
240 disposed: AtomicBool,
241}
242
243impl SharedProviderState {
244 fn new() -> Self {
245 Self {
246 disposed: AtomicBool::new(false),
247 }
248 }
249}
250
251pub struct ServiceProvider {
252 store: Arc<ServiceStore>,
254 type_map: Arc<HashMap<&'static str, TypeId>>,
257 singleton_cache: Arc<LazyCache>,
262 root_scoped_cache: LazyCache,
270 pub(crate) named: Arc<RwLock<HashMap<String, Arc<dyn Any + Send + Sync>>>>,
275 self_weak: OnceLock<Weak<ServiceProvider>>,
280 scope_factory_cache: OnceLock<Arc<dyn ScopeFactory>>,
284 disposables: Mutex<Vec<Box<dyn FnOnce() + Send>>>,
289 shared: Arc<SharedProviderState>,
291 disposed: AtomicBool,
293 is_root: bool,
295 validate_scopes: bool,
297}
298
299impl ServiceProvider {
300 pub(crate) fn new_with(
301 store: ServiceStore,
302 options: ServiceProviderOptions,
303 ) -> Result<Arc<Self>, RdiError> {
304 if let Some(entry) = store
306 .values()
307 .flat_map(|entries| entries.iter())
308 .find(|e| e.async_factory.is_some())
309 {
310 return Err(RdiError::AsyncServiceRequiresBuildAsync {
311 service: entry.type_name.to_string(),
312 });
313 }
314
315 let mut type_map = HashMap::new();
317 for (&tid, entries) in &store {
318 if let Some(e) = entries.first() {
319 type_map.entry(e.type_name).or_insert(tid);
320 }
321 }
322
323 let singleton_cache = Arc::new(LazyCache::new());
324
325 let sp_arc = Arc::new(Self {
331 store: Arc::new(store),
332 type_map: Arc::new(type_map),
333 singleton_cache,
334 root_scoped_cache: LazyCache::new(),
335 named: Arc::new(RwLock::new(HashMap::new())),
336 self_weak: OnceLock::new(),
337 scope_factory_cache: OnceLock::new(),
338 disposables: Mutex::new(Vec::new()),
339 shared: Arc::new(SharedProviderState::new()),
340 disposed: AtomicBool::new(false),
341 is_root: true,
342 validate_scopes: options.validate_scopes,
343 });
344 sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
345
346 Self::validate_dependencies(&sp_arc)?;
349
350 Self::init_sync_singletons(&sp_arc);
353 Ok(sp_arc)
354 }
355
356 fn init_sync_singletons(sp_arc: &Arc<Self>) {
366 let mut singleton_entries: Vec<(usize, ServiceFactory)> = sp_arc
367 .store
368 .values()
369 .flat_map(|entries| entries.iter())
370 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
371 .map(|e| (e.cache_key, e.factory.clone()))
372 .collect();
373 singleton_entries.sort_by_key(|(cache_key, _)| *cache_key);
374
375 for (ck, factory) in &singleton_entries {
376 let resolver = sp_arc.as_ref() as &dyn IServiceResolver;
377 let factory = factory.clone();
378 sp_arc
379 .singleton_cache
380 .get_or_init_with(*ck, move || factory(resolver));
381 }
382 }
383
384 pub(crate) async fn new_async_with(
393 store: ServiceStore,
394 options: ServiceProviderOptions,
395 ) -> Result<Arc<Self>, RdiError> {
396 let mut type_map = HashMap::new();
398 for (&tid, entries) in &store {
399 if let Some(e) = entries.first() {
400 type_map.entry(e.type_name).or_insert(tid);
401 }
402 }
403
404 let singleton_cache = Arc::new(LazyCache::new());
405
406 let sp_arc = Arc::new(Self {
410 store: Arc::new(store),
411 type_map: Arc::new(type_map),
412 singleton_cache,
413 root_scoped_cache: LazyCache::new(),
414 named: Arc::new(RwLock::new(HashMap::new())),
415 self_weak: OnceLock::new(),
416 scope_factory_cache: OnceLock::new(),
417 disposables: Mutex::new(Vec::new()),
418 shared: Arc::new(SharedProviderState::new()),
419 disposed: AtomicBool::new(false),
420 is_root: true,
421 validate_scopes: options.validate_scopes,
422 });
423 sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
424
425 Self::validate_dependencies(&sp_arc)?;
427
428 Self::init_sync_singletons(&sp_arc);
430
431 let mut async_singletons: Vec<(usize, &'static str, AsyncServiceFactory)> = sp_arc
434 .store
435 .values()
436 .flat_map(|entries| entries.iter())
437 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_some())
438 .map(|e| {
439 (
440 e.cache_key,
441 e.type_name,
442 e.async_factory.clone().expect("async singleton factory"),
443 )
444 })
445 .collect();
446 async_singletons.sort_by_key(|(cache_key, _, _)| *cache_key);
447
448 for (ck, type_name, async_factory) in async_singletons {
449 let result = match futures::FutureExt::catch_unwind(AssertUnwindSafe(async_factory(
450 Arc::clone(&sp_arc),
451 )))
452 .await
453 {
454 Ok(value) => value,
455 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
456 };
457 sp_arc.singleton_cache.get_or_init_with(ck, || result);
458 }
459
460 Ok(sp_arc)
461 }
462
463 pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
470 let sp = Self {
471 store: Arc::clone(&parent.store),
472 type_map: Arc::clone(&parent.type_map),
473 singleton_cache: Arc::clone(&parent.singleton_cache),
474 root_scoped_cache: LazyCache::new(),
475 named: Arc::clone(&parent.named),
476 self_weak: OnceLock::new(),
477 scope_factory_cache: OnceLock::new(),
478 disposables: Mutex::new(Vec::new()),
479 shared: Arc::clone(&parent.shared),
480 disposed: AtomicBool::new(false),
481 is_root: false,
482 validate_scopes: parent.validate_scopes,
483 };
484 let arc = Arc::new(sp);
485 let this: &Self = &arc;
486 this.self_weak.get_or_init(|| Arc::downgrade(&arc));
487 arc
488 }
489
490 pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
496 self.disposables.lock().unwrap().push(cleanup);
497 }
498
499 pub fn dispose(&self) {
520 if self.disposed.swap(true, Ordering::SeqCst) {
521 return;
522 }
523 if self.is_root {
524 self.shared.disposed.store(true, Ordering::SeqCst);
525 }
526
527 let mut first_panic = drop_instances_safely(self.root_scoped_cache.drain_reverse());
530
531 if self.is_root {
532 let singleton_panic = drop_instances_safely(self.singleton_cache.drain_reverse());
534 if first_panic.is_none() {
535 first_panic = singleton_panic;
536 }
537 self.named.write().unwrap().clear();
538 }
539
540 let cleanup_panic = self.run_cleanups();
541 if first_panic.is_none() {
542 first_panic = cleanup_panic;
543 }
544
545 if let Some(payload) = first_panic {
546 if !std::thread::panicking() {
547 std::panic::resume_unwind(payload);
548 }
549 }
550 }
551
552 fn run_cleanups(&self) -> Option<Box<dyn Any + Send>> {
559 let mut cleanups: Vec<Box<dyn FnOnce() + Send>> = {
560 let mut guard = self.disposables.lock().unwrap();
561 std::mem::take(&mut *guard)
562 };
563 cleanups.reverse();
564
565 let mut first_panic: Option<Box<dyn Any + Send>> = None;
566 for cleanup in cleanups {
567 if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(cleanup)) {
568 if first_panic.is_none() {
569 first_panic = Some(payload);
570 }
571 }
572 }
573 first_panic
574 }
575
576 fn validate_dependencies(sp: &Arc<Self>) -> Result<(), RdiError> {
589 let type_names: HashMap<TypeId, &'static str> = sp
591 .store
592 .iter()
593 .map(|(&tid, entries)| {
594 let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
595 (tid, name)
596 })
597 .collect();
598
599 let mut singletons: Vec<&ServiceEntry> = sp
600 .store
601 .values()
602 .flat_map(|entries| entries.iter())
603 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
604 .collect();
605 singletons.sort_by_key(|e| e.cache_key);
606
607 for entry in singletons {
615 let resolver = ValidationResolver::new(
616 &sp.store,
617 &type_names,
618 &sp.singleton_cache,
619 Arc::clone(sp),
620 );
621 let type_name = entry.type_name;
622
623 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
624 resolver.validate_entry(entry)
625 }));
626
627 if let Some(err) = resolver.take_error() {
628 return Err(err);
629 }
630
631 match result {
632 Ok(_) => {}
633 Err(panic_info) => {
634 return Err(RdiError::from_panic_payload(type_name, panic_info));
635 }
636 }
637 }
638
639 Ok(())
640 }
641
642 fn unkeyed_entry(&self, tid: TypeId) -> Option<&ServiceEntry> {
647 self.store.get(&tid)?.iter().rev().find(|e| e.key.is_none())
648 }
649
650 fn keyed_entry(&self, tid: TypeId, key: &str) -> Option<&ServiceEntry> {
652 self.store
653 .get(&tid)?
654 .iter()
655 .rev()
656 .find(|e| e.key.as_deref() == Some(key))
657 }
658
659 fn entry_by_str(&self, type_name: &str, key: Option<&str>) -> Option<&ServiceEntry> {
660 let tid = *self.type_map.get(type_name)?;
661 match key {
662 Some(k) => self.keyed_entry(tid, k),
663 None => self.unkeyed_entry(tid),
664 }
665 }
666
667 fn check_alive(&self) -> Result<(), RdiError> {
671 if self.shared.disposed.load(Ordering::SeqCst) {
672 return Err(RdiError::ProviderDisposed);
673 }
674 if self.disposed.load(Ordering::SeqCst) {
675 return Err(RdiError::ScopeDisposed);
676 }
677 Ok(())
678 }
679
680 fn check_scope_validation(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
683 if entry.lifetime == ServiceLifetime::Scoped && self.is_root && self.validate_scopes {
684 return Err(RdiError::ScopedFromRootProvider {
685 service: entry.type_name.to_string(),
686 });
687 }
688 Ok(())
689 }
690
691 fn check_resolvable(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
692 self.check_alive()?;
693 self.check_scope_validation(entry)
694 }
695
696 fn resolve_entry_catching(&self, entry: &ServiceEntry) -> Result<AnyService, RdiError> {
701 self.check_resolvable(entry)?;
702 match std::panic::catch_unwind(AssertUnwindSafe(|| self.get_any_by_entry(entry))) {
703 Ok(Some(v)) => Ok(v),
704 Ok(None) => Err(RdiError::not_found(entry.type_name, None)),
705 Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
706 }
707 }
708
709 fn resolve_entry_panicking(&self, entry: &ServiceEntry) -> AnyService {
714 if let Err(err) = self.check_resolvable(entry) {
715 std::panic::panic_any(err);
716 }
717 match self.get_any_by_entry(entry) {
718 Some(v) => v,
719 None => std::panic::panic_any(RdiError::not_found(entry.type_name, None)),
720 }
721 }
722
723 fn resolve_unkeyed_optional<T: ?Sized + Send + Sync + 'static>(
728 &self,
729 ) -> Result<Option<Arc<T>>, RdiError> {
730 self.check_alive()?;
731 if let Some(entry) = self.unkeyed_entry(TypeId::of::<T>()) {
732 return Ok(Self::extract(self.resolve_entry_catching(entry)?));
733 }
734 Ok(self
738 .builtin_service_by_type_id(TypeId::of::<T>())
739 .and_then(Self::extract))
740 }
741
742 pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
750 let type_name = std::any::type_name::<T>();
751 match self.resolve_unkeyed_optional::<T>() {
752 Ok(Some(v)) => Ok(v),
753 Ok(None) => Err(RdiError::not_found(type_name, None)),
754 Err(e) => Err(e),
755 }
756 }
757
758 pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
763 self.resolve_unkeyed_optional::<T>().ok().flatten()
764 }
765
766 pub async fn get_async<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
772 let type_name = std::any::type_name::<T>();
773 let tid = TypeId::of::<T>();
774 let entry = self
775 .unkeyed_entry(tid)
776 .ok_or_else(|| RdiError::not_found(type_name, None))?;
777
778 if entry.lifetime == ServiceLifetime::Singleton {
779 if entry.async_factory.is_some() && self.singleton_cache.get(entry.cache_key).is_none()
785 {
786 return Err(RdiError::FactoryPanic {
787 service: type_name.to_string(),
788 payload: format!(
789 "async singleton '{type_name}' was resolved before its build-time \
790 initialization completed; async singletons are initialized in \
791 registration order, so register dependencies before their dependents"
792 ),
793 });
794 }
795 return self.get::<T>();
796 }
797 self.check_resolvable(entry)?;
798
799 match self.resolve_async_any(entry, type_name).await? {
800 Some(arc_any) => {
801 Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))
802 }
803 None => self.get::<T>(),
804 }
805 }
806
807 pub async fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
809 &self,
810 key: &str,
811 ) -> Result<Arc<T>, RdiError> {
812 let type_name = std::any::type_name::<T>();
813 let tid = TypeId::of::<T>();
814 let entry = self
815 .keyed_entry(tid, key)
816 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
817
818 if entry.lifetime == ServiceLifetime::Singleton {
819 if entry.async_factory.is_some() && self.singleton_cache.get(entry.cache_key).is_none()
820 {
821 return Err(RdiError::FactoryPanic {
822 service: type_name.to_string(),
823 payload: format!(
824 "async singleton '{type_name}' (key '{key}') was resolved before its \
825 build-time initialization completed; async singletons are initialized \
826 in registration order, so register dependencies before their dependents"
827 ),
828 });
829 }
830 return self.get_keyed::<T>(key);
831 }
832 self.check_resolvable(entry)?;
833
834 match self.resolve_async_any(entry, type_name).await? {
835 Some(arc_any) => Self::extract(arc_any)
836 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None)),
837 None => self.get_keyed::<T>(key),
838 }
839 }
840
841 async fn resolve_async_any(
851 &self,
852 entry: &ServiceEntry,
853 type_name: &'static str,
854 ) -> Result<Option<AnyService>, RdiError> {
855 match entry.lifetime {
856 ServiceLifetime::Scoped => {
857 let Some(async_factory) = entry.async_factory.clone() else {
861 return Ok(None);
862 };
863 check_not_resolving(entry.cache_key, entry.type_name)?;
865 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
866 service: type_name.to_string(),
867 payload: "provider_arc() returned None for async resolution".into(),
868 })?;
869 poll_guard(
870 entry.cache_key,
871 entry.type_name,
872 self.root_scoped_cache
873 .get_or_init_with_async(entry.cache_key, || {
874 Self::run_async_factory_safely(type_name, async_factory, provider_arc)
875 }),
876 )
877 .await
878 .map(Some)
879 }
880 ServiceLifetime::Transient => {
881 if let Some(async_factory) = entry.async_factory.clone() {
882 check_not_resolving(entry.cache_key, entry.type_name)?;
883 let provider_arc =
884 self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
885 service: type_name.to_string(),
886 payload: "provider_arc() returned None for async resolution".into(),
887 })?;
888 poll_guard(
889 entry.cache_key,
890 entry.type_name,
891 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
892 )
893 .await
894 .map(Some)
895 } else {
896 Ok(None)
897 }
898 }
899 _ => Ok(None),
900 }
901 }
902
903 async fn run_async_factory_safely(
908 type_name: &'static str,
909 async_factory: AsyncServiceFactory,
910 provider_arc: Arc<ServiceProvider>,
911 ) -> Result<AnyService, RdiError> {
912 let fut = async_factory(provider_arc);
913 match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
914 Ok(arc_any) => Ok(arc_any),
915 Err(payload) => Err(RdiError::from_panic_payload(type_name, payload)),
916 }
917 }
918
919 pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
922 &self,
923 key: &str,
924 ) -> Result<Arc<T>, RdiError> {
925 let type_name = std::any::type_name::<T>();
926 if let Some(entry) = self.keyed_entry(TypeId::of::<T>(), key) {
927 let any = self.resolve_entry_catching(entry)?;
928 return Self::extract(any)
929 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None));
930 }
931 Err(RdiError::keyed_not_found(type_name, key, None))
932 }
933
934 pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
942 let type_name = std::any::type_name::<T>();
943 let tid = TypeId::of::<T>();
944 let entry = self
945 .unkeyed_entry(tid)
946 .ok_or_else(|| RdiError::not_found(type_name, None))?;
947 if entry.lifetime == ServiceLifetime::Singleton {
948 return Err(RdiError::OwnedNotSupported(type_name));
949 }
950 self.check_alive()?;
951 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
952 self.create_owned_any_by_entry(entry)
953 })) {
954 Ok(Some(v)) => v,
955 Ok(None) => return Err(RdiError::not_found(type_name, None)),
956 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
957 };
958 let arc_t = Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))?;
959 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
960 }
961
962 pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
965 self.get_owned().ok()
966 }
967
968 pub fn get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Result<T, RdiError> {
971 let type_name = std::any::type_name::<T>();
972 let tid = TypeId::of::<T>();
973 let entry = self
974 .keyed_entry(tid, key)
975 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
976 if entry.lifetime == ServiceLifetime::Singleton {
977 return Err(RdiError::OwnedNotSupported(type_name));
978 }
979 self.check_alive()?;
980 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
981 self.create_owned_any_by_entry(entry)
982 })) {
983 Ok(Some(v)) => v,
984 Ok(None) => return Err(RdiError::keyed_not_found(type_name, key, None)),
985 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
986 };
987 let arc_t = Self::extract(arc_any)
988 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
989 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
990 }
991
992 pub fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Option<T> {
995 self.get_keyed_owned(key).ok()
996 }
997
998 pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1006 self.collect_all::<T>(false)
1007 }
1008
1009 pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1012 self.collect_all::<T>(true)
1013 }
1014
1015 fn collect_all<T: ?Sized + Send + Sync + 'static>(&self, keyed_only: bool) -> Vec<Arc<T>> {
1016 if self.check_alive().is_err() {
1017 return Vec::new();
1018 }
1019 let Some(entries) = self.store.get(&TypeId::of::<T>()) else {
1020 return Vec::new();
1021 };
1022 let mut out = Vec::new();
1023 for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1024 match self.resolve_entry_catching(entry) {
1025 Ok(any) => {
1026 if let Some(v) = Self::extract(any) {
1027 out.push(v);
1028 }
1029 }
1030 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1033 Err(err) => std::panic::panic_any(err),
1034 }
1035 }
1036 out
1037 }
1038
1039 pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
1044 crate::scope::Scope::new(self.clone())
1045 }
1046
1047 pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
1052 let tid = TypeId::of::<T>();
1053 self.store
1054 .get(&tid)
1055 .is_some_and(|entries| entries.iter().any(|e| e.key.is_none()))
1056 || tid == TypeId::of::<dyn ScopeFactory>()
1057 || tid == TypeId::of::<ServiceProvider>()
1058 }
1059
1060 pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> bool {
1062 self.store
1063 .get(&TypeId::of::<T>())
1064 .is_some_and(|entries| entries.iter().any(|e| e.key.as_deref() == Some(key)))
1065 }
1066
1067 fn builtin_scope_factory(&self) -> Option<Arc<dyn ScopeFactory>> {
1069 let weak = self.self_weak.get()?.clone();
1070 Some(Arc::clone(
1071 self.scope_factory_cache
1072 .get_or_init(|| crate::scope::builtin_scope_factory(weak)),
1073 ))
1074 }
1075
1076 fn builtin_scope_factory_any(&self) -> Option<AnyService> {
1077 Some(crate::scope::builtin_scope_factory_any(
1078 self.builtin_scope_factory()?,
1079 ))
1080 }
1081
1082 pub(crate) fn builtin_scope_factory_any_cached(&self) -> Option<AnyService> {
1087 self.builtin_scope_factory_any()
1088 }
1089
1090 fn builtin_service_by_type_id(&self, tid: TypeId) -> Option<AnyService> {
1097 if tid == TypeId::of::<dyn ScopeFactory>() {
1098 return self.builtin_scope_factory_any();
1099 }
1100 if tid == TypeId::of::<ServiceProvider>() {
1101 let provider = self.self_weak.get()?.upgrade()?;
1102 return Some(Arc::new(provider) as AnyService);
1103 }
1104 None
1105 }
1106
1107 fn builtin_service_by_name(&self, key: &str) -> Option<AnyService> {
1110 if key == std::any::type_name::<dyn ScopeFactory>() {
1111 return self.builtin_scope_factory_any();
1112 }
1113 if key == std::any::type_name::<ServiceProvider>() {
1114 let provider = self.self_weak.get()?.upgrade()?;
1115 return Some(Arc::new(provider) as AnyService);
1116 }
1117 None
1118 }
1119
1120 pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1121 reject_build_time_provider_resolution(entry.type_name);
1122 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1123 Ok(g) => g,
1124 Err(e) => std::panic::panic_any(e),
1125 };
1126 match entry.lifetime {
1127 ServiceLifetime::Singleton => {
1128 let factory = entry.factory.clone();
1133 let resolver = self as &dyn IServiceResolver;
1134 Some(
1135 self.singleton_cache
1136 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1137 )
1138 }
1139 ServiceLifetime::Scoped => {
1140 let factory = entry.factory.clone();
1141 let resolver = self as &dyn IServiceResolver;
1142 Some(
1143 self.root_scoped_cache
1144 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1145 )
1146 }
1147 ServiceLifetime::Transient => Some((entry.factory)(self)),
1148 }
1149 }
1150
1151 pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1159 reject_build_time_provider_resolution(entry.type_name);
1160 match entry.lifetime {
1161 ServiceLifetime::Singleton => None,
1162 ServiceLifetime::Scoped | ServiceLifetime::Transient => {
1163 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1164 Ok(g) => g,
1165 Err(e) => std::panic::panic_any(e),
1166 };
1167 Some((entry.factory)(self as &dyn IServiceResolver))
1168 }
1169 }
1170 }
1171
1172 pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
1175 arc: Arc<dyn Any + Send + Sync>,
1176 ) -> Option<Arc<T>> {
1177 let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
1178 Some(Arc::clone(&*double))
1179 }
1180
1181 pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1183 self.named
1184 .read()
1185 .unwrap()
1186 .get(name)?
1187 .clone()
1188 .downcast::<T>()
1189 .ok()
1190 }
1191
1192 pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1194 self.named.read().unwrap().get(name).cloned()
1195 }
1196
1197 pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
1202 if self.check_alive().is_err() {
1203 return;
1204 }
1205 self.named
1206 .write()
1207 .unwrap()
1208 .insert(name.to_string(), service);
1209 }
1210
1211 pub fn remove_named(&self, name: &str) {
1213 if self.check_alive().is_err() {
1214 return;
1215 }
1216 self.named.write().unwrap().remove(name);
1217 }
1218
1219 pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
1223 if self.check_alive().is_err() {
1224 return;
1225 }
1226 self.named
1227 .write()
1228 .unwrap()
1229 .insert(name.to_string(), service);
1230 }
1231
1232 pub fn rdi_remove_named(&self, name: &str) {
1234 if self.check_alive().is_err() {
1235 return;
1236 }
1237 self.named.write().unwrap().remove(name);
1238 }
1239
1240 fn builtin_service_checked(&self, key: &str) -> Option<AnyService> {
1244 if let Err(err) = self.check_alive() {
1245 std::panic::panic_any(err);
1246 }
1247 self.builtin_service_by_name(key)
1248 }
1249
1250 fn builtin_service_by_type_id_checked(&self, tid: TypeId) -> Option<AnyService> {
1251 if let Err(err) = self.check_alive() {
1252 std::panic::panic_any(err);
1253 }
1254 self.builtin_service_by_type_id(tid)
1255 }
1256}
1257
1258impl ScopeFactory for ServiceProvider {
1259 fn create_scope(&self) -> crate::scope::Scope {
1260 self.self_weak
1262 .get()
1263 .and_then(|w| w.upgrade())
1264 .map(crate::scope::Scope::new)
1265 .expect("ScopeFactory::create_scope: ServiceProvider self_weak not initialized")
1266 }
1267}
1268
1269impl IServiceResolver for ServiceProvider {
1270 fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1271 if let Some(entry) = self.entry_by_str(key, None) {
1272 return Some(self.resolve_entry_panicking(entry));
1273 }
1274 self.builtin_service_checked(key)
1277 }
1278
1279 fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1280 let entry = self.entry_by_str(key, Some(variant))?;
1281 Some(self.resolve_entry_panicking(entry))
1282 }
1283
1284 fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
1285 if let Some(entry) = self.unkeyed_entry(tid) {
1286 return Some(self.resolve_entry_panicking(entry));
1287 }
1288 self.builtin_service_by_type_id_checked(tid)
1289 }
1290
1291 fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1292 let entry = self.keyed_entry(tid, key)?;
1293 Some(self.resolve_entry_panicking(entry))
1294 }
1295
1296 fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1297 self.collect_all_any(key, false)
1298 }
1299
1300 fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1301 self.collect_all_any(key, true)
1302 }
1303
1304 fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
1305 self.check_alive()?;
1306 let Some(tid) = self.type_map.get(key) else {
1307 return Ok(Vec::new());
1308 };
1309 let Some(entries) = self.store.get(tid) else {
1310 return Ok(Vec::new());
1311 };
1312 let mut out = Vec::new();
1313 for entry in entries.iter().filter(|e| e.key.is_none()) {
1314 out.push(self.resolve_entry_catching(entry)?);
1315 }
1316 Ok(out)
1317 }
1318
1319 fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1320 let entry = self.entry_by_str(key, None)?;
1321 if entry.lifetime == ServiceLifetime::Singleton {
1322 return None;
1323 }
1324 self.check_alive().ok()?;
1325 self.create_owned_any_by_entry(entry)
1326 }
1327
1328 fn try_get_any_result(&self, key: &str) -> Result<Option<AnyService>, RdiError> {
1333 self.check_alive()?;
1334 if let Some(entry) = self.entry_by_str(key, None) {
1335 return self.resolve_entry_catching(entry).map(Some);
1336 }
1337 Ok(self.builtin_service_by_name(key))
1338 }
1339
1340 fn try_get_keyed_any_result(
1342 &self,
1343 key: &str,
1344 variant: &str,
1345 ) -> Result<Option<AnyService>, RdiError> {
1346 self.check_alive()?;
1347 match self.entry_by_str(key, Some(variant)) {
1348 Some(entry) => self.resolve_entry_catching(entry).map(Some),
1349 None => Ok(None),
1350 }
1351 }
1352
1353 fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1354 let entry = self.entry_by_str(key, Some(variant))?;
1355 if entry.lifetime == ServiceLifetime::Singleton {
1356 return None;
1357 }
1358 self.check_alive().ok()?;
1359 self.create_owned_any_by_entry(entry)
1360 }
1361
1362 fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
1363 self.self_weak.get().and_then(|w| w.upgrade())
1364 }
1365}
1366
1367impl ServiceProvider {
1368 fn collect_all_any(&self, key: &str, keyed_only: bool) -> Vec<Arc<dyn Any + Send + Sync>> {
1369 if self.check_alive().is_err() {
1370 return Vec::new();
1371 }
1372 let Some(tid) = self.type_map.get(key) else {
1373 return Vec::new();
1374 };
1375 let Some(entries) = self.store.get(tid) else {
1376 return Vec::new();
1377 };
1378 let mut out = Vec::new();
1379 for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1380 match self.resolve_entry_catching(entry) {
1381 Ok(any) => out.push(any),
1382 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1383 Err(err) => std::panic::panic_any(err),
1384 }
1385 }
1386 out
1387 }
1388}
1389
1390#[cfg(test)]
1391mod tests {
1392 use super::ServiceProviderOptions;
1393 use crate::collection::ServiceCollection;
1394 use std::sync::Arc;
1395
1396 #[derive(Debug, PartialEq)]
1397 struct Calc(i32);
1398 #[test]
1399 fn optional_missing() {
1400 let p = ServiceCollection::new().build().unwrap();
1401 assert!(p.get_optional::<i32>().is_none());
1402 }
1403 #[test]
1404 fn get_all_includes_only_unkeyed() {
1405 let p = ServiceCollection::new()
1406 .keyed_singleton("a", |_| Arc::new(Calc(1)))
1407 .keyed_singleton("b", |_| Arc::new(Calc(2)))
1408 .build()
1409 .unwrap();
1410 assert_eq!(p.get_all::<Calc>().len(), 0, "get_all excludes keyed");
1411 assert_eq!(p.get_all_keyed::<Calc>().len(), 2);
1412 }
1413 #[test]
1414 fn later_registration_wins() {
1415 let p = ServiceCollection::new()
1416 .singleton(|_| Arc::new(Calc(1)))
1417 .singleton(|_| Arc::new(Calc(2)))
1418 .build()
1419 .unwrap();
1420 assert_eq!(
1421 p.get::<Calc>().unwrap().0,
1422 2,
1423 "MEDI: last registration wins"
1424 );
1425 }
1426 #[test]
1427 fn root_scoped_is_rejected_by_default() {
1428 let p = ServiceCollection::new()
1429 .scoped(|_| Arc::new(Calc(9)))
1430 .build()
1431 .unwrap();
1432 match p.get::<Calc>() {
1433 Err(crate::error::RdiError::ScopedFromRootProvider { service }) => {
1434 assert!(service.contains("Calc"));
1435 }
1436 other => panic!("expected ScopedFromRootProvider, got {other:?}"),
1437 }
1438 assert!(p.get_optional::<Calc>().is_none());
1439 assert!(p.get_all::<Calc>().is_empty());
1440 }
1441 #[test]
1442 fn lenient_options_restore_root_scope() {
1443 let p = ServiceCollection::new()
1444 .scoped(|_| Arc::new(Calc(9)))
1445 .build_with(ServiceProviderOptions::lenient())
1446 .unwrap();
1447 assert_eq!(p.get::<Calc>().unwrap().0, 9);
1448 assert!(Arc::ptr_eq(
1449 &p.get::<Calc>().unwrap(),
1450 &p.get::<Calc>().unwrap()
1451 ));
1452 }
1453 #[test]
1454 fn scope_resolution_works_and_is_cached() {
1455 let p = ServiceCollection::new()
1456 .scoped(|_| Arc::new(Calc(3)))
1457 .build()
1458 .unwrap();
1459 let s1 = p.scope();
1460 let a = s1.get::<Calc>().unwrap();
1461 let b = s1.get::<Calc>().unwrap();
1462 assert!(Arc::ptr_eq(&a, &b));
1463 let s2 = p.scope();
1464 assert!(!Arc::ptr_eq(&a, &s2.get::<Calc>().unwrap()));
1465 }
1466 #[test]
1467 fn is_registered_reports_lookup_state() {
1468 let p = ServiceCollection::new()
1469 .singleton(|_| Arc::new(Calc(1)))
1470 .keyed_singleton("k", |_| Arc::new(Calc(2)))
1471 .build()
1472 .unwrap();
1473 assert!(p.is_registered::<Calc>());
1474 assert!(p.is_registered::<crate::ServiceProvider>());
1475 assert!(p.is_registered::<dyn crate::ScopeFactory>());
1476 assert!(!p.is_registered::<String>());
1477 assert!(p.is_registered_keyed::<Calc>("k"));
1478 assert!(!p.is_registered_keyed::<Calc>("missing"));
1479 }
1480 #[test]
1481 fn dispose_is_idempotent_and_blocks_resolution() {
1482 let p = ServiceCollection::new()
1483 .singleton(|_| Arc::new(Calc(1)))
1484 .build()
1485 .unwrap();
1486 p.dispose();
1487 p.dispose();
1488 assert!(matches!(
1489 p.get::<Calc>(),
1490 Err(crate::error::RdiError::ProviderDisposed)
1491 ));
1492 assert!(p.get_optional::<Calc>().is_none());
1493 assert!(p.get_all::<Calc>().is_empty());
1494 }
1495 #[test]
1496 fn dispose_releases_singletons_in_reverse_creation_order() {
1497 use std::sync::Mutex;
1498 static DROPS: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1499 #[derive(Debug)]
1500 struct Tracked(&'static str);
1501 impl Drop for Tracked {
1502 fn drop(&mut self) {
1503 DROPS.lock().unwrap().push(self.0);
1504 }
1505 }
1506 struct First(#[allow(dead_code)] Arc<Tracked>);
1507 struct Second(#[allow(dead_code)] Arc<Tracked>);
1508
1509 let p = ServiceCollection::new()
1510 .singleton(|_| Arc::new(First(Arc::new(Tracked("first")))))
1511 .singleton(|_| Arc::new(Second(Arc::new(Tracked("second")))))
1512 .build()
1513 .unwrap();
1514 p.dispose();
1515
1516 let drops = DROPS.lock().unwrap().clone();
1517 assert_eq!(
1518 drops,
1519 vec!["second", "first"],
1520 "singletons must be released in reverse creation order"
1521 );
1522 }
1523
1524 #[test]
1525 fn eager_singletons_are_created_in_registration_order() {
1526 use std::sync::Mutex;
1527 static CREATED: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1528 #[derive(Debug)]
1529 struct A;
1530 #[derive(Debug)]
1531 struct B;
1532 let p = ServiceCollection::new()
1533 .singleton(|_| {
1534 CREATED.lock().unwrap().push("a");
1535 Arc::new(A)
1536 })
1537 .singleton(|_| {
1538 CREATED.lock().unwrap().push("b");
1539 Arc::new(B)
1540 })
1541 .build()
1542 .unwrap();
1543 assert_eq!(
1544 *CREATED.lock().unwrap(),
1545 vec!["a", "b"],
1546 "eager init must be deterministic (registration order)"
1547 );
1548 drop(p);
1549 }
1550
1551 #[test]
1552 fn async_singleton_panic_becomes_typed_error() {
1553 let result = futures::executor::block_on(
1554 ServiceCollection::new()
1555 .async_singleton::<Calc>(|_| Box::pin(async { panic!("boom") }))
1556 .build_async(),
1557 );
1558 match result {
1559 Ok(_) => panic!("build_async must fail when an async singleton factory panics"),
1560 Err(crate::error::RdiError::FactoryPanic { payload, .. }) => {
1561 assert!(payload.contains("boom"), "payload={payload}");
1562 }
1563 Err(other) => panic!("expected FactoryPanic, got {other:?}"),
1564 }
1565 }
1566}