use alloc::boxed::Box;
use core::{error::Error, fmt};
use ts_ansi::ansi::{BOLD, DEFAULT, RED, RESET};
pub trait IntoReport<T> {
fn into_report(self) -> Result<T, Report<'static>>;
}
impl<T, E: Error + 'static> IntoReport<T> for Result<T, E> {
fn into_report(self) -> Result<T, Report<'static>> {
self.map_err(|source| Report::new(source))
}
}
pub struct Report<'e> {
pub source: Box<dyn Error + 'e>,
}
impl<'e> Report<'e> {
pub fn new<E: Error + 'e>(source: E) -> Self {
Self {
source: Box::new(source),
}
}
}
impl Error for Report<'static> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self.source.as_ref())
}
}
impl fmt::Debug for Report<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl fmt::Display for Report<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut current_error = Some(self.source.as_ref());
let mut count = 1;
while let Some(error) = current_error {
writeln!(f, " {BOLD}{RED}{count}{DEFAULT}.{RESET} {error}")?;
count += 1;
current_error = error.source();
}
Ok(())
}
}