1 /*!
2 Iterate over error `.source()` chains.
3 
4 NOTE: This module is taken wholesale from <https://crates.io/crates/eyre>.
5 */
6 use std::error::Error as StdError;
7 use std::vec;
8 
9 use ChainState::*;
10 
11 /// Iterator of a chain of source errors.
12 ///
13 /// This type is the iterator returned by [`Report::chain`].
14 ///
15 /// # Example
16 ///
17 /// ```
18 /// use miette::Report;
19 /// use std::io;
20 ///
21 /// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
22 ///     for cause in error.chain() {
23 ///         if let Some(io_error) = cause.downcast_ref::<io::Error>() {
24 ///             return Some(io_error.kind());
25 ///         }
26 ///     }
27 ///     None
28 /// }
29 /// ```
30 #[derive(Clone)]
31 #[allow(missing_debug_implementations)]
32 pub struct Chain<'a> {
33     state: crate::chain::ChainState<'a>,
34 }
35 
36 #[derive(Clone)]
37 pub(crate) enum ChainState<'a> {
38     Linked {
39         next: Option<&'a (dyn StdError + 'static)>,
40     },
41     Buffered {
42         rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
43     },
44 }
45 
46 impl<'a> Chain<'a> {
new(head: &'a (dyn StdError + 'static)) -> Self47     pub(crate) fn new(head: &'a (dyn StdError + 'static)) -> Self {
48         Chain {
49             state: ChainState::Linked { next: Some(head) },
50         }
51     }
52 }
53 
54 impl<'a> Iterator for Chain<'a> {
55     type Item = &'a (dyn StdError + 'static);
56 
next(&mut self) -> Option<Self::Item>57     fn next(&mut self) -> Option<Self::Item> {
58         match &mut self.state {
59             Linked { next } => {
60                 let error = (*next)?;
61                 *next = error.source();
62                 Some(error)
63             }
64             Buffered { rest } => rest.next(),
65         }
66     }
67 
size_hint(&self) -> (usize, Option<usize>)68     fn size_hint(&self) -> (usize, Option<usize>) {
69         let len = self.len();
70         (len, Some(len))
71     }
72 }
73 
74 impl DoubleEndedIterator for Chain<'_> {
next_back(&mut self) -> Option<Self::Item>75     fn next_back(&mut self) -> Option<Self::Item> {
76         match &mut self.state {
77             Linked { mut next } => {
78                 let mut rest = Vec::new();
79                 while let Some(cause) = next {
80                     next = cause.source();
81                     rest.push(cause);
82                 }
83                 let mut rest = rest.into_iter();
84                 let last = rest.next_back();
85                 self.state = Buffered { rest };
86                 last
87             }
88             Buffered { rest } => rest.next_back(),
89         }
90     }
91 }
92 
93 impl ExactSizeIterator for Chain<'_> {
len(&self) -> usize94     fn len(&self) -> usize {
95         match &self.state {
96             Linked { mut next } => {
97                 let mut len = 0;
98                 while let Some(cause) = next {
99                     next = cause.source();
100                     len += 1;
101                 }
102                 len
103             }
104             Buffered { rest } => rest.len(),
105         }
106     }
107 }
108 
109 impl Default for Chain<'_> {
default() -> Self110     fn default() -> Self {
111         Chain {
112             state: ChainState::Buffered {
113                 rest: Vec::new().into_iter(),
114             },
115         }
116     }
117 }
118