diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 50415d9aeb9c8..de27333d28c64 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -667,6 +667,158 @@ impl dyn Error { Err(self) } } + + /// Returns an iterator starting with the current error and continuing with + /// recursively calling [`source`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// + /// // let err : Box = b.into(); // or + /// let err = &b as &(dyn Error); + /// + /// let mut iter = err.iter_chain(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`source`]: trait.Error.html#method.source + #[unstable(feature = "error_iter", issue = "58289")] + #[inline] + pub fn iter_chain(&self) -> ErrorIter { + ErrorIter { + current: Some(self), + } + } + + /// Returns an iterator starting with the [`source`] of this error + /// and continuing with recursively calling [`source`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option>); + /// + /// #[derive(Debug)] + /// struct C(Option>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl fmt::Display for C { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "C") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// impl Error for C { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// let c = C(Some(Box::new(b))); + /// + /// // let err : Box = c.into(); // or + /// let err = &c as &(dyn Error); + /// + /// let mut iter = err.iter_sources(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`source`]: trait.Error.html#method.source + #[inline] + #[unstable(feature = "error_iter", issue = "58289")] + pub fn iter_sources(&self) -> ErrorIter { + ErrorIter { + current: self.source(), + } + } +} + +/// An iterator over [`Error`] +/// +/// [`Error`]: trait.Error.html +#[unstable(feature = "error_iter", issue = "58289")] +#[derive(Copy, Clone, Debug)] +pub struct ErrorIter<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58289")] +impl<'a> Iterator for ErrorIter<'a> { + type Item = &'a (dyn Error + 'static); + + fn next(&mut self) -> Option { + let current = self.current; + self.current = self.current.and_then(Error::source); + current + } } impl dyn Error + Send {