1 | use super::*; |
2 | |
3 | /// An error code value returned by most COM functions. |
4 | #[repr (transparent)] |
5 | #[derive (Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] |
6 | #[must_use ] |
7 | #[allow (non_camel_case_types)] |
8 | pub struct HRESULT(pub i32); |
9 | |
10 | impl HRESULT { |
11 | /// Returns [`true`] if `self` is a success code. |
12 | #[inline ] |
13 | pub const fn is_ok(self) -> bool { |
14 | self.0 >= 0 |
15 | } |
16 | |
17 | /// Returns [`true`] if `self` is a failure code. |
18 | #[inline ] |
19 | pub const fn is_err(self) -> bool { |
20 | !self.is_ok() |
21 | } |
22 | |
23 | /// Asserts that `self` is a success code. |
24 | /// |
25 | /// This will invoke the [`panic!`] macro if `self` is a failure code and display |
26 | /// the [`HRESULT`] value for diagnostics. |
27 | #[inline ] |
28 | #[track_caller ] |
29 | pub fn unwrap(self) { |
30 | assert!(self.is_ok(), "HRESULT 0x {:X}" , self.0); |
31 | } |
32 | |
33 | /// Converts the [`HRESULT`] to [`Result<()>`][Result<_>]. |
34 | #[inline ] |
35 | pub fn ok(self) -> Result<()> { |
36 | if self.is_ok() { |
37 | Ok(()) |
38 | } else { |
39 | Err(self.into()) |
40 | } |
41 | } |
42 | |
43 | /// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`] |
44 | /// converted to [`Result<T>`]. |
45 | #[inline ] |
46 | pub fn map<F, T>(self, op: F) -> Result<T> |
47 | where |
48 | F: FnOnce() -> T, |
49 | { |
50 | self.ok()?; |
51 | Ok(op()) |
52 | } |
53 | |
54 | /// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`] |
55 | /// converted to [`Result<T>`]. |
56 | #[inline ] |
57 | pub fn and_then<F, T>(self, op: F) -> Result<T> |
58 | where |
59 | F: FnOnce() -> Result<T>, |
60 | { |
61 | self.ok()?; |
62 | op() |
63 | } |
64 | |
65 | /// The error message describing the error. |
66 | pub fn message(self) -> String { |
67 | #[cfg (windows)] |
68 | { |
69 | let mut message = HeapString::default(); |
70 | let mut code = self.0; |
71 | let mut module = core::ptr::null_mut(); |
72 | |
73 | let mut flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
74 | | FORMAT_MESSAGE_FROM_SYSTEM |
75 | | FORMAT_MESSAGE_IGNORE_INSERTS; |
76 | |
77 | unsafe { |
78 | if self.0 & 0x1000_0000 == 0x1000_0000 { |
79 | code ^= 0x1000_0000; |
80 | flags |= FORMAT_MESSAGE_FROM_HMODULE; |
81 | |
82 | module = LoadLibraryExA( |
83 | b"ntdll.dll \0" .as_ptr(), |
84 | core::ptr::null_mut(), |
85 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, |
86 | ); |
87 | } |
88 | |
89 | let size = FormatMessageW( |
90 | flags, |
91 | module as _, |
92 | code as _, |
93 | 0, |
94 | &mut message.0 as *mut _ as *mut _, |
95 | 0, |
96 | core::ptr::null(), |
97 | ); |
98 | |
99 | if !message.0.is_null() && size > 0 { |
100 | String::from_utf16_lossy(wide_trim_end(core::slice::from_raw_parts( |
101 | message.0, |
102 | size as usize, |
103 | ))) |
104 | } else { |
105 | String::default() |
106 | } |
107 | } |
108 | } |
109 | |
110 | #[cfg (not(windows))] |
111 | { |
112 | return alloc::format!("0x {:08x}" , self.0 as u32); |
113 | } |
114 | } |
115 | |
116 | /// Maps a Win32 error code to an HRESULT value. |
117 | pub const fn from_win32(error: u32) -> Self { |
118 | Self(if error as i32 <= 0 { |
119 | error |
120 | } else { |
121 | (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 |
122 | } as i32) |
123 | } |
124 | |
125 | /// Maps an NT error code to an HRESULT value. |
126 | pub const fn from_nt(error: i32) -> Self { |
127 | Self(if error >= 0 { |
128 | error |
129 | } else { |
130 | error | 0x1000_0000 |
131 | }) |
132 | } |
133 | } |
134 | |
135 | impl<T> From<Result<T>> for HRESULT { |
136 | fn from(result: Result<T>) -> Self { |
137 | if let Err(error: Error) = result { |
138 | return error.into(); |
139 | } |
140 | HRESULT(0) |
141 | } |
142 | } |
143 | |
144 | impl core::fmt::Display for HRESULT { |
145 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
146 | f.write_fmt(format_args!(" {:#010X}" , self.0)) |
147 | } |
148 | } |
149 | |
150 | impl core::fmt::Debug for HRESULT { |
151 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
152 | f.write_fmt(format_args!("HRESULT( {})" , self)) |
153 | } |
154 | } |
155 | |