1use alloc::boxed::Box;
2use core::{error::Error, fmt};
3
4use ts_ansi::style::{BOLD, DEFAULT, RED, RESET};
5
6pub trait IntoReport<T> {
8 fn into_report(self) -> Result<T, Report<'static>>;
10}
11
12impl<T, E: Error + 'static> IntoReport<T> for Result<T, E> {
13 fn into_report(self) -> Result<T, Report<'static>> {
14 self.map_err(|source| Report::new(source))
15 }
16}
17
18pub struct Report<'e> {
20 pub source: Box<dyn Error + 'e>,
22}
23impl<'e> Report<'e> {
24 pub fn new<E: Error + 'e>(source: E) -> Self {
26 Self {
27 source: Box::new(source),
28 }
29 }
30}
31impl Error for Report<'static> {
32 fn source(&self) -> Option<&(dyn Error + 'static)> {
33 Some(self.source.as_ref())
34 }
35}
36impl fmt::Debug for Report<'_> {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "{self}")
39 }
40}
41impl fmt::Display for Report<'_> {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 let mut current_error = Some(self.source.as_ref());
44 let mut count = 1;
45
46 while let Some(error) = current_error {
47 writeln!(f, " {BOLD}{RED}{count}{DEFAULT}.{RESET} {error}")?;
48
49 count += 1;
50 current_error = error.source();
51 }
52
53 Ok(())
54 }
55}