1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use crate::util::{byte_to_ascii_hex_lower, parse_byte_from_ascii_str_at};
10 use crate::GuidFromStrError;
11 use core::fmt::{self, Display, Formatter};
12 use core::str::{self, FromStr};
13 
14 #[cfg(feature = "serde")]
15 use {
16     serde::de::{self, Visitor},
17     serde::{Deserialize, Deserializer, Serialize, Serializer},
18 };
19 
20 #[cfg(feature = "bytemuck")]
21 use bytemuck::{Pod, Zeroable};
22 
23 /// Globally-unique identifier.
24 ///
25 /// The format is defined in [RFC 4122]. However, unlike "normal" UUIDs
26 /// (such as those provided by the [`uuid`] crate), the first three
27 /// fields are little-endian. See also [Appendix A] of the UEFI
28 /// Specification.
29 ///
30 /// This type is 4-byte aligned. The UEFI Specification says the GUID
31 /// type should be 8-byte aligned, but most C implementations have
32 /// 4-byte alignment, so we do the same here for compatibility.
33 ///
34 /// [Appendix A]: https://uefi.org/specs/UEFI/2.10/Apx_A_GUID_and_Time_Formats.html
35 /// [RFC 4122]: https://datatracker.ietf.org/doc/html/rfc4122
36 /// [`uuid`]: https://docs.rs/uuid/latest/uuid
37 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
38 #[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
39 #[repr(C)]
40 pub struct Guid {
41     // Use `u32` rather than `[u8; 4]` here so that the natural
42     // alignment of the struct is four bytes. This is better for the end
43     // user than setting `repr(align(4))` because it doesn't prevent use
44     // of the type in a `repr(packed)` struct. For more discussion, see
45     // https://github.com/rust-lang/rfcs/pull/1358#issuecomment-217582887
46     time_low: u32,
47     time_mid: [u8; 2],
48     time_high_and_version: [u8; 2],
49     clock_seq_high_and_reserved: u8,
50     clock_seq_low: u8,
51     node: [u8; 6],
52 }
53 
54 impl Guid {
55     /// GUID with all fields set to zero.
56     pub const ZERO: Self = Self {
57         time_low: 0,
58         time_mid: [0, 0],
59         time_high_and_version: [0, 0],
60         clock_seq_high_and_reserved: 0,
61         clock_seq_low: 0,
62         node: [0; 6],
63     };
64 
65     /// Create a new GUID.
66     #[must_use]
new( time_low: [u8; 4], time_mid: [u8; 2], time_high_and_version: [u8; 2], clock_seq_high_and_reserved: u8, clock_seq_low: u8, node: [u8; 6], ) -> Self67     pub const fn new(
68         time_low: [u8; 4],
69         time_mid: [u8; 2],
70         time_high_and_version: [u8; 2],
71         clock_seq_high_and_reserved: u8,
72         clock_seq_low: u8,
73         node: [u8; 6],
74     ) -> Self {
75         Self {
76             time_low: u32::from_ne_bytes([
77                 time_low[0],
78                 time_low[1],
79                 time_low[2],
80                 time_low[3],
81             ]),
82             time_mid: [time_mid[0], time_mid[1]],
83             time_high_and_version: [
84                 time_high_and_version[0],
85                 time_high_and_version[1],
86             ],
87             clock_seq_high_and_reserved,
88             clock_seq_low,
89             node,
90         }
91     }
92 
93     /// Create a version 4 GUID from provided random bytes.
94     ///
95     /// See [RFC 4122 section 4.4][rfc] for the definition of a version
96     /// 4 GUID.
97     ///
98     /// This constructor does not itself generate random bytes, but
99     /// instead expects the caller to provide suitably random bytes.
100     ///
101     /// # Example
102     ///
103     /// ```
104     /// use uguid::{Guid, Variant};
105     ///
106     /// let guid = Guid::from_random_bytes([
107     ///     104, 192, 95, 215, 120, 33, 249, 1, 102, 21, 171, 84, 233, 204, 68, 176,
108     /// ]);
109     /// assert_eq!(guid.variant(), Variant::Rfc4122);
110     /// assert_eq!(guid.version(), 4);
111     /// ```
112     ///
113     /// [rfc]: https://datatracker.ietf.org/doc/html/rfc4122#section-4.4
114     #[must_use]
from_random_bytes(mut random_bytes: [u8; 16]) -> Self115     pub const fn from_random_bytes(mut random_bytes: [u8; 16]) -> Self {
116         // Set the variant in byte 8: set bit 7, clear bit 6.
117         random_bytes[8] &= 0b1011_1111;
118         random_bytes[8] |= 0b1000_0000;
119         // Set the version in byte 7: set the most-significant-nibble to 4.
120         random_bytes[7] &= 0b0000_1111;
121         random_bytes[7] |= 0b0100_1111;
122 
123         Self::from_bytes(random_bytes)
124     }
125 
126     /// True if all bits are zero, false otherwise.
127     ///
128     /// # Example
129     ///
130     /// ```
131     /// use uguid::guid;
132     ///
133     /// assert!(guid!("00000000-0000-0000-0000-000000000000").is_zero());
134     /// assert!(!guid!("308bbc16-a308-47e8-8977-5e5646c5291f").is_zero());
135     /// ```
136     #[must_use]
is_zero(self) -> bool137     pub const fn is_zero(self) -> bool {
138         let b = self.to_bytes();
139         b[0] == 0
140             && b[1] == 0
141             && b[2] == 0
142             && b[3] == 0
143             && b[4] == 0
144             && b[5] == 0
145             && b[6] == 0
146             && b[7] == 0
147             && b[8] == 0
148             && b[9] == 0
149             && b[10] == 0
150             && b[11] == 0
151             && b[12] == 0
152             && b[13] == 0
153             && b[14] == 0
154             && b[15] == 0
155     }
156 
157     /// The little-endian low field of the timestamp.
158     #[must_use]
time_low(self) -> [u8; 4]159     pub const fn time_low(self) -> [u8; 4] {
160         self.time_low.to_ne_bytes()
161     }
162 
163     /// The little-endian middle field of the timestamp.
164     #[must_use]
time_mid(self) -> [u8; 2]165     pub const fn time_mid(self) -> [u8; 2] {
166         self.time_mid
167     }
168 
169     /// The little-endian high field of the timestamp multiplexed with
170     /// the version number.
171     #[must_use]
time_high_and_version(self) -> [u8; 2]172     pub const fn time_high_and_version(self) -> [u8; 2] {
173         self.time_high_and_version
174     }
175 
176     /// The high field of the clock sequence multiplexed with the
177     /// variant.
178     #[must_use]
clock_seq_high_and_reserved(self) -> u8179     pub const fn clock_seq_high_and_reserved(self) -> u8 {
180         self.clock_seq_high_and_reserved
181     }
182 
183     /// The low field of the clock sequence.
184     #[must_use]
clock_seq_low(self) -> u8185     pub const fn clock_seq_low(self) -> u8 {
186         self.clock_seq_low
187     }
188 
189     /// The spatially unique node identifier.
190     #[must_use]
node(self) -> [u8; 6]191     pub const fn node(self) -> [u8; 6] {
192         self.node
193     }
194 
195     /// Get the GUID variant.
196     ///
197     /// # Example
198     ///
199     /// ```
200     /// use uguid::{guid, Variant};
201     ///
202     /// assert_eq!(
203     ///     guid!("308bbc16-a308-47e8-8977-5e5646c5291f").variant(),
204     ///     Variant::Rfc4122
205     /// );
206     /// ```
207     #[must_use]
variant(self) -> Variant208     pub const fn variant(self) -> Variant {
209         // Get the 3 most significant bits of `clock_seq_high_and_reserved`.
210         let bits = (self.clock_seq_high_and_reserved & 0b1110_0000) >> 5;
211 
212         if (bits & 0b100) == 0 {
213             Variant::ReservedNcs
214         } else if (bits & 0b010) == 0 {
215             Variant::Rfc4122
216         } else if (bits & 0b001) == 0 {
217             Variant::ReservedMicrosoft
218         } else {
219             Variant::ReservedFuture
220         }
221     }
222 
223     /// Get the GUID version. This is a sub-type of the variant as
224     /// defined in [RFC4122].
225     ///
226     /// [RFC4122]: https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.3
227     ///
228     /// # Example
229     ///
230     /// ```
231     /// use uguid::guid;
232     ///
233     /// assert_eq!(guid!("308bbc16-a308-47e8-8977-5e5646c5291f").version(), 4);
234     /// ```
235     #[must_use]
version(self) -> u8236     pub const fn version(self) -> u8 {
237         (self.time_high_and_version[1] & 0b1111_0000) >> 4
238     }
239 
240     /// Parse a GUID from a string.
241     ///
242     /// This is functionally the same as [`Self::from_str`], but is
243     /// exposed separately to provide a `const` method for parsing.
try_parse(s: &str) -> Result<Self, GuidFromStrError>244     pub const fn try_parse(s: &str) -> Result<Self, GuidFromStrError> {
245         // Treat input as ASCII.
246         let s = s.as_bytes();
247 
248         if s.len() != 36 {
249             return Err(GuidFromStrError::Length);
250         }
251 
252         let sep = b'-';
253         if s[8] != sep {
254             return Err(GuidFromStrError::Separator(8));
255         }
256         if s[13] != sep {
257             return Err(GuidFromStrError::Separator(13));
258         }
259         if s[18] != sep {
260             return Err(GuidFromStrError::Separator(18));
261         }
262         if s[23] != sep {
263             return Err(GuidFromStrError::Separator(23));
264         }
265 
266         Ok(Self::from_bytes([
267             mtry!(parse_byte_from_ascii_str_at(s, 6)),
268             mtry!(parse_byte_from_ascii_str_at(s, 4)),
269             mtry!(parse_byte_from_ascii_str_at(s, 2)),
270             mtry!(parse_byte_from_ascii_str_at(s, 0)),
271             mtry!(parse_byte_from_ascii_str_at(s, 11)),
272             mtry!(parse_byte_from_ascii_str_at(s, 9)),
273             mtry!(parse_byte_from_ascii_str_at(s, 16)),
274             mtry!(parse_byte_from_ascii_str_at(s, 14)),
275             mtry!(parse_byte_from_ascii_str_at(s, 19)),
276             mtry!(parse_byte_from_ascii_str_at(s, 21)),
277             mtry!(parse_byte_from_ascii_str_at(s, 24)),
278             mtry!(parse_byte_from_ascii_str_at(s, 26)),
279             mtry!(parse_byte_from_ascii_str_at(s, 28)),
280             mtry!(parse_byte_from_ascii_str_at(s, 30)),
281             mtry!(parse_byte_from_ascii_str_at(s, 32)),
282             mtry!(parse_byte_from_ascii_str_at(s, 34)),
283         ]))
284     }
285 
286     /// Parse a GUID from a string, panicking on failure.
287     ///
288     /// The input must be in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
289     /// format, where each `x` is a hex digit (any of `0-9`, `a-f`, or
290     /// `A-F`).
291     ///
292     /// This function is marked `track_caller` so that error messages
293     /// point directly to the invalid GUID string.
294     ///
295     /// # Panics
296     ///
297     /// This function will panic if the input is not in the format shown
298     /// above. In particular, it will panic if the input is not exactly
299     /// 36 bytes long, or if the input does not have separators at the
300     /// expected positions, or if any of the remaining characters are
301     /// not valid hex digits.
302     #[must_use]
303     #[track_caller]
parse_or_panic(s: &str) -> Self304     pub const fn parse_or_panic(s: &str) -> Self {
305         match Self::try_parse(s) {
306             Ok(g) => g,
307             Err(GuidFromStrError::Length) => {
308                 panic!("GUID string has wrong length (expected 36 bytes)");
309             }
310             Err(GuidFromStrError::Separator(_)) => {
311                 panic!("GUID string is missing one or more separators (`-`)");
312             }
313             Err(GuidFromStrError::Hex(_)) => {
314                 panic!("GUID string contains one or more invalid characters");
315             }
316         }
317     }
318 
319     /// Create a GUID from a 16-byte array. No changes to byte order are made.
320     #[must_use]
from_bytes(bytes: [u8; 16]) -> Self321     pub const fn from_bytes(bytes: [u8; 16]) -> Self {
322         Self::new(
323             [bytes[0], bytes[1], bytes[2], bytes[3]],
324             [bytes[4], bytes[5]],
325             [bytes[6], bytes[7]],
326             bytes[8],
327             bytes[9],
328             [
329                 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
330                 bytes[15],
331             ],
332         )
333     }
334 
335     /// Convert to a 16-byte array.
336     #[must_use]
to_bytes(self) -> [u8; 16]337     pub const fn to_bytes(self) -> [u8; 16] {
338         let time_low = self.time_low();
339 
340         [
341             time_low[0],
342             time_low[1],
343             time_low[2],
344             time_low[3],
345             self.time_mid[0],
346             self.time_mid[1],
347             self.time_high_and_version[0],
348             self.time_high_and_version[1],
349             self.clock_seq_high_and_reserved,
350             self.clock_seq_low,
351             self.node[0],
352             self.node[1],
353             self.node[2],
354             self.node[3],
355             self.node[4],
356             self.node[5],
357         ]
358     }
359 
360     /// Convert to a lower-case hex ASCII string.
361     ///
362     /// The output is in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" format.
363     #[must_use]
to_ascii_hex_lower(self) -> [u8; 36]364     pub const fn to_ascii_hex_lower(self) -> [u8; 36] {
365         let bytes = self.to_bytes();
366 
367         let mut buf = [0; 36];
368         (buf[0], buf[1]) = byte_to_ascii_hex_lower(bytes[3]);
369         (buf[2], buf[3]) = byte_to_ascii_hex_lower(bytes[2]);
370         (buf[4], buf[5]) = byte_to_ascii_hex_lower(bytes[1]);
371         (buf[6], buf[7]) = byte_to_ascii_hex_lower(bytes[0]);
372         buf[8] = b'-';
373         (buf[9], buf[10]) = byte_to_ascii_hex_lower(bytes[5]);
374         (buf[11], buf[12]) = byte_to_ascii_hex_lower(bytes[4]);
375         buf[13] = b'-';
376         (buf[14], buf[15]) = byte_to_ascii_hex_lower(bytes[7]);
377         (buf[16], buf[17]) = byte_to_ascii_hex_lower(bytes[6]);
378         buf[18] = b'-';
379         (buf[19], buf[20]) = byte_to_ascii_hex_lower(bytes[8]);
380         (buf[21], buf[22]) = byte_to_ascii_hex_lower(bytes[9]);
381         buf[23] = b'-';
382         (buf[24], buf[25]) = byte_to_ascii_hex_lower(bytes[10]);
383         (buf[26], buf[27]) = byte_to_ascii_hex_lower(bytes[11]);
384         (buf[28], buf[29]) = byte_to_ascii_hex_lower(bytes[12]);
385         (buf[30], buf[31]) = byte_to_ascii_hex_lower(bytes[13]);
386         (buf[32], buf[33]) = byte_to_ascii_hex_lower(bytes[14]);
387         (buf[34], buf[35]) = byte_to_ascii_hex_lower(bytes[15]);
388         buf
389     }
390 }
391 
392 impl Default for Guid {
default() -> Self393     fn default() -> Self {
394         Self::ZERO
395     }
396 }
397 
398 impl Display for Guid {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result399     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
400         let ascii = self.to_ascii_hex_lower();
401         // OK to unwrap since the ascii output is valid utf-8.
402         let s = str::from_utf8(&ascii).unwrap();
403         f.write_str(s)
404     }
405 }
406 
407 impl FromStr for Guid {
408     type Err = GuidFromStrError;
409 
410     /// Parse a GUID from a string, panicking on failure.
411     ///
412     /// The input must be in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
413     /// format, where each `x` is a hex digit (any of `0-9`, `a-f`, or
414     /// `A-F`).
from_str(s: &str) -> Result<Self, Self::Err>415     fn from_str(s: &str) -> Result<Self, Self::Err> {
416         Self::try_parse(s)
417     }
418 }
419 
420 #[cfg(feature = "serde")]
421 impl Serialize for Guid {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,422     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
423     where
424         S: Serializer,
425     {
426         let ascii = self.to_ascii_hex_lower();
427         // OK to unwrap since the ascii output is valid utf-8.
428         let s = str::from_utf8(&ascii).unwrap();
429         serializer.serialize_str(s)
430     }
431 }
432 
433 #[cfg(feature = "serde")]
434 struct DeserializerVisitor;
435 
436 #[cfg(feature = "serde")]
437 impl<'de> Visitor<'de> for DeserializerVisitor {
438     type Value = Guid;
439 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result440     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
441         formatter.write_str(
442             "a string in the format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"",
443         )
444     }
445 
visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error,446     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
447     where
448         E: de::Error,
449     {
450         Guid::try_parse(value).map_err(E::custom)
451     }
452 }
453 
454 #[cfg(feature = "serde")]
455 impl<'de> Deserialize<'de> for Guid {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,456     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
457     where
458         D: Deserializer<'de>,
459     {
460         deserializer.deserialize_str(DeserializerVisitor)
461     }
462 }
463 
464 /// Variant or type of GUID, as defined in [RFC4122].
465 ///
466 /// [RFC4122]: https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.3
467 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
468 pub enum Variant {
469     /// Reserved, NCS backward compatibility.
470     ReservedNcs,
471 
472     /// The GUID variant described by RFC4122.
473     Rfc4122,
474 
475     /// Reserved, Microsoft Corporation backward compatibility.
476     ReservedMicrosoft,
477 
478     /// Reserved for future use.
479     ReservedFuture,
480 }
481