1#![allow(clippy::many_single_char_names)]
2
3use super::*;
4
5/// A globally unique identifier ([GUID](https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid))
6/// used to identify COM and WinRT interfaces.
7#[repr(C)]
8#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
9pub struct GUID {
10 pub data1: u32,
11 pub data2: u16,
12 pub data3: u16,
13 pub data4: [u8; 8],
14}
15
16impl GUID {
17 /// Creates a unique `GUID` value.
18 pub fn new() -> Result<Self> {
19 unsafe { imp::CoCreateGuid() }
20 }
21
22 /// Creates a `GUID` represented by the all-zero byte-pattern.
23 pub const fn zeroed() -> Self {
24 Self { data1: 0, data2: 0, data3: 0, data4: [0, 0, 0, 0, 0, 0, 0, 0] }
25 }
26
27 /// Creates a `GUID` with the given constant values.
28 pub const fn from_values(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
29 Self { data1, data2, data3, data4 }
30 }
31
32 /// Creates a `GUID` from a `u128` value.
33 pub const fn from_u128(uuid: u128) -> Self {
34 Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() }
35 }
36
37 /// Converts a `GUID` to a `u128` value.
38 pub const fn to_u128(&self) -> u128 {
39 ((self.data1 as u128) << 96) + ((self.data2 as u128) << 80) + ((self.data3 as u128) << 64) + u64::from_be_bytes(self.data4) as u128
40 }
41
42 /// Creates a `GUID` for a "generic" WinRT type.
43 pub const fn from_signature(signature: imp::ConstBuffer) -> Self {
44 let data = imp::ConstBuffer::from_slice(&[0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee]);
45
46 let data = data.push_other(signature);
47
48 let bytes = imp::sha1(&data).bytes();
49 let first = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
50
51 let second = u16::from_be_bytes([bytes[4], bytes[5]]);
52 let mut third = u16::from_be_bytes([bytes[6], bytes[7]]);
53 third = (third & 0x0fff) | (5 << 12);
54 let fourth = (bytes[8] & 0x3f) | 0x80;
55
56 Self::from_values(first, second, third, [fourth, bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]])
57 }
58}
59
60impl RuntimeType for GUID {
61 const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"g16");
62}
63
64impl TypeKind for GUID {
65 type TypeKind = CopyType;
66}
67
68impl std::fmt::Debug for GUID {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 write!(f, "{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}", self.data1, self.data2, self.data3, self.data4[0], self.data4[1], self.data4[2], self.data4[3], self.data4[4], self.data4[5], self.data4[6], self.data4[7])
71 }
72}
73
74impl std::convert::From<&str> for GUID {
75 fn from(value: &str) -> Self {
76 assert!(value.len() == 36, "Invalid GUID string");
77 let mut bytes = value.bytes();
78
79 let a = ((bytes.next_u32() * 16 + bytes.next_u32()) << 24) + ((bytes.next_u32() * 16 + bytes.next_u32()) << 16) + ((bytes.next_u32() * 16 + bytes.next_u32()) << 8) + bytes.next_u32() * 16 + bytes.next_u32();
80 assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
81 let b = ((bytes.next_u16() * 16 + (bytes.next_u16())) << 8) + bytes.next_u16() * 16 + bytes.next_u16();
82 assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
83 let c = ((bytes.next_u16() * 16 + bytes.next_u16()) << 8) + bytes.next_u16() * 16 + bytes.next_u16();
84 assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
85 let d = bytes.next_u8() * 16 + bytes.next_u8();
86 let e = bytes.next_u8() * 16 + bytes.next_u8();
87 assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
88
89 let f = bytes.next_u8() * 16 + bytes.next_u8();
90 let g = bytes.next_u8() * 16 + bytes.next_u8();
91 let h = bytes.next_u8() * 16 + bytes.next_u8();
92 let i = bytes.next_u8() * 16 + bytes.next_u8();
93 let j = bytes.next_u8() * 16 + bytes.next_u8();
94 let k = bytes.next_u8() * 16 + bytes.next_u8();
95
96 Self::from_values(a, b, c, [d, e, f, g, h, i, j, k])
97 }
98}
99
100impl std::convert::From<u128> for GUID {
101 fn from(value: u128) -> Self {
102 Self::from_u128(uuid:value)
103 }
104}
105
106impl std::convert::From<GUID> for u128 {
107 fn from(value: GUID) -> Self {
108 value.to_u128()
109 }
110}
111
112trait HexReader {
113 fn next_u8(&mut self) -> u8;
114 fn next_u16(&mut self) -> u16;
115 fn next_u32(&mut self) -> u32;
116}
117
118impl HexReader for std::str::Bytes<'_> {
119 fn next_u8(&mut self) -> u8 {
120 let value: u8 = self.next().unwrap();
121 match value {
122 b'0'..=b'9' => value - b'0',
123 b'A'..=b'F' => 10 + value - b'A',
124 b'a'..=b'f' => 10 + value - b'a',
125 _ => panic!(),
126 }
127 }
128
129 fn next_u16(&mut self) -> u16 {
130 self.next_u8().into()
131 }
132
133 fn next_u32(&mut self) -> u32 {
134 self.next_u8().into()
135 }
136}
137