use std::borrow::Borrow; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::id_unchecked::IdUnchecked; use crate::invalid_id::InvalidId; pub const SYSTEM_ID: Id<&'static str> = Id("x_system"); #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Id = String>(S); impl> Id { pub fn try_from(value: S) -> Result { if value .as_ref() .chars() .all(|c| c.is_ascii_lowercase() || c == '-') { Ok(Id(value)) } else { Err(InvalidId) } } } impl<'a> Id<&'a str> { pub fn owned(&self) -> Id { Id(self.0.to_owned()) } } impl From for String { fn from(value: Id) -> Self { value.0 } } impl> std::ops::Deref for Id { type Target = S; fn deref(&self) -> &Self::Target { &self.0 } } impl> std::fmt::Display for Id { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_ref()) } } impl> AsRef for Id { fn as_ref(&self) -> &str { self.0.as_ref() } } impl> Borrow for Id { fn borrow(&self) -> &str { self.0.as_ref() } } impl<'de, S> Deserialize<'de> for Id where S: AsRef, IdUnchecked: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let unchecked: IdUnchecked = Deserialize::deserialize(deserializer)?; Id::try_from(unchecked.0).map_err(serde::de::Error::custom) } } impl> Serialize for Id { fn serialize(&self, serializer: Ser) -> Result where Ser: Serializer, { serializer.serialize_str(self.as_ref()) } }