| use super::*; |
| use imp::*; |
| |
| /// An error code value returned by most COM functions. |
| #[repr(transparent)] |
| #[derive(Copy, Clone, Default, Eq, PartialEq)] |
| #[must_use] |
| #[allow(non_camel_case_types)] |
| pub struct HRESULT(pub i32); |
| |
| impl HRESULT { |
| /// Returns [`true`] if `self` is a success code. |
| #[inline] |
| pub const fn is_ok(self) -> bool { |
| self.0 >= 0 |
| } |
| |
| /// Returns [`true`] if `self` is a failure code. |
| #[inline] |
| pub const fn is_err(self) -> bool { |
| !self.is_ok() |
| } |
| |
| /// Asserts that `self` is a success code. |
| /// |
| /// This will invoke the [`panic!`] macro if `self` is a failure code and display |
| /// the [`HRESULT`] value for diagnostics. |
| #[inline] |
| #[track_caller] |
| pub fn unwrap(self) { |
| assert!(self.is_ok(), "HRESULT 0x{:X}", self.0); |
| } |
| |
| /// Converts the [`HRESULT`] to [`Result<()>`][Result<_>]. |
| #[inline] |
| pub fn ok(self) -> Result<()> { |
| if self.is_ok() { |
| Ok(()) |
| } else { |
| Err(Error::from(self)) |
| } |
| } |
| |
| /// Returns the [`Option`] as a [`Result`] if the option is a [`Some`] value, returning |
| /// a suitable error if not. |
| pub fn and_some<T: Interface>(self, some: Option<T>) -> Result<T> { |
| if self.is_ok() { |
| if let Some(result) = some { |
| Ok(result) |
| } else { |
| Err(Error::OK) |
| } |
| } else { |
| Err(Error::from(self)) |
| } |
| } |
| |
| /// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`] |
| /// converted to [`Result<T>`]. |
| #[inline] |
| pub fn and_then<F, T>(self, op: F) -> Result<T> |
| where |
| F: FnOnce() -> T, |
| { |
| self.ok()?; |
| Ok(op()) |
| } |
| |
| /// If the [`Result`] is [`Ok`] converts the `T::Abi` into `T`. |
| /// |
| /// # Safety |
| /// |
| /// Safe to call if |
| /// * `abi` is initialized if `self` is `Ok` |
| /// * `abi` can be safely transmuted to `T` |
| pub unsafe fn from_abi<T: Type<T>>(self, abi: T::Abi) -> Result<T> { |
| if self.is_ok() { |
| T::from_abi(abi) |
| } else { |
| Err(Error::from(self)) |
| } |
| } |
| |
| /// The error message describing the error. |
| pub fn message(&self) -> HSTRING { |
| let mut message = HeapString(std::ptr::null_mut()); |
| |
| unsafe { |
| let size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, std::ptr::null(), self.0 as _, 0, PWSTR(&mut message.0 as *mut _ as *mut _), 0, std::ptr::null()); |
| |
| HSTRING::from_wide(wide_trim_end(std::slice::from_raw_parts(message.0 as *const u16, size as usize))).unwrap_or_default() |
| } |
| } |
| |
| /// Maps a Win32 error code to an HRESULT value. |
| pub(crate) fn from_win32(error: u32) -> Self { |
| Self(if error == 0 { 0 } else { (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as _) |
| } |
| } |
| |
| impl RuntimeType for HRESULT { |
| const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"struct(Windows.Foundation.HResult;i32)"); |
| } |
| |
| impl TypeKind for HRESULT { |
| type TypeKind = CopyType; |
| } |
| |
| impl<T> std::convert::From<Result<T>> for HRESULT { |
| fn from(result: Result<T>) -> Self { |
| if let Err(error) = result { |
| return error.into(); |
| } |
| |
| HRESULT(0) |
| } |
| } |
| |
| impl std::fmt::Display for HRESULT { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| f.write_fmt(format_args!("{:#010X}", self.0)) |
| } |
| } |
| |
| impl std::fmt::Debug for HRESULT { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| f.write_fmt(format_args!("HRESULT({})", self)) |
| } |
| } |
| |
| struct HeapString(*mut u16); |
| |
| impl Drop for HeapString { |
| fn drop(&mut self) { |
| if !self.0.is_null() { |
| unsafe { |
| heap_free(self.0 as _); |
| } |
| } |
| } |
| } |