use std::{
backtrace::Backtrace,
error::Error,
fmt::{Debug, Display},
ops::{Deref, DerefMut},
};
pub struct BacktraceError<E: Error> {
pub inner: E,
pub backtrace: Box<Backtrace>,
}
impl<E: Error> Display for BacktraceError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Initial error: {:}", self.inner)?;
writeln!(f, "Error context:")?;
writeln!(f, "{:}", self.backtrace)
}
}
impl<E: Error> Debug for BacktraceError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl<E: Error + 'static> Error for BacktraceError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.inner)
}
}
impl<E: Error + 'static> From<E> for BacktraceError<E> {
fn from(inner: E) -> Self {
let backtrace = Box::new(Backtrace::capture());
Self { inner, backtrace }
}
}
pub trait ResultExt: Sized {
type T;
fn unwrap_or_backtrace(self) -> Self::T {
self.expect_or_backtrace("ResultExt::unwrap_or_backtrace found Err")
}
fn expect_or_backtrace(self, msg: &str) -> Self::T;
}
impl<T, E: Error> ResultExt for Result<T, BacktraceError<E>> {
type T = T;
fn expect_or_backtrace(self, msg: &str) -> T {
match self {
Ok(ok) => ok,
Err(bterr) => {
eprintln!("{}", msg);
eprintln!("");
eprintln!("{:}", bterr);
panic!("{}", msg);
}
}
}
}
pub struct DynBacktraceError {
inner: Box<dyn Error + Send + Sync + 'static>,
backtrace: Box<Backtrace>,
}
impl<E: Error + Send + Sync + 'static> From<E> for DynBacktraceError {
fn from(inner: E) -> Self {
let backtrace = Box::new(Backtrace::capture());
Self {
inner: Box::new(inner),
backtrace,
}
}
}
impl Deref for DynBacktraceError {
type Target = dyn Error + Send + Sync + 'static;
fn deref(&self) -> &Self::Target {
&*self.inner
}
}
impl DerefMut for DynBacktraceError {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.inner
}
}
impl Display for DynBacktraceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Initial error: {:}", self.inner)?;
writeln!(f, "Error context:")?;
writeln!(f, "{:}", self.backtrace)
}
}
impl Debug for DynBacktraceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl ResultExt for Result<(), DynBacktraceError> {
type T = ();
fn expect_or_backtrace(self, msg: &str) -> () {
match self {
Ok(()) => (),
Err(bterr) => {
eprintln!("{}", msg);
eprintln!("");
eprintln!("{:}", bterr);
panic!("{}", msg);
}
}
}
}