windows_result/
hresult.rs1use super::*;
2
3#[repr(transparent)]
5#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
6#[must_use]
7#[allow(non_camel_case_types)]
8pub struct HRESULT(pub i32);
9
10impl HRESULT {
11 #[inline]
13 pub const fn is_ok(self) -> bool {
14 self.0 >= 0
15 }
16
17 #[inline]
19 pub const fn is_err(self) -> bool {
20 !self.is_ok()
21 }
22
23 #[inline]
28 #[track_caller]
29 pub fn unwrap(self) {
30 assert!(self.is_ok(), "HRESULT 0x{:X}", self.0);
31 }
32
33 #[inline]
35 pub fn ok(self) -> Result<()> {
36 if self.is_ok() {
37 Ok(())
38 } else {
39 Err(self.into())
40 }
41 }
42
43 #[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 #[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 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 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 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
135impl<T> From<Result<T>> for HRESULT {
136 fn from(result: Result<T>) -> Self {
137 if let Err(error) = result {
138 return error.into();
139 }
140 HRESULT(0)
141 }
142}
143
144impl 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
150impl 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}