directxtex 1.3.0

Unofficial Rust bindings for Microsoft's DirectXTex library
Documentation
use core::fmt::{self, Debug, Display, Formatter};
use std::error;

#[repr(transparent)]
pub struct HResultError(HResult);

impl HResultError {
    #[must_use]
    pub fn code(self) -> u16 {
        self.0.code()
    }

    #[must_use]
    pub fn facility(self) -> u16 {
        self.0.facility()
    }

    #[must_use]
    pub fn is_customer(self) -> bool {
        self.0.is_customer()
    }

    #[must_use]
    pub fn is_microsoft(self) -> bool {
        self.0.is_microsoft()
    }

    #[must_use]
    pub fn into_underlying(self) -> u32 {
        self.0.into()
    }
}

impl Debug for HResultError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "HResultError({self})")
    }
}

impl Display for HResultError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "0x{:08X} {:?}",
            self.0 .0,
            winresult::HResultError::from_constant(self.0 .0)
        )
    }
}

impl error::Error for HResultError {}

#[derive(Clone, Copy, Default, Eq, PartialEq)]
#[must_use]
#[repr(transparent)]
pub(crate) struct HResult(u32);

impl HResult {
    #[must_use]
    pub(crate) fn code(self) -> u16 {
        (self.0 & 0x0000_FFFF) as _
    }

    #[must_use]
    pub(crate) fn facility(self) -> u16 {
        ((self.0 & 0x07FF_0000) >> 16) as _
    }

    #[must_use]
    pub(crate) fn is_customer(self) -> bool {
        !self.is_microsoft()
    }

    #[must_use]
    pub(crate) fn is_microsoft(self) -> bool {
        (self.0 & 0x2000_0000) == 0
    }

    #[must_use]
    pub(crate) fn is_success(self) -> bool {
        (self.0 & 0x8000_0000) == 0
    }

    pub(crate) fn success<T>(self, value: T) -> Result<T, HResultError> {
        if self.is_success() {
            Ok(value)
        } else {
            Err(HResultError(self))
        }
    }
}

impl From<u32> for HResult {
    fn from(value: u32) -> Self {
        Self(value)
    }
}

impl From<HResult> for u32 {
    fn from(value: HResult) -> Self {
        value.0
    }
}

#[cfg(test)]
mod tests {
    use crate::hresult::HResult;

    #[test]
    fn error() {
        macro_rules! test {
            ($error_code:literal, $message:literal) => {{
                let error = {
                    let result = HResult::from($error_code);
                    assert!(!result.is_success());
                    let success = result.success(0);
                    assert!(success.is_err());
                    success.unwrap_err()
                };
                let display = format!("{error}");
                assert!(display.ends_with($message));
                let debug = format!("{error:?}");
                assert!(debug.ends_with(core::concat!($message, ")")));
            }};
        }

        test!(0x80080200, "E_PACKAGING_INTERNAL");
        test!(0x800B0101, "E_EXPIRED");
        test!(0x80094001, "E_BAD_REQUESTSUBJECT");
        test!(0x80004006, "E_INIT_TLS");
        test!(0x80110401, "E_OBJECTERRORS");
    }
}