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