1use crate::cache::{AnyService, LazyCache};
2use crate::entry::{
3 AsyncServiceFactory, IServiceResolver, ServiceEntry, ServiceFactory,
4 ServiceLifetime, ServiceStore,
5};
6use crate::error::RdiError;
7use crate::scope::ScopeFactory;
8use crate::validation::ValidationResolver;
9use std::any::{Any, TypeId};
10use std::collections::HashMap;
11use std::panic::AssertUnwindSafe;
12use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
13
14pub struct ServiceProvider {
15 store: Arc<ServiceStore>,
17 type_map: Arc<HashMap<&'static str, TypeId>>,
20 singleton_cache: Arc<LazyCache>,
24 root_scoped_cache: LazyCache,
32 pub(crate) named: Arc<RwLock<HashMap<String, Arc<dyn Any + Send + Sync>>>>,
37 self_weak: OnceLock<Weak<ServiceProvider>>,
42 disposables: Mutex<Vec<Box<dyn FnOnce() + Send>>>,
46}
47
48impl ServiceProvider {
49 pub(crate) fn new(store: ServiceStore) -> Result<Arc<Self>, RdiError> {
50 let mut type_map = HashMap::new();
52 for (&tid, entries) in &store {
53 if let Some(e) = entries.first() {
54 type_map.entry(e.type_name).or_insert(tid);
55 }
56 }
57
58 let singleton_cache = Arc::new(LazyCache::new());
60 Self::validate_dependencies(&store, &singleton_cache)?;
61
62 let sp_arc = Arc::new(Self {
64 store: Arc::new(store),
65 type_map: Arc::new(type_map),
66 singleton_cache,
67 root_scoped_cache: LazyCache::new(),
68 named: Arc::new(RwLock::new(HashMap::new())),
69 self_weak: OnceLock::new(),
70 disposables: Mutex::new(Vec::new()),
71 });
72 sp_arc
73 .self_weak
74 .get_or_init(|| Arc::downgrade(&sp_arc));
75
76 Self::init_sync_singletons(&sp_arc);
77 Ok(sp_arc)
78 }
79
80 fn init_sync_singletons(sp_arc: &Arc<Self>) {
85 let singleton_entries: Vec<(usize, ServiceFactory)> = sp_arc
86 .store
87 .values()
88 .flat_map(|entries| entries.iter())
89 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
90 .map(|e| (e.cache_key, e.factory.clone()))
91 .collect();
92
93 for (ck, factory) in &singleton_entries {
94 let resolver = sp_arc.as_ref() as &dyn IServiceResolver;
95 let factory = factory.clone();
96 sp_arc
97 .singleton_cache
98 .get_or_init_with(*ck, move || factory(resolver));
99 }
100 }
101
102 pub(crate) async fn new_async(
111 store: ServiceStore,
112 ) -> Result<Arc<Self>, RdiError> {
113 let mut type_map = HashMap::new();
115 for (&tid, entries) in &store {
116 if let Some(e) = entries.first() {
117 type_map.entry(e.type_name).or_insert(tid);
118 }
119 }
120
121 let singleton_cache = Arc::new(LazyCache::new());
123 Self::validate_dependencies(&store, &singleton_cache)?;
124
125 let sp_arc = Arc::new(Self {
127 store: Arc::new(store),
128 type_map: Arc::new(type_map),
129 singleton_cache,
130 root_scoped_cache: LazyCache::new(),
131 named: Arc::new(RwLock::new(HashMap::new())),
132 self_weak: OnceLock::new(),
133 disposables: Mutex::new(Vec::new()),
134 });
135 sp_arc
136 .self_weak
137 .get_or_init(|| Arc::downgrade(&sp_arc));
138
139 Self::init_sync_singletons(&sp_arc);
140
141 let async_singletons: Vec<(usize, AsyncServiceFactory)> = sp_arc
143 .store
144 .values()
145 .flat_map(|entries| entries.iter())
146 .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_some())
147 .map(|e| (e.cache_key, e.async_factory.clone().unwrap()))
148 .collect();
149
150 for (ck, async_factory) in async_singletons {
151 let result = async_factory(Arc::clone(&sp_arc)).await;
152 sp_arc.singleton_cache.get_or_init_with(ck, || result);
153 }
154
155 Ok(sp_arc)
156 }
157
158 pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
168 let sp = Self {
169 store: Arc::clone(&parent.store),
170 type_map: Arc::clone(&parent.type_map),
171 singleton_cache: Arc::clone(&parent.singleton_cache),
172 root_scoped_cache: LazyCache::new(),
173 named: Arc::clone(&parent.named),
174 self_weak: OnceLock::new(),
175 disposables: Mutex::new(Vec::new()),
176 };
177 let arc = Arc::new(sp);
178 let this: &Self = &arc;
179 this.self_weak.get_or_init(|| Arc::downgrade(&arc));
180 arc
181 }
182
183 pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
190 self.disposables.lock().unwrap().push(cleanup);
191 }
192
193 pub(crate) fn dispose_scoped(&self) {
200 let to_run: Vec<Box<dyn FnOnce() + Send>> = match self.disposables.try_lock() {
203 Ok(mut guard) => std::mem::take(&mut *guard),
204 Err(_) => return,
205 };
206 for cleanup in to_run {
208 cleanup();
209 }
210 }
211
212 fn validate_dependencies(store: &ServiceStore, cache: &LazyCache) -> Result<(), RdiError> {
216 let type_names: HashMap<TypeId, &'static str> = store
218 .iter()
219 .map(|(&tid, entries)| {
220 let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
221 (tid, name)
222 })
223 .collect();
224
225 for entries in store.values() {
230 for entry in entries {
231 if entry.lifetime == ServiceLifetime::Singleton
232 && entry.async_factory.is_none()
233 {
234 let resolver = ValidationResolver::new(store, &type_names, cache);
235 let type_name = entry.type_name;
236
237 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
243 resolver.get_any(type_name)
244 }));
245
246 if let Some(err) = resolver.take_error() {
248 return Err(err);
249 }
250
251 match result {
252 Ok(_) => {}
253 Err(panic_info) => {
254 let payload = if let Some(s) = panic_info.downcast_ref::<String>() {
257 s.clone()
258 } else if let Some(s) = panic_info.downcast_ref::<&str>() {
259 s.to_string()
260 } else {
261 "unknown".to_string()
262 };
263 return Err(RdiError::FactoryPanic {
264 service: type_name.to_string(),
265 payload,
266 });
267 }
268 }
269 }
270 }
271 }
272
273 Ok(())
274 }
275
276 pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
279 let type_name = std::any::type_name::<T>();
280 self.try_get::<T>()
281 .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })
282 }
283
284 pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
286 self.try_get::<T>()
287 }
288
289 pub async fn get_async<T: ?Sized + Send + Sync + 'static>(
295 &self,
296 ) -> Result<Arc<T>, RdiError> {
297 let type_name = std::any::type_name::<T>();
298 let tid = TypeId::of::<T>();
299 let entry = self
300 .store
301 .get(&tid)
302 .and_then(|entries| entries.iter().find(|e| e.key.is_none()))
303 .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })?;
304
305 if entry.lifetime == ServiceLifetime::Singleton {
306 return self.get::<T>();
307 }
308
309 match self.resolve_async_any(entry, type_name).await? {
310 Some(arc_any) => {
311 Self::extract(arc_any)
312 .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })
313 }
314 None => self.get::<T>(),
315 }
316 }
317
318 pub async fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
320 &self,
321 key: &str,
322 ) -> Result<Arc<T>, RdiError> {
323 let type_name = std::any::type_name::<T>();
324 let tid = TypeId::of::<T>();
325 let entry = self
326 .store
327 .get(&tid)
328 .and_then(|entries| entries.iter().find(|e| e.key.as_deref() == Some(key)))
329 .ok_or(RdiError::KeyedServiceNotFound {
330 key: key.to_string(),
331 ty: type_name,
332 })?;
333
334 if entry.lifetime == ServiceLifetime::Singleton {
335 return self.get_keyed::<T>(key);
336 }
337
338 match self.resolve_async_any(entry, type_name).await? {
339 Some(arc_any) => Self::extract(arc_any).ok_or(RdiError::KeyedServiceNotFound {
340 key: key.to_string(),
341 ty: type_name,
342 }),
343 None => self.get_keyed::<T>(key),
344 }
345 }
346
347 async fn resolve_async_any(
350 &self,
351 entry: &ServiceEntry,
352 type_name: &'static str,
353 ) -> Result<Option<AnyService>, RdiError> {
354 match entry.lifetime {
355 ServiceLifetime::Scoped => {
356 let async_factory = entry.async_factory.clone()
357 .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })?;
358 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
359 service: type_name.to_string(),
360 payload: "provider_arc() returned None for async resolution".into(),
361 })?;
362 self.root_scoped_cache
363 .get_or_init_with_async(entry.cache_key, || {
364 Self::run_async_factory_safely(type_name, async_factory, provider_arc)
365 })
366 .await
367 .map(Some)
368 }
369 ServiceLifetime::Transient => {
370 if let Some(async_factory) = entry.async_factory.clone() {
371 let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
372 service: type_name.to_string(),
373 payload: "provider_arc() returned None for async resolution".into(),
374 })?;
375 Self::run_async_factory_safely(type_name, async_factory, provider_arc)
376 .await
377 .map(Some)
378 } else {
379 Ok(None)
380 }
381 }
382 _ => Ok(None),
383 }
384 }
385
386 async fn run_async_factory_safely(
391 type_name: &'static str,
392 async_factory: AsyncServiceFactory,
393 provider_arc: Arc<ServiceProvider>,
394 ) -> Result<AnyService, RdiError> {
395 let fut = async_factory(provider_arc);
396 match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
397 Ok(arc_any) => Ok(arc_any),
398 Err(payload) => {
399 let msg = payload
400 .downcast_ref::<&'static str>()
401 .map(|s| (*s).to_string())
402 .or_else(|| payload.downcast_ref::<String>().cloned())
403 .unwrap_or_else(|| "<non-string panic payload>".to_string());
404 Err(RdiError::FactoryPanic {
405 service: type_name.to_string(),
406 payload: msg,
407 })
408 }
409 }
410 }
411
412 pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> Result<Arc<T>, RdiError> {
415 let type_name = std::any::type_name::<T>();
416 self.try_get_keyed::<T>(key).ok_or(RdiError::KeyedServiceNotFound {
417 key: key.to_string(),
418 ty: type_name,
419 })
420 }
421
422 pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
425 let type_name = std::any::type_name::<T>();
426 self.try_get_owned::<T>()
427 .ok_or(RdiError::ServiceNotFound { ty: type_name, context: None })
428 }
429
430 pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
432 let tid = TypeId::of::<T>();
433 let entry = self.store.get(&tid)?.iter().find(|e| e.key.is_none())?;
434 let arc_any = self.create_owned_any_by_entry(entry)?;
435 let arc_t = Self::extract(arc_any)?;
436 Arc::try_unwrap(arc_t).ok()
437 }
438
439 pub fn get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Result<T, RdiError> {
442 let type_name = std::any::type_name::<T>();
443 self.try_get_keyed_owned::<T>(key).ok_or(RdiError::KeyedServiceNotFound {
444 key: key.to_string(),
445 ty: type_name,
446 })
447 }
448
449 pub fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Option<T> {
451 let tid = TypeId::of::<T>();
452 let entry = self
453 .store
454 .get(&tid)?
455 .iter()
456 .find(|e| e.key.as_deref() == Some(key))?;
457 let arc_any = self.create_owned_any_by_entry(entry)?;
458 let arc_t = Self::extract(arc_any)?;
459 Arc::try_unwrap(arc_t).ok()
460 }
461
462 pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
464 let tid = TypeId::of::<T>();
465 match self.store.get(&tid) {
466 Some(entries) => entries
467 .iter()
468 .filter_map(|e| {
469 let arc = self.get_any_by_entry(e)?;
470 Self::extract(arc)
471 })
472 .collect(),
473 None => Vec::new(),
474 }
475 }
476
477 pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
482 crate::scope::Scope::new(self.clone())
483 }
484
485 fn try_get<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
486 let tid = TypeId::of::<T>();
487 let entry = self.store.get(&tid)?.iter().find(|e| e.key.is_none())?;
488 let arc = self.get_any_by_entry(entry)?;
489 Self::extract(arc)
490 }
491
492 fn try_get_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> Option<Arc<T>> {
493 let tid = TypeId::of::<T>();
494 let entry = self
495 .store
496 .get(&tid)?
497 .iter()
498 .find(|e| e.key.as_deref() == Some(key))?;
499 let arc = self.get_any_by_entry(entry)?;
500 Self::extract(arc)
501 }
502
503 pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
504 match entry.lifetime {
505 ServiceLifetime::Singleton => {
506 let factory = entry.factory.clone();
511 let resolver = self as &dyn IServiceResolver;
512 Some(self.singleton_cache.get_or_init_with(entry.cache_key, move || {
513 factory(resolver)
514 }))
515 }
516 ServiceLifetime::Scoped => {
517 let factory = entry.factory.clone();
520 let resolver = self as &dyn IServiceResolver;
521 Some(self.root_scoped_cache.get_or_init_with(entry.cache_key, move || {
522 factory(resolver)
523 }))
524 }
525 ServiceLifetime::Transient => {
526 Some((entry.factory)(self))
527 }
528 }
529 }
530
531 pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
540 match entry.lifetime {
541 ServiceLifetime::Singleton => None,
542 ServiceLifetime::Scoped | ServiceLifetime::Transient => {
543 Some((entry.factory)(self as &dyn IServiceResolver))
544 }
545 }
546 }
547
548 pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
551 arc: Arc<dyn Any + Send + Sync>,
552 ) -> Option<Arc<T>> {
553 let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
554 Some(Arc::clone(&*double))
555 }
556
557 pub(crate) fn entry_by_str(&self, type_name: &str, variant: &str) -> Option<&ServiceEntry> {
559 let tid = self.type_map.get(type_name)?;
560 self.store
561 .get(tid)?
562 .iter()
563 .find(|e| e.key.as_deref() == Some(variant))
564 }
565
566 pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
568 self.named
569 .read()
570 .unwrap()
571 .get(name)?
572 .clone()
573 .downcast::<T>()
574 .ok()
575 }
576
577 pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
579 self.named.read().unwrap().get(name).cloned()
580 }
581
582 pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
584 self.named
585 .write()
586 .unwrap()
587 .insert(name.to_string(), service);
588 }
589
590 pub fn remove_named(&self, name: &str) {
592 self.named.write().unwrap().remove(name);
593 }
594
595 pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
597 self.named
598 .write()
599 .unwrap()
600 .insert(name.to_string(), service);
601 }
602
603 pub fn rdi_remove_named(&self, name: &str) {
605 self.named.write().unwrap().remove(name);
606 }
607}
608
609impl ScopeFactory for ServiceProvider {
610 fn create_scope(&self) -> crate::scope::Scope {
611 self.self_weak
613 .get()
614 .and_then(|w| w.upgrade())
615 .map(crate::scope::Scope::new)
616 .expect("ScopeFactory::create_scope called before self_weak initialization")
617 }
618}
619
620impl IServiceResolver for ServiceProvider {
621 fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
622 let tid = self.type_map.get(key)?;
623 let entry = self.store.get(tid)?.iter().find(|e| e.key.is_none())?;
624 self.get_any_by_entry(entry)
625 }
626 fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
627 let entry = self.entry_by_str(key, variant)?;
628 self.get_any_by_entry(entry)
629 }
630 fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
631 let entry = self.store.get(&tid)?.iter().find(|e| e.key.is_none())?;
632 self.get_any_by_entry(entry)
633 }
634 fn get_keyed_by_type_id(
635 &self,
636 tid: TypeId,
637 key: &str,
638 ) -> Option<Arc<dyn Any + Send + Sync>> {
639 let entry = self
640 .store
641 .get(&tid)?
642 .iter()
643 .find(|e| e.key.as_deref() == Some(key))?;
644 self.get_any_by_entry(entry)
645 }
646 fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
647 let tid = match self.type_map.get(key) {
650 Some(t) => t,
651 None => return Vec::new(),
652 };
653 match self.store.get(tid) {
654 Some(entries) => entries
655 .iter()
656 .filter_map(|e| self.get_any_by_entry(e))
657 .collect(),
658 None => Vec::new(),
659 }
660 }
661 fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
662 let tid = self.type_map.get(key)?;
663 let entry = self.store.get(tid)?.iter().find(|e| e.key.is_none())?;
664 self.create_owned_any_by_entry(entry)
665 }
666 fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
667 let entry = self.entry_by_str(key, variant)?;
668 self.create_owned_any_by_entry(entry)
669 }
670 fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
671 self.self_weak.get().and_then(|w| w.upgrade())
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use crate::collection::ServiceCollection;
678 use std::sync::Arc;
679
680 #[derive(Debug, PartialEq)]
681 struct Calc(i32);
682 #[test]
683 fn optional_missing() {
684 let p = ServiceCollection::new().build().unwrap();
685 assert!(p.get_optional::<i32>().is_none());
686 }
687 #[test]
688 fn all_basic() {
689 let p = ServiceCollection::new()
690 .keyed_singleton("a", |_| Arc::new(Calc(1)))
691 .keyed_singleton("b", |_| Arc::new(Calc(2)))
692 .build()
693 .unwrap();
694 assert_eq!(p.get_all::<Calc>().len(), 2);
695 }
696}