Skip to main content

qubit_spi/
provider_registry.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Typed registry for pluggable service providers.
11
12use std::collections::{
13    HashMap,
14    HashSet,
15};
16use std::marker::PhantomData;
17use std::rc::Rc;
18use std::sync::Arc;
19
20use log::{
21    debug,
22    trace,
23};
24
25use crate::{
26    ProviderAvailability,
27    ProviderCreateError,
28    ProviderDescriptor,
29    ProviderFailure,
30    ProviderName,
31    ProviderRegistryError,
32    ProviderSelection,
33    ServiceProvider,
34    ServiceSpec,
35};
36
37/// Registry of providers for one service specification.
38///
39/// Provider descriptors are captured during registration. Provider ids and
40/// aliases are normalized into [`ProviderName`] values and indexed
41/// case-insensitively, so lookup does not depend on provider metadata changing
42/// after registration. Automatic selection order is cached during registration
43/// updates. Registries store providers behind shared trait objects, so
44/// registered providers and service specifications must be `'static`.
45#[derive(Debug)]
46pub struct ProviderRegistry<Spec>
47where
48    Spec: ServiceSpec + 'static,
49{
50    /// Registered providers in insertion order.
51    providers: Vec<ProviderEntry<Spec>>,
52    /// Normalized provider id and alias lookup table.
53    index: HashMap<ProviderName, usize>,
54    /// Cached automatic-selection candidates ordered by priority and id.
55    auto_candidates: Vec<ProviderName>,
56    /// Keeps the service specification attached to this registry type.
57    marker: PhantomData<fn() -> Spec>,
58}
59
60/// Registered provider and its captured descriptor.
61#[derive(Debug)]
62struct ProviderEntry<Spec>
63where
64    Spec: ServiceSpec + 'static,
65{
66    /// Captured provider descriptor.
67    descriptor: ProviderDescriptor,
68    /// Provider factory.
69    provider: Arc<dyn ServiceProvider<Spec>>,
70}
71
72impl<Spec> ProviderRegistry<Spec>
73where
74    Spec: ServiceSpec + 'static,
75{
76    /// Creates an empty provider registry.
77    ///
78    /// # Returns
79    /// Empty provider registry.
80    #[inline]
81    pub fn new() -> Self {
82        Self::default()
83    }
84
85    /// Gets the number of registered providers.
86    ///
87    /// # Returns
88    /// Provider count.
89    #[inline]
90    pub fn len(&self) -> usize {
91        self.providers.len()
92    }
93
94    /// Tells whether this registry contains no providers.
95    ///
96    /// # Returns
97    /// `true` when no providers are registered.
98    #[inline]
99    pub fn is_empty(&self) -> bool {
100        self.providers.is_empty()
101    }
102
103    /// Registers a provider owned by the registry.
104    ///
105    /// # Parameters
106    /// - `provider`: Provider to register.
107    ///
108    /// # Errors
109    /// Returns [`ProviderRegistryError`] when the provider descriptor is invalid
110    /// or when its id or aliases conflict with an existing provider.
111    #[inline]
112    pub fn register<P>(&mut self, provider: P) -> Result<(), ProviderRegistryError>
113    where
114        P: ServiceProvider<Spec> + 'static,
115    {
116        self.register_provider(Arc::new(provider))
117    }
118
119    /// Registers a shared provider.
120    ///
121    /// # Parameters
122    /// - `provider`: Shared provider to register.
123    ///
124    /// # Errors
125    /// Returns [`ProviderRegistryError`] when the provider descriptor is invalid
126    /// or when its id or aliases conflict with an existing provider.
127    #[inline]
128    pub fn register_shared(
129        &mut self,
130        provider: Arc<dyn ServiceProvider<Spec>>,
131    ) -> Result<(), ProviderRegistryError> {
132        self.register_provider(provider)
133    }
134
135    /// Registers a provider stored behind a trait object.
136    ///
137    /// # Parameters
138    /// - `provider`: Shared provider trait object to register.
139    ///
140    /// # Errors
141    /// Returns [`ProviderRegistryError`] when the provider descriptor is invalid
142    /// or when its id or aliases conflict with an existing provider.
143    fn register_provider(
144        &mut self,
145        provider: Arc<dyn ServiceProvider<Spec>>,
146    ) -> Result<(), ProviderRegistryError> {
147        let descriptor = provider.descriptor()?;
148        self.validate_descriptor(&descriptor)?;
149        let provider_index = self.providers.len();
150        for name in descriptor.names() {
151            self.index.insert(name.clone(), provider_index);
152        }
153        self.providers.push(ProviderEntry {
154            descriptor,
155            provider,
156        });
157        self.rebuild_auto_candidates();
158        debug!(
159            "registered provider '{}' with {} aliases and priority {}",
160            self.providers[provider_index].descriptor.id(),
161            self.providers[provider_index].descriptor.aliases().len(),
162            self.providers[provider_index].descriptor.priority(),
163        );
164        Ok(())
165    }
166
167    /// Gets canonical provider ids in registration order.
168    ///
169    /// # Returns
170    /// Registered provider ids.
171    #[inline]
172    pub fn provider_names(&self) -> Vec<&str> {
173        self.iter_provider_names().collect()
174    }
175
176    /// Iterates over canonical provider ids in registration order.
177    ///
178    /// # Returns
179    /// Iterator over registered provider ids.
180    #[inline]
181    pub fn iter_provider_names(&self) -> impl Iterator<Item = &str> + '_ {
182        self.providers
183            .iter()
184            .map(|entry| entry.descriptor.id().as_str())
185    }
186
187    /// Gets captured provider descriptors in registration order.
188    ///
189    /// # Returns
190    /// Provider descriptors captured during registration.
191    #[inline]
192    pub fn provider_descriptors(&self) -> Vec<&ProviderDescriptor> {
193        self.iter_provider_descriptors().collect()
194    }
195
196    /// Iterates over captured provider descriptors in registration order.
197    ///
198    /// # Returns
199    /// Iterator over provider descriptors captured during registration.
200    #[inline]
201    pub fn iter_provider_descriptors(&self) -> impl Iterator<Item = &ProviderDescriptor> + '_ {
202        self.providers.iter().map(|entry| &entry.descriptor)
203    }
204
205    /// Finds a provider by id or alias.
206    ///
207    /// # Parameters
208    /// - `name`: Provider id or alias. Names are normalized before lookup.
209    ///
210    /// # Returns
211    /// Matching provider, or `None` when no provider matches or `name` is
212    /// invalid.
213    #[inline]
214    pub fn find_provider(&self, name: &str) -> Option<&dyn ServiceProvider<Spec>> {
215        self.resolve_provider(name).ok()
216    }
217
218    /// Resolves a provider by id or alias.
219    ///
220    /// # Parameters
221    /// - `name`: Provider id or alias. Names are normalized before lookup.
222    ///
223    /// # Returns
224    /// Matching provider.
225    ///
226    /// # Errors
227    /// Returns [`ProviderRegistryError::EmptyProviderName`] or
228    /// [`ProviderRegistryError::InvalidProviderName`] when `name` is invalid,
229    /// or [`ProviderRegistryError::UnknownProvider`] when no provider matches.
230    pub fn resolve_provider(
231        &self,
232        name: &str,
233    ) -> Result<&dyn ServiceProvider<Spec>, ProviderRegistryError> {
234        let name = match ProviderName::new(name) {
235            Ok(name) => name,
236            Err(error) => {
237                trace!("provider resolution rejected invalid name: {error}");
238                return Err(error);
239            }
240        };
241        let Some(entry) = self.find_entry_by_name(&name) else {
242            trace!("provider resolution missed provider '{name}'");
243            return Err(ProviderRegistryError::UnknownProvider { name });
244        };
245        trace!(
246            "provider resolution matched '{}' to registered provider '{}'",
247            name,
248            entry.descriptor.id(),
249        );
250        Ok(entry.provider.as_ref())
251    }
252
253    /// Creates a boxed service from one provider name.
254    ///
255    /// # Parameters
256    /// - `name`: Provider id or alias.
257    /// - `config`: Configuration passed to the provider.
258    ///
259    /// # Returns
260    /// Boxed service value created by the selected provider.
261    ///
262    /// # Errors
263    /// Returns [`ProviderRegistryError::EmptyProviderName`] or
264    /// [`ProviderRegistryError::InvalidProviderName`] when `name` is invalid,
265    /// [`ProviderRegistryError::UnknownProvider`] when no provider matches,
266    /// [`ProviderRegistryError::ProviderUnavailable`] when the provider is not
267    /// available, or [`ProviderRegistryError::ProviderCreate`] when the provider
268    /// factory fails.
269    #[inline]
270    pub fn create_box(
271        &self,
272        name: &str,
273        config: &Spec::Config,
274    ) -> Result<Box<Spec::Service>, ProviderRegistryError> {
275        self.create_with(name, config, |provider, config| provider.create_box(config))
276    }
277
278    /// Creates an atomically shared service from one provider name.
279    ///
280    /// # Parameters
281    /// - `name`: Provider id or alias.
282    /// - `config`: Configuration passed to the provider.
283    ///
284    /// # Returns
285    /// Atomically shared service value created by the selected provider.
286    ///
287    /// # Errors
288    /// Returns [`ProviderRegistryError::EmptyProviderName`] or
289    /// [`ProviderRegistryError::InvalidProviderName`] when `name` is invalid,
290    /// [`ProviderRegistryError::UnknownProvider`] when no provider matches,
291    /// [`ProviderRegistryError::ProviderUnavailable`] when the provider is not
292    /// available, or [`ProviderRegistryError::ProviderCreate`] when the provider
293    /// factory fails.
294    #[inline]
295    pub fn create_arc(
296        &self,
297        name: &str,
298        config: &Spec::Config,
299    ) -> Result<Arc<Spec::Service>, ProviderRegistryError> {
300        self.create_with(name, config, |provider, config| provider.create_arc(config))
301    }
302
303    /// Creates a locally shared service from one provider name.
304    ///
305    /// # Parameters
306    /// - `name`: Provider id or alias.
307    /// - `config`: Configuration passed to the provider.
308    ///
309    /// # Returns
310    /// Locally shared service value created by the selected provider.
311    ///
312    /// # Errors
313    /// Returns [`ProviderRegistryError::EmptyProviderName`] or
314    /// [`ProviderRegistryError::InvalidProviderName`] when `name` is invalid,
315    /// [`ProviderRegistryError::UnknownProvider`] when no provider matches,
316    /// [`ProviderRegistryError::ProviderUnavailable`] when the provider is not
317    /// available, or [`ProviderRegistryError::ProviderCreate`] when the provider
318    /// factory fails.
319    #[inline]
320    pub fn create_rc(
321        &self,
322        name: &str,
323        config: &Spec::Config,
324    ) -> Result<Rc<Spec::Service>, ProviderRegistryError> {
325        self.create_with(name, config, |provider, config| provider.create_rc(config))
326    }
327
328    /// Creates a service handle from one provider name.
329    ///
330    /// # Parameters
331    /// - `name`: Provider id or alias.
332    /// - `config`: Configuration passed to the provider.
333    /// - `create`: Provider factory method used to create the handle.
334    ///
335    /// # Returns
336    /// Service handle created by the selected provider.
337    ///
338    /// # Errors
339    /// Returns [`ProviderRegistryError`] when the provider name is invalid,
340    /// unknown, unavailable, or when the provider factory fails.
341    fn create_with<Handle, Create>(
342        &self,
343        name: &str,
344        config: &Spec::Config,
345        create: Create,
346    ) -> Result<Handle, ProviderRegistryError>
347    where
348        Create:
349            Fn(&dyn ServiceProvider<Spec>, &Spec::Config) -> Result<Handle, ProviderCreateError>,
350    {
351        let name = ProviderName::new(name)?;
352        let entry = self
353            .find_entry_by_name(&name)
354            .ok_or_else(|| ProviderRegistryError::UnknownProvider { name: name.clone() })?;
355        trace!("creating service from provider '{name}'");
356        match entry.provider.availability(config) {
357            ProviderAvailability::Available => match create(entry.provider.as_ref(), config) {
358                Ok(service) => {
359                    debug!("provider '{name}' created service");
360                    Ok(service)
361                }
362                Err(error) => {
363                    trace!(
364                        "provider '{name}' failed to create service: {}",
365                        error.reason(),
366                    );
367                    Err(registry_error_from_create_error(name, error))
368                }
369            },
370            ProviderAvailability::Unavailable { reason } => {
371                trace!("provider '{name}' is unavailable: {reason}");
372                Err(ProviderRegistryError::ProviderUnavailable {
373                    name,
374                    source: ProviderCreateError::unavailable(&reason),
375                })
376            }
377        }
378    }
379
380    /// Creates a boxed service using automatic provider selection.
381    ///
382    /// # Parameters
383    /// - `config`: Configuration passed to candidate providers.
384    ///
385    /// # Returns
386    /// Boxed service created by the highest-priority usable provider.
387    ///
388    /// # Errors
389    /// Returns [`ProviderRegistryError::EmptyRegistry`] when the registry has no
390    /// providers, or [`ProviderRegistryError::NoAvailableProvider`] when all
391    /// automatic candidates fail.
392    #[inline]
393    pub fn create_auto_box(
394        &self,
395        config: &Spec::Config,
396    ) -> Result<Box<Spec::Service>, ProviderRegistryError> {
397        self.create_selected_box(&ProviderSelection::Auto, config)
398    }
399
400    /// Creates an atomically shared service using automatic provider selection.
401    ///
402    /// # Parameters
403    /// - `config`: Configuration passed to candidate providers.
404    ///
405    /// # Returns
406    /// Atomically shared service created by the highest-priority usable provider.
407    ///
408    /// # Errors
409    /// Returns [`ProviderRegistryError::EmptyRegistry`] when the registry has no
410    /// providers, or [`ProviderRegistryError::NoAvailableProvider`] when all
411    /// automatic candidates fail.
412    #[inline]
413    pub fn create_auto_arc(
414        &self,
415        config: &Spec::Config,
416    ) -> Result<Arc<Spec::Service>, ProviderRegistryError> {
417        self.create_selected_arc(&ProviderSelection::Auto, config)
418    }
419
420    /// Creates a locally shared service using automatic provider selection.
421    ///
422    /// # Parameters
423    /// - `config`: Configuration passed to candidate providers.
424    ///
425    /// # Returns
426    /// Locally shared service created by the highest-priority usable provider.
427    ///
428    /// # Errors
429    /// Returns [`ProviderRegistryError::EmptyRegistry`] when the registry has no
430    /// providers, or [`ProviderRegistryError::NoAvailableProvider`] when all
431    /// automatic candidates fail.
432    #[inline]
433    pub fn create_auto_rc(
434        &self,
435        config: &Spec::Config,
436    ) -> Result<Rc<Spec::Service>, ProviderRegistryError> {
437        self.create_selected_rc(&ProviderSelection::Auto, config)
438    }
439
440    /// Creates a boxed service from explicit provider selection.
441    ///
442    /// Automatic selection tries all registered providers ordered by descending
443    /// priority and then by provider id. Named selection tries the primary
444    /// provider followed by fallbacks in order. Selection stops at the first
445    /// provider that can create a service.
446    ///
447    /// # Parameters
448    /// - `selection`: Provider selection policy.
449    /// - `config`: Configuration passed to candidate providers.
450    ///
451    /// # Returns
452    /// Boxed service created by the first successful provider candidate.
453    ///
454    /// # Errors
455    /// Returns [`ProviderRegistryError::DuplicateProviderCandidate`] when a
456    /// named selection repeats a candidate name,
457    /// [`ProviderRegistryError::EmptyRegistry`] when the registry has no providers, or
458    /// [`ProviderRegistryError::NoAvailableProvider`] when every candidate is
459    /// unknown, unavailable, or fails during creation.
460    #[inline]
461    pub fn create_selected_box(
462        &self,
463        selection: &ProviderSelection,
464        config: &Spec::Config,
465    ) -> Result<Box<Spec::Service>, ProviderRegistryError> {
466        self.create_selected_with(selection, config, |provider, config| {
467            provider.create_box(config)
468        })
469    }
470
471    /// Creates an atomically shared service from explicit provider selection.
472    ///
473    /// Automatic selection tries all registered providers ordered by descending
474    /// priority and then by provider id. Named selection tries the primary
475    /// provider followed by fallbacks in order. Selection stops at the first
476    /// provider that can create a service.
477    ///
478    /// # Parameters
479    /// - `selection`: Provider selection policy.
480    /// - `config`: Configuration passed to candidate providers.
481    ///
482    /// # Returns
483    /// Atomically shared service created by the first successful provider
484    /// candidate.
485    ///
486    /// # Errors
487    /// Returns [`ProviderRegistryError::DuplicateProviderCandidate`] when a
488    /// named selection repeats a candidate name,
489    /// [`ProviderRegistryError::EmptyRegistry`] when the registry has no providers, or
490    /// [`ProviderRegistryError::NoAvailableProvider`] when every candidate is
491    /// unknown, unavailable, or fails during creation.
492    #[inline]
493    pub fn create_selected_arc(
494        &self,
495        selection: &ProviderSelection,
496        config: &Spec::Config,
497    ) -> Result<Arc<Spec::Service>, ProviderRegistryError> {
498        self.create_selected_with(selection, config, |provider, config| {
499            provider.create_arc(config)
500        })
501    }
502
503    /// Creates a locally shared service from explicit provider selection.
504    ///
505    /// Automatic selection tries all registered providers ordered by descending
506    /// priority and then by provider id. Named selection tries the primary
507    /// provider followed by fallbacks in order. Selection stops at the first
508    /// provider that can create a service.
509    ///
510    /// # Parameters
511    /// - `selection`: Provider selection policy.
512    /// - `config`: Configuration passed to candidate providers.
513    ///
514    /// # Returns
515    /// Locally shared service created by the first successful provider
516    /// candidate.
517    ///
518    /// # Errors
519    /// Returns [`ProviderRegistryError::DuplicateProviderCandidate`] when a
520    /// named selection repeats a candidate name,
521    /// [`ProviderRegistryError::EmptyRegistry`] when the registry has no providers, or
522    /// [`ProviderRegistryError::NoAvailableProvider`] when every candidate is
523    /// unknown, unavailable, or fails during creation.
524    #[inline]
525    pub fn create_selected_rc(
526        &self,
527        selection: &ProviderSelection,
528        config: &Spec::Config,
529    ) -> Result<Rc<Spec::Service>, ProviderRegistryError> {
530        self.create_selected_with(selection, config, |provider, config| {
531            provider.create_rc(config)
532        })
533    }
534
535    /// Creates a service handle from explicit provider selection.
536    ///
537    /// # Parameters
538    /// - `selection`: Provider selection policy.
539    /// - `config`: Configuration passed to candidate providers.
540    /// - `create`: Provider factory method used to create the handle.
541    ///
542    /// # Returns
543    /// Service handle created by the first successful provider candidate.
544    ///
545    /// # Errors
546    /// Returns [`ProviderRegistryError::DuplicateProviderCandidate`] when a
547    /// named selection repeats a candidate name,
548    /// [`ProviderRegistryError::EmptyRegistry`] when the registry has no providers, or
549    /// [`ProviderRegistryError::NoAvailableProvider`] when every candidate is
550    /// unknown, unavailable, or fails during creation.
551    fn create_selected_with<Handle, Create>(
552        &self,
553        selection: &ProviderSelection,
554        config: &Spec::Config,
555        create: Create,
556    ) -> Result<Handle, ProviderRegistryError>
557    where
558        Create:
559            Fn(&dyn ServiceProvider<Spec>, &Spec::Config) -> Result<Handle, ProviderCreateError>,
560    {
561        selection.validate_unique_names()?;
562        if self.providers.is_empty() {
563            trace!("provider selection failed because registry is empty");
564            return Err(ProviderRegistryError::EmptyRegistry);
565        }
566        match selection {
567            ProviderSelection::Auto => {
568                trace!(
569                    "automatic provider selection prepared {} candidate(s)",
570                    self.auto_candidates().len(),
571                );
572                self.create_from_candidates_with(self.auto_candidates().iter(), config, &create)
573            }
574            ProviderSelection::Named { primary, fallbacks } => {
575                trace!(
576                    "named provider selection will try primary '{}' with {} fallback(s)",
577                    primary,
578                    fallbacks.len(),
579                );
580                self.create_from_candidates_with(
581                    std::iter::once(primary).chain(fallbacks.iter()),
582                    config,
583                    &create,
584                )
585            }
586        }
587    }
588
589    /// Creates a service handle by trying the supplied candidates in order.
590    ///
591    /// # Parameters
592    /// - `candidates`: Candidate provider names to try.
593    /// - `config`: Configuration passed to candidate providers.
594    /// - `create`: Provider factory method used to create the handle.
595    ///
596    /// # Returns
597    /// Service handle created by the first successful candidate.
598    ///
599    /// # Errors
600    /// Returns [`ProviderRegistryError::NoAvailableProvider`] when every
601    /// candidate is unknown, unavailable, or fails during creation. Candidate
602    /// names that resolve to a provider already tried earlier in the same
603    /// selection are skipped.
604    fn create_from_candidates_with<'a, I, Handle, Create>(
605        &self,
606        candidates: I,
607        config: &Spec::Config,
608        create: &Create,
609    ) -> Result<Handle, ProviderRegistryError>
610    where
611        I: IntoIterator<Item = &'a ProviderName>,
612        Create:
613            Fn(&dyn ServiceProvider<Spec>, &Spec::Config) -> Result<Handle, ProviderCreateError>,
614    {
615        let mut failures = Vec::new();
616        let mut tried_provider_indices = HashSet::new();
617        for candidate in candidates {
618            if let Some(provider_index) = self.index.get(candidate).copied()
619                && !tried_provider_indices.insert(provider_index)
620            {
621                trace!(
622                    "provider candidate '{candidate}' resolves to an already tried provider; skipping",
623                );
624                continue;
625            }
626            match self.create_from_candidate_with(candidate, config, create) {
627                Ok(service) => {
628                    debug!("provider candidate '{candidate}' created service");
629                    return Ok(service);
630                }
631                Err(failure) => {
632                    trace!("provider candidate failed: {failure}");
633                    failures.push(failure);
634                }
635            }
636        }
637        trace!(
638            "provider selection exhausted all candidates with {} failure(s)",
639            failures.len(),
640        );
641        Err(ProviderRegistryError::NoAvailableProvider { failures })
642    }
643
644    /// Creates a service handle from one normalized candidate name.
645    ///
646    /// # Parameters
647    /// - `candidate`: Normalized provider id or alias.
648    /// - `config`: Configuration passed to the provider.
649    /// - `create`: Provider factory method used to create the handle.
650    ///
651    /// # Returns
652    /// Service handle created by the provider.
653    ///
654    /// # Errors
655    /// Returns [`ProviderFailure`] when the candidate is unknown, unavailable,
656    /// or fails during service creation.
657    fn create_from_candidate_with<Handle, Create>(
658        &self,
659        candidate: &ProviderName,
660        config: &Spec::Config,
661        create: &Create,
662    ) -> Result<Handle, ProviderFailure>
663    where
664        Create:
665            Fn(&dyn ServiceProvider<Spec>, &Spec::Config) -> Result<Handle, ProviderCreateError>,
666    {
667        let Some(entry) = self.find_entry_by_name(candidate) else {
668            trace!("provider candidate '{candidate}' is unknown");
669            return Err(ProviderFailure::unknown_name(candidate.clone()));
670        };
671        match entry.provider.availability(config) {
672            ProviderAvailability::Available => create(entry.provider.as_ref(), config)
673                .map_err(|error| failure_from_create_error(candidate.clone(), error)),
674            ProviderAvailability::Unavailable { reason } => {
675                trace!("provider candidate '{candidate}' is unavailable: {reason}");
676                Err(ProviderFailure::unavailable_name(
677                    candidate.clone(),
678                    &reason,
679                ))
680            }
681        }
682    }
683
684    /// Validates that a descriptor does not conflict with existing entries.
685    ///
686    /// # Parameters
687    /// - `descriptor`: Descriptor to validate.
688    ///
689    /// # Errors
690    /// Returns [`ProviderRegistryError::DuplicateProviderName`] when the
691    /// descriptor contains duplicate names or conflicts with an existing name.
692    fn validate_descriptor(
693        &self,
694        descriptor: &ProviderDescriptor,
695    ) -> Result<(), ProviderRegistryError> {
696        let mut local_names = HashSet::with_capacity(descriptor.aliases().len() + 1);
697        for name in descriptor.names() {
698            if !local_names.insert(name.clone()) || self.index.contains_key(name) {
699                return Err(ProviderRegistryError::DuplicateProviderName { name: name.clone() });
700            }
701        }
702        Ok(())
703    }
704
705    /// Finds a provider entry by a normalized provider name.
706    ///
707    /// # Parameters
708    /// - `name`: Normalized provider id or alias.
709    ///
710    /// # Returns
711    /// Matching provider entry, or `None` when no provider matches.
712    fn find_entry_by_name(&self, name: &ProviderName) -> Option<&ProviderEntry<Spec>> {
713        self.index
714            .get(name)
715            .and_then(|provider_index| self.providers.get(*provider_index))
716    }
717
718    /// Gets cached automatic provider candidates.
719    ///
720    /// # Returns
721    /// Provider ids ordered by descending priority and then ascending id.
722    fn auto_candidates(&self) -> &[ProviderName] {
723        &self.auto_candidates
724    }
725
726    /// Rebuilds cached automatic provider candidates.
727    fn rebuild_auto_candidates(&mut self) {
728        let mut provider_indices: Vec<usize> = (0..self.providers.len()).collect();
729        provider_indices.sort_by(|left, right| {
730            let left_descriptor = &self.providers[*left].descriptor;
731            let right_descriptor = &self.providers[*right].descriptor;
732            right_descriptor
733                .priority()
734                .cmp(&left_descriptor.priority())
735                .then_with(|| left_descriptor.id().cmp(right_descriptor.id()))
736        });
737        self.auto_candidates = provider_indices
738            .into_iter()
739            .map(|provider_index| self.providers[provider_index].descriptor.id().clone())
740            .collect();
741    }
742}
743
744impl<Spec> Clone for ProviderRegistry<Spec>
745where
746    Spec: ServiceSpec + 'static,
747{
748    /// Clones the provider list while sharing provider instances.
749    #[inline]
750    fn clone(&self) -> Self {
751        Self {
752            providers: self.providers.clone(),
753            index: self.index.clone(),
754            auto_candidates: self.auto_candidates.clone(),
755            marker: PhantomData,
756        }
757    }
758}
759
760impl<Spec> Clone for ProviderEntry<Spec>
761where
762    Spec: ServiceSpec + 'static,
763{
764    /// Clones one provider entry while sharing the provider instance.
765    #[inline]
766    fn clone(&self) -> Self {
767        Self {
768            descriptor: self.descriptor.clone(),
769            provider: self.provider.clone(),
770        }
771    }
772}
773
774impl<Spec> Default for ProviderRegistry<Spec>
775where
776    Spec: ServiceSpec + 'static,
777{
778    /// Creates an empty provider registry.
779    #[inline]
780    fn default() -> Self {
781        Self {
782            providers: Vec::new(),
783            index: HashMap::new(),
784            auto_candidates: Vec::new(),
785            marker: PhantomData,
786        }
787    }
788}
789
790/// Converts a provider creation error into a registry error.
791///
792/// # Parameters
793/// - `name`: Provider name being created.
794/// - `error`: Provider creation error.
795///
796/// # Returns
797/// Registry error with provider-name context.
798fn registry_error_from_create_error(
799    name: ProviderName,
800    error: ProviderCreateError,
801) -> ProviderRegistryError {
802    if error.is_unavailable() {
803        ProviderRegistryError::ProviderUnavailable {
804            name,
805            source: error,
806        }
807    } else {
808        ProviderRegistryError::ProviderCreate {
809            name,
810            source: error,
811        }
812    }
813}
814
815/// Converts a provider creation error into a candidate failure.
816///
817/// # Parameters
818/// - `name`: Candidate provider name.
819/// - `error`: Provider creation error.
820///
821/// # Returns
822/// Candidate failure with provider-name context.
823fn failure_from_create_error(name: ProviderName, error: ProviderCreateError) -> ProviderFailure {
824    if error.is_unavailable() {
825        ProviderFailure::unavailable_error(name, error)
826    } else {
827        ProviderFailure::create_failed_error(name, error)
828    }
829}