Simple String Errors

The most simplest of doing error handling in rust is by returning String as a Box<Error>.

As you can see by running the example, this only prints out the last Error.

If the rust main function returns an Err(), this Err() will be displayed with std::fmt::Debug.

use std::error::Error;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err("do_some_io error")?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    if let Err(_) = do_some_io() {
        Err("func2 error")?;
    }
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    if let Err(_) = func2() {
        Err("func1 error")?;
    }
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    func1()
}

Simple Chained String Errors

Now with the help of the chainerror crate, we can have a nicer output.

Press the play button in the upper right corner and see the nice debug output.

use crate::chainerror::*;
use std::error::Error;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err("do_some_io error")?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    if let Err(e) = do_some_io() {
        Err(cherr!(e, "func2 error"))?;
    }
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    if let Err(e) = func2() {
        Err(cherr!(e, "func1 error"))?;
    }
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    func1()
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

What did we do here?

    if let Err(e) = do_some_io() {
        Err(cherr!(e, "func2 error"))?;
    }

The macro cherr!(cause, newerror) stores cause as the source/cause of newerror and returns newerror, along with the filename (file!()) and line number (line!()).

Err(e)? then returns the error e applying e.into(), so that we again have a Err(Box<Error>) as a result.

The Debug implementation of ChainError<T> (which is returned by cherr!()) prints the Debug of T prefixed with the stored filename and line number.

ChainError<T> is in our case ChainError<String>.

Mapping Errors

Now let's get more rust idiomatic by using .map_err().

use crate::chainerror::*;
use std::error::Error;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err("do_some_io error")?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    do_some_io().map_err(|e| cherr!(e, "func2 error"))?;
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(|e| cherr!(e, "func1 error"))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        eprintln!("{:?}", e);
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

If you compare the output to the previous example, you will see, that:

Error: src/main.rs:19: "func1 error"

changed to just:

src/main.rs:16: "func1 error"

This is, because we caught the error of func1() in main() and print it out ourselves.

We can now control, whether to output in Debug or Display mode. Maybe depending on --debug as a CLI argument.

Saving coding chars

Because decorating an error with more information should not let you jump through hoops, chainerror has a quick macro for that.

mstrerror!() fits right into .map_err() letting you quickly add more debug strings.

mstrerror!() even understands format!() syntax like println!().

use crate::chainerror::*;
use std::error::Error;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err("do_some_io error")?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(mstrerr!("func1 error"))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        eprintln!("{:?}", e);
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

The source() of Errors

Sometimes you want to inspect the source() of an Error. chainerror implements std::error::Error::source(), so you can get the cause of an error.

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    if let Err(e) = func2() {
        if let Some(s) = e.source() {
            eprintln!("func2 failed because of '{}'", s);
            Err(e).map_err(mstrerr!("func1 error"))?;
        }
    }
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        eprintln!("{}", e);
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

Note, that we changed the output of the error in main() from Debug to Display, so we don't see the error backtrace with filename and line number.

To enable the Display backtrace, you have to enable the feature display-cause for chainerror.

Downcast the Errors

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(mstrerr!("func1 error"))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        eprintln!("Error: {}", e);
        let mut s = 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 {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

The root cause of all Errors

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
    Ok(())
}

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(mstrerr!("func1 error"))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        eprintln!("Error: {}", e);
        if let Some(s) = e.downcast_chain_ref::<String>() {
            if let Some(ioerror) = s.find_cause::<io::Error>() {
                eprintln!("caused by: std::io::Error: {}", ioerror);
                match ioerror.kind() {
                    io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"),
                    _ => {}
                }
            }

            if let Some(e) = s.root_cause() {
                let ioerror = e.downcast_ref::<io::Error>().unwrap();
                eprintln!("The root cause was: std::io::Error: {:#?}", ioerror);
            }
        }
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

Finding an Error cause

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

derive_str_cherr!(Func2Error);

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
    Ok(())
}

derive_str_cherr!(Func1Error);

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    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 {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

Selective Error Handling

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

derive_str_cherr!(Func2Error);

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
    Ok(())
}

derive_str_cherr!(Func1ErrorFunc2);
derive_str_cherr!(Func1ErrorIO);

fn func1() -> Result<(), Box<Error>> {
    func2().map_err(mstrerr!(Func1ErrorFunc2, "func1 error calling func2"))?;
    let filename = "bar.txt";
    do_some_io().map_err(mstrerr!(Func1ErrorIO, "Error reading '{}'", filename))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        if let Some(s) = e.downcast_ref::<ChainError<Func1ErrorIO>>() {
            eprintln!("Func1ErrorIO:\n{:?}", s);
        }

        if let Some(s) = try_cherr_ref!(e, Func1ErrorFunc2) {
            eprintln!("Func1ErrorFunc2:\n{:?}", s);
        }
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

ErrorKind to the rescue

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

derive_str_cherr!(Func2Error);

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
    Ok(())
}

#[derive(Debug)]
enum Func1Error {
    Func2,
    IO(String),
}

impl ::std::fmt::Display for Func1Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            Func1Error::Func2 => write!(f, "func1 error calling func2"),
            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
        }
    }
}

fn func1() -> ChainResult<(), Func1Error> {
    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
    let filename = String::from("bar.txt");
    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        match e.kind() {
            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
            Func1Error::IO(filename) => {
                eprintln!("Main Error Report: func1 error reading '{}'", filename)
            }
        }

        if let Some(e) = e.find_chain_cause::<Func2Error>() {
            eprintln!("Error reported by Func2Error: {}", e)
        }

        eprintln!("\nDebug Error:\n{:?}", e);
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }

Debug for the ErrorKind

[TBD]

use crate::chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;

fn do_some_io() -> Result<(), Box<Error>> {
    Err(io::Error::from(io::ErrorKind::NotFound))?;
    Ok(())
}

derive_str_cherr!(Func2Error);

fn func2() -> Result<(), Box<Error>> {
    let filename = "foo.txt";
    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
    Ok(())
}

enum Func1Error {
    Func2,
    IO(String),
}

impl ::std::fmt::Display for Func1Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            Func1Error::Func2 => write!(f, "func1 error calling func2"),
            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
        }
    }
}

impl ::std::fmt::Debug for Func1Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "{}", self)
    }
}

fn func1() -> ChainResult<(), Func1Error> {
    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
    let filename = String::from("bar.txt");
    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
    Ok(())
}

fn main() -> Result<(), Box<Error>> {
    if let Err(e) = func1() {
        match e.kind() {
            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
            Func1Error::IO(filename) => {
                eprintln!("Main Error Report: func1 error reading '{}'", filename)
            }
        }

        if let Some(e) = e.find_chain_cause::<Func2Error>() {
            eprintln!("Error reported by Func2Error: {}", e)
        }

        eprintln!("\nDebug Error:\n{:?}", e);
    }
    Ok(())
}
# #[allow(dead_code)]
# mod chainerror {
# use std::error::Error;
# use std::fmt::{Debug, Display, Formatter, Result};
# use std::result::Result as StdResult;
# 
# pub struct ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     occurrence: Option<(u32, &'static str)>,
#     kind: T,
#     error_cause: Option<Box<dyn Error + 'static>>,
# }
# 
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
# 
# impl<T: 'static + Display + Debug> ChainError<T> {
#     #[cfg(not(feature = "no-fileline"))]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self {
#             occurrence,
#             kind,
#             error_cause,
#         }
#     }
# 
#     #[cfg(feature = "no-fileline")]
#     pub fn new(
#         kind: T,
#         error_cause: Option<Box<dyn Error + 'static>>,
#         _occurrence: Option<(u32, &'static str)>,
#     ) -> Self {
#         Self { kind, error_cause }
#     }
# 
#     pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
#         let mut cause = self as &(dyn Error + 'static);
#         while let Some(c) = cause.source() {
#             cause = c;
#         }
#         Some(cause)
#     }
# 
#     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<U>() {
#                 return cause.downcast_ref::<U>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
#         let mut cause = self as &(dyn Error + 'static);
#         loop {
#             if cause.is::<ChainError<U>>() {
#                 return cause.downcast_ref::<ChainError<U>>();
#             }
# 
#             match cause.source() {
#                 Some(c) => cause = c,
#                 None => return None,
#             }
#         }
#     }
# 
#     pub fn kind<'a>(&'a self) -> &'a T {
#         &self.kind
#     }
# }
# 
# pub trait ChainErrorDown {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
# }
# 
# use std::any::TypeId;
# 
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         TypeId::of::<T>() == TypeId::of::<U>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         if self.is_chain::<T>() {
#             unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
#         } else {
#             None
#         }
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl ChainErrorDown for dyn Error + 'static + Send + Sync {
#     fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
#         self.is::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
#         self.downcast_ref::<ChainError<T>>()
#     }
# 
#     fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
#         self.downcast_mut::<ChainError<T>>()
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
#     fn source(&self) -> Option<&(dyn Error + 'static)> {
#         if let Some(ref e) = self.error_cause {
#             Some(e.as_ref())
#         } else {
#             None
#         }
#     }
# }
# 
# impl<T: 'static + Display + Debug> Display for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         write!(f, "{}", self.kind)?;
# 
#         #[cfg(feature = "display-cause")]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Display::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# impl<T: 'static + Display + Debug> Debug for ChainError<T> {
#     fn fmt(&self, f: &mut Formatter) -> Result {
#         #[cfg(not(feature = "no-fileline"))]
#         {
#             if let Some(o) = self.occurrence {
#                 write!(f, "{}:{}: ", o.1, o.0)?;
#             }
#         }
# 
#         Debug::fmt(&self.kind, f)?;
# 
#         #[cfg(not(feature = "no-debug-cause"))]
#         {
#             if let Some(e) = self.source() {
#                 writeln!(f, "\nCaused by:")?;
#                 Debug::fmt(&e, f)?;
#             }
#         }
#         Ok(())
#     }
# }
# 
# #[macro_export]
# macro_rules! cherr {
#     ( $k:expr ) => {
#         ChainError::<_>::new($k, None, Some((line!(), file!())))
#     };
#     ( $e:expr, $k:expr ) => {
#         ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
#     };
# }
# 
# #[macro_export]
# macro_rules! mstrerr {
#     ( $t:ident, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $t:path, $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, $t (format!($v, $( $more , )* )))
#     };
#     ( $v:expr $(, $more:expr)* ) => {
#         |e| cherr!(e, format!($v, $( $more , )* ))
#     };
# }
# 
# #[macro_export]
# macro_rules! derive_str_cherr {
#     ($e:ident) => {
#         struct $e(String);
#         impl ::std::fmt::Display for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}", self.0)
#             }
#         }
#         impl ::std::fmt::Debug for $e {
#             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
#                 write!(f, "{}({})", stringify!($e), self.0)
#             }
#         }
#         impl ::std::error::Error for $e {}
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_ref {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_ref::<ChainError<$t>>()
#     };
# }
# 
# #[macro_export]
# macro_rules! try_cherr_mut {
#     ( $e:expr, $t:ident ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
#     ( $e:expr, $t:path ) => {
#         $e.downcast_mut::<ChainError<$t>>()
#     };
# }
# }