1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//  ERRORS.rs
//    by Lut99
//
//  Created:
//    10 May 2023, 16:35:29
//  Last edited:
//    10 May 2023, 16:45:29
//  Auto updated?
//    Yes
//
//  Description:
//!   Defines commonly used functions and structs relating to error
//!   handling.
//

use std::error::Error;
use std::fmt::{Display, Formatter, Result as FResult};


/***** AUXILLARY *****/
/// Defines the formatter used in the [`ErrorTrace`] trait.
#[derive(Debug)]
pub struct ErrorTraceFormatter<'e> {
    /// The error to format.
    err: &'e dyn Error,
}
impl<'e> Display for ErrorTraceFormatter<'e> {
    fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
        // We can always serialize the error itself
        write!(f, "{}", self.err)?;

        // If it has a source, recurse to print them all
        if let Some(source) = self.err.source() {
            write!(f, "\n\nCaused by:")?;

            // Write them all
            let mut i: usize = 1;
            let mut source: Option<&dyn Error> = Some(source);
            while let Some(err) = source {
                write!(f, "\n  {i}) {err}")?;
                source = err.source();
                i += 1;
            }
        }

        // Done!
        Ok(())
    }
}





/***** LIBRARY *****/
/// Implements a function over a normal [`Error`] that prints it and any [`Error::source()`] it has.
pub trait ErrorTrace: Error {
    /// Returns a formatter that writes the error to the given formatter, with any sources it has.
    ///
    /// # Returns
    /// A new [`ErrorTraceFormatter`] that can write this error and its sources.
    fn trace(&self) -> ErrorTraceFormatter;
}

// We auto-implement [`ErrorTrace`] for everything [`Error`]
impl<T: Error> ErrorTrace for T {
    #[inline]
    fn trace(&self) -> ErrorTraceFormatter { ErrorTraceFormatter { err: self } }
}