anyhow/
chain.rs

1use self::ChainState::*;
2use crate::StdError;
3
4#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
5use alloc::vec::{self, Vec};
6
7#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
8pub(crate) use crate::Chain;
9
10#[cfg(all(not(feature = "std"), anyhow_no_core_error))]
11pub(crate) struct Chain<'a> {
12    state: ChainState<'a>,
13}
14
15#[derive(Clone)]
16pub(crate) enum ChainState<'a> {
17    Linked {
18        next: Option<&'a (dyn StdError + 'static)>,
19    },
20    #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
21    Buffered {
22        rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
23    },
24}
25
26impl<'a> Chain<'a> {
27    #[cold]
28    pub fn new(head: &'a (dyn StdError + 'static)) -> Self {
29        Chain {
30            state: ChainState::Linked { next: Some(head) },
31        }
32    }
33}
34
35impl<'a> Iterator for Chain<'a> {
36    type Item = &'a (dyn StdError + 'static);
37
38    fn next(&mut self) -> Option<Self::Item> {
39        match &mut self.state {
40            Linked { next } => {
41                let error = (*next)?;
42                *next = error.source();
43                Some(error)
44            }
45            #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
46            Buffered { rest } => rest.next(),
47        }
48    }
49
50    fn size_hint(&self) -> (usize, Option<usize>) {
51        let len = self.len();
52        (len, Some(len))
53    }
54}
55
56#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
57impl DoubleEndedIterator for Chain<'_> {
58    fn next_back(&mut self) -> Option<Self::Item> {
59        match &mut self.state {
60            Linked { mut next } => {
61                let mut rest = Vec::new();
62                while let Some(cause) = next {
63                    next = cause.source();
64                    rest.push(cause);
65                }
66                let mut rest = rest.into_iter();
67                let last = rest.next_back();
68                self.state = Buffered { rest };
69                last
70            }
71            Buffered { rest } => rest.next_back(),
72        }
73    }
74}
75
76impl ExactSizeIterator for Chain<'_> {
77    fn len(&self) -> usize {
78        match &self.state {
79            Linked { mut next } => {
80                let mut len = 0;
81                while let Some(cause) = next {
82                    next = cause.source();
83                    len += 1;
84                }
85                len
86            }
87            #[cfg(any(feature = "std", not(anyhow_no_core_error)))]
88            Buffered { rest } => rest.len(),
89        }
90    }
91}
92
93#[cfg(any(feature = "std", not(anyhow_no_core_error)))]
94impl Default for Chain<'_> {
95    fn default() -> Self {
96        Chain {
97            state: ChainState::Buffered {
98                rest: Vec::new().into_iter(),
99            },
100        }
101    }
102}