use std::fmt;
use crate::HResult;
#[cfg(test)]
mod tests;
const SEVERITY_SHIFT: u32 = 30;
const SEVERITY_MASK: u32 = 0b11;
const CUSTOMER_BIT: u32 = 0x2000_0000;
const FACILITY_SHIFT: u32 = 16;
const FACILITY_MASK: u32 = 0x0FFF;
const CODE_MASK: u32 = 0x0000_FFFF;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum NtSeverity {
Success = 0,
Informational = 1,
Warning = 2,
Error = 3,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct NtStatus(i32);
impl NtStatus {
#[must_use]
pub const fn from_raw(raw: i32) -> Self {
Self(raw)
}
#[must_use]
pub const fn raw(self) -> i32 {
self.0
}
#[must_use]
pub const fn severity(self) -> NtSeverity {
match (self.0.cast_unsigned() >> SEVERITY_SHIFT) & SEVERITY_MASK {
0 => NtSeverity::Success,
1 => NtSeverity::Informational,
2 => NtSeverity::Warning,
_ => NtSeverity::Error,
}
}
#[must_use]
pub const fn is_success(self) -> bool {
self.0 >= 0
}
#[must_use]
pub const fn is_information(self) -> bool {
matches!(self.severity(), NtSeverity::Informational)
}
#[must_use]
pub const fn is_warning(self) -> bool {
matches!(self.severity(), NtSeverity::Warning)
}
#[must_use]
pub const fn is_error(self) -> bool {
matches!(self.severity(), NtSeverity::Error)
}
pub const fn into_result(self) -> Result<(), Self> {
if self.is_success() { Ok(()) } else { Err(self) }
}
#[must_use]
pub const fn code(self) -> u16 {
(self.0.cast_unsigned() & CODE_MASK) as u16
}
#[must_use]
pub const fn facility(self) -> u16 {
((self.0.cast_unsigned() >> FACILITY_SHIFT) & FACILITY_MASK) as u16
}
#[must_use]
pub const fn is_customer(self) -> bool {
self.0.cast_unsigned() & CUSTOMER_BIT != 0
}
}
impl HResult {
#[must_use]
pub const fn from_ntstatus(status: NtStatus) -> Self {
Self::from_raw((status.raw().cast_unsigned() | crate::hresult::NTSTATUS_BIT).cast_signed())
}
#[must_use]
pub const fn ntstatus(self) -> Option<NtStatus> {
if self.is_ntstatus_mapped() {
Some(NtStatus::from_raw(
(self.raw().cast_unsigned() & !crate::hresult::NTSTATUS_BIT).cast_signed(),
))
} else {
None
}
}
}
impl fmt::Display for NtStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#010X}", self.0.cast_unsigned())
}
}
impl fmt::Debug for NtStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NtStatus({self})")
}
}