1use super::{AnyProvider, FromModuleRef, ProviderDefinition, ProviderScope, ProviderToken};
2use crate::{BootError, Result};
3use std::collections::BTreeMap;
4use std::fmt;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::{Arc, RwLock};
7
8#[derive(Clone, Default)]
10pub struct ModuleRef {
11 providers: Arc<RwLock<BTreeMap<ProviderToken, ProviderEntry>>>,
12 provider_order: Arc<RwLock<Vec<ProviderToken>>>,
13 visible_scopes: Arc<RwLock<Vec<ModuleRef>>>,
14 request_cache: Option<ProviderCache>,
15 resolution_stack: Option<ProviderResolutionStack>,
16}
17
18type ProviderCache = Arc<RwLock<BTreeMap<ProviderCacheKey, Arc<AnyProvider>>>>;
19type ProviderResolutionStack = Arc<RwLock<Vec<ProviderToken>>>;
20
21static NEXT_PROVIDER_CACHE_KEY: AtomicU64 = AtomicU64::new(1);
22
23fn new_resolution_stack() -> ProviderResolutionStack {
24 Arc::new(RwLock::new(Vec::new()))
25}
26
27fn enter_resolution_stack(
28 resolution_stack: &ProviderResolutionStack,
29 token: &ProviderToken,
30) -> Result<()> {
31 let mut stack = resolution_stack.write().map_err(|_| {
32 BootError::Internal("provider resolution stack lock is poisoned".to_string())
33 })?;
34 if let Some(index) = stack.iter().position(|active| active == token) {
35 let mut chain = stack[index..].to_vec();
36 chain.push(token.clone());
37 let chain = chain
38 .iter()
39 .map(ToString::to_string)
40 .collect::<Vec<_>>()
41 .join(" -> ");
42 return Err(BootError::Internal(format!(
43 "cyclic provider dependency detected: {chain}"
44 )));
45 }
46
47 stack.push(token.clone());
48 Ok(())
49}
50
51fn exit_resolution_stack(resolution_stack: &ProviderResolutionStack) -> Result<()> {
52 let mut stack = resolution_stack.write().map_err(|_| {
53 BootError::Internal("provider resolution stack lock is poisoned".to_string())
54 })?;
55 stack
56 .pop()
57 .ok_or_else(|| BootError::Internal("provider resolution stack underflow".to_string()))?;
58 Ok(())
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
62struct ProviderCacheKey(u64);
63
64impl ProviderCacheKey {
65 fn next() -> Self {
66 Self(NEXT_PROVIDER_CACHE_KEY.fetch_add(1, Ordering::Relaxed))
67 }
68}
69
70#[derive(Clone)]
71struct ProviderEntry {
72 cache_key: ProviderCacheKey,
73 definition: ProviderDefinition,
74 singleton: ProviderCache,
75 owner: Option<ModuleRef>,
76}
77
78impl ProviderEntry {
79 fn new(definition: ProviderDefinition) -> Self {
80 Self {
81 cache_key: ProviderCacheKey::next(),
82 definition,
83 singleton: Arc::new(RwLock::new(BTreeMap::new())),
84 owner: None,
85 }
86 }
87
88 fn with_owner(mut self, owner: ModuleRef) -> Self {
89 if self.owner.is_none() {
90 self.owner = Some(owner);
91 }
92 self
93 }
94
95 fn scope(&self) -> ProviderScope {
96 self.definition.scope()
97 }
98
99 fn is_local_singleton(&self) -> bool {
100 self.scope() == ProviderScope::Singleton && !self.definition.is_alias()
101 }
102
103 fn is_async_factory(&self) -> bool {
104 self.definition.is_async_factory()
105 }
106
107 fn resolve(
108 &self,
109 module_ref: &ModuleRef,
110 request_cache: Option<ProviderCache>,
111 resolution_stack: &ProviderResolutionStack,
112 alias_path: &mut Vec<ProviderToken>,
113 ) -> Result<Arc<AnyProvider>> {
114 let base_ref = self.owner.as_ref().unwrap_or(module_ref);
115 if let Some(target) = self.definition.alias_target() {
116 return self.resolve_alias(
117 base_ref,
118 target,
119 request_cache,
120 resolution_stack,
121 alias_path,
122 );
123 }
124
125 match self.scope() {
126 ProviderScope::Singleton => self.resolve_singleton(base_ref, resolution_stack),
127 ProviderScope::Transient => {
128 let factory_ref =
129 self.factory_ref(base_ref, request_cache.clone(), resolution_stack);
130 self.build_with_resolution_stack(&factory_ref, resolution_stack)
131 }
132 ProviderScope::Request => {
133 let factory_ref =
134 self.factory_ref(base_ref, request_cache.clone(), resolution_stack);
135 self.resolve_request(&factory_ref, request_cache, resolution_stack)
136 }
137 }
138 }
139
140 fn resolve_alias(
141 &self,
142 module_ref: &ModuleRef,
143 target: &ProviderToken,
144 request_cache: Option<ProviderCache>,
145 resolution_stack: &ProviderResolutionStack,
146 alias_path: &mut Vec<ProviderToken>,
147 ) -> Result<Arc<AnyProvider>> {
148 if alias_path.contains(self.definition.token()) {
149 alias_path.push(self.definition.token().clone());
150 let chain = alias_path
151 .iter()
152 .map(ToString::to_string)
153 .collect::<Vec<_>>()
154 .join(" -> ");
155 return Err(BootError::Internal(format!(
156 "cyclic provider alias detected: {chain}"
157 )));
158 }
159
160 alias_path.push(self.definition.token().clone());
161 let value = module_ref.get_any_with_request_cache_inner(
162 target,
163 request_cache,
164 resolution_stack,
165 alias_path,
166 )?;
167 alias_path.pop();
168
169 value.ok_or_else(|| BootError::MissingProvider(target.to_string()))
170 }
171
172 fn resolve_singleton(
173 &self,
174 module_ref: &ModuleRef,
175 resolution_stack: &ProviderResolutionStack,
176 ) -> Result<Arc<AnyProvider>> {
177 if let Some(value) = self
178 .read_cache(&self.singleton)?
179 .get(&self.cache_key)
180 .cloned()
181 {
182 return Ok(value);
183 }
184
185 let factory_ref = module_ref.with_resolution_stack(Arc::clone(resolution_stack));
186 let value = self.build_with_resolution_stack(&factory_ref, resolution_stack)?;
187 self.write_cache(&self.singleton)?
188 .insert(self.cache_key, Arc::clone(&value));
189 Ok(value)
190 }
191
192 fn resolve_request(
193 &self,
194 module_ref: &ModuleRef,
195 request_cache: Option<ProviderCache>,
196 resolution_stack: &ProviderResolutionStack,
197 ) -> Result<Arc<AnyProvider>> {
198 let Some(request_cache) = request_cache else {
199 return self.build_with_resolution_stack(module_ref, resolution_stack);
200 };
201
202 if let Some(value) = self
203 .read_cache(&request_cache)?
204 .get(&self.cache_key)
205 .cloned()
206 {
207 return Ok(value);
208 }
209
210 let value = self.build_with_resolution_stack(module_ref, resolution_stack)?;
211 self.write_cache(&request_cache)?
212 .insert(self.cache_key, Arc::clone(&value));
213 Ok(value)
214 }
215
216 async fn seed_singleton_async(&self, module_ref: ModuleRef) -> Result<()> {
217 let resolution_stack = new_resolution_stack();
218 let module_ref = module_ref.with_resolution_stack(Arc::clone(&resolution_stack));
219 enter_resolution_stack(&resolution_stack, self.definition.token())?;
220 let result = self.definition.build_async(module_ref).await;
221 let exit_result = exit_resolution_stack(&resolution_stack);
222 let value = match (result, exit_result) {
223 (Ok(value), Ok(())) => value,
224 (Err(error), _) => return Err(error),
225 (Ok(_), Err(error)) => return Err(error),
226 };
227 self.seed_singleton(value)
228 }
229
230 fn seed_singleton(&self, value: Arc<AnyProvider>) -> Result<()> {
231 self.write_cache(&self.singleton)?
232 .insert(self.cache_key, value);
233 Ok(())
234 }
235
236 fn on_module_init(&self, module_ref: &ModuleRef) -> Result<()> {
237 let Some(hook) = self.definition.lifecycle().on_module_init() else {
238 return Ok(());
239 };
240
241 let resolution_stack = new_resolution_stack();
242 let value = self.resolve_singleton(module_ref, &resolution_stack)?;
243 hook(value, module_ref)
244 }
245
246 async fn on_application_bootstrap(&self, module_ref: ModuleRef) -> Result<()> {
247 let Some(hook) = self.definition.lifecycle().on_application_bootstrap() else {
248 return Ok(());
249 };
250
251 let resolution_stack = new_resolution_stack();
252 let value = self.resolve_singleton(&module_ref, &resolution_stack)?;
253 hook(value, module_ref).await
254 }
255
256 async fn on_application_shutdown(&self, module_ref: ModuleRef) -> Result<()> {
257 let Some(hook) = self.definition.lifecycle().on_application_shutdown() else {
258 return Ok(());
259 };
260
261 let resolution_stack = new_resolution_stack();
262 let value = self.resolve_singleton(&module_ref, &resolution_stack)?;
263 hook(value, module_ref).await
264 }
265
266 fn factory_ref(
267 &self,
268 module_ref: &ModuleRef,
269 request_cache: Option<ProviderCache>,
270 resolution_stack: &ProviderResolutionStack,
271 ) -> ModuleRef {
272 let factory_ref = module_ref.with_resolution_stack(Arc::clone(resolution_stack));
273 match request_cache {
274 Some(request_cache) => factory_ref.with_request_cache(request_cache),
275 None => factory_ref,
276 }
277 }
278
279 fn build_with_resolution_stack(
280 &self,
281 module_ref: &ModuleRef,
282 resolution_stack: &ProviderResolutionStack,
283 ) -> Result<Arc<AnyProvider>> {
284 enter_resolution_stack(resolution_stack, self.definition.token())?;
285 let result = self.definition.build(module_ref);
286 let exit_result = exit_resolution_stack(resolution_stack);
287 match (result, exit_result) {
288 (Ok(value), Ok(())) => Ok(value),
289 (Err(error), _) => Err(error),
290 (Ok(_), Err(error)) => Err(error),
291 }
292 }
293
294 fn read_cache<'a>(
295 &self,
296 cache: &'a ProviderCache,
297 ) -> Result<std::sync::RwLockReadGuard<'a, BTreeMap<ProviderCacheKey, Arc<AnyProvider>>>> {
298 cache
299 .read()
300 .map_err(|_| BootError::Internal("provider cache lock is poisoned".to_string()))
301 }
302
303 fn write_cache<'a>(
304 &self,
305 cache: &'a ProviderCache,
306 ) -> Result<std::sync::RwLockWriteGuard<'a, BTreeMap<ProviderCacheKey, Arc<AnyProvider>>>> {
307 cache
308 .write()
309 .map_err(|_| BootError::Internal("provider cache lock is poisoned".to_string()))
310 }
311}
312
313impl fmt::Debug for ModuleRef {
314 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315 let len = self
316 .providers
317 .read()
318 .map(|providers| providers.len())
319 .unwrap_or(0);
320 let visible = self
321 .visible_scopes
322 .read()
323 .map(|scopes| scopes.len())
324 .unwrap_or(0);
325 f.debug_struct("ModuleRef")
326 .field("providers", &len)
327 .field("visible_scopes", &visible)
328 .finish()
329 }
330}
331
332impl ModuleRef {
333 pub fn new() -> Self {
334 Self::default()
335 }
336
337 pub fn request_scope(&self) -> Self {
338 self.with_request_cache(Arc::new(RwLock::new(BTreeMap::new())))
339 }
340
341 fn with_request_cache(&self, request_cache: ProviderCache) -> Self {
342 Self {
343 providers: Arc::clone(&self.providers),
344 provider_order: Arc::clone(&self.provider_order),
345 visible_scopes: Arc::clone(&self.visible_scopes),
346 request_cache: Some(request_cache),
347 resolution_stack: self.resolution_stack.clone(),
348 }
349 }
350
351 fn with_resolution_stack(&self, resolution_stack: ProviderResolutionStack) -> Self {
352 Self {
353 providers: Arc::clone(&self.providers),
354 provider_order: Arc::clone(&self.provider_order),
355 visible_scopes: Arc::clone(&self.visible_scopes),
356 request_cache: self.request_cache.clone(),
357 resolution_stack: Some(resolution_stack),
358 }
359 }
360
361 pub fn register(&self, definition: ProviderDefinition) -> Result<()> {
362 let token = definition.token().clone();
363 self.validate_registration(&token, &definition)?;
364 if definition.is_async_factory() {
365 return Err(BootError::Internal(format!(
366 "async provider factory requires async registration: {token}"
367 )));
368 }
369
370 let entry = ProviderEntry::new(definition);
371 self.insert_entry(token, entry)
372 }
373
374 pub async fn register_async(&self, definition: ProviderDefinition) -> Result<()> {
375 let token = definition.token().clone();
376 self.validate_registration(&token, &definition)?;
377
378 let entry = ProviderEntry::new(definition);
379 self.insert_entry(token, entry)
380 }
381
382 pub fn insert<T>(&self, value: T) -> Result<()>
383 where
384 T: Send + Sync + 'static,
385 {
386 self.insert_arc(Arc::new(value))
387 }
388
389 pub fn insert_arc<T>(&self, value: Arc<T>) -> Result<()>
390 where
391 T: Send + Sync + 'static,
392 {
393 let token = ProviderToken::of::<T>();
394 let entry = ProviderEntry::new(ProviderDefinition::from_arc(value));
395 self.insert_entry(token, entry)
396 }
397
398 pub fn get<T>(&self) -> Result<Arc<T>>
399 where
400 T: Send + Sync + 'static,
401 {
402 self.get_token::<T>(&ProviderToken::of::<T>())
403 }
404
405 pub fn get_named<T>(&self, token: &str) -> Result<Arc<T>>
406 where
407 T: Send + Sync + 'static,
408 {
409 self.get_token::<T>(&ProviderToken::named(token))
410 }
411
412 pub fn get_optional<T>(&self) -> Result<Option<Arc<T>>>
413 where
414 T: Send + Sync + 'static,
415 {
416 self.get_optional_token::<T>(&ProviderToken::of::<T>())
417 }
418
419 pub fn get_optional_named<T>(&self, token: &str) -> Result<Option<Arc<T>>>
420 where
421 T: Send + Sync + 'static,
422 {
423 self.get_optional_token::<T>(&ProviderToken::named(token))
424 }
425
426 pub fn resolve<T>(&self) -> Result<Arc<T>>
432 where
433 T: Send + Sync + 'static,
434 {
435 self.resolve_token::<T>(&ProviderToken::of::<T>())
436 }
437
438 pub fn resolve_named<T>(&self, token: &str) -> Result<Arc<T>>
440 where
441 T: Send + Sync + 'static,
442 {
443 self.resolve_token::<T>(&ProviderToken::named(token))
444 }
445
446 pub fn resolve_optional<T>(&self) -> Result<Option<Arc<T>>>
448 where
449 T: Send + Sync + 'static,
450 {
451 self.resolve_optional_token::<T>(&ProviderToken::of::<T>())
452 }
453
454 pub fn resolve_optional_named<T>(&self, token: &str) -> Result<Option<Arc<T>>>
456 where
457 T: Send + Sync + 'static,
458 {
459 self.resolve_optional_token::<T>(&ProviderToken::named(token))
460 }
461
462 pub fn create<T>(&self) -> Result<T>
464 where
465 T: FromModuleRef,
466 {
467 T::from_module_ref(self)
468 }
469
470 pub fn create_arc<T>(&self) -> Result<Arc<T>>
472 where
473 T: FromModuleRef,
474 {
475 Ok(Arc::new(self.create::<T>()?))
476 }
477
478 pub fn contains(&self, token: &ProviderToken) -> Result<bool> {
479 Ok(self.get_entry(token)?.is_some())
480 }
481
482 pub fn contains_provider<T>(&self) -> Result<bool>
483 where
484 T: Send + Sync + 'static,
485 {
486 self.contains(&ProviderToken::of::<T>())
487 }
488
489 pub fn contains_named(&self, token: &str) -> Result<bool> {
490 self.contains(&ProviderToken::named(token))
491 }
492
493 pub fn tokens(&self) -> Result<Vec<ProviderToken>> {
494 let mut tokens = BTreeMap::new();
495 self.collect_tokens(&mut tokens)?;
496 Ok(tokens.into_keys().collect())
497 }
498
499 fn insert_entry(&self, token: ProviderToken, entry: ProviderEntry) -> Result<()> {
500 let mut provider_order = self.write_provider_order()?;
501 let mut providers = self.write_providers()?;
502 if providers.contains_key(&token) {
503 return Err(BootError::DuplicateProvider(token.to_string()));
504 }
505 providers.insert(token.clone(), entry);
506 provider_order.push(token);
507 Ok(())
508 }
509
510 fn validate_registration(
511 &self,
512 token: &ProviderToken,
513 definition: &ProviderDefinition,
514 ) -> Result<()> {
515 if self.contains_local(token)? {
516 return Err(BootError::DuplicateProvider(token.to_string()));
517 }
518 if definition.is_async_factory() && definition.scope() != ProviderScope::Singleton {
519 return Err(BootError::Internal(format!(
520 "async provider factories require singleton scope: {token}"
521 )));
522 }
523 if definition.lifecycle().has_hooks() && definition.scope() != ProviderScope::Singleton {
524 return Err(BootError::Internal(format!(
525 "provider lifecycle hooks require singleton scope: {token}"
526 )));
527 }
528 if definition.lifecycle().has_hooks() && definition.is_alias() {
529 return Err(BootError::Internal(format!(
530 "provider aliases cannot define lifecycle hooks: {token}"
531 )));
532 }
533 Ok(())
534 }
535
536 pub(crate) fn add_visible_scope(&self, module_ref: ModuleRef) -> Result<()> {
537 self.write_visible_scopes()?.push(module_ref);
538 Ok(())
539 }
540
541 pub(crate) fn export_from(&self, module_ref: &ModuleRef, token: &ProviderToken) -> Result<()> {
542 let entry = module_ref
543 .get_entry(token)?
544 .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
545 self.insert_entry(token.clone(), entry.with_owner(module_ref.clone()))
546 }
547
548 pub(crate) fn local_tokens(&self) -> Result<Vec<ProviderToken>> {
549 Ok(self.read_provider_order()?.clone())
550 }
551
552 pub(crate) fn initialize_local_singletons(&self) -> Result<()> {
553 for entry in self.local_entries()? {
554 if entry.is_local_singleton() {
555 let resolution_stack = new_resolution_stack();
556 entry.resolve_singleton(self, &resolution_stack)?;
557 }
558 }
559 Ok(())
560 }
561
562 pub(crate) async fn initialize_local_singletons_async(&self) -> Result<()> {
563 for entry in self.local_entries()? {
564 if entry.is_local_singleton() && entry.is_async_factory() {
565 entry.seed_singleton_async(self.clone()).await?;
566 }
567 }
568
569 self.initialize_local_singletons()
570 }
571
572 pub(crate) fn initialize_local_providers(&self) -> Result<()> {
573 for entry in self.local_entries()? {
574 entry.on_module_init(self)?;
575 }
576 Ok(())
577 }
578
579 pub(crate) async fn bootstrap_local_providers(&self) -> Result<()> {
580 for entry in self.local_entries()? {
581 entry.on_application_bootstrap(self.clone()).await?;
582 }
583 Ok(())
584 }
585
586 pub(crate) async fn shutdown_local_providers(&self) -> Result<()> {
587 let mut entries = self.local_entries()?;
588 entries.reverse();
589 for entry in entries {
590 entry.on_application_shutdown(self.clone()).await?;
591 }
592 Ok(())
593 }
594
595 fn get_token<T>(&self, token: &ProviderToken) -> Result<Arc<T>>
596 where
597 T: Send + Sync + 'static,
598 {
599 let value = self
600 .get_any(token)?
601 .ok_or_else(|| BootError::MissingProvider(token.to_string()))?;
602
603 Arc::downcast::<T>(value).map_err(|_| BootError::ProviderTypeMismatch(token.to_string()))
604 }
605
606 fn get_optional_token<T>(&self, token: &ProviderToken) -> Result<Option<Arc<T>>>
607 where
608 T: Send + Sync + 'static,
609 {
610 let value = self.get_any(token)?;
611 match value {
612 Some(value) => Arc::downcast::<T>(value)
613 .map(Some)
614 .map_err(|_| BootError::ProviderTypeMismatch(token.to_string())),
615 None => Ok(None),
616 }
617 }
618
619 fn resolve_token<T>(&self, token: &ProviderToken) -> Result<Arc<T>>
620 where
621 T: Send + Sync + 'static,
622 {
623 self.request_scope().get_token(token)
624 }
625
626 fn resolve_optional_token<T>(&self, token: &ProviderToken) -> Result<Option<Arc<T>>>
627 where
628 T: Send + Sync + 'static,
629 {
630 self.request_scope().get_optional_token(token)
631 }
632
633 fn get_any(&self, token: &ProviderToken) -> Result<Option<Arc<AnyProvider>>> {
634 let mut alias_path = Vec::new();
635 let resolution_stack = self
636 .resolution_stack
637 .clone()
638 .unwrap_or_else(new_resolution_stack);
639 self.get_any_with_request_cache_inner(
640 token,
641 self.request_cache.clone(),
642 &resolution_stack,
643 &mut alias_path,
644 )
645 }
646
647 fn get_any_with_request_cache_inner(
648 &self,
649 token: &ProviderToken,
650 request_cache: Option<ProviderCache>,
651 resolution_stack: &ProviderResolutionStack,
652 alias_path: &mut Vec<ProviderToken>,
653 ) -> Result<Option<Arc<AnyProvider>>> {
654 if let Some(entry) = self.read_providers()?.get(token).cloned() {
655 return entry
656 .resolve(self, request_cache, resolution_stack, alias_path)
657 .map(Some);
658 }
659
660 for scope in self.visible_scopes()? {
661 if let Some(value) = scope.get_any_with_request_cache_inner(
662 token,
663 request_cache.clone(),
664 resolution_stack,
665 alias_path,
666 )? {
667 return Ok(Some(value));
668 }
669 }
670
671 Ok(None)
672 }
673
674 fn get_entry(&self, token: &ProviderToken) -> Result<Option<ProviderEntry>> {
675 if let Some(entry) = self.read_providers()?.get(token).cloned() {
676 return Ok(Some(entry));
677 }
678
679 for scope in self.visible_scopes()? {
680 if let Some(entry) = scope.get_entry(token)? {
681 return Ok(Some(entry));
682 }
683 }
684
685 Ok(None)
686 }
687
688 fn contains_local(&self, token: &ProviderToken) -> Result<bool> {
689 Ok(self.read_providers()?.contains_key(token))
690 }
691
692 fn collect_tokens(&self, tokens: &mut BTreeMap<ProviderToken, ()>) -> Result<()> {
693 for token in self.read_providers()?.keys() {
694 tokens.insert(token.clone(), ());
695 }
696 for scope in self.visible_scopes()? {
697 scope.collect_tokens(tokens)?;
698 }
699 Ok(())
700 }
701
702 fn local_entries(&self) -> Result<Vec<ProviderEntry>> {
703 let provider_order = self.read_provider_order()?.clone();
704 let providers = self.read_providers()?;
705 let mut entries = Vec::with_capacity(provider_order.len());
706 for token in provider_order {
707 if let Some(entry) = providers.get(&token) {
708 entries.push(entry.clone());
709 }
710 }
711 Ok(entries)
712 }
713
714 fn visible_scopes(&self) -> Result<Vec<ModuleRef>> {
715 Ok(self.read_visible_scopes()?.clone())
716 }
717
718 fn read_providers(
719 &self,
720 ) -> Result<std::sync::RwLockReadGuard<'_, BTreeMap<ProviderToken, ProviderEntry>>> {
721 self.providers
722 .read()
723 .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
724 }
725
726 fn write_providers(
727 &self,
728 ) -> Result<std::sync::RwLockWriteGuard<'_, BTreeMap<ProviderToken, ProviderEntry>>> {
729 self.providers
730 .write()
731 .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
732 }
733
734 fn read_provider_order(&self) -> Result<std::sync::RwLockReadGuard<'_, Vec<ProviderToken>>> {
735 self.provider_order
736 .read()
737 .map_err(|_| BootError::Internal("provider order lock is poisoned".to_string()))
738 }
739
740 fn write_provider_order(&self) -> Result<std::sync::RwLockWriteGuard<'_, Vec<ProviderToken>>> {
741 self.provider_order
742 .write()
743 .map_err(|_| BootError::Internal("provider order lock is poisoned".to_string()))
744 }
745
746 fn read_visible_scopes(&self) -> Result<std::sync::RwLockReadGuard<'_, Vec<ModuleRef>>> {
747 self.visible_scopes
748 .read()
749 .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
750 }
751
752 fn write_visible_scopes(&self) -> Result<std::sync::RwLockWriteGuard<'_, Vec<ModuleRef>>> {
753 self.visible_scopes
754 .write()
755 .map_err(|_| BootError::Internal("provider registry lock is poisoned".to_string()))
756 }
757}