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