Skip to main content

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}