| use self::ChainState::*; |
| use crate::StdError; |
| |
| use std::vec; |
| |
| pub(crate) use crate::Chain; |
| |
| #[derive(Clone)] |
| pub(crate) enum ChainState<'a> { |
| Linked { |
| next: Option<&'a (dyn StdError + 'static)>, |
| }, |
| Buffered { |
| rest: vec::IntoIter<&'a (dyn StdError + 'static)>, |
| }, |
| } |
| |
| impl<'a> Chain<'a> { |
| /// Construct an iterator over a chain of errors via the `source` method |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use std::error::Error; |
| /// use std::fmt::{self, Write}; |
| /// use eyre::Chain; |
| /// use indenter::indented; |
| /// |
| /// fn report(error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| /// let mut errors = Chain::new(error).enumerate(); |
| /// for (i, error) in errors { |
| /// writeln!(f)?; |
| /// write!(indented(f).ind(i), "{}", error)?; |
| /// } |
| /// |
| /// Ok(()) |
| /// } |
| /// ``` |
| 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) |
| } |
| Buffered { rest } => rest.next(), |
| } |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| let len = self.len(); |
| (len, Some(len)) |
| } |
| } |
| |
| 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 |
| } |
| Buffered { rest } => rest.len(), |
| } |
| } |
| } |
| |
| impl Default for Chain<'_> { |
| fn default() -> Self { |
| Chain { |
| state: ChainState::Buffered { |
| rest: Vec::new().into_iter(), |
| }, |
| } |
| } |
| } |