use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub struct MontyUuid(#[serde(with = "serde_bytes")] [u8; 16]);
impl MontyUuid {
#[must_use]
pub const fn from_bytes(bytes: [u8; 16]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn from_u128(v: u128) -> Self {
Self(v.to_be_bytes())
}
#[must_use]
pub const fn from_random_bytes(mut bytes: [u8; 16]) -> Self {
bytes[6] = (bytes[6] & 0x0f) | 0x40; bytes[8] = (bytes[8] & 0x3f) | 0x80; Self(bytes)
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; 16] {
&self.0
}
#[must_use]
pub fn try_from_slice(bytes: &[u8]) -> Option<Self> {
<[u8; 16]>::try_from(bytes).ok().map(Self)
}
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
let raw = s.as_bytes();
if raw.len() != 36 || raw[8] != b'-' || raw[13] != b'-' || raw[18] != b'-' || raw[23] != b'-' {
return None;
}
let mut bytes = [0u8; 16];
let mut out = 0;
let mut i = 0;
while i < 36 {
if matches!(i, 8 | 13 | 18 | 23) {
i += 1;
continue;
}
let hi = hex_value(raw[i])?;
let lo = hex_value(raw[i + 1])?;
bytes[out] = (hi << 4) | lo;
out += 1;
i += 2;
}
Some(Self(bytes))
}
}
impl fmt::Display for MontyUuid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, byte) in self.0.iter().enumerate() {
if matches!(i, 4 | 6 | 8 | 10) {
f.write_str("-")?;
}
write!(f, "{byte:02x}")?;
}
Ok(())
}
}
const fn hex_value(c: u8) -> Option<u8> {
match c {
b'0'..=b'9' => Some(c - b'0'),
b'a'..=b'f' => Some(c - b'a' + 10),
b'A'..=b'F' => Some(c - b'A' + 10),
_ => None,
}
}