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<&ServiceEntry> = sp_arc
439 .store
440 .values()
441 .flat_map(|entries| entries.iter())
442 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_some())
443 .collect();
444 async_singletons.sort_by_key(|e| e.cache_key);
445
446 for entry in async_singletons {
447 sp_arc.ensure_async_singleton(entry).await?;
448 }
449
450 Ok(sp_arc)
451 }
452
453 async fn ensure_async_singleton(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
464 self.check_alive()?;
465 if self.singleton_cache.get(entry.cache_key).is_some() {
466 return Ok(());
467 }
468 let Some(async_factory) = entry.async_factory.clone() else {
469 return Ok(());
471 };
472
473 check_not_resolving(entry.cache_key, entry.type_name)?;
475
476 let key = entry.cache_key;
477 let type_name = entry.type_name;
478 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
479 service: type_name.to_string(),
480 payload: "provider_arc() returned None for async singleton initialization".into(),
481 })?;
482
483 self.singleton_cache
484 .get_or_init_with_async(key, || {
485 poll_guard(
486 key,
487 type_name,
488 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
489 )
490 })
491 .await?;
492 Ok(())
493 }
494
495 pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
502 let sp = Self {
503 store: Arc::clone(&parent.store),
504 type_map: Arc::clone(&parent.type_map),
505 singleton_cache: Arc::clone(&parent.singleton_cache),
506 root_scoped_cache: LazyCache::new(),
507 named: Arc::clone(&parent.named),
508 self_weak: OnceLock::new(),
509 scope_factory_cache: OnceLock::new(),
510 disposables: Mutex::new(Vec::new()),
511 shared: Arc::clone(&parent.shared),
512 disposed: AtomicBool::new(false),
513 is_root: false,
514 validate_scopes: parent.validate_scopes,
515 };
516 let arc = Arc::new(sp);
517 let this: &Self = &arc;
518 this.self_weak.get_or_init(|| Arc::downgrade(&arc));
519 arc
520 }
521
522 pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
528 self.disposables.lock().unwrap().push(cleanup);
529 }
530
531 pub fn dispose(&self) {
552 if self.disposed.swap(true, Ordering::SeqCst) {
553 return;
554 }
555 if self.is_root {
556 self.shared.disposed.store(true, Ordering::SeqCst);
557 }
558
559 let mut first_panic = drop_instances_safely(self.root_scoped_cache.drain_reverse());
562
563 if self.is_root {
564 let singleton_panic = drop_instances_safely(self.singleton_cache.drain_reverse());
566 if first_panic.is_none() {
567 first_panic = singleton_panic;
568 }
569 self.named.write().unwrap().clear();
570 }
571
572 let cleanup_panic = self.run_cleanups();
573 if first_panic.is_none() {
574 first_panic = cleanup_panic;
575 }
576
577 if let Some(payload) = first_panic {
578 if !std::thread::panicking() {
579 std::panic::resume_unwind(payload);
580 }
581 }
582 }
583
584 fn run_cleanups(&self) -> Option<Box<dyn Any + Send>> {
591 let mut cleanups: Vec<Box<dyn FnOnce() + Send>> = {
592 let mut guard = self.disposables.lock().unwrap();
593 std::mem::take(&mut *guard)
594 };
595 cleanups.reverse();
596
597 let mut first_panic: Option<Box<dyn Any + Send>> = None;
598 for cleanup in cleanups {
599 if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(cleanup)) {
600 if first_panic.is_none() {
601 first_panic = Some(payload);
602 }
603 }
604 }
605 first_panic
606 }
607
608 fn validate_dependencies(sp: &Arc<Self>) -> Result<(), RdiError> {
621 let type_names: HashMap<TypeId, &'static str> = sp
623 .store
624 .iter()
625 .map(|(&tid, entries)| {
626 let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
627 (tid, name)
628 })
629 .collect();
630
631 let mut singletons: Vec<&ServiceEntry> = sp
632 .store
633 .values()
634 .flat_map(|entries| entries.iter())
635 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
636 .collect();
637 singletons.sort_by_key(|e| e.cache_key);
638
639 for entry in singletons {
647 let resolver = ValidationResolver::new(
648 &sp.store,
649 &type_names,
650 &sp.singleton_cache,
651 Arc::clone(sp),
652 );
653 let type_name = entry.type_name;
654
655 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
656 resolver.validate_entry(entry)
657 }));
658
659 if let Some(err) = resolver.take_error() {
660 return Err(err);
661 }
662
663 match result {
664 Ok(_) => {}
665 Err(panic_info) => {
666 return Err(RdiError::from_panic_payload(type_name, panic_info));
667 }
668 }
669 }
670
671 Ok(())
672 }
673
674 fn unkeyed_entry(&self, tid: TypeId) -> Option<&ServiceEntry> {
679 self.store.get(&tid)?.iter().rev().find(|e| e.key.is_none())
680 }
681
682 fn keyed_entry(&self, tid: TypeId, key: &str) -> Option<&ServiceEntry> {
684 self.store
685 .get(&tid)?
686 .iter()
687 .rev()
688 .find(|e| e.key.as_deref() == Some(key))
689 }
690
691 fn entry_by_str(&self, type_name: &str, key: Option<&str>) -> Option<&ServiceEntry> {
692 let tid = *self.type_map.get(type_name)?;
693 match key {
694 Some(k) => self.keyed_entry(tid, k),
695 None => self.unkeyed_entry(tid),
696 }
697 }
698
699 fn check_alive(&self) -> Result<(), RdiError> {
703 if self.shared.disposed.load(Ordering::SeqCst) {
704 return Err(RdiError::ProviderDisposed);
705 }
706 if self.disposed.load(Ordering::SeqCst) {
707 return Err(RdiError::ScopeDisposed);
708 }
709 Ok(())
710 }
711
712 fn check_scope_validation(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
715 if entry.lifetime == ServiceLifetime::Scoped && self.is_root && self.validate_scopes {
716 return Err(RdiError::ScopedFromRootProvider {
717 service: entry.type_name.to_string(),
718 });
719 }
720 Ok(())
721 }
722
723 fn check_resolvable(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
724 self.check_alive()?;
725 self.check_scope_validation(entry)
726 }
727
728 fn resolve_entry_catching(&self, entry: &ServiceEntry) -> Result<AnyService, RdiError> {
733 self.check_resolvable(entry)?;
734 match std::panic::catch_unwind(AssertUnwindSafe(|| self.get_any_by_entry(entry))) {
735 Ok(Some(v)) => Ok(v),
736 Ok(None) => Err(RdiError::not_found(entry.type_name, None)),
737 Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
738 }
739 }
740
741 fn resolve_entry_panicking(&self, entry: &ServiceEntry) -> AnyService {
746 if let Err(err) = self.check_resolvable(entry) {
747 std::panic::panic_any(err);
748 }
749 match self.get_any_by_entry(entry) {
750 Some(v) => v,
751 None => std::panic::panic_any(RdiError::not_found(entry.type_name, None)),
752 }
753 }
754
755 fn resolve_unkeyed_optional<T: ?Sized + Send + Sync + 'static>(
760 &self,
761 ) -> Result<Option<Arc<T>>, RdiError> {
762 self.check_alive()?;
763 if let Some(entry) = self.unkeyed_entry(TypeId::of::<T>()) {
764 return Ok(Self::extract(self.resolve_entry_catching(entry)?));
765 }
766 Ok(self
770 .builtin_service_by_type_id(TypeId::of::<T>())
771 .and_then(Self::extract))
772 }
773
774 pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
782 let type_name = std::any::type_name::<T>();
783 match self.resolve_unkeyed_optional::<T>() {
784 Ok(Some(v)) => Ok(v),
785 Ok(None) => Err(RdiError::not_found(type_name, None)),
786 Err(e) => Err(e),
787 }
788 }
789
790 pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
795 self.resolve_unkeyed_optional::<T>().ok().flatten()
796 }
797
798 pub async fn get_async<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
804 let type_name = std::any::type_name::<T>();
805 let tid = TypeId::of::<T>();
806 let entry = self
807 .unkeyed_entry(tid)
808 .ok_or_else(|| RdiError::not_found(type_name, None))?;
809
810 if entry.lifetime == ServiceLifetime::Singleton {
811 self.ensure_async_singleton(entry).await?;
814 return self.get::<T>();
815 }
816 self.check_resolvable(entry)?;
817
818 match self.resolve_async_any(entry, type_name).await? {
819 Some(arc_any) => {
820 Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))
821 }
822 None => self.get::<T>(),
823 }
824 }
825
826 pub async fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
828 &self,
829 key: &str,
830 ) -> Result<Arc<T>, RdiError> {
831 let type_name = std::any::type_name::<T>();
832 let tid = TypeId::of::<T>();
833 let entry = self
834 .keyed_entry(tid, key)
835 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
836
837 if entry.lifetime == ServiceLifetime::Singleton {
838 self.ensure_async_singleton(entry).await?;
839 return self.get_keyed::<T>(key);
840 }
841 self.check_resolvable(entry)?;
842
843 match self.resolve_async_any(entry, type_name).await? {
844 Some(arc_any) => Self::extract(arc_any)
845 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None)),
846 None => self.get_keyed::<T>(key),
847 }
848 }
849
850 async fn resolve_async_any(
860 &self,
861 entry: &ServiceEntry,
862 type_name: &'static str,
863 ) -> Result<Option<AnyService>, RdiError> {
864 match entry.lifetime {
865 ServiceLifetime::Scoped => {
866 let Some(async_factory) = entry.async_factory.clone() else {
870 return Ok(None);
871 };
872 check_not_resolving(entry.cache_key, entry.type_name)?;
874 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
875 service: type_name.to_string(),
876 payload: "provider_arc() returned None for async resolution".into(),
877 })?;
878 poll_guard(
879 entry.cache_key,
880 entry.type_name,
881 self.root_scoped_cache
882 .get_or_init_with_async(entry.cache_key, || {
883 Self::run_async_factory_safely(type_name, async_factory, provider_arc)
884 }),
885 )
886 .await
887 .map(Some)
888 }
889 ServiceLifetime::Transient => {
890 if let Some(async_factory) = entry.async_factory.clone() {
891 check_not_resolving(entry.cache_key, entry.type_name)?;
892 let provider_arc =
893 self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
894 service: type_name.to_string(),
895 payload: "provider_arc() returned None for async resolution".into(),
896 })?;
897 poll_guard(
898 entry.cache_key,
899 entry.type_name,
900 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
901 )
902 .await
903 .map(Some)
904 } else {
905 Ok(None)
906 }
907 }
908 _ => Ok(None),
909 }
910 }
911
912 async fn run_async_factory_safely(
917 type_name: &'static str,
918 async_factory: AsyncServiceFactory,
919 provider_arc: Arc<ServiceProvider>,
920 ) -> Result<AnyService, RdiError> {
921 let fut = async_factory(provider_arc);
922 match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
923 Ok(arc_any) => Ok(arc_any),
924 Err(payload) => Err(RdiError::from_panic_payload(type_name, payload)),
925 }
926 }
927
928 pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
931 &self,
932 key: &str,
933 ) -> Result<Arc<T>, RdiError> {
934 let type_name = std::any::type_name::<T>();
935 if let Some(entry) = self.keyed_entry(TypeId::of::<T>(), key) {
936 let any = self.resolve_entry_catching(entry)?;
937 return Self::extract(any)
938 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None));
939 }
940 Err(RdiError::keyed_not_found(type_name, key, None))
941 }
942
943 pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
951 let type_name = std::any::type_name::<T>();
952 let tid = TypeId::of::<T>();
953 let entry = self
954 .unkeyed_entry(tid)
955 .ok_or_else(|| RdiError::not_found(type_name, None))?;
956 if entry.lifetime == ServiceLifetime::Singleton {
957 return Err(RdiError::OwnedNotSupported(type_name));
958 }
959 self.check_alive()?;
960 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
961 self.create_owned_any_by_entry(entry)
962 })) {
963 Ok(Some(v)) => v,
964 Ok(None) => return Err(RdiError::not_found(type_name, None)),
965 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
966 };
967 let arc_t = Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))?;
968 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
969 }
970
971 pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
974 self.get_owned().ok()
975 }
976
977 pub fn get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Result<T, RdiError> {
980 let type_name = std::any::type_name::<T>();
981 let tid = TypeId::of::<T>();
982 let entry = self
983 .keyed_entry(tid, key)
984 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
985 if entry.lifetime == ServiceLifetime::Singleton {
986 return Err(RdiError::OwnedNotSupported(type_name));
987 }
988 self.check_alive()?;
989 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
990 self.create_owned_any_by_entry(entry)
991 })) {
992 Ok(Some(v)) => v,
993 Ok(None) => return Err(RdiError::keyed_not_found(type_name, key, None)),
994 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
995 };
996 let arc_t = Self::extract(arc_any)
997 .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
998 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
999 }
1000
1001 pub fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Option<T> {
1004 self.get_keyed_owned(key).ok()
1005 }
1006
1007 pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1015 self.collect_all::<T>(false)
1016 }
1017
1018 pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1021 self.collect_all::<T>(true)
1022 }
1023
1024 fn collect_all<T: ?Sized + Send + Sync + 'static>(&self, keyed_only: bool) -> Vec<Arc<T>> {
1025 if self.check_alive().is_err() {
1026 return Vec::new();
1027 }
1028 let Some(entries) = self.store.get(&TypeId::of::<T>()) else {
1029 return Vec::new();
1030 };
1031 let mut out = Vec::new();
1032 for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1033 match self.resolve_entry_catching(entry) {
1034 Ok(any) => {
1035 if let Some(v) = Self::extract(any) {
1036 out.push(v);
1037 }
1038 }
1039 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1042 Err(err) => std::panic::panic_any(err),
1043 }
1044 }
1045 out
1046 }
1047
1048 pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
1053 crate::scope::Scope::new(self.clone())
1054 }
1055
1056 pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
1061 let tid = TypeId::of::<T>();
1062 self.store
1063 .get(&tid)
1064 .is_some_and(|entries| entries.iter().any(|e| e.key.is_none()))
1065 || tid == TypeId::of::<dyn ScopeFactory>()
1066 || tid == TypeId::of::<ServiceProvider>()
1067 }
1068
1069 pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> bool {
1071 self.store
1072 .get(&TypeId::of::<T>())
1073 .is_some_and(|entries| entries.iter().any(|e| e.key.as_deref() == Some(key)))
1074 }
1075
1076 fn builtin_scope_factory(&self) -> Option<Arc<dyn ScopeFactory>> {
1078 let weak = self.self_weak.get()?.clone();
1079 Some(Arc::clone(
1080 self.scope_factory_cache
1081 .get_or_init(|| crate::scope::builtin_scope_factory(weak)),
1082 ))
1083 }
1084
1085 fn builtin_scope_factory_any(&self) -> Option<AnyService> {
1086 Some(crate::scope::builtin_scope_factory_any(
1087 self.builtin_scope_factory()?,
1088 ))
1089 }
1090
1091 pub(crate) fn builtin_scope_factory_any_cached(&self) -> Option<AnyService> {
1096 self.builtin_scope_factory_any()
1097 }
1098
1099 fn builtin_service_by_type_id(&self, tid: TypeId) -> Option<AnyService> {
1106 if tid == TypeId::of::<dyn ScopeFactory>() {
1107 return self.builtin_scope_factory_any();
1108 }
1109 if tid == TypeId::of::<ServiceProvider>() {
1110 let provider = self.self_weak.get()?.upgrade()?;
1111 return Some(Arc::new(provider) as AnyService);
1112 }
1113 None
1114 }
1115
1116 fn builtin_service_by_name(&self, key: &str) -> Option<AnyService> {
1119 if key == std::any::type_name::<dyn ScopeFactory>() {
1120 return self.builtin_scope_factory_any();
1121 }
1122 if key == std::any::type_name::<ServiceProvider>() {
1123 let provider = self.self_weak.get()?.upgrade()?;
1124 return Some(Arc::new(provider) as AnyService);
1125 }
1126 None
1127 }
1128
1129 pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1130 reject_build_time_provider_resolution(entry.type_name);
1131 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1132 Ok(g) => g,
1133 Err(e) => std::panic::panic_any(e),
1134 };
1135 match entry.lifetime {
1136 ServiceLifetime::Singleton => {
1137 let factory = entry.factory.clone();
1142 let resolver = self as &dyn IServiceResolver;
1143 Some(
1144 self.singleton_cache
1145 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1146 )
1147 }
1148 ServiceLifetime::Scoped => {
1149 let factory = entry.factory.clone();
1150 let resolver = self as &dyn IServiceResolver;
1151 Some(
1152 self.root_scoped_cache
1153 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1154 )
1155 }
1156 ServiceLifetime::Transient => Some((entry.factory)(self)),
1157 }
1158 }
1159
1160 pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1168 reject_build_time_provider_resolution(entry.type_name);
1169 match entry.lifetime {
1170 ServiceLifetime::Singleton => None,
1171 ServiceLifetime::Scoped | ServiceLifetime::Transient => {
1172 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1173 Ok(g) => g,
1174 Err(e) => std::panic::panic_any(e),
1175 };
1176 Some((entry.factory)(self as &dyn IServiceResolver))
1177 }
1178 }
1179 }
1180
1181 pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
1184 arc: Arc<dyn Any + Send + Sync>,
1185 ) -> Option<Arc<T>> {
1186 let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
1187 Some(Arc::clone(&*double))
1188 }
1189
1190 pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1192 self.named
1193 .read()
1194 .unwrap()
1195 .get(name)?
1196 .clone()
1197 .downcast::<T>()
1198 .ok()
1199 }
1200
1201 pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1203 self.named.read().unwrap().get(name).cloned()
1204 }
1205
1206 pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
1211 if self.check_alive().is_err() {
1212 return;
1213 }
1214 self.named
1215 .write()
1216 .unwrap()
1217 .insert(name.to_string(), service);
1218 }
1219
1220 pub fn remove_named(&self, name: &str) {
1222 if self.check_alive().is_err() {
1223 return;
1224 }
1225 self.named.write().unwrap().remove(name);
1226 }
1227
1228 pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
1232 if self.check_alive().is_err() {
1233 return;
1234 }
1235 self.named
1236 .write()
1237 .unwrap()
1238 .insert(name.to_string(), service);
1239 }
1240
1241 pub fn rdi_remove_named(&self, name: &str) {
1243 if self.check_alive().is_err() {
1244 return;
1245 }
1246 self.named.write().unwrap().remove(name);
1247 }
1248
1249 fn builtin_service_checked(&self, key: &str) -> Option<AnyService> {
1253 if let Err(err) = self.check_alive() {
1254 std::panic::panic_any(err);
1255 }
1256 self.builtin_service_by_name(key)
1257 }
1258
1259 fn builtin_service_by_type_id_checked(&self, tid: TypeId) -> Option<AnyService> {
1260 if let Err(err) = self.check_alive() {
1261 std::panic::panic_any(err);
1262 }
1263 self.builtin_service_by_type_id(tid)
1264 }
1265}
1266
1267impl ScopeFactory for ServiceProvider {
1268 fn create_scope(&self) -> crate::scope::Scope {
1269 self.self_weak
1271 .get()
1272 .and_then(|w| w.upgrade())
1273 .map(crate::scope::Scope::new)
1274 .expect("ScopeFactory::create_scope: ServiceProvider self_weak not initialized")
1275 }
1276}
1277
1278impl IServiceResolver for ServiceProvider {
1279 fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1280 if let Some(entry) = self.entry_by_str(key, None) {
1281 return Some(self.resolve_entry_panicking(entry));
1282 }
1283 self.builtin_service_checked(key)
1286 }
1287
1288 fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1289 let entry = self.entry_by_str(key, Some(variant))?;
1290 Some(self.resolve_entry_panicking(entry))
1291 }
1292
1293 fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
1294 if let Some(entry) = self.unkeyed_entry(tid) {
1295 return Some(self.resolve_entry_panicking(entry));
1296 }
1297 self.builtin_service_by_type_id_checked(tid)
1298 }
1299
1300 fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1301 let entry = self.keyed_entry(tid, key)?;
1302 Some(self.resolve_entry_panicking(entry))
1303 }
1304
1305 fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1306 self.collect_all_any(key, false)
1307 }
1308
1309 fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1310 self.collect_all_any(key, true)
1311 }
1312
1313 fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
1314 self.check_alive()?;
1315 let Some(tid) = self.type_map.get(key) else {
1316 return Ok(Vec::new());
1317 };
1318 let Some(entries) = self.store.get(tid) else {
1319 return Ok(Vec::new());
1320 };
1321 let mut out = Vec::new();
1322 for entry in entries.iter().filter(|e| e.key.is_none()) {
1323 out.push(self.resolve_entry_catching(entry)?);
1324 }
1325 Ok(out)
1326 }
1327
1328 fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1329 let entry = self.entry_by_str(key, None)?;
1330 if entry.lifetime == ServiceLifetime::Singleton {
1331 return None;
1332 }
1333 self.check_alive().ok()?;
1334 self.create_owned_any_by_entry(entry)
1335 }
1336
1337 fn try_get_any_result(&self, key: &str) -> Result<Option<AnyService>, RdiError> {
1342 self.check_alive()?;
1343 if let Some(entry) = self.entry_by_str(key, None) {
1344 return self.resolve_entry_catching(entry).map(Some);
1345 }
1346 Ok(self.builtin_service_by_name(key))
1347 }
1348
1349 fn try_get_keyed_any_result(
1351 &self,
1352 key: &str,
1353 variant: &str,
1354 ) -> Result<Option<AnyService>, RdiError> {
1355 self.check_alive()?;
1356 match self.entry_by_str(key, Some(variant)) {
1357 Some(entry) => self.resolve_entry_catching(entry).map(Some),
1358 None => Ok(None),
1359 }
1360 }
1361
1362 fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1363 let entry = self.entry_by_str(key, Some(variant))?;
1364 if entry.lifetime == ServiceLifetime::Singleton {
1365 return None;
1366 }
1367 self.check_alive().ok()?;
1368 self.create_owned_any_by_entry(entry)
1369 }
1370
1371 fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
1372 self.self_weak.get().and_then(|w| w.upgrade())
1373 }
1374}
1375
1376impl ServiceProvider {
1377 fn collect_all_any(&self, key: &str, keyed_only: bool) -> Vec<Arc<dyn Any + Send + Sync>> {
1378 if self.check_alive().is_err() {
1379 return Vec::new();
1380 }
1381 let Some(tid) = self.type_map.get(key) else {
1382 return Vec::new();
1383 };
1384 let Some(entries) = self.store.get(tid) else {
1385 return Vec::new();
1386 };
1387 let mut out = Vec::new();
1388 for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1389 match self.resolve_entry_catching(entry) {
1390 Ok(any) => out.push(any),
1391 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1392 Err(err) => std::panic::panic_any(err),
1393 }
1394 }
1395 out
1396 }
1397}
1398
1399#[cfg(test)]
1400mod tests {
1401 use super::ServiceProviderOptions;
1402 use crate::collection::ServiceCollection;
1403 use std::sync::Arc;
1404
1405 #[derive(Debug, PartialEq)]
1406 struct Calc(i32);
1407 #[test]
1408 fn optional_missing() {
1409 let p = ServiceCollection::new().build().unwrap();
1410 assert!(p.get_optional::<i32>().is_none());
1411 }
1412 #[test]
1413 fn get_all_includes_only_unkeyed() {
1414 let p = ServiceCollection::new()
1415 .keyed_singleton("a", |_| Arc::new(Calc(1)))
1416 .keyed_singleton("b", |_| Arc::new(Calc(2)))
1417 .build()
1418 .unwrap();
1419 assert_eq!(p.get_all::<Calc>().len(), 0, "get_all excludes keyed");
1420 assert_eq!(p.get_all_keyed::<Calc>().len(), 2);
1421 }
1422 #[test]
1423 fn later_registration_wins() {
1424 let p = ServiceCollection::new()
1425 .singleton(|_| Arc::new(Calc(1)))
1426 .singleton(|_| Arc::new(Calc(2)))
1427 .build()
1428 .unwrap();
1429 assert_eq!(
1430 p.get::<Calc>().unwrap().0,
1431 2,
1432 "MEDI: last registration wins"
1433 );
1434 }
1435 #[test]
1436 fn root_scoped_is_rejected_by_default() {
1437 let p = ServiceCollection::new()
1438 .scoped(|_| Arc::new(Calc(9)))
1439 .build()
1440 .unwrap();
1441 match p.get::<Calc>() {
1442 Err(crate::error::RdiError::ScopedFromRootProvider { service }) => {
1443 assert!(service.contains("Calc"));
1444 }
1445 other => panic!("expected ScopedFromRootProvider, got {other:?}"),
1446 }
1447 assert!(p.get_optional::<Calc>().is_none());
1448 assert!(p.get_all::<Calc>().is_empty());
1449 }
1450 #[test]
1451 fn lenient_options_restore_root_scope() {
1452 let p = ServiceCollection::new()
1453 .scoped(|_| Arc::new(Calc(9)))
1454 .build_with(ServiceProviderOptions::lenient())
1455 .unwrap();
1456 assert_eq!(p.get::<Calc>().unwrap().0, 9);
1457 assert!(Arc::ptr_eq(
1458 &p.get::<Calc>().unwrap(),
1459 &p.get::<Calc>().unwrap()
1460 ));
1461 }
1462 #[test]
1463 fn scope_resolution_works_and_is_cached() {
1464 let p = ServiceCollection::new()
1465 .scoped(|_| Arc::new(Calc(3)))
1466 .build()
1467 .unwrap();
1468 let s1 = p.scope();
1469 let a = s1.get::<Calc>().unwrap();
1470 let b = s1.get::<Calc>().unwrap();
1471 assert!(Arc::ptr_eq(&a, &b));
1472 let s2 = p.scope();
1473 assert!(!Arc::ptr_eq(&a, &s2.get::<Calc>().unwrap()));
1474 }
1475 #[test]
1476 fn is_registered_reports_lookup_state() {
1477 let p = ServiceCollection::new()
1478 .singleton(|_| Arc::new(Calc(1)))
1479 .keyed_singleton("k", |_| Arc::new(Calc(2)))
1480 .build()
1481 .unwrap();
1482 assert!(p.is_registered::<Calc>());
1483 assert!(p.is_registered::<crate::ServiceProvider>());
1484 assert!(p.is_registered::<dyn crate::ScopeFactory>());
1485 assert!(!p.is_registered::<String>());
1486 assert!(p.is_registered_keyed::<Calc>("k"));
1487 assert!(!p.is_registered_keyed::<Calc>("missing"));
1488 }
1489 #[test]
1490 fn dispose_is_idempotent_and_blocks_resolution() {
1491 let p = ServiceCollection::new()
1492 .singleton(|_| Arc::new(Calc(1)))
1493 .build()
1494 .unwrap();
1495 p.dispose();
1496 p.dispose();
1497 assert!(matches!(
1498 p.get::<Calc>(),
1499 Err(crate::error::RdiError::ProviderDisposed)
1500 ));
1501 assert!(p.get_optional::<Calc>().is_none());
1502 assert!(p.get_all::<Calc>().is_empty());
1503 }
1504 #[test]
1505 fn dispose_releases_singletons_in_reverse_creation_order() {
1506 use std::sync::Mutex;
1507 static DROPS: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1508 #[derive(Debug)]
1509 struct Tracked(&'static str);
1510 impl Drop for Tracked {
1511 fn drop(&mut self) {
1512 DROPS.lock().unwrap().push(self.0);
1513 }
1514 }
1515 struct First(#[allow(dead_code)] Arc<Tracked>);
1516 struct Second(#[allow(dead_code)] Arc<Tracked>);
1517
1518 let p = ServiceCollection::new()
1519 .singleton(|_| Arc::new(First(Arc::new(Tracked("first")))))
1520 .singleton(|_| Arc::new(Second(Arc::new(Tracked("second")))))
1521 .build()
1522 .unwrap();
1523 p.dispose();
1524
1525 let drops = DROPS.lock().unwrap().clone();
1526 assert_eq!(
1527 drops,
1528 vec!["second", "first"],
1529 "singletons must be released in reverse creation order"
1530 );
1531 }
1532
1533 #[test]
1534 fn eager_singletons_are_created_in_registration_order() {
1535 use std::sync::Mutex;
1536 static CREATED: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1537 #[derive(Debug)]
1538 struct A;
1539 #[derive(Debug)]
1540 struct B;
1541 let p = ServiceCollection::new()
1542 .singleton(|_| {
1543 CREATED.lock().unwrap().push("a");
1544 Arc::new(A)
1545 })
1546 .singleton(|_| {
1547 CREATED.lock().unwrap().push("b");
1548 Arc::new(B)
1549 })
1550 .build()
1551 .unwrap();
1552 assert_eq!(
1553 *CREATED.lock().unwrap(),
1554 vec!["a", "b"],
1555 "eager init must be deterministic (registration order)"
1556 );
1557 drop(p);
1558 }
1559
1560 #[test]
1561 fn async_singleton_panic_becomes_typed_error() {
1562 let result = futures::executor::block_on(
1563 ServiceCollection::new()
1564 .async_singleton::<Calc>(|_| Box::pin(async { panic!("boom") }))
1565 .build_async(),
1566 );
1567 match result {
1568 Ok(_) => panic!("build_async must fail when an async singleton factory panics"),
1569 Err(crate::error::RdiError::FactoryPanic { payload, .. }) => {
1570 assert!(payload.contains("boom"), "payload={payload}");
1571 }
1572 Err(other) => panic!("expected FactoryPanic, got {other:?}"),
1573 }
1574 }
1575}