miette/
chain.rs

1/*!
2Iterate over error `.source()` chains.
3
4NOTE: This module is taken wholesale from <https://crates.io/crates/eyre>.
5*/
6use std::error::Error as StdError;
7use std::vec;
8
9use 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)]
32pub struct Chain<'a> {
33    state: crate::chain::ChainState<'a>,
34}
35
36#[derive(Clone)]
37pub(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
46impl<'a> Chain<'a> {
47    #[cold]
48    pub(crate) fn new(head: &'a (dyn StdError + 'static)) -> Self {
49        Chain {
50            state: ChainState::Linked { next: Some(head) },
51        }
52    }
53}
54
55impl<'a> Iterator for Chain<'a> {
56    type Item = &'a (dyn StdError + 'static);
57
58    fn next(&mut self) -> Option<Self::Item> {
59        match &mut self.state {
60            Linked { next } => {
61                let error = (*next)?;
62                *next = error.source();
63                Some(error)
64            }
65            Buffered { rest } => rest.next(),
66        }
67    }
68
69    fn size_hint(&self) -> (usize, Option<usize>) {
70        let len = self.len();
71        (len, Some(len))
72    }
73}
74
75impl DoubleEndedIterator for Chain<'_> {
76    fn next_back(&mut self) -> Option<Self::Item> {
77        match &mut self.state {
78            Linked { mut next } => {
79                let mut rest = Vec::new();
80                while let Some(cause) = next {
81                    next = cause.source();
82                    rest.push(cause);
83                }
84                let mut rest = rest.into_iter();
85                let last = rest.next_back();
86                self.state = Buffered { rest };
87                last
88            }
89            Buffered { rest } => rest.next_back(),
90        }
91    }
92}
93
94impl ExactSizeIterator for Chain<'_> {
95    fn len(&self) -> usize {
96        match &self.state {
97            Linked { mut next } => {
98                let mut len = 0;
99                while let Some(cause) = next {
100                    next = cause.source();
101                    len += 1;
102                }
103                len
104            }
105            Buffered { rest } => rest.len(),
106        }
107    }
108}
109
110impl Default for Chain<'_> {
111    fn default() -> Self {
112        Chain {
113            state: ChainState::Buffered {
114                rest: Vec::new().into_iter(),
115            },
116        }
117    }
118}