Skip to content

Commit

Permalink
Rollup merge of rust-lang#58289 - haraldh:master, r=sfackler
Browse files Browse the repository at this point in the history
impl iter() for dyn Error

Examples:

```rust
let next_error_type_a = err
    .iter()
    .filter_map(Error::downcast_ref::<ErrorTypeA>)
    .next();
```

```rust
let source_root_error = err.iter().last();
```

Credit for the ErrorIter goes to reddit user /u/tdiekmann (Tim Diekmann)
https://www.reddit.com/r/rust/comments/aj3lpg/is_an_iterator_impl_over_errorsource_possible/
  • Loading branch information
Centril committed Feb 13, 2019
2 parents 55bc4f6 + f06af1f commit 41488c8
Showing 1 changed file with 152 additions and 0 deletions.
152 changes: 152 additions & 0 deletions src/libstd/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Box<dyn Error + 'static>>);
///
/// 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<Error> = 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<Box<dyn Error + 'static>>);
///
/// #[derive(Debug)]
/// struct C(Option<Box<dyn Error + 'static>>);
///
/// 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<Error> = 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<Self::Item> {
let current = self.current;
self.current = self.current.and_then(Error::source);
current
}
}

impl dyn Error + Send {
Expand Down

0 comments on commit 41488c8

Please sign in to comment.