1use std::error::Error as StdError;
7use std::vec;
8
9use ChainState::*;
10
11#[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}