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}