use std::fmt; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct InvalidOid; impl fmt::Display for InvalidOid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid object id") } } impl std::error::Error for InvalidOid {} #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[serde(transparent)] pub struct ObjectId(Box); impl ObjectId { pub fn from_hex(bytes: &[u8]) -> Result { let text = std::str::from_utf8(bytes).map_err(|_| InvalidOid)?; Self::parse(text) } pub fn parse(text: &str) -> Result { let text = text.trim(); if !matches!(text.len(), 40 | 64) || !text.bytes().all(|b| b.is_ascii_hexdigit()) { return Err(InvalidOid); } Ok(Self(text.to_ascii_lowercase().into_boxed_str())) } pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() } pub fn to_hex(&self) -> &str { &self.0 } pub fn as_str(&self) -> &str { &self.0 } pub fn short(&self, len: usize) -> &str { let end = len.min(self.0.len()); &self.0[..end] } } impl fmt::Display for ObjectId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } } impl fmt::Debug for ObjectId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ObjectId({})", self.0) } } impl std::str::FromStr for ObjectId { type Err = InvalidOid; fn from_str(s: &str) -> Result { Self::parse(s) } } impl AsRef for ObjectId { fn as_ref(&self) -> &str { &self.0 } }