use std::fmt::{self, Display, Formatter};
use rustc_hash::FxHashSet;
use url::Url;
use uv_redacted::DisplaySafeUrl;
#[derive(
Copy,
Clone,
Debug,
Default,
Hash,
Eq,
PartialEq,
Ord,
PartialOrd,
serde::Serialize,
serde::Deserialize,
)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum AuthPolicy {
#[default]
Auto,
Always,
Never,
}
impl Display for AuthPolicy {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Auto => write!(f, "auto"),
Self::Always => write!(f, "always"),
Self::Never => write!(f, "never"),
}
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Index {
pub url: DisplaySafeUrl,
pub root_url: DisplaySafeUrl,
pub auth_policy: AuthPolicy,
}
impl Index {
pub fn is_prefix_for(&self, url: &Url) -> bool {
if self.root_url.scheme() != url.scheme()
|| self.root_url.host_str() != url.host_str()
|| self.root_url.port_or_known_default() != url.port_or_known_default()
{
return false;
}
url.path().starts_with(self.root_url.path())
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Indexes(FxHashSet<Index>);
impl Indexes {
pub fn new() -> Self {
Self(FxHashSet::default())
}
pub fn from_indexes(urls: impl IntoIterator<Item = Index>) -> Self {
let mut index_urls = Self::new();
for url in urls {
index_urls.0.insert(url);
}
index_urls
}
pub fn index_for(&self, url: &Url) -> Option<&Index> {
self.find_prefix_index(url)
}
pub fn auth_policy_for(&self, url: &Url) -> AuthPolicy {
self.find_prefix_index(url)
.map(|index| index.auth_policy)
.unwrap_or(AuthPolicy::Auto)
}
fn find_prefix_index(&self, url: &Url) -> Option<&Index> {
self.0.iter().find(|&index| index.is_prefix_for(url))
}
}