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