use std::collections::HashSet;
use crate::{
ProviderName,
ProviderRegistryError,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProviderSelection {
Auto,
Named {
primary: ProviderName,
fallbacks: Vec<ProviderName>,
},
}
impl ProviderSelection {
#[inline]
pub fn auto() -> Self {
Self::Auto
}
#[inline]
pub fn named(primary: &str) -> Result<Self, ProviderRegistryError> {
Ok(Self::Named {
primary: ProviderName::new(primary)?,
fallbacks: Vec::new(),
})
}
#[inline]
pub fn from_names(primary: &str, fallbacks: &[&str]) -> Result<Self, ProviderRegistryError> {
let primary = ProviderName::new(primary)?;
let fallbacks = normalize_borrowed_names(fallbacks)?;
validate_unique_candidate_names(&primary, &fallbacks)?;
Ok(Self::Named { primary, fallbacks })
}
#[inline]
pub fn from_owned_names(
primary: &str,
fallbacks: &[String],
) -> Result<Self, ProviderRegistryError> {
let primary = ProviderName::new(primary)?;
let fallbacks = normalize_owned_names(fallbacks)?;
validate_unique_candidate_names(&primary, &fallbacks)?;
Ok(Self::Named { primary, fallbacks })
}
#[inline]
pub fn is_auto(&self) -> bool {
matches!(self, Self::Auto)
}
#[inline]
pub fn primary(&self) -> Option<&ProviderName> {
match self {
Self::Auto => None,
Self::Named { primary, .. } => Some(primary),
}
}
#[inline]
pub fn fallbacks(&self) -> &[ProviderName] {
match self {
Self::Auto => &[],
Self::Named { fallbacks, .. } => fallbacks,
}
}
pub(crate) fn validate_unique_names(&self) -> Result<(), ProviderRegistryError> {
match self {
Self::Auto => Ok(()),
Self::Named { primary, fallbacks } => {
validate_unique_candidate_names(primary, fallbacks)
}
}
}
}
impl Default for ProviderSelection {
#[inline]
fn default() -> Self {
Self::Auto
}
}
fn normalize_owned_names(names: &[String]) -> Result<Vec<ProviderName>, ProviderRegistryError> {
names
.iter()
.map(String::as_str)
.map(ProviderName::new)
.collect()
}
fn normalize_borrowed_names(names: &[&str]) -> Result<Vec<ProviderName>, ProviderRegistryError> {
names.iter().copied().map(ProviderName::new).collect()
}
fn validate_unique_candidate_names(
primary: &ProviderName,
fallbacks: &[ProviderName],
) -> Result<(), ProviderRegistryError> {
let mut names = HashSet::with_capacity(fallbacks.len() + 1);
names.insert(primary.clone());
for fallback in fallbacks {
if !names.insert(fallback.clone()) {
return Err(ProviderRegistryError::DuplicateProviderCandidate {
name: fallback.clone(),
});
}
}
Ok(())
}