Skip to main content

a3s_boot/provider/
module_ref.rs

1use super::cache::{new_provider_cache, ProviderCache, ProviderCacheKey};
2use super::entry::ProviderEntry;
3use super::provider_ref::ProviderRef;
4use super::resolution::{
5    enter_resolution_stack, new_resolution_stack, resolution_stack_is_empty,
6    ProviderResolutionStack,
7};
8use super::{
9    AnyProvider, ContextId, ContextIdFactory, FromModuleRef, ProviderDefinition, ProviderScope,
10    ProviderToken,
11};
12use crate::{BootError, BoxFuture, Result};
13use std::collections::{BTreeMap, BTreeSet};
14use std::fmt;
15use std::sync::{Arc, RwLock};
16
17/// Runtime provider container. This is Boot's Rust equivalent of Nest's ModuleRef.
18#[derive(Clone, Default)]
19pub struct ModuleRef {
20    providers: Arc<RwLock<BTreeMap<ProviderToken, ProviderEntry>>>,
21    provider_order: Arc<RwLock<Vec<ProviderToken>>>,
22    visible_scopes: Arc<RwLock<Vec<ModuleRef>>>,
23    context_id: Option<ContextId>,
24    transient_cache: ProviderCache,
25    inquirer: Option<ProviderCacheKey>,
26    resolution_stack: Option<ProviderResolutionStack>,
27}
28
29#[derive(Default)]
30struct AsyncProviderSeedState {
31    complete: BTreeSet<ProviderCacheKey>,
32    visiting: Vec<(ProviderCacheKey, ProviderToken)>,
33}
34
35impl AsyncProviderSeedState {
36    fn enter(&mut self, entry: &ProviderEntry) -> Result<bool> {
37        let cache_key = entry.cache_key();
38        if self.complete.contains(&cache_key) {
39            return Ok(false);
40        }
41        if let Some(index) = self
42            .visiting
43            .iter()
44            .position(|(active, _)| *active == cache_key)
45        {
46            let mut chain = self.visiting[index..]
47                .iter()
48                .map(|(_, token)| token.to_string())
49                .collect::<Vec<_>>();
50            chain.push(entry.token().to_string());
51            return Err(BootError::Internal(format!(
52                "cyclic async provider dependency detected: {}",
53                chain.join(" -> ")
54            )));
55        }
56
57        self.visiting.push((cache_key, entry.token().clone()));
58        Ok(true)
59    }
60
61    fn exit(&mut self, cache_key: ProviderCacheKey, complete: bool) -> Result<()> {
62        let Some((active, _)) = self.visiting.pop() else {
63            return Err(BootError::Internal(
64                "async provider dependency stack underflow".to_string(),
65            ));
66        };
67        if active != cache_key {
68            return Err(BootError::Internal(
69                "async provider dependency stack is inconsistent".to_string(),
70            ));
71        }
72        if complete {
73            self.complete.insert(cache_key);
74        }
75        Ok(())
76    }
77}
78
79impl fmt::Debug for ModuleRef {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        let len = self
82            .providers
83            .read()
84            .map(|providers| providers.len())
85            .unwrap_or(0);
86        let visible = self
87            .visible_scopes
88            .read()
89            .map(|scopes| scopes.len())
90            .unwrap_or(0);
91        f.debug_struct("ModuleRef")
92            .field("providers", &len)
93            .field("visible_scopes", &visible)
94            .finish()
95    }
96}
97
98impl ModuleRef {
99    pub fn new() -> Self {
100        Self::default()
101    }
102
103    pub fn request_scope(&self) -> Self {
104        self.context_scope(&ContextIdFactory::create())
105    }
106
107    /// Bind this module view to an existing dependency-injection context.
108    pub fn context_scope(&self, context_id: &ContextId) -> Self {
109        Self {
110            providers: Arc::clone(&self.providers),
111            provider_order: Arc::clone(&self.provider_order),
112            visible_scopes: Arc::clone(&self.visible_scopes),
113            context_id: Some(context_id.clone()),
114            transient_cache: self.transient_cache.clone(),
115            inquirer: self.inquirer,
116            resolution_stack: self.resolution_stack.clone(),
117        }
118    }
119
120    pub(crate) fn weak_context_scope(&self, context_id: &ContextId) -> Self {
121        Self {
122            providers: Arc::clone(&self.providers),
123            provider_order: Arc::clone(&self.provider_order),
124            visible_scopes: Arc::clone(&self.visible_scopes),
125            context_id: Some(context_id.downgrade()),
126            transient_cache: self.transient_cache.clone(),
127            inquirer: self.inquirer,
128            resolution_stack: self.resolution_stack.clone(),
129        }
130    }
131
132    /// Return the dependency-injection context attached to this module view.
133    pub fn context_id(&self) -> Option<&ContextId> {
134        self.context_id.as_ref()
135    }
136
137    pub(crate) fn with_resolution_stack(&self, resolution_stack: ProviderResolutionStack) -> Self {
138        Self {
139            providers: Arc::clone(&self.providers),
140            provider_order: Arc::clone(&self.provider_order),
141            visible_scopes: Arc::clone(&self.visible_scopes),
142            context_id: self.context_id.clone(),
143            transient_cache: self.transient_cache.clone(),
144            inquirer: self.inquirer,
145            resolution_stack: Some(resolution_stack),
146        }
147    }
148
149    pub(crate) fn without_resolution_stack(&self) -> Self {
150        Self {
151            providers: Arc::clone(&self.providers),
152            provider_order: Arc::clone(&self.provider_order),
153            visible_scopes: Arc::clone(&self.visible_scopes),
154            context_id: self.context_id.clone(),
155            transient_cache: self.transient_cache.clone(),
156            inquirer: self.inquirer,
157            resolution_stack: None,
158        }
159    }
160
161    pub(crate) fn with_inquirer(&self, inquirer: ProviderCacheKey) -> Self {
162        Self {
163            providers: Arc::clone(&self.providers),
164            provider_order: Arc::clone(&self.provider_order),
165            visible_scopes: Arc::clone(&self.visible_scopes),
166            context_id: self.context_id.clone(),
167            transient_cache: self.transient_cache.clone(),
168            inquirer: Some(inquirer),
169            resolution_stack: self.resolution_stack.clone(),
170        }
171    }
172
173    pub(crate) fn without_context(&self) -> Self {
174        Self {
175            providers: Arc::clone(&self.providers),
176            provider_order: Arc::clone(&self.provider_order),
177            visible_scopes: Arc::clone(&self.visible_scopes),
178            context_id: None,
179            transient_cache: self.transient_cache.clone(),
180            inquirer: self.inquirer,
181            resolution_stack: self.resolution_stack.clone(),
182        }
183    }
184
185    pub(crate) fn with_transient_cache(&self, transient_cache: ProviderCache) -> Self {
186        Self {
187            providers: Arc::clone(&self.providers),
188            provider_order: Arc::clone(&self.provider_order),
189            visible_scopes: Arc::clone(&self.visible_scopes),
190            context_id: self.context_id.clone(),
191            transient_cache,
192            inquirer: self.inquirer,
193            resolution_stack: self.resolution_stack.clone(),
194        }
195    }
196
197    pub(crate) fn transient_cache(&self) -> ProviderCache {
198        self.transient_cache.clone()
199    }
200
201    pub fn register(&self, definition: ProviderDefinition) -> Result<()> {
202        let token = definition.token().clone();
203        self.validate_registration(&token, &definition)?;
204        if definition.is_async_factory() {
205            return Err(BootError::Internal(format!(
206                "async provider factory requires async registration: {token}"
207            )));
208        }
209
210        let entry = ProviderEntry::new(definition);
211        self.insert_entry(token, entry)
212    }
213
214    pub async fn register_async(&self, definition: ProviderDefinition) -> Result<()> {
215        let token = definition.token().clone();
216        self.validate_registration(&token, &definition)?;
217
218        let entry = ProviderEntry::new(definition);
219        self.insert_entry(token, entry)
220    }
221
222    pub fn insert<T>(&self, value: T) -> Result<()>
223    where
224        T: Send + Sync + 'static,
225    {
226        self.insert_arc(Arc::new(value))
227    }
228
229    pub fn insert_arc<T>(&self, value: Arc<T>) -> Result<()>
230    where
231        T: Send + Sync + 'static,
232    {
233        let token = ProviderToken::of::<T>();
234        let entry = ProviderEntry::new(ProviderDefinition::from_arc(value));
235        self.insert_entry(token, entry)
236    }
237
238    pub fn get<T>(&self) -> Result<Arc<T>>
239    where
240        T: Send + Sync + 'static,
241    {
242        self.get_token::<T>(&ProviderToken::of::<T>())
243    }
244
245    pub fn get_named<T>(&self, token: &str) -> Result<Arc<T>>
246    where
247        T: Send + Sync + 'static,
248    {
249        self.get_token::<T>(&ProviderToken::named(token))
250    }
251
252    pub fn get_optional<T>(&self) -> Result<Option<Arc<T>>>
253    where
254        T: Send + Sync + 'static,
255    {
256        self.get_optional_token::<T>(&ProviderToken::of::<T>())
257    }
258
259    pub fn get_optional_named<T>(&self, token: &str) -> Result<Option<Arc<T>>>
260    where
261        T: Send + Sync + 'static,
262    {
263        self.get_optional_token::<T>(&ProviderToken::named(token))
264    }
265
266    /// Create a lazy provider handle for a typed dependency.
267    pub fn provider_ref<T>(&self) -> ProviderRef<T>
268    where
269        T: Send + Sync + 'static,
270    {
271        ProviderRef::new(self.clone(), ProviderToken::of::<T>())
272    }
273
274    /// Create a lazy provider handle for a named dependency.
275    pub fn named_provider_ref<T>(&self, token: &str) -> ProviderRef<T>
276    where
277        T: Send + Sync + 'static,
278    {
279        ProviderRef::new(self.clone(), ProviderToken::named(token))
280    }
281
282    /// Create a lazy provider handle only when the typed dependency is visible.
283    pub fn optional_provider_ref<T>(&self) -> Result<Option<ProviderRef<T>>>
284    where
285        T: Send + Sync + 'static,
286    {
287        if self.contains_provider::<T>()? {
288            Ok(Some(self.provider_ref::<T>()))
289        } else {
290            Ok(None)
291        }
292    }
293
294    /// Create a lazy provider handle only when the named dependency is visible.
295    pub fn optional_named_provider_ref<T>(&self, token: &str) -> Result<Option<ProviderRef<T>>>
296    where
297        T: Send + Sync + 'static,
298    {
299        if self.contains_named(token)? {
300            Ok(Some(self.named_provider_ref::<T>(token)))
301        } else {
302            Ok(None)
303        }
304    }
305
306    /// Resolve a typed provider in a fresh resolution context.
307    ///
308    /// This mirrors Nest's `ModuleRef.resolve(...)`: singleton providers reuse
309    /// their application instance, while request-scoped dependencies share one
310    /// temporary context for this resolution and transient providers are rebuilt.
311    pub fn resolve<T>(&self) -> Result<Arc<T>>
312    where
313        T: Send + Sync + 'static,
314    {
315        self.resolve_token::<T>(&ProviderToken::of::<T>())
316    }
317
318    /// Resolve a typed provider in a caller-supplied resolution context.
319    pub fn resolve_with_context<T>(&self, context_id: &ContextId) -> Result<Arc<T>>
320    where
321        T: Send + Sync + 'static,
322    {
323        self.resolve_token_with_context::<T>(&ProviderToken::of::<T>(), context_id)
324    }
325
326    /// Resolve a named provider in a fresh resolution context.
327    pub fn resolve_named<T>(&self, token: &str) -> Result<Arc<T>>
328    where
329        T: Send + Sync + 'static,
330    {
331        self.resolve_token::<T>(&ProviderToken::named(token))
332    }
333
334    /// Resolve a named provider in a caller-supplied resolution context.
335    pub fn resolve_named_with_context<T>(
336        &self,
337        token: &str,
338        context_id: &ContextId,
339    ) -> Result<Arc<T>>
340    where
341        T: Send + Sync + 'static,
342    {
343        self.resolve_token_with_context::<T>(&ProviderToken::named(token), context_id)
344    }
345
346    /// Resolve a typed provider in a fresh resolution context when it exists.
347    pub fn resolve_optional<T>(&self) -> Result<Option<Arc<T>>>
348    where
349        T: Send + Sync + 'static,
350    {
351        self.resolve_optional_token::<T>(&ProviderToken::of::<T>())
352    }
353
354    /// Resolve an optional typed provider in a caller-supplied context.
355    pub fn resolve_optional_with_context<T>(&self, context_id: &ContextId) -> Result<Option<Arc<T>>>
356    where
357        T: Send + Sync + 'static,
358    {
359        self.resolve_optional_token_with_context::<T>(&ProviderToken::of::<T>(), context_id)
360    }
361
362    /// Resolve a named provider in a fresh resolution context when it exists.
363    pub fn resolve_optional_named<T>(&self, token: &str) -> Result<Option<Arc<T>>>
364    where
365        T: Send + Sync + 'static,
366    {
367        self.resolve_optional_token::<T>(&ProviderToken::named(token))
368    }
369
370    /// Resolve an optional named provider in a caller-supplied context.
371    pub fn resolve_optional_named_with_context<T>(
372        &self,
373        token: &str,
374        context_id: &ContextId,
375    ) -> Result<Option<Arc<T>>>
376    where
377        T: Send + Sync + 'static,
378    {
379        self.resolve_optional_token_with_context::<T>(&ProviderToken::named(token), context_id)
380    }
381
382    /// Create an injectable value without registering it in the provider graph.
383    pub fn create<T>(&self) -> Result<T>
384    where
385        T: FromModuleRef,
386    {
387        let inquirer = ProviderCacheKey::next();
388        let token = ProviderToken::of::<T>();
389        let (resolution_stack, _guard) =
390            enter_resolution_stack(&new_resolution_stack(), inquirer, &token)?;
391        let factory_ref = self
392            .with_transient_cache(new_provider_cache())
393            .with_inquirer(inquirer)
394            .with_resolution_stack(resolution_stack);
395        T::from_module_ref(&factory_ref)
396    }
397
398    /// Create an injectable `Arc<T>` without registering it in the provider graph.
399    pub fn create_arc<T>(&self) -> Result<Arc<T>>
400    where
401        T: FromModuleRef,
402    {
403        Ok(Arc::new(self.create::<T>()?))
404    }
405
406    pub fn contains(&self, token: &ProviderToken) -> Result<bool> {
407        Ok(self.get_entry(token)?.is_some())
408    }
409
410    pub fn contains_provider<T>(&self) -> Result<bool>
411    where
412        T: Send + Sync + 'static,
413    {
414        self.contains(&ProviderToken::of::<T>())
415    }
416
417    pub fn contains_named(&self, token: &str) -> Result<bool> {
418        self.contains(&ProviderToken::named(token))
419    }
420
421    /// Return whether a typed provider requires a request-resolution context.
422    ///
423    /// This includes explicitly request-scoped providers and singleton or
424    /// transient providers whose declared dependency tree reaches one.
425    pub fn provider_is_contextual<T>(&self) -> Result<bool>
426    where
427        T: Send + Sync + 'static,
428    {
429        self.token_is_contextual(&ProviderToken::of::<T>())
430    }
431
432    /// Return the provider's declared cache scope after following aliases.
433    pub fn provider_scope<T>(&self) -> Result<ProviderScope>
434    where
435        T: Send + Sync + 'static,
436    {
437        self.token_scope(&ProviderToken::of::<T>())
438    }
439
440    /// Return whether a named provider requires a request-resolution context.
441    pub fn named_provider_is_contextual(&self, token: &str) -> Result<bool> {
442        self.token_is_contextual(&ProviderToken::named(token))
443    }
444
445    /// Return a named provider's declared cache scope after following aliases.
446    pub fn named_provider_scope(&self, token: &str) -> Result<ProviderScope> {
447        self.token_scope(&ProviderToken::named(token))
448    }
449
450    pub(crate) fn token_is_contextual(&self, token: &ProviderToken) -> Result<bool> {
451        let entry = self
452            .get_entry(token)?
453            .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
454        Ok(entry.resolution_plan(self)?.is_contextual())
455    }
456
457    pub(crate) fn token_scope(&self, token: &ProviderToken) -> Result<ProviderScope> {
458        let entry = self
459            .get_entry(token)?
460            .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
461        Ok(entry.resolution_plan(self)?.scope())
462    }
463
464    pub fn tokens(&self) -> Result<Vec<ProviderToken>> {
465        let mut tokens = BTreeMap::new();
466        self.collect_tokens(&mut tokens)?;
467        Ok(tokens.into_keys().collect())
468    }
469
470    fn insert_entry(&self, token: ProviderToken, entry: ProviderEntry) -> Result<()> {
471        let mut provider_order = self.write_provider_order()?;
472        let mut providers = self.write_providers()?;
473        if providers.contains_key(&token) {
474            return Err(BootError::DuplicateProvider(token.to_string()));
475        }
476        providers.insert(token.clone(), entry);
477        provider_order.push(token);
478        Ok(())
479    }
480
481    fn validate_registration(
482        &self,
483        token: &ProviderToken,
484        definition: &ProviderDefinition,
485    ) -> Result<()> {
486        if self.contains_local(token)? {
487            return Err(BootError::DuplicateProvider(token.to_string()));
488        }
489        if definition.is_async_factory() && definition.scope() != ProviderScope::Singleton {
490            return Err(BootError::Internal(format!(
491                "async provider factories require singleton scope: {token}"
492            )));
493        }
494        if definition.lifecycle().has_hooks() && definition.scope() != ProviderScope::Singleton {
495            return Err(BootError::Internal(format!(
496                "provider lifecycle hooks require singleton scope: {token}"
497            )));
498        }
499        if definition.lifecycle().has_hooks() && definition.is_alias() {
500            return Err(BootError::Internal(format!(
501                "provider aliases cannot define lifecycle hooks: {token}"
502            )));
503        }
504        Ok(())
505    }
506
507    pub(crate) fn add_visible_scope(&self, module_ref: ModuleRef) -> Result<()> {
508        self.write_visible_scopes()?.push(module_ref);
509        Ok(())
510    }
511
512    pub(crate) fn export_from(&self, module_ref: &ModuleRef, token: &ProviderToken) -> Result<()> {
513        let entry = module_ref
514            .get_entry(token)?
515            .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
516        self.insert_entry(token.clone(), entry.with_owner(module_ref.clone()))
517    }
518
519    pub(crate) fn local_tokens(&self) -> Result<Vec<ProviderToken>> {
520        Ok(self.read_provider_order()?.clone())
521    }
522
523    pub(crate) fn initialize_local_singletons(&self) -> Result<()> {
524        for entry in self.local_entries()? {
525            let plan = entry.resolution_plan(self)?;
526            self.validate_resolution_plan(&entry, plan)?;
527            if plan.scope() == ProviderScope::Singleton
528                && !plan.is_contextual()
529                && !entry.is_alias()
530            {
531                let resolution_stack = new_resolution_stack();
532                entry.resolve_singleton(self, self.transient_cache(), &resolution_stack)?;
533            }
534        }
535        Ok(())
536    }
537
538    pub(crate) fn validate_local_resolution_plans(&self) -> Result<()> {
539        for entry in self.local_entries()? {
540            let plan = entry.resolution_plan(self)?;
541            self.validate_resolution_plan(&entry, plan)?;
542        }
543        Ok(())
544    }
545
546    pub(crate) async fn seed_local_async_singletons(&self) -> Result<()> {
547        let entries = self.local_entries()?;
548        for entry in &entries {
549            let plan = entry.resolution_plan(self)?;
550            self.validate_resolution_plan(entry, plan)?;
551        }
552
553        let mut state = AsyncProviderSeedState::default();
554        for entry in entries {
555            let plan = entry.resolution_plan(self)?;
556            if plan.scope() == ProviderScope::Singleton
557                && !plan.is_contextual()
558                && !entry.is_alias()
559                && entry.is_async_factory()
560            {
561                self.seed_async_dependency_tree(entry, &mut state).await?;
562            }
563        }
564        Ok(())
565    }
566
567    fn seed_async_dependency_tree<'a>(
568        &'a self,
569        entry: ProviderEntry,
570        state: &'a mut AsyncProviderSeedState,
571    ) -> BoxFuture<'a, Result<()>> {
572        Box::pin(async move {
573            let cache_key = entry.cache_key();
574            if !state.enter(&entry)? {
575                return Ok(());
576            }
577
578            let owner = entry.owner_module_ref(self);
579            let result = async {
580                let plan = entry.resolution_plan(&owner)?;
581                owner.validate_resolution_plan(&entry, plan)?;
582                for dependency in entry.eager_dependency_entries(&owner)? {
583                    owner.seed_async_dependency_tree(dependency, state).await?;
584                }
585                if entry.is_async_factory() {
586                    entry.seed_singleton_async(owner).await?;
587                }
588                Ok(())
589            }
590            .await;
591            let exit_result = state.exit(cache_key, result.is_ok());
592            match (result, exit_result) {
593                (Ok(()), Ok(())) => Ok(()),
594                (Err(error), _) => Err(error),
595                (Ok(()), Err(error)) => Err(error),
596            }
597        })
598    }
599
600    fn validate_resolution_plan(
601        &self,
602        entry: &ProviderEntry,
603        plan: super::entry::ProviderResolutionPlan,
604    ) -> Result<()> {
605        if plan.is_contextual() && entry.is_async_factory() {
606            return Err(BootError::Internal(format!(
607                "async provider `{}` cannot depend on a request-context provider",
608                entry.token()
609            )));
610        }
611        if plan.is_contextual() && entry.has_lifecycle_hooks() {
612            return Err(BootError::Internal(format!(
613                "provider `{}` cannot use singleton lifecycle hooks because request scope propagated through its dependencies",
614                entry.token()
615            )));
616        }
617        Ok(())
618    }
619
620    pub(crate) fn initialize_local_providers(&self) -> Result<()> {
621        for entry in self.local_entries()? {
622            entry.on_module_init(self)?;
623        }
624        Ok(())
625    }
626
627    pub(crate) async fn bootstrap_local_providers(&self) -> Result<()> {
628        for entry in self.local_entries()? {
629            entry.on_application_bootstrap(self.clone()).await?;
630        }
631        Ok(())
632    }
633
634    pub(crate) async fn destroy_local_providers(&self, signal: Option<String>) -> Result<()> {
635        let mut entries = self.local_entries()?;
636        entries.reverse();
637        for entry in entries {
638            entry
639                .on_module_destroy(self.clone(), signal.clone())
640                .await?;
641        }
642        Ok(())
643    }
644
645    pub(crate) async fn before_application_shutdown_local_providers(
646        &self,
647        signal: Option<String>,
648    ) -> Result<()> {
649        let mut entries = self.local_entries()?;
650        entries.reverse();
651        for entry in entries {
652            entry
653                .before_application_shutdown(self.clone(), signal.clone())
654                .await?;
655        }
656        Ok(())
657    }
658
659    pub(crate) async fn shutdown_local_providers(&self, signal: Option<String>) -> Result<()> {
660        let mut entries = self.local_entries()?;
661        entries.reverse();
662        for entry in entries {
663            entry
664                .on_application_shutdown(self.clone(), signal.clone())
665                .await?;
666        }
667        Ok(())
668    }
669
670    pub(crate) fn get_token<T>(&self, token: &ProviderToken) -> Result<Arc<T>>
671    where
672        T: Send + Sync + 'static,
673    {
674        let value = self
675            .get_any(token)?
676            .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
677
678        Arc::downcast::<T>(value).map_err(|_| BootError::ProviderTypeMismatch(token.to_string()))
679    }
680
681    pub(crate) fn get_optional_token<T>(&self, token: &ProviderToken) -> Result<Option<Arc<T>>>
682    where
683        T: Send + Sync + 'static,
684    {
685        let value = self.get_any(token)?;
686        match value {
687            Some(value) => Arc::downcast::<T>(value)
688                .map(Some)
689                .map_err(|_| BootError::ProviderTypeMismatch(token.to_string())),
690            None => Ok(None),
691        }
692    }
693
694    pub(crate) fn resolve_token<T>(&self, token: &ProviderToken) -> Result<Arc<T>>
695    where
696        T: Send + Sync + 'static,
697    {
698        self.resolve_token_with_context(token, &ContextIdFactory::create())
699    }
700
701    pub(crate) fn resolve_token_with_context<T>(
702        &self,
703        token: &ProviderToken,
704        context_id: &ContextId,
705    ) -> Result<Arc<T>>
706    where
707        T: Send + Sync + 'static,
708    {
709        self.context_scope(context_id).get_token(token)
710    }
711
712    pub(crate) fn resolve_optional_token<T>(&self, token: &ProviderToken) -> Result<Option<Arc<T>>>
713    where
714        T: Send + Sync + 'static,
715    {
716        self.resolve_optional_token_with_context(token, &ContextIdFactory::create())
717    }
718
719    pub(crate) fn resolve_optional_token_with_context<T>(
720        &self,
721        token: &ProviderToken,
722        context_id: &ContextId,
723    ) -> Result<Option<Arc<T>>>
724    where
725        T: Send + Sync + 'static,
726    {
727        self.context_scope(context_id).get_optional_token(token)
728    }
729
730    fn get_any(&self, token: &ProviderToken) -> Result<Option<Arc<AnyProvider>>> {
731        let mut alias_path = Vec::new();
732        let resolution_stack = match &self.resolution_stack {
733            Some(resolution_stack) if !resolution_stack_is_empty(resolution_stack) => {
734                Arc::clone(resolution_stack)
735            }
736            Some(_) | None => new_resolution_stack(),
737        };
738        self.get_any_with_context_inner(
739            token,
740            self.context_id.clone(),
741            self.transient_cache.clone(),
742            self.inquirer,
743            &resolution_stack,
744            &mut alias_path,
745        )
746    }
747
748    pub(crate) fn get_any_with_context_inner(
749        &self,
750        token: &ProviderToken,
751        context_id: Option<ContextId>,
752        transient_cache: ProviderCache,
753        inquirer: Option<ProviderCacheKey>,
754        resolution_stack: &ProviderResolutionStack,
755        alias_path: &mut Vec<ProviderToken>,
756    ) -> Result<Option<Arc<AnyProvider>>> {
757        if let Some(entry) = self.read_providers()?.get(token).cloned() {
758            return entry
759                .resolve(
760                    self,
761                    context_id,
762                    transient_cache,
763                    inquirer,
764                    resolution_stack,
765                    alias_path,
766                )
767                .map(Some);
768        }
769
770        for scope in self.visible_scopes()? {
771            if let Some(value) = scope.get_any_with_context_inner(
772                token,
773                context_id.clone(),
774                transient_cache.clone(),
775                inquirer,
776                resolution_stack,
777                alias_path,
778            )? {
779                return Ok(Some(value));
780            }
781        }
782
783        Ok(None)
784    }
785
786    pub(crate) fn get_entry(&self, token: &ProviderToken) -> Result<Option<ProviderEntry>> {
787        if let Some(entry) = self.read_providers()?.get(token).cloned() {
788            return Ok(Some(entry.with_owner(self.clone())));
789        }
790
791        for scope in self.visible_scopes()? {
792            if let Some(entry) = scope.get_entry(token)? {
793                return Ok(Some(entry));
794            }
795        }
796
797        Ok(None)
798    }
799
800    fn contains_local(&self, token: &ProviderToken) -> Result<bool> {
801        Ok(self.read_providers()?.contains_key(token))
802    }
803
804    fn collect_tokens(&self, tokens: &mut BTreeMap<ProviderToken, ()>) -> Result<()> {
805        for token in self.read_providers()?.keys() {
806            tokens.insert(token.clone(), ());
807        }
808        for scope in self.visible_scopes()? {
809            scope.collect_tokens(tokens)?;
810        }
811        Ok(())
812    }
813
814    fn local_entries(&self) -> Result<Vec<ProviderEntry>> {
815        let provider_order = self.read_provider_order()?.clone();
816        let providers = self.read_providers()?;
817        let mut entries = Vec::with_capacity(provider_order.len());
818        for token in provider_order {
819            if let Some(entry) = providers.get(&token) {
820                entries.push(entry.clone());
821            }
822        }
823        Ok(entries)
824    }
825
826    fn visible_scopes(&self) -> Result<Vec<ModuleRef>> {
827        Ok(self.read_visible_scopes()?.clone())
828    }
829
830    fn read_providers(
831        &self,
832    ) -> Result<std::sync::RwLockReadGuard<'_, BTreeMap<ProviderToken, ProviderEntry>>> {
833        self.providers
834            .read()
835            .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
836    }
837
838    fn write_providers(
839        &self,
840    ) -> Result<std::sync::RwLockWriteGuard<'_, BTreeMap<ProviderToken, ProviderEntry>>> {
841        self.providers
842            .write()
843            .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
844    }
845
846    fn read_provider_order(&self) -> Result<std::sync::RwLockReadGuard<'_, Vec<ProviderToken>>> {
847        self.provider_order
848            .read()
849            .map_err(|_| BootError::Internal("provider order lock is poisoned".to_string()))
850    }
851
852    fn write_provider_order(&self) -> Result<std::sync::RwLockWriteGuard<'_, Vec<ProviderToken>>> {
853        self.provider_order
854            .write()
855            .map_err(|_| BootError::Internal("provider order lock is poisoned".to_string()))
856    }
857
858    fn read_visible_scopes(&self) -> Result<std::sync::RwLockReadGuard<'_, Vec<ModuleRef>>> {
859        self.visible_scopes
860            .read()
861            .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
862    }
863
864    fn write_visible_scopes(&self) -> Result<std::sync::RwLockWriteGuard<'_, Vec<ModuleRef>>> {
865        self.visible_scopes
866            .write()
867            .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
868    }
869}