fenestroj 0.0.11

Easier wrappers for Win32 API stuff, safe when possible
Documentation
#![allow(missing_docs)]

//! Basic error code stuff.
//!
//! To actually _obtain_ an error code from the system you probably want the
//! [`errhandlingapi`] module.

use super::*;

pub use winapi::shared::winerror::*;

/// Newtype for an error code value.
///
/// Note that the `Display` impl is only available if the `winbase` feature is
/// activate.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ErrorCode(pub u32);

impl ErrorCode {
  /// Bit that signifies if an error code is an application error.
  pub const APPLICATION_ERROR_BIT: u32 = 1 << 29;

  /// Checks if this error code is an application error code.
  #[inline(always)]
  pub const fn is_application_error(self) -> bool {
    (self.0 & Self::APPLICATION_ERROR_BIT) > 0
  }
}

#[cfg(feature = "winbase")]
impl core::fmt::Display for ErrorCode {
  /// Attempts to format the `ErrorCode` as a human readable message obtained
  /// from Windows.
  ///
  /// If Windows can't give us a message, we fall back to giving the plan
  /// `Debug` format instead.
  #[allow(clippy::single_match_else)]
  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
    use winapi::um::winbase::{
      FormatMessageW, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
      FORMAT_MESSAGE_IGNORE_INSERTS,
    };
    if self.is_application_error() {
      write!(f, "Application Error: {:?}", self)
    } else {
      let dw_flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
        | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS;
      let lp_source = null_mut();
      let dw_message_id = self.0;
      let dw_language_id = 0;
      let mut buffer_ptr: *mut u16 = null_mut();
      let n_size = 0;
      let arguments = null_mut();
      let t_chars_excluding_null = unsafe {
        FormatMessageW(
          dw_flags,
          lp_source,
          dw_message_id,
          dw_language_id,
          &mut buffer_ptr as *mut _ as *mut _,
          n_size,
          arguments,
        )
      };
      if !buffer_ptr.is_null() {
        let owned_local = unsafe { OwnedLocalHandle::new(buffer_ptr as HLOCAL) };
        if t_chars_excluding_null == 0 {
          write!(f, "{:?}", self)
        } else {
          let fls = unsafe {
            FixedLocalSlice::new(owned_local, t_chars_excluding_null as usize)
          };
          for decode_result in core::char::decode_utf16(fls.iter().copied()) {
            match decode_result.map_err(|_| core::fmt::Error)? {
              '\r' | '\n' => continue,
              ch => write!(f, "{}", ch)?,
            }
          }
          Ok(())
        }
      } else {
        write!(f, "{:?}", self)
      }
    }
  }
}