windows_result/
hresult.rs1use super::*;
2
3#[repr(transparent)]
5#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
6#[must_use]
7pub struct HRESULT(pub i32);
8
9impl HRESULT {
10 #[inline]
12 pub const fn is_ok(self) -> bool {
13 self.0 >= 0
14 }
15
16 #[inline]
18 pub const fn is_err(self) -> bool {
19 !self.is_ok()
20 }
21
22 #[inline]
27 #[track_caller]
28 pub fn unwrap(self) {
29 assert!(self.is_ok(), "HRESULT 0x{:X}", self.0);
30 }
31
32 #[inline]
34 pub fn ok(self) -> Result<()> {
35 if self.is_ok() {
36 Ok(())
37 } else {
38 Err(self.into())
39 }
40 }
41
42 #[inline]
45 pub fn map<F, T>(self, op: F) -> Result<T>
46 where
47 F: FnOnce() -> T,
48 {
49 self.ok()?;
50 Ok(op())
51 }
52
53 #[inline]
56 pub fn and_then<F, T>(self, op: F) -> Result<T>
57 where
58 F: FnOnce() -> Result<T>,
59 {
60 self.ok()?;
61 op()
62 }
63
64 pub fn message(self) -> String {
66 #[cfg(windows)]
67 {
68 let mut message = HeapString::default();
69 let mut code = self.0;
70 let mut module = core::ptr::null_mut();
71
72 let mut flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
73 | FORMAT_MESSAGE_FROM_SYSTEM
74 | FORMAT_MESSAGE_IGNORE_INSERTS;
75
76 unsafe {
77 if self.0 & 0x1000_0000 == 0x1000_0000 {
78 code ^= 0x1000_0000;
79 flags |= FORMAT_MESSAGE_FROM_HMODULE;
80
81 module = LoadLibraryExA(
82 c"ntdll.dll".as_ptr() as _,
83 core::ptr::null_mut(),
84 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
85 );
86 }
87
88 let size = FormatMessageW(
89 flags,
90 module as _,
91 code as _,
92 0,
93 &mut message.0 as *mut _ as *mut _,
94 0,
95 core::ptr::null(),
96 );
97
98 if !message.0.is_null() && size > 0 {
99 String::from_utf16_lossy(wide_trim_end(core::slice::from_raw_parts(
100 message.0,
101 size as usize,
102 )))
103 } else {
104 String::default()
105 }
106 }
107 }
108
109 #[cfg(not(windows))]
110 {
111 return alloc::format!("0x{:08x}", self.0 as u32);
112 }
113 }
114
115 pub fn from_thread() -> Self {
117 #[cfg(windows)]
118 {
119 let error = unsafe { GetLastError() };
120 Self::from_win32(error)
121 }
122 #[cfg(not(windows))]
123 {
124 unimplemented!()
125 }
126 }
127
128 pub const fn from_win32(error: u32) -> Self {
130 Self(if error as i32 <= 0 {
131 error
132 } else {
133 (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000
134 } as i32)
135 }
136
137 pub const fn from_nt(error: i32) -> Self {
139 Self(if error >= 0 {
140 error
141 } else {
142 error | 0x1000_0000
143 })
144 }
145}
146
147impl<T> From<Result<T>> for HRESULT {
148 fn from(result: Result<T>) -> Self {
149 if let Err(error) = result {
150 return error.into();
151 }
152 Self(0)
153 }
154}
155
156impl core::fmt::Display for HRESULT {
157 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
158 f.write_fmt(format_args!("{:#010X}", self.0))
159 }
160}
161
162impl core::fmt::Debug for HRESULT {
163 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
164 f.write_fmt(format_args!("HRESULT({self})"))
165 }
166}