1 /*!
2 Iterate over error `.diagnostic_source()` chains.
3 */
4 
5 use crate::protocol::Diagnostic;
6 
7 /// Iterator of a chain of cause errors.
8 #[derive(Clone, Default)]
9 #[allow(missing_debug_implementations)]
10 pub(crate) struct DiagnosticChain<'a> {
11     state: Option<ErrorKind<'a>>,
12 }
13 
14 impl<'a> DiagnosticChain<'a> {
from_diagnostic(head: &'a dyn Diagnostic) -> Self15     pub(crate) fn from_diagnostic(head: &'a dyn Diagnostic) -> Self {
16         DiagnosticChain {
17             state: Some(ErrorKind::Diagnostic(head)),
18         }
19     }
20 
from_stderror(head: &'a (dyn std::error::Error + 'static)) -> Self21     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 
28 impl<'a> Iterator for DiagnosticChain<'a> {
29     type Item = ErrorKind<'a>;
30 
next(&mut self) -> Option<Self::Item>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 
size_hint(&self) -> (usize, Option<usize>)40     fn size_hint(&self) -> (usize, Option<usize>) {
41         let len = self.len();
42         (len, Some(len))
43     }
44 }
45 
46 impl ExactSizeIterator for DiagnosticChain<'_> {
len(&self) -> usize47     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)]
60 pub(crate) enum ErrorKind<'a> {
61     Diagnostic(&'a dyn Diagnostic),
62     StdError(&'a (dyn std::error::Error + 'static)),
63 }
64 
65 impl<'a> ErrorKind<'a> {
get_nested(&self) -> Option<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 
77 impl<'a> std::fmt::Debug for ErrorKind<'a> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result78     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 
86 impl<'a> std::fmt::Display for ErrorKind<'a> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result87     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 }
94