hresult/
lib.rs

1//! See: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
2
3/// The HRESULT numbering space is vendor-extensible. Vendors can supply their own values for this field, as long as the C bit (`0x20000000`) is set, indicating it is a customer code.
4///
5/// The HRESULT numbering space has the following internal structure. Any protocol that uses NTSTATUS values on the wire is responsible for stating the order in which the bytes are placed on the wire.
6pub struct HRESULT(i32);
7
8impl std::fmt::Debug for HRESULT {
9    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
10        f.debug_struct("HRESULT")
11            .field("s", &self.s()) // as 0/1?
12            .field("r", &self.r()) // as 0/1?
13            .field("c", &self.c()) // as 0/1?
14            .field("n", &self.n()) // as 0/1?
15            .field("x", &self.x()) // as 0/1?
16            .field("facility", &self.facility()) // as hex?
17            .field("code", &self.code()) // as hex?
18            .finish()
19    }
20}
21
22impl std::fmt::Display for HRESULT {
23    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
24        write!(f, "{:#08X}", self.0)
25    }
26}
27
28impl From<i32> for HRESULT {
29    fn from(val: i32) -> Self {
30        HRESULT(val)
31    }
32}
33
34impl From<u32> for HRESULT {
35    fn from(val: u32) -> Self {
36        HRESULT(val as i32)
37    }
38}
39
40impl HRESULT {
41    pub fn is_success(&self) -> bool {
42        self.s()
43    }
44
45    pub fn is_customer(&self) -> bool {
46        self.c()
47    }
48
49    /// Severity. If set, indicates a failure result. If clear, indicates a success result.
50    pub fn s(&self) -> bool {
51        self.0 >= 0
52    }
53
54    /// Reserved. If the N bit is clear, this bit MUST be set to 0. If the N bit is set, this bit is defined by the NTSTATUS numbering space (as specified in section 2.3).
55    pub fn r(&self) -> bool {
56        self.0 & 0b0100_0000_0000_0000_0000_0000_0000_0000 != 0
57    }
58
59    /// Customer. This bit specifies if the value is customer-defined or Microsoft-defined. The bit is set for customer-defined values and clear for Microsoft-defined values. <1>
60    pub fn c(&self) -> bool {
61        self.0 & 0b0010_0000_0000_0000_0000_0000_0000_0000 != 0
62    }
63
64    /// If set, indicates that the error code is an NTSTATUS value (as specified in section 2.3), except that this bit is set.
65    pub fn n(&self) -> bool {
66        self.0 & 0b0001_0000_0000_0000_0000_0000_0000_0000 != 0
67    }
68
69    /// Reserved. SHOULD be set to 0. <2>
70    pub fn x(&self) -> bool {
71        self.0 & 0b0000_1000_0000_0000_0000_0000_0000_0000 != 0
72    }
73
74    /// An indicator of the source of the error. New facilities are occasionally added by Microsoft.
75    pub fn facility(&self) -> u16 {
76        (self.0 >> 16) as u16 & 0b0000_0111_1111_1111
77    }
78
79    pub fn code(&self) -> u16 {
80        self.0 as u16
81    }
82}
83
84#[allow(clippy::unreadable_literal)]
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn simple() {
91        let hr: HRESULT = 0x80070005_u32.into();
92        assert!(!hr.s());
93        assert!(!hr.r());
94        assert!(!hr.c());
95        assert!(!hr.n());
96        assert!(!hr.x());
97        assert_eq!(hr.facility(), 0x7);
98        assert_eq!(hr.code(), 0x5);
99
100        let hr: HRESULT = 0x80004005_u32.into();
101        assert!(!hr.s());
102        assert!(!hr.r());
103        assert!(!hr.c());
104        assert!(!hr.n());
105        assert!(!hr.x());
106        assert_eq!(hr.facility(), 0x0);
107        assert_eq!(hr.code(), 0x4005);
108    }
109}