Finding an Error cause
To distinguish the errors occuring in various places, we can define named string errors with the "new type" pattern.
derive_str_cherr!(Func2Error);
derive_str_cherr!(Func1Error);
Instead of ChainError<String>
we now have struct Func1Error(String)
and ChainError<Func1Error>
.
In the main
function you can see, how we can match the different errors.
Also see:
if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() {
as a shortcut to
if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() {
hiding the ChainError<T>
implementation detail.
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(()) } derive_str_cherr!(Func2Error); fn func2() -> Result<(), Box<Error + Send + Sync>> { let filename = "foo.txt"; do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; Ok(()) } derive_str_cherr!(Func1Error); fn func1() -> Result<(), Box<Error + Send + Sync>> { func2().map_err(mstrerr!(Func1Error, "func1 error"))?; Ok(()) } fn main() -> Result<(), Box<Error + Send + Sync>> { if let Err(e) = func1() { if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() { eprintln!("Func1Error: {}", f1err); if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() { eprintln!("Func2Error: {}", f2err); } if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() { eprintln!("Debug Func2Error:\n{:?}", f2err); } } } Ok(()) } #[allow(dead_code)] mod chainerror { {{#includecomment ../src/lib.rs}} }