use thiserror::Error;
use std::borrow::Cow;
#[derive(Debug, Error)]
pub enum ErrorBase {
#[error(transparent)]
IO(#[from] std::io::Error),
#[error("Invalid {0}: {1}")]
Invalid(&'static str, Cow<'static, str>),
#[error(transparent)]
MUTF(#[from] crate::mod_utf8::MUTFError),
#[error("Attribute length mismatch: actual length ({0}) is greater than length consumed ({1}) for variant ${2}")]
AttributeLength(u32, u32, &'static str),
#[error(transparent)]
Custom(#[from] Box<dyn std::error::Error>)
}
#[cfg(any(feature = "backtrace", test, doc))]
pub mod backtrace {
use std::backtrace::Backtrace;
use std::borrow::Cow;
use crate::error::ErrorBase;
use std::error::Error;
use std::fmt::Formatter;
impl<T> From<T> for ErrorTrace where ErrorBase: From<T> {
#[inline(always)]
fn from(t: T) -> Self {
Self {
inner: t.into(),
trace: Backtrace::force_capture()
}
}
}
#[derive(Debug)]
pub struct ErrorTrace {
pub inner: ErrorBase,
trace: Backtrace
}
impl std::fmt::Display for ErrorTrace {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}\nBacktrace:\n{}", self.inner, self.trace)
}
}
impl Error for ErrorTrace {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.inner.source()
}
fn backtrace(&self) -> Option<&Backtrace> {
Some(&self.trace)
}
}
macro_rules! functions {
($($(#[$doc:meta])* $i: ident($($arg_i: ident: $ty: ty),*)),*) => {
$(
$(#[$doc])*
#[inline]
#[allow(non_snake_case)]
pub fn $i($($arg_i: $ty),*) -> ErrorTrace {
ErrorTrace {
inner: ErrorBase::$i($($arg_i),*),
trace: Backtrace::force_capture()
}
}
)*
};
}
impl ErrorTrace {
functions!(
IO(e: std::io::Error),
Invalid(st: &'static str, cow: Cow<'static, str>),
MUTF(e: crate::mod_utf8::MUTFError),
AttributeLength(act: u32, exp: u32, var: &'static str),
Custom(b: Box<dyn std::error::Error>)
);
}
}
#[cfg(any(feature = "backtrace", test, doc))]
pub type Error = backtrace::ErrorTrace;
#[cfg(not(any(feature = "backtrace", test, doc)))]
pub type Error = ErrorBase;
pub type Result<T, E = Error> = std::result::Result<T, E>;