1use core::fmt;
15
16#[derive(Copy, Clone, PartialEq, Eq, Hash)]
22#[repr(transparent)]
23pub struct HResult(pub i32);
24
25impl HResult {
26 pub const S_OK: Self = Self(0);
28 pub const S_FALSE: Self = Self(1);
31
32 pub const E_NOTIMPL: Self = Self(0x8000_4001_u32 as i32);
34 pub const E_NOINTERFACE: Self = Self(0x8000_4002_u32 as i32);
37 pub const E_POINTER: Self = Self(0x8000_4003_u32 as i32);
39 pub const E_FAIL: Self = Self(0x8000_4005_u32 as i32);
41 pub const E_UNEXPECTED: Self = Self(0x8000_FFFF_u32 as i32);
43 pub const E_OUTOFMEMORY: Self = Self(0x8007_000E_u32 as i32);
45 pub const E_INVALIDARG: Self = Self(0x8007_0057_u32 as i32);
47
48 pub const CLASS_E_CLASSNOTAVAILABLE: Self = Self(0x8004_0111_u32 as i32);
51 pub const CLASS_E_NOAGGREGATION: Self = Self(0x8004_0110_u32 as i32);
53
54 pub const APOERR_INVALID_INPUT_DATA: Self = Self(0x8889_0001_u32 as i32);
57 pub const APOERR_FORMAT_NOT_SUPPORTED: Self = Self(0x8889_0008_u32 as i32);
60 pub const APOERR_INVALID_API_VERSION: Self = Self(0x8889_0007_u32 as i32);
63 pub const APOERR_NUM_CONNECTIONS_INVALID: Self = Self(0x8889_000B_u32 as i32);
66 pub const APOERR_NOT_LOCKED: Self = Self(0x8889_000A_u32 as i32);
69 pub const APOERR_ALREADY_LOCKED: Self = Self(0x8889_0006_u32 as i32);
71
72 #[inline]
74 #[must_use]
75 pub const fn is_ok(self) -> bool {
76 self.0 >= 0
77 }
78
79 #[inline]
81 #[must_use]
82 pub const fn is_err(self) -> bool {
83 self.0 < 0
84 }
85
86 #[inline]
89 pub const fn ok(self) -> Result<(), Self> {
90 if self.is_ok() {
91 Ok(())
92 } else {
93 Err(self)
94 }
95 }
96}
97
98impl fmt::Debug for HResult {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(f, "HResult(0x{:08X})", self.0 as u32)
101 }
102}
103
104impl fmt::Display for HResult {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "HRESULT 0x{:08X}", self.0 as u32)
107 }
108}
109
110impl From<i32> for HResult {
111 #[inline]
112 fn from(value: i32) -> Self {
113 Self(value)
114 }
115}
116
117impl From<HResult> for i32 {
118 #[inline]
119 fn from(value: HResult) -> Self {
120 value.0
121 }
122}
123
124#[cfg(windows)]
125impl From<windows_core::HRESULT> for HResult {
126 #[inline]
127 fn from(value: windows_core::HRESULT) -> Self {
128 Self(value.0)
129 }
130}
131
132#[cfg(windows)]
133impl From<HResult> for windows_core::HRESULT {
134 #[inline]
135 fn from(value: HResult) -> Self {
136 Self(value.0)
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn success_codes_classify_correctly() {
146 assert!(HResult::S_OK.is_ok());
147 assert!(!HResult::S_OK.is_err());
148 assert!(HResult::S_FALSE.is_ok());
149 assert!(!HResult::S_FALSE.is_err());
150 }
151
152 #[test]
153 fn failure_codes_classify_correctly() {
154 assert!(HResult::E_FAIL.is_err());
155 assert!(!HResult::E_FAIL.is_ok());
156 assert!(HResult::E_INVALIDARG.is_err());
157 assert!(HResult::APOERR_FORMAT_NOT_SUPPORTED.is_err());
158 assert!(HResult::APOERR_INVALID_INPUT_DATA.is_err());
159 assert!(HResult::CLASS_E_CLASSNOTAVAILABLE.is_err());
160 }
161
162 #[test]
163 fn ok_method_converts_to_result() {
164 assert_eq!(HResult::S_OK.ok(), Ok(()));
165 assert_eq!(HResult::S_FALSE.ok(), Ok(()));
166 assert_eq!(HResult::E_FAIL.ok(), Err(HResult::E_FAIL));
167 }
168
169 #[test]
170 fn raw_constant_values_match_microsoft_definitions() {
171 assert_eq!(HResult::E_NOTIMPL.0 as u32, 0x8000_4001);
174 assert_eq!(HResult::E_POINTER.0 as u32, 0x8000_4003);
175 assert_eq!(HResult::E_OUTOFMEMORY.0 as u32, 0x8007_000E);
176 assert_eq!(HResult::E_INVALIDARG.0 as u32, 0x8007_0057);
177 assert_eq!(HResult::CLASS_E_CLASSNOTAVAILABLE.0 as u32, 0x8004_0111);
178 }
179
180 #[test]
181 fn debug_formatting_is_hex() {
182 let s = format!("{:?}", HResult::E_INVALIDARG);
183 assert_eq!(s, "HResult(0x80070057)");
184 }
185}