| 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 | |