#[cfg(feature = "backtrace")]
use std::backtrace::Backtrace;
use std::{io::Error as ioError, path::Path};
pub type Result<T> = std::result::Result<T, Error>;
macro_rules! fn_string {
($fn_name:ident, $fortype:expr) => {
#[doc = concat!("Create a new [Self] as [", stringify!($fortype), "]")]
pub fn $fn_name<M>(msg: M) -> Self
where
M: Into<String>,
{
return Self::new($fortype(msg.into()));
}
};
}
#[derive(Debug)]
pub struct Error {
source: ErrorEnum,
#[cfg(feature = "backtrace")]
backtrace: Backtrace,
}
impl Error {
pub fn new(source: ErrorEnum) -> Self {
Self {
source,
#[cfg(feature = "backtrace")]
backtrace: Backtrace::capture(),
}
}
#[cfg(feature = "backtrace")]
pub fn backtrace(&self) -> &Backtrace {
&self.backtrace
}
fn_string!(other, ErrorEnum::Other);
fn_string!(
unsupported_schema_format,
ErrorEnum::UnsupportedSchemaFormat
);
fn_string!(unsupported_type, ErrorEnum::UnsupportedType);
fn_string!(no_file_signature, ErrorEnum::NoFileSignature);
pub fn custom_ioerror_path<M, P>(kind: std::io::ErrorKind, msg: M, path: P) -> Self
where
M: Into<String>,
P: AsRef<Path>,
{
return Self::new(ErrorEnum::IoError(
ioError::new(kind, msg.into()),
format_path(path.as_ref().to_string_lossy().to_string()),
));
}
pub fn not_a_directory<M, P>(msg: M, path: P) -> Self
where
M: Into<String>,
P: AsRef<Path>,
{
return Self::new(ErrorEnum::NotADirectory(
msg.into(),
path.as_ref().to_string_lossy().to_string(),
));
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.source.fmt(f)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
return self.source.source();
}
}
impl<T> From<T> for Error
where
T: Into<ErrorEnum>,
{
fn from(value: T) -> Self {
Self::new(value.into())
}
}
#[derive(thiserror::Error, Debug)]
pub enum ErrorEnum {
#[error("IoError: {0}; {1}")]
IoError(std::io::Error, String),
#[error("NotADirectory: {0}; Path: \"{1}\"")]
NotADirectory(String, String),
#[error("UnsupportedSchemaFormat: {0}")]
UnsupportedSchemaFormat(String),
#[error("UnsupportedType: {0}")]
UnsupportedType(String),
#[error("NoFileSignature: {0}")]
NoFileSignature(String),
#[error("InvalidGenerationConfig: {0}")]
InvalidGenerationConfig(String),
#[error("Other: {0}")]
Other(String),
}
#[inline]
fn format_path(msg: String) -> String {
format!("Path \"{}\"", msg)
}
pub trait IOErrorToError<T> {
fn attach_path_err<P: AsRef<Path>>(self, path: P) -> Result<T>;
fn attach_path_msg<P: AsRef<Path>, M: AsRef<str>>(self, path: P, msg: M) -> Result<T>;
}
impl<T> IOErrorToError<T> for std::result::Result<T, std::io::Error> {
fn attach_path_err<P: AsRef<Path>>(self, path: P) -> Result<T> {
return match self {
Ok(v) => Ok(v),
Err(e) => Err(crate::Error::new(ErrorEnum::IoError(
e,
format_path(path.as_ref().to_string_lossy().to_string()),
))),
};
}
fn attach_path_msg<P: AsRef<Path>, M: AsRef<str>>(self, path: P, msg: M) -> Result<T> {
match self {
Ok(v) => Ok(v),
Err(e) => Err(crate::Error::new(ErrorEnum::IoError(
e,
format!(
"{msg} {path}",
msg = msg.as_ref(),
path = format_path(path.as_ref().to_string_lossy().to_string())
),
))),
}
}
}