reddb_server/crypto/
uuid.rs1use crate::crypto::os_random;
2use std::fmt;
3
4#[derive(Clone, Copy, Eq, PartialEq, Hash)]
5pub struct Uuid([u8; 16]);
6
7#[derive(Debug, Clone, Copy, Eq, PartialEq)]
8pub struct UuidParseError;
9
10impl Uuid {
11 pub fn new_v4() -> Self {
12 let mut bytes = [0u8; 16];
13 os_random::fill_bytes(&mut bytes).expect("OS CSPRNG unavailable");
14
15 bytes[6] = (bytes[6] & 0x0f) | 0x40;
16 bytes[8] = (bytes[8] & 0x3f) | 0x80;
17
18 Self(bytes)
19 }
20
21 pub fn new_v7() -> Self {
27 let ms = crate::utils::now_unix_millis();
28 let mut rand = [0u8; 10];
29 os_random::fill_bytes(&mut rand).expect("OS CSPRNG unavailable");
30
31 let mut bytes = [0u8; 16];
32 bytes[0] = ((ms >> 40) & 0xFF) as u8;
33 bytes[1] = ((ms >> 32) & 0xFF) as u8;
34 bytes[2] = ((ms >> 24) & 0xFF) as u8;
35 bytes[3] = ((ms >> 16) & 0xFF) as u8;
36 bytes[4] = ((ms >> 8) & 0xFF) as u8;
37 bytes[5] = (ms & 0xFF) as u8;
38 bytes[6] = (rand[0] & 0x0F) | 0x70;
39 bytes[7] = rand[1];
40 bytes[8] = (rand[2] & 0x3F) | 0x80;
41 bytes[9..16].copy_from_slice(&rand[3..10]);
42
43 Self(bytes)
44 }
45
46 pub fn parse_str(s: &str) -> Result<Self, UuidParseError> {
48 let normalized: String = s.chars().filter(|&c| c != '-').collect();
49 if normalized.len() != 32 {
50 return Err(UuidParseError);
51 }
52 let mut bytes = [0u8; 16];
53 for i in 0..16 {
54 bytes[i] = u8::from_str_radix(&normalized[i * 2..i * 2 + 2], 16)
55 .map_err(|_| UuidParseError)?;
56 }
57 Ok(Self(bytes))
58 }
59
60 pub fn as_bytes(&self) -> &[u8; 16] {
61 &self.0
62 }
63}
64
65impl fmt::Display for Uuid {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 let b = self.0;
68 write!(
69 f,
70 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
71 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11],
72 b[12], b[13], b[14], b[15]
73 )
74 }
75}
76
77impl fmt::Debug for Uuid {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 fmt::Display::fmt(self, f)
80 }
81}