miette/
diagnostic_chain.rs

1/*!
2Iterate over error `.diagnostic_source()` chains.
3*/
4
5use crate::protocol::Diagnostic;
6
7/// Iterator of a chain of cause errors.
8#[derive(Clone, Default)]
9#[allow(missing_debug_implementations)]
10pub(crate) struct DiagnosticChain<'a> {
11    state: Option<ErrorKind<'a>>,
12}
13
14impl<'a> DiagnosticChain<'a> {
15    pub(crate) fn from_diagnostic(head: &'a dyn Diagnostic) -> Self {
16        DiagnosticChain {
17            state: Some(ErrorKind::Diagnostic(head)),
18        }
19    }
20
21    pub(crate) fn from_stderror(head: &'a (dyn std::error::Error + 'static)) -> Self {
22        DiagnosticChain {
23            state: Some(ErrorKind::StdError(head)),
24        }
25    }
26}
27
28impl<'a> Iterator for DiagnosticChain<'a> {
29    type Item = ErrorKind<'a>;
30
31    fn next(&mut self) -> Option<Self::Item> {
32        if let Some(err) = self.state.take() {
33            self.state = err.get_nested();
34            Some(err)
35        } else {
36            None
37        }
38    }
39
40    fn size_hint(&self) -> (usize, Option<usize>) {
41        let len = self.len();
42        (len, Some(len))
43    }
44}
45
46impl ExactSizeIterator for DiagnosticChain<'_> {
47    fn len(&self) -> usize {
48        fn depth(d: Option<&ErrorKind<'_>>) -> usize {
49            match d {
50                Some(d) => 1 + depth(d.get_nested().as_ref()),
51                None => 0,
52            }
53        }
54
55        depth(self.state.as_ref())
56    }
57}
58
59#[derive(Clone)]
60pub(crate) enum ErrorKind<'a> {
61    Diagnostic(&'a dyn Diagnostic),
62    StdError(&'a (dyn std::error::Error + 'static)),
63}
64
65impl<'a> ErrorKind<'a> {
66    fn get_nested(&self) -> Option<ErrorKind<'a>> {
67        match self {
68            ErrorKind::Diagnostic(d) => d
69                .diagnostic_source()
70                .map(ErrorKind::Diagnostic)
71                .or_else(|| d.source().map(ErrorKind::StdError)),
72            ErrorKind::StdError(e) => e.source().map(ErrorKind::StdError),
73        }
74    }
75}
76
77impl<'a> std::fmt::Debug for ErrorKind<'a> {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        match self {
80            ErrorKind::Diagnostic(d) => d.fmt(f),
81            ErrorKind::StdError(e) => e.fmt(f),
82        }
83    }
84}
85
86impl<'a> std::fmt::Display for ErrorKind<'a> {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        match self {
89            ErrorKind::Diagnostic(d) => d.fmt(f),
90            ErrorKind::StdError(e) => e.fmt(f),
91        }
92    }
93}