impl iter_sources() and iter_chain() for dyn Error
Examples: ```rust let next_error_type_a = err .iter_chain() .filter_map(Error::downcast_ref::<ErrorTypeA>) .next(); ``` ```rust let source_root_error = err.iter_chain().last(); ``` Credit for the ErrorIter goes to Tim Diekmann https://www.reddit.com/r/rust/comments/aj3lpg/is_an_iterator_impl_over_errorsource_possible/
This commit is contained in:
parent
825f355c74
commit
f06af1ff17
1 changed files with 152 additions and 0 deletions
|
@ -667,6 +667,158 @@ impl dyn Error {
|
||||||
Err(self)
|
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 {
|
impl dyn Error + Send {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue