1use super::*;
2
3/// A globally unique identifier ([GUID](https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid))
4/// used to identify COM and WinRT interfaces.
5#[repr(C)]
6#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
7pub struct GUID {
8 /// Specifies the first 8 hexadecimal digits.
9 pub data1: u32,
10
11 /// Specifies the first group of 4 hexadecimal digits.
12 pub data2: u16,
13
14 /// Specifies the second group of 4 hexadecimal digits.
15 pub data3: u16,
16
17 /// The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits.
18 pub data4: [u8; 8],
19}
20
21impl GUID {
22 /// Creates a unique `GUID` value.
23 pub fn new() -> Result<Self> {
24 unsafe { imp::CoCreateGuid() }
25 }
26
27 /// Creates a `GUID` represented by the all-zero byte-pattern.
28 pub const fn zeroed() -> Self {
29 Self {
30 data1: 0,
31 data2: 0,
32 data3: 0,
33 data4: [0, 0, 0, 0, 0, 0, 0, 0],
34 }
35 }
36
37 /// Creates a `GUID` with the given constant values.
38 pub const fn from_values(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
39 Self {
40 data1,
41 data2,
42 data3,
43 data4,
44 }
45 }
46
47 /// Creates a `GUID` from a `u128` value.
48 pub const fn from_u128(uuid: u128) -> Self {
49 Self {
50 data1: (uuid >> 96) as u32,
51 data2: ((uuid >> 80) & 0xffff) as u16,
52 data3: ((uuid >> 64) & 0xffff) as u16,
53 data4: (uuid as u64).to_be_bytes(),
54 }
55 }
56
57 /// Converts a `GUID` to a `u128` value.
58 pub const fn to_u128(&self) -> u128 {
59 ((self.data1 as u128) << 96)
60 + ((self.data2 as u128) << 80)
61 + ((self.data3 as u128) << 64)
62 + u64::from_be_bytes(self.data4) as u128
63 }
64
65 /// Creates a `GUID` for a "generic" WinRT type.
66 pub const fn from_signature(signature: imp::ConstBuffer) -> Self {
67 let data = imp::ConstBuffer::from_slice(&[
68 0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16,
69 0xad, 0xee,
70 ]);
71
72 let data = data.push_other(signature);
73
74 let bytes = imp::sha1(&data).bytes();
75 let first = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
76
77 let second = u16::from_be_bytes([bytes[4], bytes[5]]);
78 let mut third = u16::from_be_bytes([bytes[6], bytes[7]]);
79 third = (third & 0x0fff) | (5 << 12);
80 let fourth = (bytes[8] & 0x3f) | 0x80;
81
82 Self::from_values(
83 first,
84 second,
85 third,
86 [
87 fourth, bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
88 ],
89 )
90 }
91}
92
93impl RuntimeType for GUID {
94 const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"g16");
95}
96
97impl TypeKind for GUID {
98 type TypeKind = CopyType;
99}
100
101impl core::fmt::Debug for GUID {
102 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103 write!(
104 f,
105 "{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}",
106 self.data1,
107 self.data2,
108 self.data3,
109 self.data4[0],
110 self.data4[1],
111 self.data4[2],
112 self.data4[3],
113 self.data4[4],
114 self.data4[5],
115 self.data4[6],
116 self.data4[7]
117 )
118 }
119}
120
121impl TryFrom<&str> for GUID {
122 type Error = Error;
123
124 fn try_from(from: &str) -> Result<Self> {
125 if from.len() != 36 {
126 return Err(invalid_guid());
127 }
128
129 let bytes = &mut from.bytes();
130 let mut guid = Self::zeroed();
131
132 guid.data1 = try_u32(bytes, true)?;
133 guid.data2 = try_u16(bytes, true)?;
134 guid.data3 = try_u16(bytes, true)?;
135 guid.data4[0] = try_u8(bytes, false)?;
136 guid.data4[1] = try_u8(bytes, true)?;
137 guid.data4[2] = try_u8(bytes, false)?;
138 guid.data4[3] = try_u8(bytes, false)?;
139 guid.data4[4] = try_u8(bytes, false)?;
140 guid.data4[5] = try_u8(bytes, false)?;
141 guid.data4[6] = try_u8(bytes, false)?;
142 guid.data4[7] = try_u8(bytes, false)?;
143
144 Ok(guid)
145 }
146}
147
148impl From<u128> for GUID {
149 fn from(value: u128) -> Self {
150 Self::from_u128(uuid:value)
151 }
152}
153
154impl From<GUID> for u128 {
155 fn from(value: GUID) -> Self {
156 value.to_u128()
157 }
158}
159
160fn invalid_guid() -> Error {
161 Error::from_hresult(code:imp::E_INVALIDARG)
162}
163
164fn try_u32(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u32> {
165 next(bytes, 8, delimiter).ok_or_else(err:invalid_guid)
166}
167
168fn try_u16(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u16> {
169 next(bytes, 4, delimiter)
170 .map(|value| value as u16)
171 .ok_or_else(err:invalid_guid)
172}
173
174fn try_u8(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u8> {
175 next(bytes, 2, delimiter)
176 .map(|value| value as u8)
177 .ok_or_else(err:invalid_guid)
178}
179
180fn next(bytes: &mut core::str::Bytes<'_>, len: usize, delimiter: bool) -> Option<u32> {
181 let mut value: u32 = 0;
182
183 for _ in 0..len {
184 let digit: u8 = bytes.next()?;
185
186 match digit {
187 b'0'..=b'9' => value = (value << 4) + (digit - b'0') as u32,
188 b'A'..=b'F' => value = (value << 4) + (digit - b'A' + 10) as u32,
189 b'a'..=b'f' => value = (value << 4) + (digit - b'a' + 10) as u32,
190 _ => return None,
191 }
192 }
193
194 if delimiter && bytes.next() != Some(b'-') {
195 None
196 } else {
197 Some(value)
198 }
199}
200