1use crate::cache::{AnyService, KeyedInstanceCache, LazyCache};
2use crate::entry::{
3 AsyncServiceFactory, IServiceResolver, ServiceEntry, ServiceFactory, ServiceLifetime,
4 ServiceStore,
5};
6use crate::error::RdiError;
7use crate::key::ServiceKey;
8use crate::scope::ScopeFactory;
9use crate::validation::ValidationResolver;
10use std::any::{Any, TypeId};
11use std::cell::{Cell, RefCell};
12use std::collections::HashMap;
13use std::future::Future;
14use std::panic::AssertUnwindSafe;
15use std::pin::Pin;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
18use std::task::{Context, Poll};
19
20thread_local! {
21 static RESOLVING: RefCell<Vec<(ResolveToken, &'static str)>> = const { RefCell::new(Vec::new()) };
23 static BUILD_FACTORY_DEPTH: Cell<usize> = const { Cell::new(0) };
29 static CURRENT_ASYNC_CHAIN: RefCell<Option<Arc<ResolveChainNode>>> =
34 const { RefCell::new(None) };
35}
36
37#[derive(Clone, Copy, PartialEq, Eq)]
43pub(crate) enum ResolveToken {
44 CacheKey(usize),
45 AnyKey(usize, u64),
46}
47
48pub(crate) struct ResolveGuard;
49
50impl Drop for ResolveGuard {
51 fn drop(&mut self) {
52 RESOLVING.with(|stack| {
53 stack.borrow_mut().pop();
54 });
55 }
56}
57
58pub(crate) struct BuildFactoryGuard;
60
61impl BuildFactoryGuard {
62 pub(crate) fn enter() -> Self {
63 BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get() + 1));
64 Self
65 }
66}
67
68impl Drop for BuildFactoryGuard {
69 fn drop(&mut self) {
70 BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get().saturating_sub(1)));
71 }
72}
73
74fn reject_build_time_provider_resolution(type_name: &'static str) {
79 if BUILD_FACTORY_DEPTH.with(|depth| depth.get()) > 0 {
80 std::panic::panic_any(RdiError::FactoryPanic {
81 service: type_name.to_string(),
82 payload: format!(
83 "resolving services through the injected provider from a build-time constructor \
84 is not supported: store the provider/ScopeFactory and resolve lazily in methods \
85 (attempted to resolve {type_name})"
86 ),
87 });
88 }
89}
90
91pub(crate) fn enter_resolve(
92 cache_key: usize,
93 type_name: &'static str,
94) -> Result<ResolveGuard, RdiError> {
95 enter_resolve_token(ResolveToken::CacheKey(cache_key), type_name)
96}
97
98pub(crate) fn enter_resolve_token(
99 token: ResolveToken,
100 type_name: &'static str,
101) -> Result<ResolveGuard, RdiError> {
102 RESOLVING.with(|stack| {
103 let mut s = stack.borrow_mut();
104 if s.iter().any(|(k, _)| *k == token) {
105 let mut chain: Vec<&str> = s.iter().map(|(_, n)| *n).collect();
106 chain.push(type_name);
107 return Err(RdiError::CircularDependency(chain.join(" -> ")));
108 }
109 s.push((token, type_name));
110 Ok(ResolveGuard)
111 })
112}
113
114pub(crate) struct ResolveChainNode {
120 pub(crate) cache_key: usize,
121 pub(crate) type_name: &'static str,
122 pub(crate) parent: Option<Arc<ResolveChainNode>>,
123}
124
125fn current_async_chain() -> Option<Arc<ResolveChainNode>> {
127 CURRENT_ASYNC_CHAIN.with(|chain| chain.borrow().clone())
128}
129
130struct ChainScope {
131 previous: Option<Arc<ResolveChainNode>>,
132}
133
134impl ChainScope {
135 fn enter(chain: Option<Arc<ResolveChainNode>>) -> Self {
136 let previous = CURRENT_ASYNC_CHAIN.with(|current| current.replace(chain));
137 Self { previous }
138 }
139}
140
141impl Drop for ChainScope {
142 fn drop(&mut self) {
143 let previous = self.previous.take();
144 CURRENT_ASYNC_CHAIN.with(|current| {
145 *current.borrow_mut() = previous;
146 });
147 }
148}
149
150struct ChainScopeFuture<F> {
152 inner: Pin<Box<F>>,
153 chain: Option<Arc<ResolveChainNode>>,
154}
155
156impl<F: Future> Future for ChainScopeFuture<F> {
157 type Output = F::Output;
158
159 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
160 let this = self.get_mut();
162 let _scope = ChainScope::enter(this.chain.clone());
163 this.inner.as_mut().poll(cx)
164 }
165}
166
167fn chain_scope<F: Future>(chain: Option<Arc<ResolveChainNode>>, future: F) -> ChainScopeFuture<F> {
168 ChainScopeFuture {
169 inner: Box::pin(future),
170 chain,
171 }
172}
173
174fn chain_contains(chain: &Option<Arc<ResolveChainNode>>, cache_key: usize) -> Option<String> {
175 let mut path = Vec::new();
176 let mut found = false;
177 let mut current = chain.clone();
178 while let Some(node) = current {
179 path.push(node.type_name);
180 if node.cache_key == cache_key {
181 found = true;
182 }
183 current = node.parent.clone();
184 }
185 if found {
186 path.reverse();
187 Some(path.join(" -> "))
188 } else {
189 None
190 }
191}
192
193fn extend_chain(
195 chain: &Option<Arc<ResolveChainNode>>,
196 entry: &ServiceEntry,
197) -> Result<Option<Arc<ResolveChainNode>>, RdiError> {
198 if let Some(cycle) = chain_contains(chain, entry.cache_key) {
199 return Err(RdiError::CircularDependency(format!(
200 "{cycle} -> {}",
201 entry.type_name
202 )));
203 }
204 Ok(Some(Arc::new(ResolveChainNode {
205 cache_key: entry.cache_key,
206 type_name: entry.type_name,
207 parent: chain.clone(),
208 })))
209}
210
211enum KeyedLookup<'a> {
214 Exact(&'a ServiceEntry),
215 Fallback(&'a ServiceEntry),
216}
217
218fn drop_instances_safely(instances: Vec<AnyService>) -> Option<Box<dyn Any + Send>> {
224 let mut first_panic: Option<Box<dyn Any + Send>> = None;
225 for instance in instances {
226 if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(|| drop(instance))) {
227 if first_panic.is_none() {
228 first_panic = Some(payload);
229 }
230 }
231 }
232 first_panic
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241#[non_exhaustive]
242pub struct ServiceProviderOptions {
243 pub validate_scopes: bool,
260}
261
262impl ServiceProviderOptions {
263 pub fn new() -> Self {
265 Self {
266 validate_scopes: true,
267 }
268 }
269
270 pub fn with_validate_scopes(mut self, validate_scopes: bool) -> Self {
272 self.validate_scopes = validate_scopes;
273 self
274 }
275
276 pub fn lenient() -> Self {
279 Self {
280 validate_scopes: false,
281 }
282 }
283}
284
285impl Default for ServiceProviderOptions {
286 fn default() -> Self {
287 Self::new()
288 }
289}
290
291pub(crate) struct SharedProviderState {
296 disposed: AtomicBool,
297}
298
299impl SharedProviderState {
300 fn new() -> Self {
301 Self {
302 disposed: AtomicBool::new(false),
303 }
304 }
305}
306
307pub struct ServiceProvider {
308 store: Arc<ServiceStore>,
310 type_map: Arc<HashMap<&'static str, TypeId>>,
313 singleton_cache: Arc<LazyCache>,
318 root_scoped_cache: LazyCache,
326 any_singleton_cache: Arc<KeyedInstanceCache>,
329 any_scoped_cache: KeyedInstanceCache,
331 pub(crate) named: Arc<RwLock<HashMap<String, Arc<dyn Any + Send + Sync>>>>,
336 self_weak: OnceLock<Weak<ServiceProvider>>,
341 scope_factory_cache: OnceLock<Arc<dyn ScopeFactory>>,
345 disposables: Mutex<Vec<Box<dyn FnOnce() + Send>>>,
350 shared: Arc<SharedProviderState>,
352 disposed: AtomicBool,
354 is_root: bool,
356 validate_scopes: bool,
358}
359
360impl ServiceProvider {
361 pub(crate) fn new_with(
362 store: ServiceStore,
363 options: ServiceProviderOptions,
364 ) -> Result<Arc<Self>, RdiError> {
365 if let Some(entry) = store
367 .values()
368 .flat_map(|entries| entries.iter())
369 .find(|e| e.is_async())
370 {
371 return Err(RdiError::AsyncServiceRequiresBuildAsync {
372 service: entry.type_name.to_string(),
373 });
374 }
375
376 let mut type_map = HashMap::new();
378 for (&tid, entries) in &store {
379 if let Some(e) = entries.first() {
380 type_map.entry(e.type_name).or_insert(tid);
381 }
382 }
383
384 let singleton_cache = Arc::new(LazyCache::new());
385
386 let sp_arc = Arc::new(Self {
392 store: Arc::new(store),
393 type_map: Arc::new(type_map),
394 singleton_cache,
395 root_scoped_cache: LazyCache::new(),
396 any_singleton_cache: Arc::new(KeyedInstanceCache::new()),
397 any_scoped_cache: KeyedInstanceCache::new(),
398 named: Arc::new(RwLock::new(HashMap::new())),
399 self_weak: OnceLock::new(),
400 scope_factory_cache: OnceLock::new(),
401 disposables: Mutex::new(Vec::new()),
402 shared: Arc::new(SharedProviderState::new()),
403 disposed: AtomicBool::new(false),
404 is_root: true,
405 validate_scopes: options.validate_scopes,
406 });
407 sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
408
409 Self::validate_dependencies(&sp_arc)?;
412
413 Self::init_sync_singletons(&sp_arc);
416 Ok(sp_arc)
417 }
418
419 fn init_sync_singletons(sp_arc: &Arc<Self>) {
429 let mut singleton_entries: Vec<(usize, ServiceFactory)> = sp_arc
430 .store
431 .values()
432 .flat_map(|entries| entries.iter())
433 .filter(|e| {
434 e.lifetime == ServiceLifetime::Singleton && !e.is_async() && !e.is_any_key()
435 })
436 .map(|e| (e.cache_key, e.factory.clone()))
437 .collect();
438 singleton_entries.sort_by_key(|(cache_key, _)| *cache_key);
439
440 for (ck, factory) in &singleton_entries {
441 let resolver = sp_arc.as_ref() as &dyn IServiceResolver;
442 let factory = factory.clone();
443 sp_arc
444 .singleton_cache
445 .get_or_init_with(*ck, move || factory(resolver));
446 }
447 }
448
449 pub(crate) async fn new_async_with(
458 store: ServiceStore,
459 options: ServiceProviderOptions,
460 ) -> Result<Arc<Self>, RdiError> {
461 let mut type_map = HashMap::new();
463 for (&tid, entries) in &store {
464 if let Some(e) = entries.first() {
465 type_map.entry(e.type_name).or_insert(tid);
466 }
467 }
468
469 let singleton_cache = Arc::new(LazyCache::new());
470
471 let sp_arc = Arc::new(Self {
475 store: Arc::new(store),
476 type_map: Arc::new(type_map),
477 singleton_cache,
478 root_scoped_cache: LazyCache::new(),
479 any_singleton_cache: Arc::new(KeyedInstanceCache::new()),
480 any_scoped_cache: KeyedInstanceCache::new(),
481 named: Arc::new(RwLock::new(HashMap::new())),
482 self_weak: OnceLock::new(),
483 scope_factory_cache: OnceLock::new(),
484 disposables: Mutex::new(Vec::new()),
485 shared: Arc::new(SharedProviderState::new()),
486 disposed: AtomicBool::new(false),
487 is_root: true,
488 validate_scopes: options.validate_scopes,
489 });
490 sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
491
492 Self::validate_dependencies(&sp_arc)?;
494
495 Self::init_sync_singletons(&sp_arc);
497
498 let mut async_singletons: Vec<&ServiceEntry> = sp_arc
506 .store
507 .values()
508 .flat_map(|entries| entries.iter())
509 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.is_async() && !e.is_any_key())
510 .collect();
511 async_singletons.sort_by_key(|e| e.cache_key);
512
513 for entry in async_singletons {
514 sp_arc.ensure_async_singleton(entry, None).await?;
515 }
516
517 Ok(sp_arc)
518 }
519
520 async fn ensure_async_singleton(
532 &self,
533 entry: &ServiceEntry,
534 chain: Option<Arc<ResolveChainNode>>,
535 ) -> Result<(), RdiError> {
536 self.check_alive()?;
537 if self.singleton_cache.get(entry.cache_key).is_some() {
538 return Ok(());
539 }
540 let Some(async_factory) = entry.async_factory.clone() else {
541 return Ok(());
543 };
544
545 let node = extend_chain(&chain, entry)?;
546 let type_name = entry.type_name;
547 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
548 service: type_name.to_string(),
549 payload: "provider_arc() returned None for async singleton initialization".into(),
550 })?;
551
552 self.singleton_cache
553 .get_or_init_with_async(entry.cache_key, || {
554 chain_scope(
555 node.clone(),
556 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
557 )
558 })
559 .await?;
560 Ok(())
561 }
562
563 pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
570 let sp = Self {
571 store: Arc::clone(&parent.store),
572 type_map: Arc::clone(&parent.type_map),
573 singleton_cache: Arc::clone(&parent.singleton_cache),
574 root_scoped_cache: LazyCache::new(),
575 any_singleton_cache: Arc::clone(&parent.any_singleton_cache),
576 any_scoped_cache: KeyedInstanceCache::new(),
577 named: Arc::clone(&parent.named),
578 self_weak: OnceLock::new(),
579 scope_factory_cache: OnceLock::new(),
580 disposables: Mutex::new(Vec::new()),
581 shared: Arc::clone(&parent.shared),
582 disposed: AtomicBool::new(false),
583 is_root: false,
584 validate_scopes: parent.validate_scopes,
585 };
586 let arc = Arc::new(sp);
587 let this: &Self = &arc;
588 this.self_weak.get_or_init(|| Arc::downgrade(&arc));
589 arc
590 }
591
592 pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
598 self.disposables.lock().unwrap().push(cleanup);
599 }
600
601 pub fn dispose(&self) {
622 if self.disposed.swap(true, Ordering::SeqCst) {
623 return;
624 }
625 if self.is_root {
626 self.shared.disposed.store(true, Ordering::SeqCst);
627 }
628
629 let mut first_panic = drop_instances_safely(self.root_scoped_cache.drain_reverse());
632 let any_scoped_panic = drop_instances_safely(self.any_scoped_cache.drain_reverse());
633 if first_panic.is_none() {
634 first_panic = any_scoped_panic;
635 }
636
637 if self.is_root {
638 let singleton_panic = drop_instances_safely(self.singleton_cache.drain_reverse());
640 if first_panic.is_none() {
641 first_panic = singleton_panic;
642 }
643 let any_singleton_panic =
644 drop_instances_safely(self.any_singleton_cache.drain_reverse());
645 if first_panic.is_none() {
646 first_panic = any_singleton_panic;
647 }
648 self.named.write().unwrap().clear();
649 }
650
651 let cleanup_panic = self.run_cleanups();
652 if first_panic.is_none() {
653 first_panic = cleanup_panic;
654 }
655
656 if let Some(payload) = first_panic {
657 if !std::thread::panicking() {
658 std::panic::resume_unwind(payload);
659 }
660 }
661 }
662
663 fn run_cleanups(&self) -> Option<Box<dyn Any + Send>> {
670 let mut cleanups: Vec<Box<dyn FnOnce() + Send>> = {
671 let mut guard = self.disposables.lock().unwrap();
672 std::mem::take(&mut *guard)
673 };
674 cleanups.reverse();
675
676 let mut first_panic: Option<Box<dyn Any + Send>> = None;
677 for cleanup in cleanups {
678 if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(cleanup)) {
679 if first_panic.is_none() {
680 first_panic = Some(payload);
681 }
682 }
683 }
684 first_panic
685 }
686
687 fn validate_dependencies(sp: &Arc<Self>) -> Result<(), RdiError> {
700 let type_names: HashMap<TypeId, &'static str> = sp
702 .store
703 .iter()
704 .map(|(&tid, entries)| {
705 let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
706 (tid, name)
707 })
708 .collect();
709
710 let mut singletons: Vec<&ServiceEntry> = sp
711 .store
712 .values()
713 .flat_map(|entries| entries.iter())
714 .filter(|e| {
715 e.lifetime == ServiceLifetime::Singleton
716 && !e.is_async()
717 && !e.is_any_key()
720 })
721 .collect();
722 singletons.sort_by_key(|e| e.cache_key);
723
724 for entry in singletons {
732 let resolver = ValidationResolver::new(
733 &sp.store,
734 &type_names,
735 &sp.singleton_cache,
736 Arc::clone(sp),
737 entry.type_name,
738 );
739 let type_name = entry.type_name;
740
741 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
742 resolver.validate_entry(entry)
743 }));
744
745 if let Some(err) = resolver.take_error() {
746 return Err(err);
747 }
748
749 match result {
750 Ok(_) => {}
751 Err(panic_info) => {
752 return Err(RdiError::from_panic_payload(type_name, panic_info));
753 }
754 }
755 }
756
757 Ok(())
758 }
759
760 fn unkeyed_entry(&self, tid: TypeId) -> Option<&ServiceEntry> {
765 self.store.get(&tid)?.iter().rev().find(|e| e.key.is_none())
766 }
767
768 fn keyed_entry(&self, tid: TypeId, key: &ServiceKey) -> Option<KeyedLookup<'_>> {
774 let entries = self.store.get(&tid)?;
775 if key.is_any() {
776 return None;
777 }
778 if let Some(entry) = entries.iter().rev().find(|e| e.key.as_ref() == Some(key)) {
779 return Some(KeyedLookup::Exact(entry));
780 }
781 entries
782 .iter()
783 .rev()
784 .find(|e| e.is_any_key())
785 .map(KeyedLookup::Fallback)
786 }
787
788 fn entry_by_str(&self, type_name: &str, key: Option<&ServiceKey>) -> Option<&ServiceEntry> {
789 let tid = *self.type_map.get(type_name)?;
790 match key {
791 Some(k) => match self.keyed_entry(tid, k)? {
792 KeyedLookup::Exact(entry) | KeyedLookup::Fallback(entry) => Some(entry),
793 },
794 None => self.unkeyed_entry(tid),
795 }
796 }
797
798 fn resolve_keyed_lookup(
800 &self,
801 lookup: KeyedLookup<'_>,
802 requested: &ServiceKey,
803 ) -> Result<AnyService, RdiError> {
804 match lookup {
805 KeyedLookup::Exact(entry) => self.resolve_entry_catching(entry),
806 KeyedLookup::Fallback(entry) => self.resolve_any_keyed_entry(entry, requested, false),
807 }
808 }
809
810 fn resolve_any_keyed_entry(
817 &self,
818 entry: &ServiceEntry,
819 requested: &ServiceKey,
820 owned: bool,
821 ) -> Result<AnyService, RdiError> {
822 self.check_alive()?;
826 if !owned {
827 self.check_scope_validation(entry)?;
828 }
829 let Some(factory) = entry.keyed_factory.clone() else {
830 return Err(RdiError::keyed_not_found(
831 entry.type_name,
832 requested.to_string(),
833 None,
834 ));
835 };
836 if entry.lifetime == ServiceLifetime::Singleton && owned {
837 return Err(RdiError::OwnedNotSupported(entry.type_name));
838 }
839
840 let resolver = self as &dyn IServiceResolver;
841 let requested_owned = requested.clone();
842 let call = move || (factory)(resolver, &requested_owned);
843 let lifetime = entry.lifetime;
844 let _guard = enter_resolve_token(
848 ResolveToken::AnyKey(entry.cache_key, requested.stable_hash()),
849 entry.type_name,
850 )?;
851 let result = std::panic::catch_unwind(AssertUnwindSafe(move || match (lifetime, owned) {
852 (ServiceLifetime::Singleton, false) => {
853 self.any_singleton_cache
854 .get_or_init_with(entry.cache_key, requested, call)
855 }
856 (ServiceLifetime::Scoped, false) => {
857 self.any_scoped_cache
858 .get_or_init_with(entry.cache_key, requested, call)
859 }
860 _ => call(),
861 }));
862 match result {
863 Ok(value) => Ok(value),
864 Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
865 }
866 }
867
868 pub(crate) fn prefill_any_keyed_singleton(
872 &self,
873 cache_key: usize,
874 requested: &ServiceKey,
875 instance: AnyService,
876 ) {
877 self.any_singleton_cache
878 .prefill(cache_key, requested, instance);
879 }
880
881 pub(crate) fn cached_any_singleton(
886 &self,
887 cache_key: usize,
888 requested: &ServiceKey,
889 ) -> Option<AnyService> {
890 self.any_singleton_cache.get(cache_key, requested)
891 }
892
893 fn check_alive(&self) -> Result<(), RdiError> {
897 if self.shared.disposed.load(Ordering::SeqCst) {
898 return Err(RdiError::ProviderDisposed);
899 }
900 if self.disposed.load(Ordering::SeqCst) {
901 return Err(RdiError::ScopeDisposed);
902 }
903 Ok(())
904 }
905
906 fn check_scope_validation(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
909 if entry.lifetime == ServiceLifetime::Scoped && self.is_root && self.validate_scopes {
910 return Err(RdiError::ScopedFromRootProvider {
911 service: entry.type_name.to_string(),
912 });
913 }
914 Ok(())
915 }
916
917 fn check_resolvable(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
918 self.check_alive()?;
919 self.check_scope_validation(entry)
920 }
921
922 fn resolve_entry_catching(&self, entry: &ServiceEntry) -> Result<AnyService, RdiError> {
927 self.check_resolvable(entry)?;
928 match std::panic::catch_unwind(AssertUnwindSafe(|| self.get_any_by_entry(entry))) {
929 Ok(Some(v)) => Ok(v),
930 Ok(None) => Err(RdiError::not_found(entry.type_name, None)),
931 Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
932 }
933 }
934
935 fn resolve_entry_panicking(&self, entry: &ServiceEntry) -> AnyService {
940 if let Err(err) = self.check_resolvable(entry) {
941 std::panic::panic_any(err);
942 }
943 match self.get_any_by_entry(entry) {
944 Some(v) => v,
945 None => std::panic::panic_any(RdiError::not_found(entry.type_name, None)),
946 }
947 }
948
949 fn resolve_unkeyed_optional<T: ?Sized + Send + Sync + 'static>(
954 &self,
955 ) -> Result<Option<Arc<T>>, RdiError> {
956 self.check_alive()?;
957 if let Some(entry) = self.unkeyed_entry(TypeId::of::<T>()) {
958 return Ok(Self::extract(self.resolve_entry_catching(entry)?));
959 }
960 Ok(self
964 .builtin_service_by_type_id(TypeId::of::<T>())
965 .and_then(Self::extract))
966 }
967
968 pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
976 let type_name = std::any::type_name::<T>();
977 match self.resolve_unkeyed_optional::<T>() {
978 Ok(Some(v)) => Ok(v),
979 Ok(None) => Err(RdiError::not_found(type_name, None)),
980 Err(e) => Err(e),
981 }
982 }
983
984 pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
989 self.resolve_unkeyed_optional::<T>().ok().flatten()
990 }
991
992 pub fn get_async<T: ?Sized + Send + Sync + 'static>(
999 &self,
1000 ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send + '_ {
1001 let chain = current_async_chain();
1002 async move { self.resolve_async_unkeyed::<T>(chain).await }
1003 }
1004
1005 pub fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
1011 &self,
1012 key: impl Into<ServiceKey> + Send,
1013 ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send + '_ {
1014 let chain = current_async_chain();
1015 let key = key.into();
1016 async move { self.resolve_async_keyed::<T>(chain, key).await }
1017 }
1018
1019 async fn resolve_async_unkeyed<T: ?Sized + Send + Sync + 'static>(
1020 &self,
1021 chain: Option<Arc<ResolveChainNode>>,
1022 ) -> Result<Arc<T>, RdiError> {
1023 let type_name = std::any::type_name::<T>();
1024 let entry = self
1025 .unkeyed_entry(TypeId::of::<T>())
1026 .ok_or_else(|| RdiError::not_found(type_name, None))?;
1027 self.resolve_async_entry::<T>(entry, chain).await
1028 }
1029
1030 async fn resolve_async_keyed<T: ?Sized + Send + Sync + 'static>(
1031 &self,
1032 chain: Option<Arc<ResolveChainNode>>,
1033 key: ServiceKey,
1034 ) -> Result<Arc<T>, RdiError> {
1035 let type_name = std::any::type_name::<T>();
1036 let Some(lookup) = self.keyed_entry(TypeId::of::<T>(), &key) else {
1037 return Err(RdiError::keyed_not_found(type_name, key.to_string(), None));
1038 };
1039 match lookup {
1040 KeyedLookup::Exact(entry) => self.resolve_async_entry::<T>(entry, chain).await,
1041 KeyedLookup::Fallback(entry) => {
1042 if entry.is_async() {
1044 return Err(RdiError::AsyncServiceRequiresGetAsync {
1045 service: entry.type_name.to_string(),
1046 });
1047 }
1048 let any = self.resolve_any_keyed_entry(entry, &key, false)?;
1049 Self::extract(any)
1050 .ok_or_else(|| RdiError::keyed_not_found(type_name, key.to_string(), None))
1051 }
1052 }
1053 }
1054
1055 async fn resolve_async_entry<T: ?Sized + Send + Sync + 'static>(
1058 &self,
1059 entry: &ServiceEntry,
1060 chain: Option<Arc<ResolveChainNode>>,
1061 ) -> Result<Arc<T>, RdiError> {
1062 if entry.lifetime == ServiceLifetime::Singleton {
1063 self.ensure_async_singleton(entry, chain).await?;
1066 return self.resolve_entry_as::<T>(entry);
1067 }
1068 self.check_resolvable(entry)?;
1069 match self.resolve_async_non_singleton(entry, chain).await? {
1070 Some(any) => {
1071 Self::extract(any).ok_or_else(|| RdiError::not_found(entry.type_name, None))
1072 }
1073 None => self.resolve_entry_as::<T>(entry),
1074 }
1075 }
1076
1077 fn resolve_entry_as<T: ?Sized + Send + Sync + 'static>(
1080 &self,
1081 entry: &ServiceEntry,
1082 ) -> Result<Arc<T>, RdiError> {
1083 let any = self.resolve_entry_catching(entry)?;
1084 Self::extract(any).ok_or_else(|| RdiError::not_found(entry.type_name, None))
1085 }
1086
1087 async fn resolve_async_non_singleton(
1095 &self,
1096 entry: &ServiceEntry,
1097 chain: Option<Arc<ResolveChainNode>>,
1098 ) -> Result<Option<AnyService>, RdiError> {
1099 let Some(async_factory) = entry.async_factory.clone() else {
1100 return Ok(None);
1101 };
1102 let type_name = entry.type_name;
1103 let node = extend_chain(&chain, entry)?;
1104 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
1105 service: type_name.to_string(),
1106 payload: "provider_arc() returned None for async resolution".into(),
1107 })?;
1108 match entry.lifetime {
1109 ServiceLifetime::Scoped => self
1110 .root_scoped_cache
1111 .get_or_init_with_async(entry.cache_key, || {
1112 chain_scope(
1113 node.clone(),
1114 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
1115 )
1116 })
1117 .await
1118 .map(Some),
1119 ServiceLifetime::Transient => chain_scope(
1120 node,
1121 Self::run_async_factory_safely(type_name, async_factory, provider_arc),
1122 )
1123 .await
1124 .map(Some),
1125 _ => Ok(None),
1126 }
1127 }
1128
1129 async fn run_async_factory_safely(
1134 type_name: &'static str,
1135 async_factory: AsyncServiceFactory,
1136 provider_arc: Arc<ServiceProvider>,
1137 ) -> Result<AnyService, RdiError> {
1138 let fut = async_factory(provider_arc);
1139 match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
1140 Ok(arc_any) => Ok(arc_any),
1141 Err(payload) => Err(RdiError::from_panic_payload(type_name, payload)),
1142 }
1143 }
1144
1145 pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
1153 &self,
1154 key: impl Into<ServiceKey>,
1155 ) -> Result<Arc<T>, RdiError> {
1156 let key = key.into();
1157 let type_name = std::any::type_name::<T>();
1158 match self.resolve_keyed_optional::<T>(&key)? {
1159 Some(value) => Ok(value),
1160 None => Err(RdiError::keyed_not_found(type_name, key.to_string(), None)),
1161 }
1162 }
1163
1164 fn resolve_keyed_optional<T: ?Sized + Send + Sync + 'static>(
1165 &self,
1166 key: &ServiceKey,
1167 ) -> Result<Option<Arc<T>>, RdiError> {
1168 self.check_alive()?;
1169 let Some(lookup) = self.keyed_entry(TypeId::of::<T>(), key) else {
1170 return Ok(None);
1171 };
1172 let any = self.resolve_keyed_lookup(lookup, key)?;
1173 Ok(Self::extract(any))
1174 }
1175
1176 pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
1184 let type_name = std::any::type_name::<T>();
1185 let tid = TypeId::of::<T>();
1186 let entry = self
1187 .unkeyed_entry(tid)
1188 .ok_or_else(|| RdiError::not_found(type_name, None))?;
1189 if entry.lifetime == ServiceLifetime::Singleton {
1190 return Err(RdiError::OwnedNotSupported(type_name));
1191 }
1192 self.check_alive()?;
1193 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
1194 self.create_owned_any_by_entry(entry)
1195 })) {
1196 Ok(Some(v)) => v,
1197 Ok(None) => return Err(RdiError::not_found(type_name, None)),
1198 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
1199 };
1200 let arc_t = Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))?;
1201 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
1202 }
1203
1204 pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
1207 self.get_owned().ok()
1208 }
1209
1210 pub fn get_keyed_owned<T: Send + Sync + 'static>(
1213 &self,
1214 key: impl Into<ServiceKey>,
1215 ) -> Result<T, RdiError> {
1216 let key = key.into();
1217 let type_name = std::any::type_name::<T>();
1218 let tid = TypeId::of::<T>();
1219 let Some(lookup) = self.keyed_entry(tid, &key) else {
1220 return Err(RdiError::keyed_not_found(type_name, key.to_string(), None));
1221 };
1222 let (entry, any) = match lookup {
1223 KeyedLookup::Exact(entry) => {
1224 if entry.lifetime == ServiceLifetime::Singleton {
1225 return Err(RdiError::OwnedNotSupported(type_name));
1226 }
1227 self.check_alive()?;
1228 let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
1229 self.create_owned_any_by_entry(entry)
1230 })) {
1231 Ok(Some(v)) => v,
1232 Ok(None) => {
1233 return Err(RdiError::keyed_not_found(type_name, key.to_string(), None))
1234 }
1235 Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
1236 };
1237 (entry, arc_any)
1238 }
1239 KeyedLookup::Fallback(entry) => {
1240 if entry.lifetime == ServiceLifetime::Singleton {
1241 return Err(RdiError::OwnedNotSupported(type_name));
1242 }
1243 self.check_alive()?;
1244 (entry, self.resolve_any_keyed_entry(entry, &key, true)?)
1245 }
1246 };
1247 let _ = entry;
1248 let arc_t = Self::extract(any)
1249 .ok_or_else(|| RdiError::keyed_not_found(type_name, key.to_string(), None))?;
1250 Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
1251 }
1252
1253 pub fn try_get_keyed_owned<T: Send + Sync + 'static>(
1256 &self,
1257 key: impl Into<ServiceKey>,
1258 ) -> Option<T> {
1259 self.get_keyed_owned(key).ok()
1260 }
1261
1262 pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1270 self.collect_all::<T>(false)
1271 }
1272
1273 pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1279 self.collect_all::<T>(true)
1280 }
1281
1282 fn collect_all<T: ?Sized + Send + Sync + 'static>(&self, keyed_only: bool) -> Vec<Arc<T>> {
1283 if self.check_alive().is_err() {
1284 return Vec::new();
1285 }
1286 let Some(entries) = self.store.get(&TypeId::of::<T>()) else {
1287 return Vec::new();
1288 };
1289 let mut out = Vec::new();
1290 for entry in entries.iter().filter(|e| {
1291 if keyed_only {
1292 e.key.is_some() && !e.is_any_key()
1293 } else {
1294 e.key.is_none()
1295 }
1296 }) {
1297 match self.resolve_entry_catching(entry) {
1298 Ok(any) => {
1299 if let Some(v) = Self::extract(any) {
1300 out.push(v);
1301 }
1302 }
1303 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1306 Err(err) => std::panic::panic_any(err),
1307 }
1308 }
1309 out
1310 }
1311
1312 pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
1317 crate::scope::Scope::new(self.clone())
1318 }
1319
1320 pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
1325 let tid = TypeId::of::<T>();
1326 self.store
1327 .get(&tid)
1328 .is_some_and(|entries| entries.iter().any(|e| e.key.is_none()))
1329 || tid == TypeId::of::<dyn ScopeFactory>()
1330 || tid == TypeId::of::<ServiceProvider>()
1331 }
1332
1333 pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(
1336 &self,
1337 key: impl Into<ServiceKey>,
1338 ) -> bool {
1339 let key = key.into();
1340 if key.is_any() {
1341 return false;
1344 }
1345 self.store.get(&TypeId::of::<T>()).is_some_and(|entries| {
1346 entries.iter().any(|e| e.key.as_ref() == Some(&key))
1347 || entries.iter().any(|e| e.is_any_key())
1348 })
1349 }
1350
1351 fn builtin_scope_factory(&self) -> Option<Arc<dyn ScopeFactory>> {
1353 let weak = self.self_weak.get()?.clone();
1354 Some(Arc::clone(
1355 self.scope_factory_cache
1356 .get_or_init(|| crate::scope::builtin_scope_factory(weak)),
1357 ))
1358 }
1359
1360 fn builtin_scope_factory_any(&self) -> Option<AnyService> {
1361 Some(crate::scope::builtin_scope_factory_any(
1362 self.builtin_scope_factory()?,
1363 ))
1364 }
1365
1366 pub(crate) fn builtin_scope_factory_any_cached(&self) -> Option<AnyService> {
1371 self.builtin_scope_factory_any()
1372 }
1373
1374 fn builtin_service_by_type_id(&self, tid: TypeId) -> Option<AnyService> {
1381 if tid == TypeId::of::<dyn ScopeFactory>() {
1382 return self.builtin_scope_factory_any();
1383 }
1384 if tid == TypeId::of::<ServiceProvider>() {
1385 let provider = self.self_weak.get()?.upgrade()?;
1386 return Some(Arc::new(provider) as AnyService);
1387 }
1388 None
1389 }
1390
1391 fn builtin_service_by_name(&self, key: &str) -> Option<AnyService> {
1394 if key == std::any::type_name::<dyn ScopeFactory>() {
1395 return self.builtin_scope_factory_any();
1396 }
1397 if key == std::any::type_name::<ServiceProvider>() {
1398 let provider = self.self_weak.get()?.upgrade()?;
1399 return Some(Arc::new(provider) as AnyService);
1400 }
1401 None
1402 }
1403
1404 pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1405 reject_build_time_provider_resolution(entry.type_name);
1406 if entry.is_async() {
1407 let ready = entry.lifetime == ServiceLifetime::Singleton
1410 && self.singleton_cache.get(entry.cache_key).is_some();
1411 if !ready {
1412 std::panic::panic_any(RdiError::AsyncServiceRequiresGetAsync {
1413 service: entry.type_name.to_string(),
1414 });
1415 }
1416 }
1417 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1418 Ok(g) => g,
1419 Err(e) => std::panic::panic_any(e),
1420 };
1421 match entry.lifetime {
1422 ServiceLifetime::Singleton => {
1423 let factory = entry.factory.clone();
1428 let resolver = self as &dyn IServiceResolver;
1429 Some(
1430 self.singleton_cache
1431 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1432 )
1433 }
1434 ServiceLifetime::Scoped => {
1435 let factory = entry.factory.clone();
1436 let resolver = self as &dyn IServiceResolver;
1437 Some(
1438 self.root_scoped_cache
1439 .get_or_init_with(entry.cache_key, move || factory(resolver)),
1440 )
1441 }
1442 ServiceLifetime::Transient => Some((entry.factory)(self)),
1443 }
1444 }
1445
1446 pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1454 reject_build_time_provider_resolution(entry.type_name);
1455 match entry.lifetime {
1456 ServiceLifetime::Singleton => None,
1457 ServiceLifetime::Scoped | ServiceLifetime::Transient => {
1458 let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1459 Ok(g) => g,
1460 Err(e) => std::panic::panic_any(e),
1461 };
1462 Some((entry.factory)(self as &dyn IServiceResolver))
1463 }
1464 }
1465 }
1466
1467 pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
1470 arc: Arc<dyn Any + Send + Sync>,
1471 ) -> Option<Arc<T>> {
1472 let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
1473 Some(Arc::clone(&*double))
1474 }
1475
1476 pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1478 self.named
1479 .read()
1480 .unwrap()
1481 .get(name)?
1482 .clone()
1483 .downcast::<T>()
1484 .ok()
1485 }
1486
1487 pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1489 self.named.read().unwrap().get(name).cloned()
1490 }
1491
1492 pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
1497 if self.check_alive().is_err() {
1498 return;
1499 }
1500 self.named
1501 .write()
1502 .unwrap()
1503 .insert(name.to_string(), service);
1504 }
1505
1506 pub fn remove_named(&self, name: &str) {
1508 if self.check_alive().is_err() {
1509 return;
1510 }
1511 self.named.write().unwrap().remove(name);
1512 }
1513
1514 pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
1518 if self.check_alive().is_err() {
1519 return;
1520 }
1521 self.named
1522 .write()
1523 .unwrap()
1524 .insert(name.to_string(), service);
1525 }
1526
1527 pub fn rdi_remove_named(&self, name: &str) {
1529 if self.check_alive().is_err() {
1530 return;
1531 }
1532 self.named.write().unwrap().remove(name);
1533 }
1534
1535 fn builtin_service_checked(&self, key: &str) -> Option<AnyService> {
1539 if let Err(err) = self.check_alive() {
1540 std::panic::panic_any(err);
1541 }
1542 self.builtin_service_by_name(key)
1543 }
1544
1545 fn builtin_service_by_type_id_checked(&self, tid: TypeId) -> Option<AnyService> {
1546 if let Err(err) = self.check_alive() {
1547 std::panic::panic_any(err);
1548 }
1549 self.builtin_service_by_type_id(tid)
1550 }
1551}
1552
1553#[derive(Clone)]
1572pub struct AsyncFactoryContext {
1573 provider: Arc<ServiceProvider>,
1574 chain: Option<Arc<ResolveChainNode>>,
1575}
1576
1577impl AsyncFactoryContext {
1578 pub fn provider(&self) -> &Arc<ServiceProvider> {
1580 &self.provider
1581 }
1582
1583 pub fn get_async<T: ?Sized + Send + Sync + 'static>(
1585 &self,
1586 ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send + 'static {
1587 let provider = Arc::clone(&self.provider);
1588 let chain = self.chain.clone();
1589 async move { provider.resolve_async_unkeyed::<T>(chain).await }
1590 }
1591
1592 pub fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
1594 &self,
1595 key: impl Into<ServiceKey> + Send + 'static,
1596 ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send + 'static {
1597 let provider = Arc::clone(&self.provider);
1598 let chain = self.chain.clone();
1599 let key = key.into();
1600 async move { provider.resolve_async_keyed::<T>(chain, key).await }
1601 }
1602}
1603
1604impl ServiceProvider {
1605 pub fn async_context(&self) -> Option<AsyncFactoryContext> {
1613 Some(AsyncFactoryContext {
1614 provider: self.provider_arc()?,
1615 chain: current_async_chain(),
1616 })
1617 }
1618}
1619
1620impl ScopeFactory for ServiceProvider {
1621 fn create_scope(&self) -> crate::scope::Scope {
1622 self.self_weak
1624 .get()
1625 .and_then(|w| w.upgrade())
1626 .map(crate::scope::Scope::new)
1627 .expect("ScopeFactory::create_scope: ServiceProvider self_weak not initialized")
1628 }
1629}
1630
1631impl IServiceResolver for ServiceProvider {
1632 fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1633 if let Some(entry) = self.entry_by_str(key, None) {
1634 return Some(self.resolve_entry_panicking(entry));
1635 }
1636 self.builtin_service_checked(key)
1639 }
1640
1641 fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1642 let requested = ServiceKey::from(variant);
1643 self.resolve_keyed_panicking(key, &requested)
1644 }
1645
1646 fn get_keyed_any_key(
1647 &self,
1648 key: &str,
1649 variant: &ServiceKey,
1650 ) -> Option<Arc<dyn Any + Send + Sync>> {
1651 self.resolve_keyed_panicking(key, variant)
1652 }
1653
1654 fn try_get_keyed_any_result_key(
1655 &self,
1656 key: &str,
1657 variant: &ServiceKey,
1658 ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
1659 self.check_alive()?;
1660 let Some(tid) = self.type_map.get(key) else {
1661 return Ok(None);
1662 };
1663 match self.keyed_entry(*tid, variant) {
1664 Some(KeyedLookup::Exact(entry)) => self.resolve_entry_catching(entry).map(Some),
1665 Some(KeyedLookup::Fallback(entry)) => self
1666 .resolve_any_keyed_entry(entry, variant, false)
1667 .map(Some),
1668 None => Ok(None),
1669 }
1670 }
1671
1672 fn get_keyed_owned_any_key(
1673 &self,
1674 key: &str,
1675 variant: &ServiceKey,
1676 ) -> Option<Arc<dyn Any + Send + Sync>> {
1677 let tid = self.type_map.get(key)?;
1678 match self.keyed_entry(*tid, variant)? {
1679 KeyedLookup::Exact(entry) => {
1680 if entry.lifetime == ServiceLifetime::Singleton {
1681 return None;
1682 }
1683 self.check_alive().ok()?;
1684 self.create_owned_any_by_entry(entry)
1685 }
1686 KeyedLookup::Fallback(entry) => {
1687 if entry.lifetime == ServiceLifetime::Singleton {
1688 return None;
1689 }
1690 self.check_alive().ok()?;
1691 self.resolve_any_keyed_entry(entry, variant, true).ok()
1692 }
1693 }
1694 }
1695
1696 fn try_get_keyed_owned_any_key(
1697 &self,
1698 key: &str,
1699 variant: &ServiceKey,
1700 ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError> {
1701 self.check_alive()?;
1702 let Some(tid) = self.type_map.get(key) else {
1703 return Ok(None);
1704 };
1705 match self.keyed_entry(*tid, variant) {
1706 Some(KeyedLookup::Exact(entry)) => {
1707 if entry.lifetime == ServiceLifetime::Singleton {
1708 return Ok(None);
1709 }
1710 Ok(self.create_owned_any_by_entry(entry))
1711 }
1712 Some(KeyedLookup::Fallback(entry)) => {
1713 if entry.lifetime == ServiceLifetime::Singleton {
1714 return Ok(None);
1715 }
1716 self.resolve_any_keyed_entry(entry, variant, true).map(Some)
1717 }
1718 None => Ok(None),
1719 }
1720 }
1721
1722 fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
1723 if let Some(entry) = self.unkeyed_entry(tid) {
1724 return Some(self.resolve_entry_panicking(entry));
1725 }
1726 self.builtin_service_by_type_id_checked(tid)
1727 }
1728
1729 fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1730 let requested = ServiceKey::from(key);
1731 match self.keyed_entry(tid, &requested)? {
1732 KeyedLookup::Exact(entry) => Some(self.resolve_entry_panicking(entry)),
1733 KeyedLookup::Fallback(entry) => {
1734 match self.resolve_any_keyed_entry(entry, &requested, false) {
1735 Ok(value) => Some(value),
1736 Err(err) => std::panic::panic_any(err),
1737 }
1738 }
1739 }
1740 }
1741
1742 fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1743 self.collect_all_any(key, false)
1744 }
1745
1746 fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1747 self.collect_all_any(key, true)
1748 }
1749
1750 fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
1751 self.check_alive()?;
1752 let Some(tid) = self.type_map.get(key) else {
1753 return Ok(Vec::new());
1754 };
1755 let Some(entries) = self.store.get(tid) else {
1756 return Ok(Vec::new());
1757 };
1758 let mut out = Vec::new();
1759 for entry in entries.iter().filter(|e| e.key.is_none()) {
1760 if entry.is_async() {
1761 let ready = entry.lifetime == ServiceLifetime::Singleton
1765 && self.singleton_cache.get(entry.cache_key).is_some();
1766 if !ready {
1767 return Err(RdiError::AsyncServiceRequiresGetAsync {
1768 service: entry.type_name.to_string(),
1769 });
1770 }
1771 }
1772 out.push(self.resolve_entry_catching(entry)?);
1773 }
1774 Ok(out)
1775 }
1776
1777 fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1778 let entry = self.entry_by_str(key, None)?;
1779 if entry.lifetime == ServiceLifetime::Singleton {
1780 return None;
1781 }
1782 self.check_alive().ok()?;
1783 self.create_owned_any_by_entry(entry)
1784 }
1785
1786 fn try_get_any_result(&self, key: &str) -> Result<Option<AnyService>, RdiError> {
1791 self.check_alive()?;
1792 if let Some(entry) = self.entry_by_str(key, None) {
1793 return self.resolve_entry_catching(entry).map(Some);
1794 }
1795 Ok(self.builtin_service_by_name(key))
1796 }
1797
1798 fn try_get_keyed_any_result(
1800 &self,
1801 key: &str,
1802 variant: &str,
1803 ) -> Result<Option<AnyService>, RdiError> {
1804 self.check_alive()?;
1805 let requested = ServiceKey::from(variant);
1806 let Some(tid) = self.type_map.get(key) else {
1807 return Ok(None);
1808 };
1809 match self.keyed_entry(*tid, &requested) {
1810 Some(KeyedLookup::Exact(entry)) => self.resolve_entry_catching(entry).map(Some),
1811 Some(KeyedLookup::Fallback(entry)) => self
1812 .resolve_any_keyed_entry(entry, &requested, false)
1813 .map(Some),
1814 None => Ok(None),
1815 }
1816 }
1817
1818 fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1819 let requested = ServiceKey::from(variant);
1820 let tid = self.type_map.get(key)?;
1821 match self.keyed_entry(*tid, &requested)? {
1822 KeyedLookup::Exact(entry) => {
1823 if entry.lifetime == ServiceLifetime::Singleton {
1824 return None;
1825 }
1826 self.check_alive().ok()?;
1827 self.create_owned_any_by_entry(entry)
1828 }
1829 KeyedLookup::Fallback(entry) => {
1830 if entry.lifetime == ServiceLifetime::Singleton {
1831 return None;
1832 }
1833 self.check_alive().ok()?;
1834 self.resolve_any_keyed_entry(entry, &requested, true).ok()
1835 }
1836 }
1837 }
1838
1839 fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
1840 self.self_weak.get().and_then(|w| w.upgrade())
1841 }
1842}
1843
1844impl ServiceProvider {
1845 fn resolve_keyed_panicking(
1848 &self,
1849 type_name: &str,
1850 requested: &ServiceKey,
1851 ) -> Option<AnyService> {
1852 let tid = *self.type_map.get(type_name)?;
1853 match self.keyed_entry(tid, requested)? {
1854 KeyedLookup::Exact(entry) => Some(self.resolve_entry_panicking(entry)),
1855 KeyedLookup::Fallback(entry) => {
1856 match self.resolve_any_keyed_entry(entry, requested, false) {
1857 Ok(value) => Some(value),
1858 Err(err) => std::panic::panic_any(err),
1859 }
1860 }
1861 }
1862 }
1863
1864 fn collect_all_any(&self, key: &str, keyed_only: bool) -> Vec<Arc<dyn Any + Send + Sync>> {
1865 if self.check_alive().is_err() {
1866 return Vec::new();
1867 }
1868 let Some(tid) = self.type_map.get(key) else {
1869 return Vec::new();
1870 };
1871 let Some(entries) = self.store.get(tid) else {
1872 return Vec::new();
1873 };
1874 let mut out = Vec::new();
1875 for entry in entries.iter().filter(|e| {
1876 if keyed_only {
1877 e.key.is_some() && !e.is_any_key()
1878 } else {
1879 e.key.is_none()
1880 }
1881 }) {
1882 match self.resolve_entry_catching(entry) {
1883 Ok(any) => out.push(any),
1884 Err(RdiError::ScopedFromRootProvider { .. }) => {}
1885 Err(err) => std::panic::panic_any(err),
1886 }
1887 }
1888 out
1889 }
1890}
1891
1892#[cfg(test)]
1893mod tests {
1894 use super::ServiceProviderOptions;
1895 use crate::collection::ServiceCollection;
1896 use std::sync::Arc;
1897
1898 #[derive(Debug, PartialEq)]
1899 struct Calc(i32);
1900 #[test]
1901 fn optional_missing() {
1902 let p = ServiceCollection::new().build().unwrap();
1903 assert!(p.get_optional::<i32>().is_none());
1904 }
1905 #[test]
1906 fn get_all_includes_only_unkeyed() {
1907 let p = ServiceCollection::new()
1908 .keyed_singleton("a", |_| Arc::new(Calc(1)))
1909 .keyed_singleton("b", |_| Arc::new(Calc(2)))
1910 .build()
1911 .unwrap();
1912 assert_eq!(p.get_all::<Calc>().len(), 0, "get_all excludes keyed");
1913 assert_eq!(p.get_all_keyed::<Calc>().len(), 2);
1914 }
1915 #[test]
1916 fn later_registration_wins() {
1917 let p = ServiceCollection::new()
1918 .singleton(|_| Arc::new(Calc(1)))
1919 .singleton(|_| Arc::new(Calc(2)))
1920 .build()
1921 .unwrap();
1922 assert_eq!(
1923 p.get::<Calc>().unwrap().0,
1924 2,
1925 "MEDI: last registration wins"
1926 );
1927 }
1928 #[test]
1929 fn root_scoped_is_rejected_by_default() {
1930 let p = ServiceCollection::new()
1931 .scoped(|_| Arc::new(Calc(9)))
1932 .build()
1933 .unwrap();
1934 match p.get::<Calc>() {
1935 Err(crate::error::RdiError::ScopedFromRootProvider { service }) => {
1936 assert!(service.contains("Calc"));
1937 }
1938 other => panic!("expected ScopedFromRootProvider, got {other:?}"),
1939 }
1940 assert!(p.get_optional::<Calc>().is_none());
1941 assert!(p.get_all::<Calc>().is_empty());
1942 }
1943 #[test]
1944 fn lenient_options_restore_root_scope() {
1945 let p = ServiceCollection::new()
1946 .scoped(|_| Arc::new(Calc(9)))
1947 .build_with(ServiceProviderOptions::lenient())
1948 .unwrap();
1949 assert_eq!(p.get::<Calc>().unwrap().0, 9);
1950 assert!(Arc::ptr_eq(
1951 &p.get::<Calc>().unwrap(),
1952 &p.get::<Calc>().unwrap()
1953 ));
1954 }
1955 #[test]
1956 fn scope_resolution_works_and_is_cached() {
1957 let p = ServiceCollection::new()
1958 .scoped(|_| Arc::new(Calc(3)))
1959 .build()
1960 .unwrap();
1961 let s1 = p.scope();
1962 let a = s1.get::<Calc>().unwrap();
1963 let b = s1.get::<Calc>().unwrap();
1964 assert!(Arc::ptr_eq(&a, &b));
1965 let s2 = p.scope();
1966 assert!(!Arc::ptr_eq(&a, &s2.get::<Calc>().unwrap()));
1967 }
1968 #[test]
1969 fn is_registered_reports_lookup_state() {
1970 let p = ServiceCollection::new()
1971 .singleton(|_| Arc::new(Calc(1)))
1972 .keyed_singleton("k", |_| Arc::new(Calc(2)))
1973 .build()
1974 .unwrap();
1975 assert!(p.is_registered::<Calc>());
1976 assert!(p.is_registered::<crate::ServiceProvider>());
1977 assert!(p.is_registered::<dyn crate::ScopeFactory>());
1978 assert!(!p.is_registered::<String>());
1979 assert!(p.is_registered_keyed::<Calc>("k"));
1980 assert!(!p.is_registered_keyed::<Calc>("missing"));
1981 }
1982 #[test]
1983 fn dispose_is_idempotent_and_blocks_resolution() {
1984 let p = ServiceCollection::new()
1985 .singleton(|_| Arc::new(Calc(1)))
1986 .build()
1987 .unwrap();
1988 p.dispose();
1989 p.dispose();
1990 assert!(matches!(
1991 p.get::<Calc>(),
1992 Err(crate::error::RdiError::ProviderDisposed)
1993 ));
1994 assert!(p.get_optional::<Calc>().is_none());
1995 assert!(p.get_all::<Calc>().is_empty());
1996 }
1997 #[test]
1998 fn dispose_releases_singletons_in_reverse_creation_order() {
1999 use std::sync::Mutex;
2000 static DROPS: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
2001 #[derive(Debug)]
2002 struct Tracked(&'static str);
2003 impl Drop for Tracked {
2004 fn drop(&mut self) {
2005 DROPS.lock().unwrap().push(self.0);
2006 }
2007 }
2008 struct First(#[allow(dead_code)] Arc<Tracked>);
2009 struct Second(#[allow(dead_code)] Arc<Tracked>);
2010
2011 let p = ServiceCollection::new()
2012 .singleton(|_| Arc::new(First(Arc::new(Tracked("first")))))
2013 .singleton(|_| Arc::new(Second(Arc::new(Tracked("second")))))
2014 .build()
2015 .unwrap();
2016 p.dispose();
2017
2018 let drops = DROPS.lock().unwrap().clone();
2019 assert_eq!(
2020 drops,
2021 vec!["second", "first"],
2022 "singletons must be released in reverse creation order"
2023 );
2024 }
2025
2026 #[test]
2027 fn eager_singletons_are_created_in_registration_order() {
2028 use std::sync::Mutex;
2029 static CREATED: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
2030 #[derive(Debug)]
2031 struct A;
2032 #[derive(Debug)]
2033 struct B;
2034 let p = ServiceCollection::new()
2035 .singleton(|_| {
2036 CREATED.lock().unwrap().push("a");
2037 Arc::new(A)
2038 })
2039 .singleton(|_| {
2040 CREATED.lock().unwrap().push("b");
2041 Arc::new(B)
2042 })
2043 .build()
2044 .unwrap();
2045 assert_eq!(
2046 *CREATED.lock().unwrap(),
2047 vec!["a", "b"],
2048 "eager init must be deterministic (registration order)"
2049 );
2050 drop(p);
2051 }
2052
2053 #[test]
2054 fn async_singleton_panic_becomes_typed_error() {
2055 let result = futures::executor::block_on(
2056 ServiceCollection::new()
2057 .async_singleton::<Calc>(|_| Box::pin(async { panic!("boom") }))
2058 .build_async(),
2059 );
2060 match result {
2061 Ok(_) => panic!("build_async must fail when an async singleton factory panics"),
2062 Err(crate::error::RdiError::FactoryPanic { payload, .. }) => {
2063 assert!(payload.contains("boom"), "payload={payload}");
2064 }
2065 Err(other) => panic!("expected FactoryPanic, got {other:?}"),
2066 }
2067 }
2068}