Skip to main content

windows_ccd/
error.rs

1use std::fmt::Display;
2
3use crate::Result;
4use crate::windows::{
5    ERROR_ACCESS_DENIED, ERROR_GEN_FAILURE, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER,
6    ERROR_NOT_SUPPORTED, ERROR_SUCCESS, WIN32_ERROR,
7};
8
9macro_rules! codes {
10    (
11        $(
12            ( $code:ident, $text:literal ),
13        )*
14    ) => {
15        &[
16            $(
17                ($code, stringify!($code), $text),
18            )*
19        ]
20    };
21}
22
23static CODES: &[(WIN32_ERROR, &str, &str)] = codes![
24    (ERROR_SUCCESS, "The function succeeded"),
25    (
26        ERROR_INVALID_PARAMETER,
27        "The combination of parameters and flags that are specified is invalid."
28    ),
29    (
30        ERROR_NOT_SUPPORTED,
31        "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."
32    ),
33    (
34        ERROR_ACCESS_DENIED,
35        "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."
36    ),
37    (ERROR_GEN_FAILURE, "An unspecified error occurred."),
38    (
39        ERROR_INSUFFICIENT_BUFFER,
40        "The supplied path and mode buffer are too small."
41    ),
42];
43
44/// Error type for this crate.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub struct Error {
47    pub(crate) win32_error: Win32Error,
48    pub(crate) function: &'static str,
49}
50
51impl Error {
52    pub(crate) fn new(win32_error: impl Into<Win32Error>, function: &'static str) -> Self {
53        win32_error.into().to_error(function)
54    }
55
56    /// The Windows API error code wrapper.
57    #[must_use]
58    pub fn win32_error(self) -> Win32Error {
59        self.win32_error
60    }
61
62    /// The name of the Windows API function that failed.
63    #[must_use]
64    pub fn function(self) -> &'static str {
65        self.function
66    }
67
68    #[cfg(feature = "dump")]
69    #[must_use]
70    pub(crate) fn is_ok(self) -> bool {
71        self.win32_error.is_ok()
72    }
73
74    #[cfg(feature = "dump")]
75    #[must_use]
76    pub(crate) fn is_err(&self) -> bool {
77        self.win32_error.is_err()
78    }
79
80    pub(crate) fn to_result<T>(self, value: T) -> Result<T> {
81        self.to_result_with(|| value)
82    }
83
84    pub(crate) fn to_result_with<T>(self, f: impl FnOnce() -> T) -> Result<T> {
85        if self.win32_error.is_ok() {
86            Ok(f())
87        } else {
88            Err(self)
89        }
90    }
91}
92
93impl std::error::Error for Error {}
94
95impl Display for Error {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        write!(f, "{}: {}", self.function, self.win32_error)
98    }
99}
100
101/// A [`WIN32_ERROR`] wrapper.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct Win32Error(WIN32_ERROR);
104
105impl Win32Error {
106    /// Tells whether the error is [`ERROR_SUCCESS`].
107    #[must_use]
108    pub fn is_ok(self) -> bool {
109        self.0.is_ok()
110    }
111
112    /// Tells whether the error is *not* [`ERROR_SUCCESS`].
113    #[must_use]
114    pub fn is_err(self) -> bool {
115        self.0.is_err()
116    }
117
118    /// The numeric error code.
119    ///
120    /// # Example
121    ///
122    /// ```
123    /// use windows_ccd::Win32Error;
124    /// use windows_ccd::windows::ERROR_INVALID_PARAMETER;
125    ///
126    /// let e = Win32Error::from(ERROR_INVALID_PARAMETER);
127    /// assert_eq!(e.code_number(), 87);
128    /// ```
129    #[must_use]
130    pub fn code_number(self) -> u32 {
131        self.0.0
132    }
133
134    /// The name and description of the error.
135    ///
136    /// # Example
137    /// ```
138    /// use windows_ccd::Win32Error;
139    /// use windows_ccd::windows::ERROR_INVALID_PARAMETER;
140    ///
141    /// let e = Win32Error::from(ERROR_INVALID_PARAMETER);
142    /// let (error_code_str, error_text) = e.code_str_and_text().unwrap();
143    /// assert_eq!(error_code_str, "ERROR_INVALID_PARAMETER");
144    /// assert_eq!(error_text, "The combination of parameters and flags that are specified is invalid.");
145    /// ```
146    #[must_use]
147    pub fn code_str_and_text(self) -> Option<(&'static str, &'static str)> {
148        CODES
149            .iter()
150            .find_map(|(code, code_str, text)| (self.0 == *code).then_some((*code_str, *text)))
151    }
152
153    fn to_error(self, function: &'static str) -> Error {
154        Error {
155            win32_error: self,
156            function,
157        }
158    }
159}
160
161impl From<WIN32_ERROR> for Win32Error {
162    fn from(value: WIN32_ERROR) -> Self {
163        Win32Error(value)
164    }
165}
166
167impl From<u32> for Win32Error {
168    fn from(value: u32) -> Self {
169        Win32Error::from(WIN32_ERROR(value))
170    }
171}
172
173impl From<i32> for Win32Error {
174    fn from(value: i32) -> Self {
175        Win32Error::from(value.cast_unsigned())
176    }
177}
178
179impl Display for Win32Error {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        match self.code_str_and_text() {
182            Some((code_str, text)) => write!(f, "{code_str} - {text}"),
183            None => write!(f, "{} - Unknown error", self.code_number()),
184        }
185    }
186}