use core::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct HResult(pub i32);
impl HResult {
pub const S_OK: Self = Self(0);
pub const S_FALSE: Self = Self(1);
pub const E_NOTIMPL: Self = Self(0x8000_4001_u32 as i32);
pub const E_NOINTERFACE: Self = Self(0x8000_4002_u32 as i32);
pub const E_POINTER: Self = Self(0x8000_4003_u32 as i32);
pub const E_FAIL: Self = Self(0x8000_4005_u32 as i32);
pub const E_UNEXPECTED: Self = Self(0x8000_FFFF_u32 as i32);
pub const E_OUTOFMEMORY: Self = Self(0x8007_000E_u32 as i32);
pub const E_INVALIDARG: Self = Self(0x8007_0057_u32 as i32);
pub const CLASS_E_CLASSNOTAVAILABLE: Self = Self(0x8004_0111_u32 as i32);
pub const CLASS_E_NOAGGREGATION: Self = Self(0x8004_0110_u32 as i32);
pub const APOERR_INVALID_INPUT_DATA: Self = Self(0x8889_0001_u32 as i32);
pub const APOERR_FORMAT_NOT_SUPPORTED: Self = Self(0x8889_0008_u32 as i32);
pub const APOERR_INVALID_API_VERSION: Self = Self(0x8889_0007_u32 as i32);
pub const APOERR_NUM_CONNECTIONS_INVALID: Self = Self(0x8889_000B_u32 as i32);
pub const APOERR_NOT_LOCKED: Self = Self(0x8889_000A_u32 as i32);
pub const APOERR_ALREADY_LOCKED: Self = Self(0x8889_0006_u32 as i32);
#[inline]
#[must_use]
pub const fn is_ok(self) -> bool {
self.0 >= 0
}
#[inline]
#[must_use]
pub const fn is_err(self) -> bool {
self.0 < 0
}
#[inline]
pub const fn ok(self) -> Result<(), Self> {
if self.is_ok() {
Ok(())
} else {
Err(self)
}
}
}
impl fmt::Debug for HResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HResult(0x{:08X})", self.0 as u32)
}
}
impl fmt::Display for HResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HRESULT 0x{:08X}", self.0 as u32)
}
}
impl From<i32> for HResult {
#[inline]
fn from(value: i32) -> Self {
Self(value)
}
}
impl From<HResult> for i32 {
#[inline]
fn from(value: HResult) -> Self {
value.0
}
}
#[cfg(windows)]
impl From<windows_core::HRESULT> for HResult {
#[inline]
fn from(value: windows_core::HRESULT) -> Self {
Self(value.0)
}
}
#[cfg(windows)]
impl From<HResult> for windows_core::HRESULT {
#[inline]
fn from(value: HResult) -> Self {
Self(value.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn success_codes_classify_correctly() {
assert!(HResult::S_OK.is_ok());
assert!(!HResult::S_OK.is_err());
assert!(HResult::S_FALSE.is_ok());
assert!(!HResult::S_FALSE.is_err());
}
#[test]
fn failure_codes_classify_correctly() {
assert!(HResult::E_FAIL.is_err());
assert!(!HResult::E_FAIL.is_ok());
assert!(HResult::E_INVALIDARG.is_err());
assert!(HResult::APOERR_FORMAT_NOT_SUPPORTED.is_err());
assert!(HResult::APOERR_INVALID_INPUT_DATA.is_err());
assert!(HResult::CLASS_E_CLASSNOTAVAILABLE.is_err());
}
#[test]
fn ok_method_converts_to_result() {
assert_eq!(HResult::S_OK.ok(), Ok(()));
assert_eq!(HResult::S_FALSE.ok(), Ok(()));
assert_eq!(HResult::E_FAIL.ok(), Err(HResult::E_FAIL));
}
#[test]
fn raw_constant_values_match_microsoft_definitions() {
assert_eq!(HResult::E_NOTIMPL.0 as u32, 0x8000_4001);
assert_eq!(HResult::E_POINTER.0 as u32, 0x8000_4003);
assert_eq!(HResult::E_OUTOFMEMORY.0 as u32, 0x8007_000E);
assert_eq!(HResult::E_INVALIDARG.0 as u32, 0x8007_0057);
assert_eq!(HResult::CLASS_E_CLASSNOTAVAILABLE.0 as u32, 0x8004_0111);
}
#[test]
fn debug_formatting_is_hex() {
let s = format!("{:?}", HResult::E_INVALIDARG);
assert_eq!(s, "HResult(0x80070057)");
}
}