Downcast the Errors
std::error::Error
comes with some helper methods to get to the original object of the
&(dyn Error + 'static)
returned by .source()
.
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T>
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T>
This is how it looks like, when using those:
use chainerror::*; use std::error::Error; use std::io; use std::result::Result; fn do_some_io() -> Result<(), Box<Error + Send + Sync>> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(()) } fn func2() -> Result<(), Box<Error + Send + Sync>> { let filename = "foo.txt"; do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; Ok(()) } fn func1() -> Result<(), Box<Error + Send + Sync>> { func2().map_err(mstrerr!("func1 error"))?; Ok(()) } fn main() -> Result<(), Box<Error + Send + Sync>> { if let Err(e) = func1() { eprintln!("Error: {}", e); let mut s : &(dyn Error) = e.as_ref(); while let Some(c) = s.source() { if let Some(ioerror) = c.downcast_ref::<io::Error>() { eprintln!("caused by: std::io::Error: {}", ioerror); match ioerror.kind() { io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"), _ => {} } } else { eprintln!("caused by: {}", c); } s = c; } } Ok(()) } #[allow(dead_code)] mod chainerror { {{#includecomment ../src/lib.rs}} }