qubit_spi/provider_descriptor.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//! Provider metadata captured by registries.
11
12use std::collections::HashSet;
13
14use crate::{
15 ProviderName,
16 ProviderRegistryError,
17};
18
19/// Stable provider metadata used for registration and selection.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct ProviderDescriptor {
22 /// Canonical provider id.
23 id: ProviderName,
24 /// Additional accepted provider aliases.
25 aliases: Vec<ProviderName>,
26 /// Priority used by automatic selection.
27 priority: i32,
28}
29
30impl ProviderDescriptor {
31 /// Creates a descriptor with no aliases and zero priority.
32 ///
33 /// # Parameters
34 /// - `id`: Provider id.
35 ///
36 /// # Returns
37 /// Provider descriptor.
38 ///
39 /// # Errors
40 /// Returns [`ProviderRegistryError`] when `id` is not a valid provider name.
41 #[inline]
42 pub fn new(id: &str) -> Result<Self, ProviderRegistryError> {
43 Ok(Self {
44 id: ProviderName::new(id)?,
45 aliases: Vec::new(),
46 priority: 0,
47 })
48 }
49
50 /// Sets provider aliases.
51 ///
52 /// # Parameters
53 /// - `aliases`: Provider aliases.
54 ///
55 /// # Returns
56 /// Updated provider descriptor.
57 ///
58 /// # Errors
59 /// Returns [`ProviderRegistryError`] when any alias is not a valid provider
60 /// name, or when aliases duplicate the descriptor id or each other.
61 #[inline]
62 pub fn with_aliases(mut self, aliases: &[&str]) -> Result<Self, ProviderRegistryError> {
63 let aliases = aliases
64 .iter()
65 .map(|alias| ProviderName::new(alias))
66 .collect::<Result<Vec<_>, _>>()?;
67 validate_unique_names(&self.id, &aliases)?;
68 self.aliases = aliases;
69 Ok(self)
70 }
71
72 /// Sets provider priority.
73 ///
74 /// # Parameters
75 /// - `priority`: Provider priority. Larger values are preferred.
76 ///
77 /// # Returns
78 /// Updated provider descriptor.
79 #[inline]
80 pub fn with_priority(mut self, priority: i32) -> Self {
81 self.priority = priority;
82 self
83 }
84
85 /// Gets the canonical provider id.
86 ///
87 /// # Returns
88 /// Provider id.
89 #[inline]
90 pub fn id(&self) -> &ProviderName {
91 &self.id
92 }
93
94 /// Gets provider aliases.
95 ///
96 /// # Returns
97 /// Provider aliases.
98 #[inline]
99 pub fn aliases(&self) -> &[ProviderName] {
100 &self.aliases
101 }
102
103 /// Gets provider aliases as string slices.
104 ///
105 /// # Returns
106 /// Provider aliases as normalized string slices.
107 #[inline]
108 pub fn aliases_as_str(&self) -> Vec<&str> {
109 self.aliases.iter().map(ProviderName::as_str).collect()
110 }
111
112 /// Gets provider priority.
113 ///
114 /// # Returns
115 /// Provider priority.
116 #[inline]
117 pub fn priority(&self) -> i32 {
118 self.priority
119 }
120
121 /// Iterates over the provider id followed by aliases.
122 ///
123 /// # Returns
124 /// Iterator over all normalized names exposed by this descriptor.
125 #[inline]
126 pub(crate) fn names(&self) -> impl Iterator<Item = &ProviderName> {
127 std::iter::once(&self.id).chain(self.aliases.iter())
128 }
129}
130
131/// Validates that descriptor names are internally unique.
132///
133/// # Parameters
134/// - `id`: Canonical provider id.
135/// - `aliases`: Normalized provider aliases.
136///
137/// # Errors
138/// Returns [`ProviderRegistryError::DuplicateProviderName`] when an alias
139/// duplicates the id or another alias.
140fn validate_unique_names(
141 id: &ProviderName,
142 aliases: &[ProviderName],
143) -> Result<(), ProviderRegistryError> {
144 let mut names = HashSet::with_capacity(aliases.len() + 1);
145 names.insert(id.clone());
146 for alias in aliases {
147 if !names.insert(alias.clone()) {
148 return Err(ProviderRegistryError::DuplicateProviderName {
149 name: alias.clone(),
150 });
151 }
152 }
153 Ok(())
154}