use std::fmt;
use std::str::FromStr;
use uuid::Uuid;
use crate::errors::DecodeError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NamespaceId(Uuid);
impl NamespaceId {
pub const DNS: Self = Self(Uuid::from_u128(0x6ba7_b810_9dad_11d1_80b4_00c0_4fd4_30c8));
pub const URL: Self = Self(Uuid::from_u128(0x6ba7_b811_9dad_11d1_80b4_00c0_4fd4_30c8));
pub const OID: Self = Self(Uuid::from_u128(0x6ba7_b812_9dad_11d1_80b4_00c0_4fd4_30c8));
pub const X500: Self = Self(Uuid::from_u128(0x6ba7_b814_9dad_11d1_80b4_00c0_4fd4_30c8));
#[must_use]
#[inline]
pub const fn new(uuid: Uuid) -> Self {
Self(uuid)
}
#[must_use]
#[inline]
pub const fn as_uuid(&self) -> &Uuid {
&self.0
}
#[must_use]
#[inline]
pub const fn into_uuid(self) -> Uuid {
self.0
}
}
impl fmt::Display for NamespaceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<Uuid> for NamespaceId {
fn from(uuid: Uuid) -> Self {
Self::new(uuid)
}
}
impl From<NamespaceId> for Uuid {
fn from(namespace: NamespaceId) -> Self {
namespace.0
}
}
impl FromStr for NamespaceId {
type Err = DecodeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let uuid =
Uuid::parse_str(s).map_err(|_| DecodeError::InvalidNamespace(s.to_string()))?;
Ok(Self::new(uuid))
}
}
impl AsRef<Uuid> for NamespaceId {
fn as_ref(&self) -> &Uuid {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn namespace_dns_constant_matches_rfc4122() {
assert_eq!(
NamespaceId::DNS.to_string(),
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn namespace_url_constant_matches_rfc4122() {
assert_eq!(
NamespaceId::URL.to_string(),
"6ba7b811-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn namespace_oid_constant_matches_rfc4122() {
assert_eq!(
NamespaceId::OID.to_string(),
"6ba7b812-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn namespace_x500_constant_matches_rfc4122() {
assert_eq!(
NamespaceId::X500.to_string(),
"6ba7b814-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn from_str_valid_uuid() {
let result = NamespaceId::from_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
assert!(result.is_ok());
assert_eq!(result.unwrap(), NamespaceId::DNS);
}
#[test]
fn from_str_invalid_uuid() {
let result = NamespaceId::from_str("not-a-uuid");
assert!(result.is_err());
match result {
Err(DecodeError::InvalidNamespace(s)) => assert_eq!(s, "not-a-uuid"),
_ => panic!("Expected InvalidNamespace error"),
}
}
#[test]
fn display_formats_as_uuid() {
let namespace = NamespaceId::DNS;
assert_eq!(
format!("{namespace}"),
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn from_uuid_conversion() {
let uuid = Uuid::new_v4();
let namespace = NamespaceId::from(uuid);
assert_eq!(*namespace.as_uuid(), uuid);
}
#[test]
fn into_uuid_conversion() {
let namespace = NamespaceId::DNS;
let uuid: Uuid = namespace.into();
assert_eq!(uuid.to_string(), "6ba7b810-9dad-11d1-80b4-00c04fd430c8");
}
#[test]
fn as_ref_provides_uuid_reference() {
let namespace = NamespaceId::DNS;
let uuid_ref: &Uuid = namespace.as_ref();
assert_eq!(
uuid_ref.to_string(),
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn new_creates_namespace_from_uuid() {
let uuid = Uuid::new_v4();
let namespace = NamespaceId::new(uuid);
assert_eq!(namespace.into_uuid(), uuid);
}
#[test]
fn as_uuid_returns_reference() {
let namespace = NamespaceId::DNS;
assert_eq!(
namespace.as_uuid().to_string(),
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
);
}
#[test]
fn namespace_equality() {
let ns1 = NamespaceId::DNS;
let ns2 = NamespaceId::from_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap();
assert_eq!(ns1, ns2);
}
#[test]
fn namespace_inequality() {
assert_ne!(NamespaceId::DNS, NamespaceId::URL);
assert_ne!(NamespaceId::OID, NamespaceId::X500);
}
}