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 as u32,
85 );
86 }
87
88 let size = FormatMessageW(
89 flags as u32,
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 alloc::format!("0x{:08x}", self.0 as u32)
112 }
113 }
114
115 pub fn from_thread() -> Self {
117 #[cfg(windows)]
118 {
119 WIN32_ERROR::from_thread().into()
120 }
121 #[cfg(not(windows))]
122 {
123 unimplemented!()
124 }
125 }
126}
127
128impl<T> From<Result<T>> for HRESULT {
129 fn from(result: Result<T>) -> Self {
130 if let Err(error) = result {
131 return error.into();
132 }
133 Self(0)
134 }
135}
136
137impl core::fmt::Display for HRESULT {
138 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
139 f.write_fmt(format_args!("{:#010X}", self.0))
140 }
141}
142
143impl core::fmt::Debug for HRESULT {
144 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
145 f.write_fmt(format_args!("HRESULT({self})"))
146 }
147}