Skip to main content

qubit_spi/
provider_selection.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//! Selection policy for provider resolution.
11
12use crate::{
13    ProviderName,
14    ProviderRegistryError,
15};
16
17/// Provider candidates used by registry selection.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum ProviderSelection {
20    /// Select providers automatically by registry priority.
21    Auto,
22    /// Try a primary provider followed by explicit fallback providers.
23    Named {
24        /// Primary provider candidate.
25        primary: ProviderName,
26        /// Ordered fallback provider candidates.
27        fallbacks: Vec<ProviderName>,
28    },
29}
30
31impl ProviderSelection {
32    /// Creates an automatic provider selection.
33    ///
34    /// # Returns
35    /// Automatic provider selection.
36    #[inline]
37    pub fn auto() -> Self {
38        Self::Auto
39    }
40
41    /// Creates a named provider selection without fallbacks.
42    ///
43    /// # Parameters
44    /// - `primary`: Primary provider name.
45    ///
46    /// # Returns
47    /// Named provider selection.
48    ///
49    /// # Errors
50    /// Returns [`ProviderRegistryError`] when `primary` is not a valid provider
51    /// name.
52    #[inline]
53    pub fn named(primary: &str) -> Result<Self, ProviderRegistryError> {
54        Ok(Self::Named {
55            primary: ProviderName::new(primary)?,
56            fallbacks: Vec::new(),
57        })
58    }
59
60    /// Creates a named provider selection from borrowed fallback names.
61    ///
62    /// # Parameters
63    /// - `primary`: Primary provider name.
64    /// - `fallbacks`: Ordered fallback provider names.
65    ///
66    /// # Returns
67    /// Named provider selection.
68    ///
69    /// # Errors
70    /// Returns [`ProviderRegistryError`] when `primary` or any fallback is not a
71    /// valid provider name.
72    #[inline]
73    pub fn from_names(primary: &str, fallbacks: &[&str]) -> Result<Self, ProviderRegistryError> {
74        Ok(Self::Named {
75            primary: ProviderName::new(primary)?,
76            fallbacks: normalize_borrowed_names(fallbacks)?,
77        })
78    }
79
80    /// Creates a named provider selection from owned fallback names.
81    ///
82    /// # Parameters
83    /// - `primary`: Primary provider name.
84    /// - `fallbacks`: Ordered fallback provider names.
85    ///
86    /// # Returns
87    /// Named provider selection.
88    ///
89    /// # Errors
90    /// Returns [`ProviderRegistryError`] when `primary` or any fallback is not a
91    /// valid provider name.
92    #[inline]
93    pub fn from_owned_names(
94        primary: &str,
95        fallbacks: &[String],
96    ) -> Result<Self, ProviderRegistryError> {
97        Ok(Self::Named {
98            primary: ProviderName::new(primary)?,
99            fallbacks: normalize_owned_names(fallbacks)?,
100        })
101    }
102
103    /// Tells whether this selection requests automatic selection.
104    ///
105    /// # Returns
106    /// `true` when this selection is [`ProviderSelection::Auto`].
107    #[inline]
108    pub fn is_auto(&self) -> bool {
109        matches!(self, Self::Auto)
110    }
111
112    /// Gets the primary provider for named selections.
113    ///
114    /// # Returns
115    /// `Some` primary provider for named selections, or `None` for automatic
116    /// selection.
117    #[inline]
118    pub fn primary(&self) -> Option<&ProviderName> {
119        match self {
120            Self::Auto => None,
121            Self::Named { primary, .. } => Some(primary),
122        }
123    }
124
125    /// Gets ordered fallback provider names.
126    ///
127    /// # Returns
128    /// Fallback provider names, or an empty slice for automatic selection.
129    #[inline]
130    pub fn fallbacks(&self) -> &[ProviderName] {
131        match self {
132            Self::Auto => &[],
133            Self::Named { fallbacks, .. } => fallbacks,
134        }
135    }
136}
137
138impl Default for ProviderSelection {
139    /// Creates an automatic provider selection.
140    #[inline]
141    fn default() -> Self {
142        Self::Auto
143    }
144}
145
146/// Normalizes owned provider names.
147///
148/// # Parameters
149/// - `names`: Raw provider names.
150///
151/// # Returns
152/// Normalized provider names.
153///
154/// # Errors
155/// Returns [`ProviderRegistryError`] when any provider name is invalid.
156fn normalize_owned_names(names: &[String]) -> Result<Vec<ProviderName>, ProviderRegistryError> {
157    names
158        .iter()
159        .map(String::as_str)
160        .map(ProviderName::new)
161        .collect()
162}
163
164/// Normalizes borrowed provider names.
165///
166/// # Parameters
167/// - `names`: Raw provider names.
168///
169/// # Returns
170/// Normalized provider names.
171///
172/// # Errors
173/// Returns [`ProviderRegistryError`] when any provider name is invalid.
174fn normalize_borrowed_names(names: &[&str]) -> Result<Vec<ProviderName>, ProviderRegistryError> {
175    names.iter().copied().map(ProviderName::new).collect()
176}