Skip to main content

irox_safe_windows/
error.rs

1use std::fmt::{Display, Formatter};
2#[cfg(windows)]
3use windows::Win32::Foundation::WIN32_ERROR;
4#[cfg(windows)]
5use windows::Win32::Networking::WinSock::WSA_ERROR;
6
7pub const WSA_INVALID_HANDLE: i32 = 6;
8pub const WSA_INVALID_PARAMETER: i32 = 87;
9pub const WSA_E_OPERATION_ABORTED: i32 = 995;
10pub const WSA_IO_INCOMPLETE: i32 = 996;
11pub const WSA_E_INTR: i32 = 10004;
12pub const WSA_E_FAULT: i32 = 10014;
13pub const WSA_E_INVAL: i32 = 10022;
14pub const WSA_E_WOULDBLOCK: i32 = 10035;
15pub const WSA_E_INPROGRESS: i32 = 10036;
16pub const WSA_E_NOTSOCK: i32 = 10038;
17pub const WSA_E_MSGSIZE: i32 = 10040;
18pub const WSA_E_OPNOTSUPP: i32 = 10045;
19pub const WSA_E_NETDOWN: i32 = 10050;
20pub const WSA_E_NETRESET: i32 = 10052;
21pub const WSA_E_CONNABORTED: i32 = 10053;
22pub const WSA_E_CONNRESET: i32 = 10054;
23pub const WSA_E_NOBUFS: i32 = 10055;
24pub const WSA_E_NOTCONN: i32 = 10057;
25pub const WSA_E_SHUTDOWN: i32 = 10058;
26pub const WSA_NOT_INITIALIZED: i32 = 10093;
27#[derive(Debug, Copy, Clone)]
28pub enum WinsockErr {
29    InvalidHandle,
30    InvalidParameter,
31}
32
33#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
34pub enum ErrorType {
35    NotFound,
36    NoConsole,
37    Network,
38    IOIncomplete,
39    #[default]
40    Other,
41}
42
43#[derive(Debug, Default, Clone, Eq, PartialEq)]
44pub struct Error {
45    msg: String,
46    err_type: ErrorType,
47}
48
49impl Display for Error {
50    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
51        write!(f, "Error: {}", self.msg)
52    }
53}
54
55impl std::error::Error for Error {}
56
57impl Error {
58    pub fn code<T>(code: u32, message: &str) -> Result<T, Error> {
59        Err(Error {
60            msg: format!("Error({code}): {message}"),
61            err_type: ErrorType::Other,
62        })
63    }
64    pub fn no_console<T>() -> Result<T, Error> {
65        Err(Error {
66            msg: "Console not allocated".to_string(),
67            err_type: ErrorType::NoConsole,
68        })
69    }
70    pub fn notfound<T>() -> Result<T, Error> {
71        Err(Error {
72            msg: "Element not found".to_string(),
73            err_type: ErrorType::NotFound,
74        })
75    }
76    pub fn msg(&self) -> &str {
77        &self.msg
78    }
79    pub fn err_type(&self) -> ErrorType {
80        self.err_type
81    }
82    pub fn is_notfound(&self) -> bool {
83        self.err_type == ErrorType::NotFound
84    }
85
86    pub fn is_ioincomplete(&self) -> bool {
87        self.err_type == ErrorType::IOIncomplete
88    }
89
90    #[cfg(windows)]
91    pub fn win32<T>(err: WIN32_ERROR) -> Result<T, Error> {
92        use windows::core::PSTR;
93        use windows::Win32::System::Diagnostics::Debug::{
94            FormatMessageA, FORMAT_MESSAGE_FROM_SYSTEM,
95        };
96        let flags = FORMAT_MESSAGE_FROM_SYSTEM;
97        let source = None;
98        let messageid = err.0;
99        let languageid = 1; // sublang_default
100
101        let mut buf = [0u8; 1024];
102        let buffer = PSTR(buf.as_mut_ptr());
103
104        let args = None;
105        let msg = unsafe {
106            let res = FormatMessageA(flags, source, messageid, languageid, buffer, 1024, args);
107            if res > 0 {
108                std::ffi::CStr::from_bytes_until_nul(&buf)
109                    .unwrap_or_default()
110                    .to_string_lossy()
111            } else {
112                Default::default()
113            }
114        };
115        Error::code(err.0, msg.trim())
116    }
117}
118
119macro_rules! impl_error {
120    ($ty:path, $pre:literal) => {
121        impl From<$ty> for Error {
122            fn from(value: $ty) -> Error {
123                Error {
124                    msg: format!("{}: {}", $pre, value),
125                    err_type: ErrorType::Other,
126                }
127            }
128        }
129    };
130}
131
132impl_error!(std::ffi::FromBytesWithNulError, "FFI");
133impl_error!(std::ffi::FromBytesUntilNulError, "FFI");
134impl_error!(std::ffi::NulError, "FFI");
135impl_error!(std::io::Error, "IOError");
136impl_error!(irox::bits::Error, "BitsError");
137impl_error!(std::string::FromUtf16Error, "UTF16Error");
138
139#[cfg(windows)]
140impl_error!(windows::core::Error, "WindowsErr");
141
142#[cfg(windows)]
143impl From<WIN32_ERROR> for Error {
144    fn from(value: WIN32_ERROR) -> Self {
145        Error {
146            msg: format!("Win32 Error: {value:?}"),
147            err_type: ErrorType::Other,
148        }
149    }
150}
151
152#[cfg(windows)]
153impl From<WSA_ERROR> for Error {
154    fn from(value: WSA_ERROR) -> Self {
155        match value.0 {
156            WSA_NOT_INITIALIZED => Error {
157                err_type: ErrorType::Network,
158                msg: "WSANOTINITIALIZED: A successful WSAStartup call must occur before using this function".to_string()
159            },
160            WSA_E_NETDOWN => Error {
161                err_type: ErrorType::Network,
162                msg: "WSAENETDOWN: The network subsystem has failed".to_string()
163            },
164            WSA_E_NOTSOCK => Error {
165                err_type: ErrorType::Network,
166                msg: "WSAENOTSOCK: The descriptor is not a socket".to_string()
167            },
168            WSA_INVALID_HANDLE => Error {
169                err_type: ErrorType::Network,
170                msg: "WSA_INVALID_HANDLE: The hEvent parameter of the overlapped structure does not contain a valid object handle".to_string()
171            },
172            WSA_INVALID_PARAMETER => Error {
173                err_type: ErrorType::Network,
174                msg: "WSA_INVALID_PARAMETER: One of the parameters is unacceptable".to_string()
175            },
176            WSA_IO_INCOMPLETE => Error {
177                err_type: ErrorType::IOIncomplete,
178                msg: "WSA_IO_INCOMPLETE: the fWait parameter is false and the operation has not completed".to_string()
179            },
180            WSA_E_FAULT => Error {
181                err_type: ErrorType::Network,
182                msg: "WSAEFAULT: one or more of the pointers are not valid".to_string()
183            },
184            e => Error {
185                err_type: ErrorType::Other,
186                msg: format!("Unknown WSA Error code: {e}")
187            }
188        }
189    }
190}