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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use super::source::ErrorSource;
use super::tracer::ErrorMessageTracer;
use core::fmt::{Debug, Display, Formatter};

/// An [`ErrorSource`] that provides both the error
/// detail and error trace separately. The error trace in an error report
/// also already contains the trace of the current error detail already.
/// so new errors that arise from an `ErrorReport` only need to access
/// the `trace` object to add new traces to it.
///
/// `ErrorReport` should be used for all application code that uses `flex-error`.
/// When defining new error types using [`define_error!`], the error name is defined
/// as a type alias to `ErrorReport`.
pub struct ErrorReport<Detail, Trace> {
    pub detail: Detail,
    pub trace: Trace,
}

impl<Detail, Trace> ErrorSource<Trace> for ErrorReport<Detail, Trace> {
    type Source = Self;
    type Detail = Detail;

    fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>) {
        (source.detail, Some(source.trace))
    }
}

impl<Detail, Trace> ErrorReport<Detail, Trace> {
    pub fn trace_from<E, Cont>(source: E::Source, cont: Cont) -> Self
    where
        Detail: Display,
        E: ErrorSource<Trace>,
        Trace: ErrorMessageTracer,
        Cont: FnOnce(E::Detail) -> Detail,
    {
        let (detail1, m_trace1) = E::error_details(source);
        let detail2 = cont(detail1);
        match m_trace1 {
            Some(trace1) => {
                let trace2 = trace1.add_message(&detail2);
                ErrorReport {
                    detail: detail2,
                    trace: trace2,
                }
            }
            None => {
                let trace2 = Trace::new_message(&detail2);
                ErrorReport {
                    detail: detail2,
                    trace: trace2,
                }
            }
        }
    }
}

impl<Detail, Trace> Debug for ErrorReport<Detail, Trace>
where
    Trace: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        self.trace.fmt(f)
    }
}

impl<Detail, Trace> Display for ErrorReport<Detail, Trace>
where
    Trace: Display,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        self.trace.fmt(f)
    }
}

#[cfg(feature = "std")]
impl<Detail, Trace> std::error::Error for ErrorReport<Detail, Trace>
where
    Detail: Display,
    Trace: Debug + Display,
    Trace: ErrorMessageTracer,
{
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.trace.as_error()
    }
}