1 | #![allow (clippy::many_single_char_names)] |
2 | |
3 | use 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)] |
9 | pub struct GUID { |
10 | pub data1: u32, |
11 | pub data2: u16, |
12 | pub data3: u16, |
13 | pub data4: [u8; 8], |
14 | } |
15 | |
16 | impl 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 | |
60 | impl RuntimeType for GUID { |
61 | const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"g16" ); |
62 | } |
63 | |
64 | impl TypeKind for GUID { |
65 | type TypeKind = CopyType; |
66 | } |
67 | |
68 | impl 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 | |
74 | impl 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 | |
100 | impl std::convert::From<u128> for GUID { |
101 | fn from(value: u128) -> Self { |
102 | Self::from_u128(uuid:value) |
103 | } |
104 | } |
105 | |
106 | impl std::convert::From<GUID> for u128 { |
107 | fn from(value: GUID) -> Self { |
108 | value.to_u128() |
109 | } |
110 | } |
111 | |
112 | trait HexReader { |
113 | fn next_u8(&mut self) -> u8; |
114 | fn next_u16(&mut self) -> u16; |
115 | fn next_u32(&mut self) -> u32; |
116 | } |
117 | |
118 | impl 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 | |