Skip to main content

uuid/
parse.rs

1use crate::{Error, Uuid};
2
3impl std::str::FromStr for Uuid {
4    type Err = Error;
5
6    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
7        Uuid::parse_str(uuid_str)
8    }
9}
10
11impl TryFrom<&'_ str> for Uuid {
12    type Error = Error;
13
14    fn try_from(uuid_str: &'_ str) -> Result<Self, Self::Error> {
15        Uuid::parse_str(uuid_str)
16    }
17}
18
19const HEX_TABLE: &[u8; 256] = &{
20    let mut buf = [0; 256];
21    let mut i: u8 = 0;
22
23    loop {
24        buf[i as usize] = match i {
25            b'0'..=b'9' => i - b'0',
26            b'a'..=b'f' => i - b'a' + 10,
27            b'A'..=b'F' => i - b'A' + 10,
28            _ => 0xff,
29        };
30
31        if i == 255 {
32            break buf;
33        }
34
35        i += 1
36    }
37};
38
39const SHL4_TABLE: &[u8; 256] = &{
40    let mut buf = [0; 256];
41    let mut i: u8 = 0;
42
43    loop {
44        buf[i as usize] = i.wrapping_shl(4);
45
46        if i == 255 {
47            break buf;
48        }
49
50        i += 1;
51    }
52};
53
54#[inline]
55pub const fn parse_hyphenated(s: &[u8]) -> Result<[u8; 16], Error> {
56    // This length check here removes all other bounds
57    // checks in this function
58    if s.len() != 36 {
59        return Err(Error::InvalidUuid);
60    }
61
62    // We look at two hex-encoded values (4 chars) at a time because
63    // that's the size of the smallest group in a hyphenated UUID.
64    // The indexes we're interested in are:
65    //
66    // uuid     : 936da01f-9abd-4d9d-80c7-02af85c822a8
67    //            |   |   ||   ||   ||   ||   |   |
68    // hyphens  : |   |   8|  13|  18|  23|   |   |
69    // positions: 0   4    9   14   19   24  28  32
70
71    // First, ensure the hyphens appear in the right places
72    match [s[8], s[13], s[18], s[23]] {
73        [b'-', b'-', b'-', b'-'] => {}
74        _ => return Err(Error::InvalidUuid),
75    }
76
77    let positions: [u8; 8] = [0, 4, 9, 14, 19, 24, 28, 32];
78    let mut buf: [u8; 16] = [0; 16];
79    let mut j = 0;
80
81    while j < 8 {
82        let i = positions[j];
83
84        // The decoding here is the same as the simple case
85        // We're just dealing with two values instead of one
86        let h1 = HEX_TABLE[s[i as usize] as usize];
87        let h2 = HEX_TABLE[s[(i + 1) as usize] as usize];
88        let h3 = HEX_TABLE[s[(i + 2) as usize] as usize];
89        let h4 = HEX_TABLE[s[(i + 3) as usize] as usize];
90
91        if h1 | h2 | h3 | h4 == 0xff {
92            return Err(Error::InvalidUuid);
93        }
94
95        buf[j * 2] = SHL4_TABLE[h1 as usize] | h2;
96        buf[j * 2 + 1] = SHL4_TABLE[h3 as usize] | h4;
97        j += 1;
98    }
99
100    Ok(buf)
101}