const ALPHABET: &[u8; 64] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
const fn reverse_table() -> [i8; 256] {
let mut table = [-1i8; 256];
let mut i = 0;
while i < 64 {
table[ALPHABET[i] as usize] = i as i8;
i += 1;
}
table
}
const REVERSE: [i8; 256] = reverse_table();
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Guid([u8; 22]);
impl Guid {
pub fn parse(text: &str) -> Option<Self> {
let bytes = text.as_bytes();
if bytes.len() != 22 {
return None;
}
if bytes.iter().any(|&b| REVERSE[b as usize] < 0) {
return None;
}
if REVERSE[bytes[0] as usize] > 3 {
return None;
}
let mut buf = [0u8; 22];
buf.copy_from_slice(bytes);
Some(Self(buf))
}
pub fn as_str(&self) -> &str {
std::str::from_utf8(&self.0).expect("alphabet is ASCII by construction")
}
pub fn from_uuid(uuid: [u8; 16]) -> Self {
let mut num = 0u128;
for b in uuid {
num = (num << 8) | b as u128;
}
let mut out = [b'0'; 22];
let mut n = num;
for slot in out.iter_mut().rev() {
*slot = ALPHABET[(n & 0x3f) as usize];
n >>= 6;
}
Self(out)
}
pub fn to_uuid(self) -> [u8; 16] {
let mut num = 0u128;
for &b in &self.0 {
num = (num << 6) | (REVERSE[b as usize] as u128);
}
let mut out = [0u8; 16];
for (i, slot) in out.iter_mut().enumerate() {
*slot = ((num >> (8 * (15 - i))) & 0xff) as u8;
}
out
}
}
impl std::fmt::Display for Guid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rejects_wrong_length_and_foreign_characters() {
assert!(Guid::parse("tooshort").is_none());
assert!(Guid::parse("0123456789ABCDEFGHIJ+/").is_none());
}
#[test]
fn accepts_a_real_globalid_from_the_fixture_corpus() {
assert!(Guid::parse("2O2Fr$t4X7Zf8NOew3FLOH").is_some());
}
#[test]
fn uuid_roundtrip_is_lossless() {
let uuid: [u8; 16] = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x32, 0x10,
];
assert_eq!(Guid::from_uuid(uuid).to_uuid(), uuid);
}
#[test]
fn rejects_a_leading_digit_beyond_the_uuid_range() {
for leading in ALPHABET.iter().skip(4) {
let mut text = [b'0'; 22];
text[0] = *leading;
let text = std::str::from_utf8(&text).unwrap();
assert!(Guid::parse(text).is_none(), "{text} was accepted");
}
for leading in b"0123" {
let mut text = [b'$'; 22];
text[0] = *leading;
assert!(Guid::parse(std::str::from_utf8(&text).unwrap()).is_some());
}
assert!(Guid::parse("4000000000000000000000").is_none());
assert!(Guid::parse("$$$$$$$$$$$$$$$$$$$$$$").is_none());
}
#[test]
fn the_uuid_range_ends_at_the_leading_digit_three() {
assert_eq!(Guid::from_uuid([0; 16]).as_str(), "0000000000000000000000");
assert_eq!(
Guid::from_uuid([0xff; 16]).as_str(),
"3$$$$$$$$$$$$$$$$$$$$$"
);
}
#[test]
fn every_accepted_text_roundtrips_through_the_uuid() {
let base = *b"2O2Fr$t4X7Zf8NOew3FLOH";
let mut checked = 0;
for position in 0..22 {
for &digit in ALPHABET {
let mut text = base;
text[position] = digit;
let text = std::str::from_utf8(&text).unwrap();
if let Some(guid) = Guid::parse(text) {
assert_eq!(Guid::from_uuid(guid.to_uuid()), guid, "{text}");
checked += 1;
}
}
}
assert_eq!(checked, 21 * 64 + 4);
}
#[test]
fn text_roundtrip_is_lossless() {
let g = Guid::parse("2O2Fr$t4X7Zf8NOew3FLOH").unwrap();
assert_eq!(Guid::from_uuid(g.to_uuid()), g);
}
}