use std::fmt::Display;
use crate::Result;
use crate::windows::{
ERROR_ACCESS_DENIED, ERROR_GEN_FAILURE, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER,
ERROR_NOT_SUPPORTED, ERROR_SUCCESS, WIN32_ERROR,
};
macro_rules! codes {
(
$(
( $code:ident, $text:literal ),
)*
) => {
&[
$(
($code, stringify!($code), $text),
)*
]
};
}
static CODES: &[(WIN32_ERROR, &str, &str)] = codes![
(ERROR_SUCCESS, "The function succeeded"),
(
ERROR_INVALID_PARAMETER,
"The combination of parameters and flags that are specified is invalid."
),
(
ERROR_NOT_SUPPORTED,
"The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function is only supported on a system with a WDDM driver running."
),
(
ERROR_ACCESS_DENIED,
"The caller does not have access to the console session. This error occurs if the calling process does not have access to the current desktop or is running on a remote session."
),
(ERROR_GEN_FAILURE, "An unspecified error occurred."),
(
ERROR_INSUFFICIENT_BUFFER,
"The supplied path and mode buffer are too small."
),
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Error {
pub(crate) win32_error: Win32Error,
pub(crate) function: &'static str,
}
impl Error {
pub(crate) fn new(win32_error: impl Into<Win32Error>, function: &'static str) -> Self {
win32_error.into().to_error(function)
}
#[must_use]
pub fn win32_error(self) -> Win32Error {
self.win32_error
}
#[must_use]
pub fn function(self) -> &'static str {
self.function
}
#[cfg(feature = "dump")]
#[must_use]
pub(crate) fn is_ok(self) -> bool {
self.win32_error.is_ok()
}
#[cfg(feature = "dump")]
#[must_use]
pub(crate) fn is_err(&self) -> bool {
self.win32_error.is_err()
}
pub(crate) fn to_result<T>(self, value: T) -> Result<T> {
self.to_result_with(|| value)
}
pub(crate) fn to_result_with<T>(self, f: impl FnOnce() -> T) -> Result<T> {
if self.win32_error.is_ok() {
Ok(f())
} else {
Err(self)
}
}
}
impl std::error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.function, self.win32_error)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Win32Error(WIN32_ERROR);
impl Win32Error {
#[must_use]
pub fn is_ok(self) -> bool {
self.0.is_ok()
}
#[must_use]
pub fn is_err(self) -> bool {
self.0.is_err()
}
#[must_use]
pub fn code_number(self) -> u32 {
self.0.0
}
#[must_use]
pub fn code_str_and_text(self) -> Option<(&'static str, &'static str)> {
CODES
.iter()
.find_map(|(code, code_str, text)| (self.0 == *code).then_some((*code_str, *text)))
}
fn to_error(self, function: &'static str) -> Error {
Error {
win32_error: self,
function,
}
}
}
impl From<WIN32_ERROR> for Win32Error {
fn from(value: WIN32_ERROR) -> Self {
Win32Error(value)
}
}
impl From<u32> for Win32Error {
fn from(value: u32) -> Self {
Win32Error::from(WIN32_ERROR(value))
}
}
impl From<i32> for Win32Error {
fn from(value: i32) -> Self {
Win32Error::from(value.cast_unsigned())
}
}
impl Display for Win32Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.code_str_and_text() {
Some((code_str, text)) => write!(f, "{code_str} - {text}"),
None => write!(f, "{} - Unknown error", self.code_number()),
}
}
}