Skip to main content

MatiOS_SDK_Rust/
uuid.rs

1use core::error;
2use core::result;
3
4
5pub struct Uuid([u8; 16]);
6
7#[macro_export]
8macro_rules! uuid {
9    ($uuid:expr) => {{
10        const OUTPUT: $crate::Uuid = match $crate::Uuid::try_parse($uuid) {
11            $crate::__macro_support::Ok(u) => u,
12            $crate::__macro_support::Err(_) => panic!("invalid UUID"),
13        };
14        OUTPUT
15    }};
16}
17impl Uuid {
18    pub const fn as_u128(&self) -> u128 {
19        u128::from_be_bytes(*self.as_bytes())
20    }
21
22    #[inline]
23    pub const fn as_bytes(&self) -> &[u8; 16] {
24        &self.0
25    }
26
27    #[inline]
28    pub const fn into_bytes(self) -> [u8; 16] {
29        self.0
30    }
31
32    pub fn parse_str(input: &str) -> Result<Uuid, u8> {
33        try_parse(input.as_bytes())
34            .map(Uuid::from_bytes)
35            .map_err(|_|1)
36    }
37
38    // pub const fn from_u128(v: u128) -> Self {
39    //     Uuid::from_bytes(v.to_be_bytes())
40    // }
41
42    #[inline]
43    pub const fn from_bytes(bytes: [u8; 16]) -> Uuid {
44        Uuid(bytes)
45    }
46    #[inline]
47    pub const fn from_u128(number: u128) -> Uuid {
48        Uuid(u128::to_be_bytes(number))
49    }
50
51    pub fn to_string(&self) -> alloc::string::String {
52        return alloc::string::String::from("Todo");
53    }
54}
55
56const fn try_parse(input: &'_ [u8]) -> Result<[u8; 16], u8> {
57    match (input.len(), input) {
58        // Inputs of 32 bytes must be a non-hyphenated UUID
59        (32, s) => parse_simple(s, true),
60        // Hyphenated UUIDs may be wrapped in various ways:
61        // - `{UUID}` for braced UUIDs
62        // - `urn:uuid:UUID` for URNs
63        // - `UUID` for a regular hyphenated UUID
64        (36, s)
65        | (38, [b'{', s @ .., b'}'])
66        | (45, [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..]) => {
67            parse_hyphenated(s)
68        }
69        // Any other shaped input is immediately invalid
70        _ => Err(1),
71    }
72}
73
74#[inline]
75#[allow(dead_code)]
76pub(crate) const fn parse_braced(input: &'_ [u8]) -> Result<[u8; 16], u8> {
77    if let (38, [b'{', s @ .., b'}']) = (input.len(), input) {
78        parse_hyphenated(s)
79    } else {
80        Err(1)
81    }
82}
83
84#[inline]
85#[allow(dead_code)]
86pub(crate) const fn parse_urn(input: &'_ [u8]) -> Result<[u8; 16], u8> {
87    if let (45, [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..]) =
88        (input.len(), input)
89    {
90        parse_hyphenated(s)
91    } else {
92        Err(1)
93    }
94}
95
96#[inline]
97pub(crate) const fn parse_simple(
98    s: &'_ [u8],
99    speculative: bool,
100) -> Result<[u8; 16], u8> {
101    // This length check here removes all other bounds
102    // checks in this function
103    if s.len() != 32 {
104        return Err(1);
105    }
106
107    let mut buf: [u8; 16] = [0; 16];
108    let mut i = 0;
109
110    while i < 16 {
111        // Convert a two-char hex value (like `A8`)
112        // into a byte (like `10101000`)
113        let h1 = HEX_TABLE[s[i * 2] as usize];
114        let h2 = HEX_TABLE[s[i * 2 + 1] as usize];
115
116        // We use `0xff` as a sentinel value to indicate
117        // an invalid hex character sequence (like the letter `G`)
118        if h1 | h2 == 0xff {
119            return Err(1);
120        }
121
122        // The upper nibble needs to be shifted into position
123        // to produce the final byte value
124        buf[i] = SHL4_TABLE[h1 as usize] | h2;
125        i += 1;
126    }
127
128    Ok(buf)
129}
130
131#[inline]
132pub(crate) const fn parse_hyphenated(s: &'_ [u8]) -> Result<[u8; 16], u8> {
133    // This length check here removes all other bounds
134    // checks in this function
135    if s.len() != 36 {
136        return Err(1);
137    }
138
139    // We look at two hex-encoded values (4 chars) at a time because
140    // that's the size of the smallest group in a hyphenated UUID.
141    // The indexes we're interested in are:
142    //
143    // uuid     : 936da01f-9abd-4d9d-80c7-02af85c822a8
144    //            |   |   ||   ||   ||   ||   |   |
145    // hyphens  : |   |   8|  13|  18|  23|   |   |
146    // positions: 0   4    9   14   19   24  28  32
147
148    // First, ensure the hyphens appear in the right places
149    match [s[8], s[13], s[18], s[23]] {
150        [b'-', b'-', b'-', b'-'] => {}
151        _ => return Err(1),
152    }
153
154    let positions: [u8; 8] = [0, 4, 9, 14, 19, 24, 28, 32];
155    let mut buf: [u8; 16] = [0; 16];
156    let mut j = 0;
157
158    while j < 8 {
159        let i = positions[j];
160
161        // The decoding here is the same as the simple case
162        // We're just dealing with two values instead of one
163        let h1 = HEX_TABLE[s[i as usize] as usize];
164        let h2 = HEX_TABLE[s[(i + 1) as usize] as usize];
165        let h3 = HEX_TABLE[s[(i + 2) as usize] as usize];
166        let h4 = HEX_TABLE[s[(i + 3) as usize] as usize];
167
168        if h1 | h2 | h3 | h4 == 0xff {
169            return Err(1);
170        }
171
172        buf[j * 2] = SHL4_TABLE[h1 as usize] | h2;
173        buf[j * 2 + 1] = SHL4_TABLE[h3 as usize] | h4;
174        j += 1;
175    }
176
177    Ok(buf)
178}
179
180
181const HEX_TABLE: &[u8; 256] = &{
182    let mut buf = [0; 256];
183    let mut i: u8 = 0;
184
185    loop {
186        buf[i as usize] = match i {
187            b'0'..=b'9' => i - b'0',
188            b'a'..=b'f' => i - b'a' + 10,
189            b'A'..=b'F' => i - b'A' + 10,
190            _ => 0xff,
191        };
192
193        if i == 255 {
194            break buf;
195        }
196
197        i += 1
198    }
199};
200
201const SHL4_TABLE: &[u8; 256] = &{
202    let mut buf = [0; 256];
203    let mut i: u8 = 0;
204
205    loop {
206        buf[i as usize] = i.wrapping_shl(4);
207
208        if i == 255 {
209            break buf;
210        }
211
212        i += 1;
213    }
214};
215
216impl Clone for Uuid {
217    fn clone(&self) -> Self {
218        Uuid::from_u128(self.as_u128())
219    }
220}