1 | use 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)] |
7 | pub 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 | |
21 | impl 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 | |
93 | impl RuntimeType for GUID { |
94 | const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"g16" ); |
95 | } |
96 | |
97 | impl TypeKind for GUID { |
98 | type TypeKind = CopyType; |
99 | } |
100 | |
101 | impl 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 | |
121 | impl 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 | |
148 | impl From<u128> for GUID { |
149 | fn from(value: u128) -> Self { |
150 | Self::from_u128(uuid:value) |
151 | } |
152 | } |
153 | |
154 | impl From<GUID> for u128 { |
155 | fn from(value: GUID) -> Self { |
156 | value.to_u128() |
157 | } |
158 | } |
159 | |
160 | fn invalid_guid() -> Error { |
161 | Error::from_hresult(code:imp::E_INVALIDARG) |
162 | } |
163 | |
164 | fn try_u32(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u32> { |
165 | next(bytes, 8, delimiter).ok_or_else(err:invalid_guid) |
166 | } |
167 | |
168 | fn 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 | |
174 | fn 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 | |
180 | fn 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 | |