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