use std::backtrace::Backtrace;
use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
use crate::Config;
use crate::Verbosity;
use crate::GLOBAL_SETTINGS;
struct Chain<'a> {
next: Option<&'a (dyn Error + 'static)>,
}
impl<'a> Chain<'a> {
pub fn new(head: &'a (dyn Error + 'static)) -> Self {
Chain { next: Some(head) }
}
}
impl<'a> Iterator for Chain<'a> {
type Item = &'a (dyn Error + 'static);
fn next(&mut self) -> Option<Self::Item> {
let yielded = self.next?;
self.next = yielded.source();
Some(yielded)
}
}
pub type DynError = ErrorUnsizingHelper<dyn Error + Send + Sync + 'static>;
pub struct ErrorUnsizingHelper<E: ?Sized> {
backtrace: Option<Backtrace>,
error: E,
}
impl DynError {
pub fn backtrace(&self) -> Option<&Backtrace> {
self.backtrace.as_ref()
}
}
impl DynError {
pub fn chain(&self) -> impl Iterator<Item = &(dyn Error + 'static)> {
Chain::new(&self.error)
}
}
impl Debug for DynError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Debug::fmt(&self.error, f)
}
}
impl Display for DynError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Display::fmt(&self.error, f)
}
}
impl Error for DynError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.error.source()
}
}
impl<E> From<E> for Box<DynError>
where
E: Error + Send + Sync + 'static,
{
fn from(value: E) -> Self {
let backtrace = GLOBAL_SETTINGS
.get()
.map(Config::selected_verbosity)
.map_or(true, |verbosity| verbosity != Verbosity::Minimal)
.then(Backtrace::force_capture);
let error = ErrorUnsizingHelper {
backtrace,
error: value,
};
Box::new(error)
}
}