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 #[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 (32, s) => parse_simple(s, true),
60 (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 _ => 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 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 let h1 = HEX_TABLE[s[i * 2] as usize];
114 let h2 = HEX_TABLE[s[i * 2 + 1] as usize];
115
116 if h1 | h2 == 0xff {
119 return Err(1);
120 }
121
122 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 if s.len() != 36 {
136 return Err(1);
137 }
138
139 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 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}