Skip to main content

rustbasic_core/
uuid.rs

1#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2pub struct Uuid(String);
3
4impl Uuid {
5    /// Generate a new version-4 UUID, setting version to 4 and variant to 1.
6    pub fn new_v4() -> Self {
7        use rand::Rng;
8        let mut bytes = [0u8; 16];
9        rand::rng().fill_bytes(&mut bytes);
10        bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4
11        bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 1
12
13        let s = format!(
14            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
15            bytes[0], bytes[1], bytes[2], bytes[3],
16            bytes[4], bytes[5],
17            bytes[6], bytes[7],
18            bytes[8], bytes[9],
19            bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
20        );
21        Self(s)
22    }
23
24    /// Parse and validate a UUID string
25    pub fn parse_str(s: &str) -> Result<Self, &'static str> {
26        if s.len() != 36 {
27            return Err("Invalid length");
28        }
29        let bytes = s.as_bytes();
30        for (i, &b) in bytes.iter().enumerate() {
31            if i == 8 || i == 13 || i == 18 || i == 23 {
32                if b != b'-' {
33                    return Err("Invalid separator");
34                }
35            } else {
36                if !b.is_ascii_hexdigit() {
37                    return Err("Invalid character");
38                }
39            }
40        }
41        Ok(Self(s.to_string()))
42    }
43}
44
45impl std::fmt::Display for Uuid {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        write!(f, "{}", self.0)
48    }
49}