use regex::Regex;
use std::sync::LazyLock;
#[allow(clippy::unwrap_used)]
static RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^https://[^/?#]+/[^/?#]+/[^/?#]+").unwrap());
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) struct Url<'a>(&'a str);
impl<'a> Url<'a> {
pub(crate) fn as_str(&self) -> &'a str {
self.0
}
pub(crate) fn leak(self) -> Url<'static> {
Url(self.0.to_owned().leak())
}
#[allow(clippy::unwrap_used)]
pub(crate) fn shorten(self) -> Option<Self> {
RE.captures(self.0)
.map(|captures| captures.get(0).unwrap().as_str().into())
}
pub(crate) fn trim_trailing_slash(self) -> Self {
self.0.strip_suffix('/').map_or(self, Self::from)
}
}
impl std::fmt::Display for Url<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_str().fmt(f)
}
}
impl<'a> From<&'a str> for Url<'a> {
fn from(value: &'a str) -> Self {
Self(value)
}
}
pub(crate) fn urls(pkg: &cargo_metadata::Package) -> impl IntoIterator<Item = Url<'_>> {
let mut urls = Vec::new();
if let Some(url_string) = &pkg.repository {
let url = Url::from(url_string.as_str()).trim_trailing_slash();
urls.push(url);
if let Some(shortened_url) = url.shorten()
&& url != shortened_url
{
urls.push(shortened_url);
}
}
urls
}