1use super::*;
2
3/// An error code value returned by most COM functions.
4#[repr(transparent)]
5#[derive(Copy, Clone, Default, Eq, PartialEq)]
6#[must_use]
7#[allow(non_camel_case_types)]
8pub struct HRESULT(pub i32);
9
10impl 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(Error::from(self))
40 }
41 }
42
43 /// Returns the [`Option`] as a [`Result`] if the option is a [`Some`] value, returning
44 /// a suitable error if not.
45 pub fn and_some<T: Interface>(self, some: Option<T>) -> Result<T> {
46 if self.is_ok() {
47 if let Some(result) = some {
48 Ok(result)
49 } else {
50 Err(Error::OK)
51 }
52 } else {
53 Err(Error::from(self))
54 }
55 }
56
57 /// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`]
58 /// converted to [`Result<T>`].
59 #[inline]
60 pub fn and_then<F, T>(self, op: F) -> Result<T>
61 where
62 F: FnOnce() -> T,
63 {
64 self.ok()?;
65 Ok(op())
66 }
67
68 /// If the [`Result`] is [`Ok`] converts the `T::Abi` into `T`.
69 ///
70 /// # Safety
71 ///
72 /// Safe to call if
73 /// * `abi` is initialized if `self` is `Ok`
74 /// * `abi` can be safely transmuted to `T`
75 pub unsafe fn from_abi<T: Type<T>>(self, abi: T::Abi) -> Result<T> {
76 if self.is_ok() {
77 T::from_abi(abi)
78 } else {
79 Err(Error::from(self))
80 }
81 }
82
83 /// The error message describing the error.
84 pub fn message(&self) -> HSTRING {
85 let mut message = HeapString(std::ptr::null_mut());
86
87 unsafe {
88 let size = crate::imp::FormatMessageW(crate::imp::FORMAT_MESSAGE_ALLOCATE_BUFFER | crate::imp::FORMAT_MESSAGE_FROM_SYSTEM | crate::imp::FORMAT_MESSAGE_IGNORE_INSERTS, std::ptr::null(), self.0 as u32, 0, &mut message.0 as *mut _ as *mut _, 0, std::ptr::null());
89
90 HSTRING::from_wide(crate::imp::wide_trim_end(std::slice::from_raw_parts(message.0 as *const u16, size as usize))).unwrap_or_default()
91 }
92 }
93
94 /// Maps a Win32 error code to an HRESULT value.
95 pub const fn from_win32(error: u32) -> Self {
96 Self(if error as i32 <= 0 { error } else { (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as i32)
97 }
98}
99
100impl RuntimeType for HRESULT {
101 const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice(b"struct(Windows.Foundation.HResult;i32)");
102}
103
104impl TypeKind for HRESULT {
105 type TypeKind = CopyType;
106}
107
108impl<T> std::convert::From<Result<T>> for HRESULT {
109 fn from(result: Result<T>) -> Self {
110 if let Err(error: Error) = result {
111 return error.into();
112 }
113
114 HRESULT(0)
115 }
116}
117
118impl std::fmt::Display for HRESULT {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 f.write_fmt(format_args!("{:#010X}", self.0))
121 }
122}
123
124impl std::fmt::Debug for HRESULT {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 f.write_fmt(format_args!("HRESULT({})", self))
127 }
128}
129
130struct HeapString(*mut u16);
131
132impl Drop for HeapString {
133 fn drop(&mut self) {
134 if !self.0.is_null() {
135 unsafe {
136 crate::imp::heap_free(self.0 as _);
137 }
138 }
139 }
140}
141