use thiserror::Error;
use windows::core::Error as WinError;
#[derive(Error, Debug)]
pub enum Error {
#[error("Windows API error: {0}")]
Windows(#[from] WinError),
#[error("Null pointer error: {context}")]
NullPointer {
context: &'static str,
},
#[error("Invalid handle: {context}")]
InvalidHandle {
context: &'static str,
},
#[error("String conversion error: {0}")]
StringConversion(String),
#[error("Buffer too small: needed {needed}, got {actual}")]
BufferTooSmall {
needed: usize,
actual: usize,
},
#[error("Not found: {0}")]
NotFound(String),
#[error("Access denied: {0}")]
AccessDenied(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("{0}")]
Custom(String),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn null_pointer(context: &'static str) -> Self {
Error::NullPointer { context }
}
pub fn invalid_handle(context: &'static str) -> Self {
Error::InvalidHandle { context }
}
pub fn string_conversion(msg: impl Into<String>) -> Self {
Error::StringConversion(msg.into())
}
pub fn buffer_too_small(needed: usize, actual: usize) -> Self {
Error::BufferTooSmall { needed, actual }
}
pub fn not_found(msg: impl Into<String>) -> Self {
Error::NotFound(msg.into())
}
pub fn access_denied(msg: impl Into<String>) -> Self {
Error::AccessDenied(msg.into())
}
pub fn custom(msg: impl Into<String>) -> Self {
Error::Custom(msg.into())
}
pub fn last_os_error() -> Self {
Error::Windows(WinError::from_win32())
}
pub fn from_win32(err: WinError) -> Self {
Error::Windows(err)
}
pub fn io_error(err: std::io::Error, context: &str) -> Self {
Error::Custom(format!("{}: {}", context, err))
}
pub fn other(msg: impl Into<String>) -> Self {
Error::Custom(msg.into())
}
pub fn raw_code(&self) -> i32 {
match self {
Error::Windows(e) => e.code().0,
_ => 0,
}
}
pub fn win32_error_code(&self) -> Option<u32> {
match self {
Error::Windows(e) => Some(e.code().0 as u32),
_ => None,
}
}
}
pub fn last_os_error() -> Error {
Error::last_os_error()
}
pub trait ResultExt<T> {
fn to_result(self) -> Result<T>;
}
impl<T> ResultExt<T> for windows::core::Result<T> {
fn to_result(self) -> Result<T> {
self.map_err(Error::from)
}
}
pub fn last_error() -> Error {
Error::Windows(WinError::from_win32())
}
pub fn check_last_error() -> Result<()> {
let err = WinError::from_win32();
if err.code().is_ok() {
Ok(())
} else {
Err(Error::Windows(err))
}
}