Skip to main content

ferroui_microcom/
guid.rs

1use std::fmt;
2
3/// Binary-compatible with the `GUID` struct declared in `com.h`.
4#[repr(C)]
5#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
6pub struct Guid {
7    pub data1: u32,
8    pub data2: u16,
9    pub data3: u16,
10    pub data4: [u8; 8],
11}
12
13impl Guid {
14    pub const ZERO: Guid = Guid::new(0, 0, 0, [0; 8]);
15
16    pub const fn new(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
17        Guid { data1, data2, data3, data4 }
18    }
19
20    /// Builds a GUID from its 128-bit big-endian textual value, e.g.
21    /// `Guid::from_u128(0x809c652e_7396_11d2_9771_00a0c9b4d50c)`.
22    pub const fn from_u128(v: u128) -> Self {
23        let b = v.to_be_bytes();
24        Guid {
25            data1: u32::from_be_bytes([b[0], b[1], b[2], b[3]]),
26            data2: u16::from_be_bytes([b[4], b[5]]),
27            data3: u16::from_be_bytes([b[6], b[7]]),
28            data4: [b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]],
29        }
30    }
31
32    /// Parses `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` (braces optional).
33    pub fn parse(s: &str) -> Option<Guid> {
34        let s = s.trim().trim_start_matches('{').trim_end_matches('}');
35        let hex: String = s.chars().filter(|c| *c != '-').collect();
36        if hex.len() != 32 || s.len() != 36 {
37            return None;
38        }
39        u128::from_str_radix(&hex, 16).ok().map(Guid::from_u128)
40    }
41
42    /// The value the native library actually materializes for this IID.
43    ///
44    /// `com.h`'s `__IID_DEF` macro (kept as it is in the native sources) initializes
45    /// `Data4` as `{d41, d42, d42, d42, d42, d42, d42, d42}` — the second
46    /// byte is repeated instead of using bytes 3..8. Native `QueryInterface`
47    /// implementations `memcmp` against those constants, so when talking to
48    /// the native side this is the IID that matches.
49    pub const fn as_com_h_materialized(&self) -> Guid {
50        let d = self.data4;
51        Guid {
52            data1: self.data1,
53            data2: self.data2,
54            data3: self.data3,
55            data4: [d[0], d[1], d[1], d[1], d[1], d[1], d[1], d[1]],
56        }
57    }
58}
59
60impl fmt::Display for Guid {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        let d = &self.data4;
63        write!(
64            f,
65            "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
66            self.data1, self.data2, self.data3, d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]
67        )
68    }
69}
70
71impl fmt::Debug for Guid {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "Guid({self})")
74    }
75}