mirror of
https://github.com/haraldh/chainerror.git
synced 2025-01-31 00:56:41 +01:00
add ChainError Iterator
This commit is contained in:
parent
49515b86f9
commit
d14af67560
52
src/lib.rs
52
src/lib.rs
|
@ -214,11 +214,7 @@ impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
|
|
||||||
/// return the root cause of the error chain, if any exists
|
/// return the root cause of the error chain, if any exists
|
||||||
pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
let mut cause = self as &(dyn Error + 'static);
|
self.iter().last()
|
||||||
while let Some(c) = cause.source() {
|
|
||||||
cause = c;
|
|
||||||
}
|
|
||||||
Some(cause)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** find the first error cause of type U, if any exists
|
/** find the first error cause of type U, if any exists
|
||||||
|
@ -270,17 +266,7 @@ impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
~~~
|
~~~
|
||||||
**/
|
**/
|
||||||
pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
let mut cause = self as &(dyn Error + 'static);
|
self.iter().filter_map(Error::downcast_ref::<U>()).next()
|
||||||
loop {
|
|
||||||
if cause.is::<U>() {
|
|
||||||
return cause.downcast_ref::<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
match cause.source() {
|
|
||||||
Some(c) => cause = c,
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** find the first error cause of type ChainError<U>, if any exists
|
/** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
@ -299,17 +285,9 @@ impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
|
|
||||||
**/
|
**/
|
||||||
pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
let mut cause = self as &(dyn Error + 'static);
|
self.iter()
|
||||||
loop {
|
.filter_map(Error::downcast_ref::<ChainError<U>>())
|
||||||
if cause.is::<ChainError<U>>() {
|
.next()
|
||||||
return cause.downcast_ref::<ChainError<U>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
match cause.source() {
|
|
||||||
Some(c) => cause = c,
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return a reference to T of `ChainError<T>`
|
/** return a reference to T of `ChainError<T>`
|
||||||
|
@ -374,6 +352,26 @@ impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
pub fn kind(&self) -> &T {
|
pub fn kind(&self) -> &T {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &(dyn Error + 'static)> {
|
||||||
|
ErrorIter {
|
||||||
|
current: Some(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ErrorIter<'a> {
|
||||||
|
current: Option<&'a (dyn Error + 'static)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** convenience trait to hide the `ChainError<T>` implementation internals
|
/** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
|
66
tests/test_iter.rs
Normal file
66
tests/test_iter.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use chainerror::*;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iter() -> Result<(), Box<Error>> {
|
||||||
|
let err = io::Error::from(io::ErrorKind::NotFound);
|
||||||
|
let err = cherr!(err, "1");
|
||||||
|
let err = cherr!(err, "2");
|
||||||
|
let err = cherr!(err, "3");
|
||||||
|
let err = cherr!(err, "4");
|
||||||
|
let err = cherr!(err, "5");
|
||||||
|
let err = cherr!(err, "6");
|
||||||
|
|
||||||
|
let mut res = String::new();
|
||||||
|
|
||||||
|
for e in err.iter() {
|
||||||
|
write!(res, "{}", e.to_string())?;
|
||||||
|
}
|
||||||
|
assert_eq!(res, "654321entity not found");
|
||||||
|
|
||||||
|
let io_error: Option<&io::Error> = err
|
||||||
|
.iter()
|
||||||
|
.filter_map(Error::downcast_ref::<io::Error>)
|
||||||
|
.next();
|
||||||
|
|
||||||
|
assert_eq!(io_error.unwrap().kind(), io::ErrorKind::NotFound);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_cause() -> Result<(), Box<Error>> {
|
||||||
|
let err = io::Error::from(io::ErrorKind::NotFound);
|
||||||
|
let err = cherr!(err, "1");
|
||||||
|
let err = cherr!(err, "2");
|
||||||
|
let err = cherr!(err, "3");
|
||||||
|
let err = cherr!(err, "4");
|
||||||
|
let err = cherr!(err, "5");
|
||||||
|
let err = cherr!(err, "6");
|
||||||
|
|
||||||
|
let io_error: Option<&io::Error> = err.find_cause::<io::Error>();
|
||||||
|
|
||||||
|
assert_eq!(io_error.unwrap().kind(), io::ErrorKind::NotFound);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_root_cause() -> Result<(), Box<Error>> {
|
||||||
|
let err = io::Error::from(io::ErrorKind::NotFound);
|
||||||
|
let err = cherr!(err, "1");
|
||||||
|
let err = cherr!(err, "2");
|
||||||
|
let err = cherr!(err, "3");
|
||||||
|
let err = cherr!(err, "4");
|
||||||
|
let err = cherr!(err, "5");
|
||||||
|
let err = cherr!(err, "6");
|
||||||
|
|
||||||
|
let err: Option<&(dyn std::error::Error + 'static)> = err.root_cause();
|
||||||
|
let io_error: Option<&io::Error> = err.and_then(Error::downcast_ref::<io::Error>);
|
||||||
|
|
||||||
|
assert_eq!(io_error.unwrap().kind(), io::ErrorKind::NotFound);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue