#[cfg(not(feature = "std"))]
use alloc::format;
use crate::{Name, pname::PrefixedName};
use core::str::FromStr;
use strum::{EnumIs, EnumTryAs};
#[cfg(feature = "genid")]
use crate::error::Error;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, EnumIs, EnumTryAs)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[allow(missing_docs)] pub enum IriRef {
Iri(Iri),
PrefixedName(PrefixedName),
}
pub type Iri = url::Url;
pub trait IriExtra {
fn with_new_path<S>(&self, path: S) -> Self
where
S: AsRef<str>;
fn with_new_fragment<S>(&self, fragment: S) -> Self
where
S: AsRef<str>;
fn with_empty_fragment(&self) -> Self;
fn with_no_fragment(&self) -> Self;
fn looks_like_namespace(&self) -> bool;
fn split(&self) -> Option<(Self, Name)>
where
Self: Sized;
fn namespace(&self) -> Option<Self>
where
Self: Sized,
{
self.split().map(|(u, _)| u)
}
fn name(&self) -> Option<Name>
where
Self: Sized,
{
self.split().map(|(_, n)| n)
}
fn make_name(&self, name: Name) -> Option<Self>
where
Self: Sized;
#[cfg(feature = "genid")]
fn genid(&self) -> Result<Self, Error>
where
Self: Sized;
}
impl From<Iri> for IriRef {
fn from(value: Iri) -> Self {
Self::Iri(value)
}
}
impl From<&Iri> for IriRef {
fn from(value: &Iri) -> Self {
Self::from(value.clone())
}
}
impl From<PrefixedName> for IriRef {
fn from(value: PrefixedName) -> Self {
Self::PrefixedName(value)
}
}
impl From<&PrefixedName> for IriRef {
fn from(value: &PrefixedName) -> Self {
Self::from(value.clone())
}
}
impl IriExtra for Iri {
fn with_new_path<S>(&self, path: S) -> Self
where
S: AsRef<str>,
{
let mut new_self = self.clone();
new_self.set_path(path.as_ref());
new_self
}
fn with_new_fragment<S>(&self, fragment: S) -> Self
where
S: AsRef<str>,
{
let mut new_self = self.clone();
new_self.set_fragment(Some(fragment.as_ref()));
new_self
}
fn with_empty_fragment(&self) -> Self {
self.with_new_fragment("")
}
fn with_no_fragment(&self) -> Self {
let mut new_self = self.clone();
new_self.set_fragment(None);
new_self
}
fn looks_like_namespace(&self) -> bool {
self.fragment() == Some("") || (self.path().ends_with("/") && self.query().is_none())
}
fn split(&self) -> Option<(Self, Name)>
where
Self: Sized,
{
if self.fragment().map(|s| !s.is_empty()).unwrap_or_default() {
if let Ok(name) = Name::from_str(self.fragment().unwrap()) {
Some((self.with_empty_fragment(), name))
} else {
None
}
} else if !self.path().is_empty() && !self.path().ends_with("/") && self.query().is_none() {
if let Ok(name) = Name::from_str(self.path_segments().unwrap().last().unwrap()) {
let path = self.path();
let path = &path[0..path.len() - name.as_ref().len()];
Some((self.with_new_path(path), name))
} else {
None
}
} else {
None
}
}
fn make_name(&self, name: Name) -> Option<Self>
where
Self: Sized,
{
if self.fragment().is_some() {
Some(self.with_new_fragment(name.as_ref()))
} else if self.path().ends_with("/") && self.query().is_none() {
Some(self.with_new_path(format!("{}{}", self.path(), name.as_ref())))
} else {
None
}
}
#[cfg(feature = "genid")]
fn genid(&self) -> Result<Self, Error>
where
Self: Sized,
{
let new_uuid = uuid::Uuid::new_v4();
let new_uuid = new_uuid
.simple()
.encode_lower(&mut uuid::Uuid::encode_buffer())
.to_string();
let path = format!("/.well-known/genid/{new_uuid}");
self.join(&path).map_err(|e| e.into())
}
}