diff --git a/print.html b/print.html
index a8d9060..c2e891c 100644
--- a/print.html
+++ b/print.html
@@ -75,7 +75,7 @@
@@ -299,7 +299,7 @@ fn main() -> Result<(), Box<Error>> {
With relatively small changes and the help of the cherr!
macro of the chainerror
crate
the String
errors are now chained together.
Press the play button in the upper right corner and see the nice debug output.
-
use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
@@ -327,6 +327,7 @@ fn func1() -> Result<(), Box<Error>> {
fn main() -> Result<(), Box<Error>> {
func1()
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -1015,15 +1016,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -1118,21 +1113,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -1185,21 +1171,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -1291,7 +1268,7 @@ prints the Debug
of T
prefixed with the stored filenam
ChainError<T>
in our case is ChainError<String>
.
Now let's get more rust idiomatic by using .map_err()
.
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
@@ -1318,6 +1295,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -2006,15 +1984,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -2109,21 +2081,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -2176,21 +2139,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -2283,7 +2237,7 @@ 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 chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -2310,6 +2264,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -2998,15 +2953,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -3101,21 +3050,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -3168,21 +3108,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -3262,7 +3193,7 @@ fn main() -> Result<(), Box<Error>> {
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 chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -3294,6 +3225,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -3982,15 +3914,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -4085,21 +4011,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -4152,21 +4069,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -4253,7 +4161,7 @@ fn main() -> Result<(), Box<Error>> {
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T>
This is how it looks like, when using those:
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -4293,6 +4201,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -4981,15 +4890,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -5084,21 +4987,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -5151,21 +5045,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -5260,7 +5145,7 @@ to call .find_cause::<io::Error>()
.
or to use .root_cause()
, which of course can be of any type implementing std::error::Error
.
if let Some(e) = s.root_cause() {
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -5301,6 +5186,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -5989,15 +5875,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -6092,21 +5972,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -6159,21 +6030,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -6265,7 +6127,7 @@ derive_str_cherr!(Func1Error);
if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() {
hiding the ChainError<T>
implementation detail.
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -6306,6 +6168,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -6994,15 +6857,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -7097,21 +6954,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -7164,21 +7012,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -7274,7 +7113,7 @@ fn main() -> Result<(), Box<Error>> {
but this is not valid rust code, so we end up doing it the hard way.
In the next chapter, we will see, how to solve this more elegantly.
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -7314,6 +7153,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -8002,15 +7842,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -8105,21 +7939,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -8172,21 +7997,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -8274,7 +8090,7 @@ use ChainResult<(), Func1ErrorKind>
.
In main
we can now directly use the methods of ChainError<T>
without downcasting the error first.
Also a nice match
on ChainError<T>.kind()
is now possible, which returns &T
, meaning
&Func1ErrorKind
here.
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -8332,6 +8148,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -9020,15 +8837,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -9123,21 +8934,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -9190,21 +8992,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -9297,7 +9090,7 @@ src/main.rs:40: func1 error calling func2
To create your own Errors, you might find crates which create enum Display+Debug
via derive macros.
Also noteworthy is custom_error to define your custom errors,
which can then be used with chainerror
.
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -9361,6 +9154,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -10049,15 +9843,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -10152,21 +9940,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -10219,21 +9998,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -10313,7 +10083,7 @@ fn main() -> Result<(), Box<Error>> {
Because ChainError implements Deref to &T, we can also match on *e
instead of e.kind()
or call a function with &e
-use crate::chainerror::*;
+use chainerror::*;
use std::error::Error;
use std::io;
use std::result::Result;
@@ -10388,6 +10158,7 @@ fn main() -> Result<(), Box<Error>> {
}
Ok(())
}
+
# #[allow(dead_code)]
# mod chainerror {
# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
@@ -11076,15 +10847,9 @@ fn main() -> Result<(), Box<Error>> {
# ( None, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!(None, format!($fmt, $($arg)+ ))
# });
-# ( $e:ident, $k:expr ) => ({
-# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
-# });
# ( $e:path, $k:expr ) => ({
# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
# });
-# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($e, format!($fmt, $($arg)+ ))
-# });
# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($e, format!($fmt, $($arg)+ ))
# });
@@ -11179,21 +10944,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! mstrerr {
-# ( $t:ident, $msg:expr ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# |e| cherr!(e, $t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# |e| cherr!(e, $t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
# });
@@ -11246,21 +11002,12 @@ fn main() -> Result<(), Box<Error>> {
# /// ~~~
# #[macro_export]
# macro_rules! strerr {
-# ( $t:ident, $msg:expr ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $msg:expr, ) => ({
-# cherr!($t ($msg.to_string()))
-# });
# ( $t:path, $msg:expr, ) => ({
# cherr!($t ($msg.to_string()))
# });
-# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({
-# cherr!($t (format!($fmt, $($arg)+ )))
-# });
# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
# cherr!($t (format!($fmt, $($arg)+ )))
# });
@@ -11337,6 +11084,1013 @@ fn main() -> Result<(), Box<Error>> {
# }
# }
+
+I would advise to only expose an mycrate::ErrorKind
and type alias mycrate::Error
to ChainError<mycrate::ErrorKind>
+so you can tell your library users to use the .kind()
method as std::io::Error
does.
+If you later decide to make your own Error
implementation, your library users don't
+have to change much or anything.
+# #[allow(dead_code)]
+# #[macro_use]
+# pub mod chainerror {
+# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
+# //! binaries, you still have the error backtrace.
+# //!
+# //! `chainerror` has no dependencies!
+# //!
+# //! `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
+# //! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
+# //!
+# //! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
+# //!
+# //! ## Features
+# //!
+# //! `no-fileline`
+# //! : completely turn off storing filename and line
+# //!
+# //! `display-cause`
+# //! : turn on printing a backtrace of the errors in `Display`
+# //!
+# //! `no-debug-cause`
+# //! : turn off printing a backtrace of the errors in `Debug`
+# //!
+# //!
+# //! # Tutorial
+# //!
+# //! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
+# //!
+# //! # Examples
+# //!
+# //! ~~~rust
+# //! use 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() {
+# //! if let Err(e) = func1() {
+# //! #[cfg(not(windows))]
+# //! assert_eq!(
+# //! format!("\n{:?}\n", e), r#"
+# //! src/lib.rs:20: func1 error
+# //! Caused by:
+# //! src/lib.rs:15: Error reading 'foo.txt'
+# //! Caused by:
+# //! Kind(NotFound)
+# //! "#
+# //! );
+# //! }
+# //! # else {
+# //! # unreachable!();
+# //! # }
+# //! }
+# //! ~~~
+# //!
+# //!
+# //! ~~~rust
+# //! use 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 func3() -> Result<(), Box<Error>> {
+# //! let filename = "foo.txt";
+# //! do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
+# //! Ok(())
+# //! }
+# //!
+# //! derive_str_cherr!(Func2Error);
+# //!
+# //! fn func2() -> ChainResult<(), Func2Error> {
+# //! func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
+# //! 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() {
+# //! if let Err(e) = func1() {
+# //! assert!(
+# //! match e.kind() {
+# //! Func1Error::Func2 => {
+# //! eprintln!("Main Error Report: func1 error calling func2");
+# //! true
+# //! }
+# //! Func1Error::IO(filename) => {
+# //! eprintln!("Main Error Report: func1 error reading '{}'", filename);
+# //! false
+# //! }
+# //! }
+# //! );
+# //!
+# //! assert!(e.find_chain_cause::<Func2Error>().is_some());
+# //!
+# //! if let Some(e) = e.find_chain_cause::<Func2Error>() {
+# //! eprintln!("\nError reported by Func2Error: {}", e)
+# //! }
+# //!
+# //!
+# //! assert!(e.root_cause().is_some());
+# //!
+# //! if let Some(e) = e.root_cause() {
+# //! let ioerror = e.downcast_ref::<io::Error>().unwrap();
+# //! eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
+# //! }
+# //!
+# //! #[cfg(not(windows))]
+# //! assert_eq!(
+# //! format!("\n{:?}\n", e), r#"
+# //! src/lib.rs:47: func1 error calling func2
+# //! Caused by:
+# //! src/lib.rs:22: Func2Error(func2 error: calling func3)
+# //! Caused by:
+# //! src/lib.rs:15: Error reading 'foo.txt'
+# //! Caused by:
+# //! Kind(NotFound)
+# //! "#
+# //! );
+# //! }
+# //! # else {
+# //! # unreachable!();
+# //! # }
+# //! }
+# //! ~~~
+#
+# use std::any::TypeId;
+# use std::error::Error;
+# use std::fmt::{Debug, Display, Formatter, Result};
+#
+# /// chains an inner error kind `T` with a causing error
+# pub struct ChainError<T> {
+# #[cfg(not(feature = "no-fileline"))]
+# occurrence: Option<(u32, &'static str)>,
+# kind: T,
+# error_cause: Option<Box<dyn Error + 'static>>,
+# }
+#
+# /// convenience type alias
+# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
+#
+# impl<T: 'static + Display + Debug> ChainError<T> {
+# #[cfg(not(feature = "no-fileline"))]
+# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
+# 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")]
+# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
+# pub fn new(
+# kind: T,
+# error_cause: Option<Box<dyn Error + 'static>>,
+# _occurrence: Option<(u32, &'static str)>,
+# ) -> Self {
+# Self { kind, error_cause }
+# }
+#
+# /// return the root cause of the error chain, if any exists
+# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
+# self.iter().last()
+# }
+#
+# /// Find the first error cause of type U, if any exists
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust
+# /// # 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() {
+# /// if let Err(e) = func1() {
+# /// if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
+# ///
+# /// assert!(f1err.find_cause::<io::Error>().is_some());
+# ///
+# /// assert!(f1err.find_chain_cause::<Func2Error>().is_some());
+# /// }
+# /// # else {
+# /// # panic!();
+# /// # }
+# /// }
+# /// # else {
+# /// # unreachable!();
+# /// # }
+# /// }
+# /// ~~~
+# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
+# self.iter().filter_map(Error::downcast_ref::<U>).next()
+# }
+#
+# /// Find the first error cause of type `ChainError<U>`, if any exists
+# ///
+# /// Same as `find_cause`, but hides the `ChainError<U>` implementation internals
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust,ignore
+# /// // Instead of writing
+# /// err.find_cause::<ChainError<FooError>>();
+# ///
+# /// // leave out the ChainError<FooError> implementation detail
+# /// err.find_chain_cause::<FooError>();
+# /// ~~~
+# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
+# self.iter()
+# .filter_map(Error::downcast_ref::<ChainError<U>>)
+# .next()
+# }
+#
+# /// Find the first error cause of type `ChainError<U>` or `U`, if any exists and return `U`
+# ///
+# /// Same as `find_cause` and `find_chain_cause`, but hides the `ChainError<U>` implementation internals
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust,ignore
+# /// // Instead of writing
+# /// err.find_cause::<ChainError<FooErrorKind>>();
+# /// // and/or
+# /// err.find_chain_cause::<FooErrorKind>();
+# /// // and/or
+# /// err.find_cause::<FooErrorKind>();
+# ///
+# /// // leave out the ChainError<FooErrorKind> implementation detail
+# /// err.find_chain_or_kind::<FooErrorKind>();
+# /// ~~~
+# pub fn find_kind_or_cause<U: Error + 'static>(&self) -> Option<&U> {
+# self.iter()
+# .filter_map(|e| {
+# e.downcast_ref::<ChainError<U>>()
+# .map(|e| e.kind())
+# .or_else(|| e.downcast_ref::<U>())
+# })
+# .next()
+# }
+#
+# /// Return a reference to T of `ChainError<T>`
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust
+# /// # 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 Func1ErrorKind {
+# /// Func2,
+# /// IO(String),
+# /// }
+# ///
+# /// /// impl ::std::fmt::Display for Func1ErrorKind {…}
+# /// # impl ::std::fmt::Display for Func1ErrorKind {
+# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+# /// # match self {
+# /// # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
+# /// # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
+# /// # }
+# /// # }
+# /// # }
+# ///
+# /// fn func1() -> ChainResult<(), Func1ErrorKind> {
+# /// func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
+# /// do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
+# /// Ok(())
+# /// }
+# ///
+# /// fn main() {
+# /// if let Err(e) = func1() {
+# /// match e.kind() {
+# /// Func1ErrorKind::Func2 => {},
+# /// Func1ErrorKind::IO(filename) => panic!(),
+# /// }
+# /// }
+# /// # else {
+# /// # unreachable!();
+# /// # }
+# /// }
+# /// ~~~
+# pub fn kind(&self) -> &T {
+# &self.kind
+# }
+#
+# /// Returns an Iterator over all error causes/sources
+# ///
+# /// # Example
+# ///
+# ///
+# pub fn iter(&self) -> impl Iterator<Item = &(dyn Error + 'static)> {
+# ErrorIter {
+# current: Some(self),
+# }
+# }
+# }
+#
+# struct ErrorIter<'a> {
+# current: Option<&'a (dyn Error + 'static)>,
+# }
+#
+# impl<'a> Iterator for ErrorIter<'a> {
+# type Item = &'a (dyn Error + 'static);
+#
+# fn next(&mut self) -> Option<Self::Item> {
+# let current = self.current;
+# self.current = self.current.and_then(Error::source);
+# current
+# }
+# }
+#
+# impl<T: 'static + Display + Debug> std::ops::Deref for ChainError<T> {
+# type Target = T;
+#
+# fn deref(&self) -> &Self::Target {
+# &self.kind
+# }
+# }
+#
+# /// Convenience trait to hide the `ChainError<T>` implementation internals
+# pub trait ChainErrorDown {
+# /// Test if of type `ChainError<T>`
+# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
+# /// Downcast to a reference of `ChainError<T>`
+# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
+# /// Downcast to a mutable reference of `ChainError<T>`
+# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
+# }
+#
+# 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>() {
+# #[allow(clippy::cast_ptr_alignment)]
+# 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>() {
+# #[allow(clippy::cast_ptr_alignment)]
+# 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)> {
+# self.error_cause.as_ref().map(|e| e.as_ref())
+# }
+# }
+#
+# impl<T: 'static + Display + Debug> Error for &ChainError<T> {
+# fn source(&self) -> Option<&(dyn Error + 'static)> {
+# self.error_cause.as_ref().map(|e| e.as_ref())
+# }
+# }
+#
+# impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
+# fn source(&self) -> Option<&(dyn Error + 'static)> {
+# self.error_cause.as_ref().map(|e| e.as_ref())
+# }
+# }
+#
+# 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)?;
+# }
+# }
+#
+# if self.is_chain::<String>() {
+# Display::fmt(&self.kind, f)?;
+# } else {
+# 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(())
+# }
+# }
+#
+# pub trait ChainErrorFrom<T>: Sized {
+# fn chain_error_from(_: T, line_filename: Option<(u32, &'static str)>) -> ChainError<Self>;
+# }
+#
+# pub trait IntoChainError<T>: Sized {
+# fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError<T>;
+# }
+#
+# impl<T, U> IntoChainError<U> for T
+# where
+# U: ChainErrorFrom<T>,
+# {
+# fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError<U> {
+# U::chain_error_from(self, line_filename)
+# }
+# }
+#
+# impl<T, U> ChainErrorFrom<T> for U
+# where
+# T: Into<U>,
+# U: 'static + Display + Debug,
+# {
+# fn chain_error_from(t: T, line_filename: Option<(u32, &'static str)>) -> ChainError<Self> {
+# let e: U = t.into();
+# ChainError::<_>::new(e, None, line_filename)
+# }
+# }
+#
+# #[macro_export]
+# macro_rules! minto_cherr {
+# ( ) => {
+# |e| e.into_chain_error(Some((line!(), file!())))
+# };
+# }
+#
+# #[macro_export]
+# macro_rules! into_cherr {
+# ( $t:expr ) => {
+# $t.into_chain_error(Some((line!(), file!())))
+# };
+# }
+#
+# /// Creates a new `ChainError<T>`
+# ///
+# /// # Examples
+# ///
+# /// Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
+# /// ~~~rust
+# /// # use chainerror::*;
+# /// #
+# /// # #[derive(Debug)]
+# /// enum FooError {
+# /// Bar,
+# /// Baz(&'static str),
+# /// }
+# /// #
+# /// # impl ::std::fmt::Display for FooError {
+# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+# /// # match self {
+# /// # FooError::Bar => write!(f, "Bar Error"),
+# /// # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
+# /// # }
+# /// # }
+# /// # }
+# ///
+# /// // impl ::std::fmt::Display for FooError
+# ///
+# /// fn do_some_stuff() -> bool {
+# /// false
+# /// }
+# ///
+# /// fn func() -> ChainResult<(), FooError> {
+# /// if ! do_some_stuff() {
+# /// Err(cherr!(FooError::Baz("Error")))?;
+# /// }
+# /// Ok(())
+# /// }
+# /// #
+# /// # pub fn main() {
+# /// # match func().unwrap_err().kind() {
+# /// # FooError::Baz(s) if s == &"Error" => {},
+# /// # _ => panic!(),
+# /// # }
+# /// # }
+# /// ~~~
+# ///
+# /// Additionally an error cause can be added.
+# ///
+# /// ~~~rust
+# /// # use chainerror::*;
+# /// # use std::io;
+# /// # use std::error::Error;
+# /// #
+# /// # #[derive(Debug)]
+# /// # enum FooError {
+# /// # Bar,
+# /// # Baz(&'static str),
+# /// # }
+# /// #
+# /// # impl ::std::fmt::Display for FooError {
+# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+# /// # match self {
+# /// # FooError::Bar => write!(f, "Bar Error"),
+# /// # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
+# /// # }
+# /// # }
+# /// # }
+# /// #
+# /// fn do_some_stuff() -> Result<(), Box<Error>> {
+# /// Err(io::Error::from(io::ErrorKind::NotFound))?;
+# /// Ok(())
+# /// }
+# ///
+# /// fn func() -> ChainResult<(), FooError> {
+# /// do_some_stuff().map_err(
+# /// |e| cherr!(e, FooError::Baz("Error"))
+# /// )?;
+# /// Ok(())
+# /// }
+# /// #
+# /// # pub fn main() {
+# /// # match func().unwrap_err().kind() {
+# /// # FooError::Baz(s) if s == &"Error" => {},
+# /// # _ => panic!(),
+# /// # }
+# /// # }
+# /// ~~~
+# #[macro_export]
+# macro_rules! cherr {
+# ( $k:expr ) => ({
+# ChainError::<_>::new($k, None, Some((line!(), file!())))
+# });
+# ( None, $k:expr ) => ({
+# ChainError::<_>::new($k, None, Some((line!(), file!())))
+# });
+# ( None, $fmt:expr, $($arg:tt)+ ) => ({
+# cherr!(None, format!($fmt, $($arg)+ ))
+# });
+# ( None, $fmt:expr, $($arg:tt)+ ) => ({
+# cherr!(None, format!($fmt, $($arg)+ ))
+# });
+# ( $e:path, $k:expr ) => ({
+# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
+# });
+# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({
+# cherr!($e, format!($fmt, $($arg)+ ))
+# });
+#
+# }
+#
+# /// Convenience macro for `|e| cherr!(e, format!(…))`
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust
+# /// # 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() {
+# /// # if let Err(e) = func1() {
+# /// # #[cfg(not(windows))]
+# /// # assert_eq!(
+# /// # format!("\n{:?}\n", e), r#"
+# /// # src/lib.rs:20: func1 error
+# /// # Caused by:
+# /// # src/lib.rs:15: Error reading 'foo.txt'
+# /// # Caused by:
+# /// # Kind(NotFound)
+# /// # "#
+# /// # );
+# /// # } else {
+# /// # unreachable!();
+# /// # }
+# /// # }
+# /// ~~~
+# ///
+# /// `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
+# /// `derive_str_cherr!(T)`
+# ///
+# /// ~~~rust
+# /// # 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() {
+# /// # if let Err(e) = func1() {
+# /// # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
+# /// # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
+# /// # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
+# /// # } else {
+# /// # panic!();
+# /// # }
+# /// # } else {
+# /// # unreachable!();
+# /// # }
+# /// # }
+# /// ~~~
+# #[macro_export]
+# macro_rules! mstrerr {
+# ( $t:path, $msg:expr ) => ({
+# |e| cherr!(e, $t ($msg.to_string()))
+# });
+# ( $t:path, $msg:expr, ) => ({
+# |e| cherr!(e, $t ($msg.to_string()))
+# });
+# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
+# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))
+# });
+# ($msg:expr) => ({
+# |e| cherr!(e, $msg.to_string())
+# });
+# ($msg:expr, ) => ({
+# |e| cherr!(e, $msg.to_string())
+# });
+# ($fmt:expr, $($arg:tt)+) => ({
+# |e| cherr!(e, format!($fmt, $($arg)+ ))
+# });
+# }
+#
+# /// Convenience macro for `cherr!(T(format!(…)))` where `T(String)`
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust
+# /// # use crate::chainerror::*;
+# /// # use std::error::Error;
+# /// # use std::result::Result;
+# /// #
+# /// derive_str_cherr!(Func2Error);
+# ///
+# /// fn func2() -> ChainResult<(), Func2Error> {
+# /// let filename = "foo.txt";
+# /// Err(strerr!(Func2Error, "Error reading '{}'", filename))
+# /// }
+# ///
+# /// derive_str_cherr!(Func1Error);
+# ///
+# /// fn func1() -> Result<(), Box<Error>> {
+# /// func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
+# /// Ok(())
+# /// }
+# /// #
+# /// # fn main() {
+# /// # if let Err(e) = func1() {
+# /// # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
+# /// # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
+# /// # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
+# /// # } else {
+# /// # panic!();
+# /// # }
+# /// # } else {
+# /// # unreachable!();
+# /// # }
+# /// # }
+# /// ~~~
+# #[macro_export]
+# macro_rules! strerr {
+# ( $t:path, $msg:expr ) => ({
+# cherr!($t ($msg.to_string()))
+# });
+# ( $t:path, $msg:expr, ) => ({
+# cherr!($t ($msg.to_string()))
+# });
+# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({
+# cherr!($t (format!($fmt, $($arg)+ )))
+# });
+# ($msg:expr) => ({
+# cherr!($msg.to_string())
+# });
+# ($msg:expr, ) => ({
+# cherr!($msg.to_string())
+# });
+# ($fmt:expr, $($arg:tt)+) => ({
+# cherr!(format!($fmt, $($arg)+ ))
+# });
+# }
+#
+# /// Convenience macro to create a "new type" T(String) and implement Display + Debug for T
+# ///
+# /// # Examples
+# ///
+# /// ~~~rust
+# /// # 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() -> ChainResult<(), Func2Error> {
+# /// 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() {
+# /// # if let Err(e) = func1() {
+# /// # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
+# /// # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
+# /// # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
+# /// # } else {
+# /// # panic!();
+# /// # }
+# /// # } else {
+# /// # unreachable!();
+# /// # }
+# /// # }
+# /// ~~~
+# #[macro_export]
+# macro_rules! derive_str_cherr {
+# ($e:ident) => {
+# pub struct $e(pub 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 {}
+# };
+# }
+# }
+pub mod mycrate {
+ use crate::chainerror::*; // omit the `crate::` part
+ use std::io;
+
+ fn do_some_io() -> std::result::Result<(), Box<std::error::Error>> {
+ Err(io::Error::from(io::ErrorKind::NotFound))?;
+ Ok(())
+ }
+
+ derive_str_cherr!(Func2Error);
+
+ fn func2() -> std::result::Result<(), Box<std::error::Error>> {
+ let filename = "foo.txt";
+ do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
+ Ok(())
+ }
+
+ #[derive(Debug)]
+ pub enum ErrorKind {
+ Func2,
+ IO(String),
+ }
+
+ pub type Error = ChainError<ErrorKind>;
+ pub type Result<T> = std::result::Result<T, Error>;
+
+ impl ::std::fmt::Display for ErrorKind {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ match self {
+ ErrorKind::Func2 => write!(f, "func1 error calling func2"),
+ ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
+ }
+ }
+ }
+
+ pub fn func1() -> Result<()> {
+ func2().map_err(|e| cherr!(e, ErrorKind::Func2))?;
+ let filename = String::from("bar.txt");
+ do_some_io().map_err(|e| cherr!(e, ErrorKind::IO(filename)))?;
+ Ok(())
+ }
+}
+
+fn main() -> Result<(), Box<std::error::Error>> {
+ use mycrate::func1;
+ use mycrate::ErrorKind;
+ use std::error::Error;
+ use std::io;
+
+ if let Err(e) = func1() {
+ match e.kind() {
+ ErrorKind::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
+ ErrorKind::IO(ref filename) => {
+ eprintln!("Main Error Report: func1 error reading '{}'", filename)
+ }
+ }
+
+ eprintln!();
+ let mut s : &Error = &e;
+ 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;
+ }
+
+ eprintln!("\nDebug Error:\n{:?}", e);
+ }
+ Ok(())
+}
+
That's it for now…
Happy error handling!
diff --git a/searchindex.js b/searchindex.js
index c8a11e5..056a08d 100644
--- a/searchindex.js
+++ b/searchindex.js
@@ -1 +1 @@
-window.search = {"doc_urls":["index.html#chainerror","index.html#example","index.html#features","tutorial1.html#simple-string-errors","tutorial2.html#simple-chained-string-errors","tutorial2.html#what-did-we-do-here","tutorial3.html#mapping-errors","tutorial4.html#saving-coding-chars","tutorial5.html#the-source-of-errors","tutorial6.html#downcast-the-errors","tutorial7.html#the-root-cause-of-all-errors","tutorial8.html#finding-an-error-cause","tutorial9.html#selective-error-handling","tutorial10.html#errorkind-to-the-rescue","tutorial11.html#debug-for-the-errorkind","tutorial12.html#deref-for-the-errorkind","end.html#the-end"],"index":{"documentStore":{"docInfo":{"0":{"body":60,"breadcrumbs":1,"title":1},"1":{"body":170,"breadcrumbs":1,"title":1},"10":{"body":1661,"breadcrumbs":3,"title":3},"11":{"body":1628,"breadcrumbs":3,"title":3},"12":{"body":1642,"breadcrumbs":3,"title":3},"13":{"body":1699,"breadcrumbs":2,"title":2},"14":{"body":1705,"breadcrumbs":2,"title":2},"15":{"body":1685,"breadcrumbs":2,"title":2},"16":{"body":18,"breadcrumbs":1,"title":1},"2":{"body":20,"breadcrumbs":1,"title":1},"3":{"body":94,"breadcrumbs":3,"title":3},"4":{"body":1599,"breadcrumbs":4,"title":4},"5":{"body":44,"breadcrumbs":1,"title":1},"6":{"body":1617,"breadcrumbs":2,"title":2},"7":{"body":1603,"breadcrumbs":3,"title":3},"8":{"body":1616,"breadcrumbs":2,"title":2},"9":{"body":1626,"breadcrumbs":2,"title":2}},"docs":{"0":{"body":"Build Status Crate Rust Documentation chainerror provides an error backtrace like failure without doing a real backtrace, so even after you strip your binaries, you still have the error backtrace. chainerror has no dependencies! chainerror uses .source() of std::error::Error along with line()! and file()! to provide a nice debug error backtrace. It encapsulates all types, which have Display + Debug and can store the error cause internally. Along with the ChainError struct, chainerror comes with some useful helper macros to save a lot of typing. Debug information is worth it! Now continue reading the Tutorial","breadcrumbs":"chainerror","id":"0","title":"chainerror"},"1":{"body":"Output: $ cargo run -q --example example\nMain Error Report: func1 error calling func2 Error reported by Func2Error: func2 error: calling func3 The root cause was: std::io::Error: Kind( NotFound\n) Debug Error:\nexamples/example.rs:45: func1 error calling func2\nCaused by:\nexamples/example.rs:20: Func2Error(func2 error: calling func3)\nCaused by:\nexamples/example.rs:13: Error reading 'foo.txt'\nCaused by:\nKind(NotFound) use chainerror::*;\nuse std::error::Error;\nuse std::io;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(())\n} fn func3() -> Result<(), Box> { let filename = \"foo.txt\"; do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?; Ok(())\n} derive_str_cherr!(Func2Error); fn func2() -> ChainResult<(), Func2Error> { func3().map_err(mstrerr!(Func2Error, \"func2 error: calling func3\"))?; Ok(())\n} enum Func1Error { Func2, IO(String),\n} 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), } }\n} impl ::std::fmt::Debug for Func1Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, \"{}\", self) }\n} 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(())\n} fn main() { 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::() { eprintln!(\"\\nError reported by Func2Error: {}\", e) } if let Some(e) = e.root_cause() { let ioerror = e.downcast_ref::().unwrap(); eprintln!(\"\\nThe root cause was: std::io::Error: {:#?}\", ioerror); } eprintln!(\"\\nDebug Error:\\n{:?}\", e); }\n}","breadcrumbs":"Example:","id":"1","title":"Example:"},"10":{"body":"chainerror also has some helper methods: fn is_chain(&self) -> bool\nfn downcast_chain_ref(&self) -> Option<&ChainError>\nfn downcast_chain_mut(&mut self) -> Option<&mut ChainError>\nfn root_cause(&self) -> Option<&(dyn Error + 'static)>\nfn find_cause(&self) -> Option<&U>\nfn find_chain_cause(&self) -> Option<&ChainError>\nfn kind<'a>(&'a self) -> &'a T Using downcast_chain_ref::() gives a ChainError , which can be used to call .find_cause::() . if let Some(s) = e.downcast_chain_ref::() { if let Some(ioerror) = s.find_cause::() { or to use .root_cause() , which of course can be of any type implementing std::error::Error . if let Some(e) = s.root_cause() { use crate::chainerror::*;\nuse std::error::Error;\nuse std::io;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(())\n} fn func2() -> Result<(), Box> { let filename = \"foo.txt\"; do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?; Ok(())\n} fn func1() -> Result<(), Box> { func2().map_err(mstrerr!(\"func1 error\"))?; Ok(())\n} fn main() -> Result<(), Box> { if let Err(e) = func1() { eprintln!(\"Error: {}\", e); if let Some(s) = e.downcast_chain_ref::() { if let Some(ioerror) = s.find_cause::() { 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::().unwrap(); eprintln!(\"The root cause was: std::io::Error: {:#?}\", ioerror); } } } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your\n# //! binaries, you still have the error backtrace.\n# //!\n# //! `chainerror` has no dependencies!\n# //!\n# //! `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.\n# //! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.\n# //!\n# //! Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing.\n# //!\n# //! ## Features\n# //!\n# //! `no-fileline`\n# //! : completely turn off storing filename and line\n# //!\n# //! `display-cause`\n# //! : turn on printing a backtrace of the errors in `Display`\n# //!\n# //! `no-debug-cause`\n# //! : turn off printing a backtrace of the errors in `Debug`\n# //!\n# //!\n# //! # Tutorial\n# //!\n# //! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)\n# //!\n# //! # Examples\n# //!\n# //! ~~~rust\n# //! use chainerror::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func2() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func1() -> Result<(), Box> {\n# //! func2().map_err(mstrerr!(\"func1 error\"))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e), r#\"\n# //! src/lib.rs:20: func1 error\n# //! Caused by:\n# //! src/lib.rs:15: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! }\n# //! ~~~\n# //!\n# //!\n# //! ~~~rust\n# //! use chainerror::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func3() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! derive_str_cherr!(Func2Error);\n# //!\n# //! fn func2() -> ChainResult<(), Func2Error> {\n# //! func3().map_err(mstrerr!(Func2Error, \"func2 error: calling func3\"))?;\n# //! Ok(())\n# //! }\n# //!\n# //! enum Func1Error {\n# //! Func2,\n# //! IO(String),\n# //! }\n# //!\n# //! impl ::std::fmt::Display for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! match self {\n# //! Func1Error::Func2 => write!(f, \"func1 error calling func2\"),\n# //! Func1Error::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# //! }\n# //! }\n# //! }\n# //!\n# //! impl ::std::fmt::Debug for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! write!(f, \"{}\", self)\n# //! }\n# //! }\n# //!\n# //! fn func1() -> ChainResult<(), Func1Error> {\n# //! func2().map_err(|e| cherr!(e, Func1Error::Func2))?;\n# //! let filename = String::from(\"bar.txt\");\n# //! do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! assert!(\n# //! match e.kind() {\n# //! Func1Error::Func2 => {\n# //! eprintln!(\"Main Error Report: func1 error calling func2\");\n# //! true\n# //! }\n# //! Func1Error::IO(filename) => {\n# //! eprintln!(\"Main Error Report: func1 error reading '{}'\", filename);\n# //! false\n# //! }\n# //! }\n# //! );\n# //!\n# //! assert!(e.find_chain_cause::().is_some());\n# //!\n# //! if let Some(e) = e.find_chain_cause::() {\n# //! eprintln!(\"\\nError reported by Func2Error: {}\", e)\n# //! }\n# //!\n# //!\n# //! assert!(e.root_cause().is_some());\n# //!\n# //! if let Some(e) = e.root_cause() {\n# //! let ioerror = e.downcast_ref::().unwrap();\n# //! eprintln!(\"\\nThe root cause was: std::io::Error: {:#?}\", ioerror);\n# //! }\n# //!\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e), r#\"\n# //! src/lib.rs:47: func1 error calling func2\n# //! Caused by:\n# //! src/lib.rs:22: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! src/lib.rs:15: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! }\n# //! ~~~\n# # use std::any::TypeId;\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# # /// chains an inner error kind `T` with a causing error\n# pub struct ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\n# occurrence: Option<(u32, &'static str)>,\n# kind: T,\n# error_cause: Option>,\n# }\n# # /// convenience type alias\n# pub type ChainResult = std::result::Result>;\n# # impl ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\n# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly\n# pub fn new(\n# kind: T,\n# error_cause: Option>,\n# occurrence: Option<(u32, &'static str)>,\n# ) -> Self {\n# Self {\n# occurrence,\n# kind,\n# error_cause,\n# }\n# }\n# # #[cfg(feature = \"no-fileline\")]\n# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly\n# pub fn new(\n# kind: T,\n# error_cause: Option>,\n# _occurrence: Option<(u32, &'static str)>,\n# ) -> Self {\n# Self { kind, error_cause }\n# }\n# # /// return the root cause of the error chain, if any exists\n# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# self.iter().last()\n# }\n# # /// Find the first error cause of type U, if any exists\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// #\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_cherr!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().map_err(mstrerr!(Func2Error, \"Error reading '{}'\", filename))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_cherr!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().map_err(mstrerr!(Func1Error, \"func1 error\"))?;\n# /// Ok(())\n# /// }\n# ///\n# /// fn main() {\n# /// if let Err(e) = func1() {\n# /// if let Some(f1err) = e.downcast_chain_ref::() {\n# ///\n# /// assert!(f1err.find_cause::().is_some());\n# ///\n# /// assert!(f1err.find_chain_cause::().is_some());\n# /// }\n# /// # else {\n# /// # panic!();\n# /// # }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// }\n# /// ~~~\n# pub fn find_cause(&self) -> Option<&U> {\n# self.iter().filter_map(Error::downcast_ref::).next()\n# }\n# # /// Find the first error cause of type `ChainError`, if any exists\n# ///\n# /// Same as `find_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust,ignore\n# /// // Instead of writing\n# /// err.find_cause::>();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_chain_cause::();\n# /// ~~~\n# pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# self.iter()\n# .filter_map(Error::downcast_ref::>)\n# .next()\n# }\n# # /// Find the first error cause of type `ChainError` or `U`, if any exists and return `U`\n# ///\n# /// Same as `find_cause` and `find_chain_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust,ignore\n# /// // Instead of writing\n# /// err.find_cause::>();\n# /// // and/or\n# /// err.find_chain_cause::();\n# /// // and/or\n# /// err.find_cause::();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_chain_or_kind::();\n# /// ~~~\n# pub fn find_kind_or_cause(&self) -> Option<&U> {\n# self.iter()\n# .filter_map(|e| {\n# e.downcast_ref::>()\n# .map(|e| e.kind())\n# .or_else(|| e.downcast_ref::())\n# })\n# .next()\n# }\n# # /// Return a reference to T of `ChainError`\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// #\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_cherr!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().map_err(mstrerr!(Func2Error, \"Error reading '{}'\", filename))?;\n# /// Ok(())\n# /// }\n# ///\n# /// #[derive(Debug)]\n# /// enum Func1ErrorKind {\n# /// Func2,\n# /// IO(String),\n# /// }\n# ///\n# /// /// impl ::std::fmt::Display for Func1ErrorKind {…}\n# /// # impl ::std::fmt::Display for Func1ErrorKind {\n# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# /// # match self {\n# /// # Func1ErrorKind::Func2 => write!(f, \"func1 error calling func2\"),\n# /// # Func1ErrorKind::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# /// # }\n# /// # }\n# /// # }\n# ///\n# /// fn func1() -> ChainResult<(), Func1ErrorKind> {\n# /// func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;\n# /// do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO(\"bar.txt\".into())))?;\n# /// Ok(())\n# /// }\n# ///\n# /// fn main() {\n# /// if let Err(e) = func1() {\n# /// match e.kind() {\n# /// Func1ErrorKind::Func2 => {},\n# /// Func1ErrorKind::IO(filename) => panic!(),\n# /// }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// }\n# /// ~~~\n# pub fn kind(&self) -> &T {\n# &self.kind\n# }\n# # /// Returns an Iterator over all error causes/sources\n# ///\n# /// # Example\n# ///\n# ///\n# pub fn iter(&self) -> impl Iterator- {\n# ErrorIter {\n# current: Some(self),\n# }\n# }\n# }\n# # struct ErrorIter<'a> {\n# current: Option<&'a (dyn Error + 'static)>,\n# }\n# # impl<'a> Iterator for ErrorIter<'a> {\n# type Item = &'a (dyn Error + 'static);\n# # fn next(&mut self) -> Option {\n# let current = self.current;\n# self.current = self.current.and_then(Error::source);\n# current\n# }\n# }\n# # impl std::ops::Deref for ChainError {\n# type Target = T;\n# # fn deref(&self) -> &Self::Target {\n# &self.kind\n# }\n# }\n# # /// Convenience trait to hide the `ChainError` implementation internals\n# pub trait ChainErrorDown {\n# /// Test if of type `ChainError`\n# fn is_chain(&self) -> bool;\n# /// Downcast to a reference of `ChainError`\n# fn downcast_chain_ref(&self) -> Option<&ChainError>;\n# /// Downcast to a mutable reference of `ChainError`\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>;\n# }\n# # impl ChainErrorDown for ChainError {\n# fn is_chain(&self) -> bool {\n# TypeId::of::() == TypeId::of::()\n# }\n# # fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# Some(&*(self as *const dyn Error as *const &ChainError))\n# }\n# } else {\n# None\n# }\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# Some(&mut *(self as *mut dyn Error as *mut &mut ChainError))\n# }\n# } else {\n# None\n# }\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static {\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static + Send {\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static + Send + Sync {\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# }\n# # impl Error for ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause.as_ref().map(|e| e.as_ref())\n# }\n# }\n# # impl Error for &ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause.as_ref().map(|e| e.as_ref())\n# }\n# }\n# # impl Error for &mut ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause.as_ref().map(|e| e.as_ref())\n# }\n# }\n# # impl Display for ChainError {\n# fn fmt(&self, f: &mut Formatter) -> Result {\n# write!(f, \"{}\", self.kind)?;\n# # #[cfg(feature = \"display-cause\")]\n# {\n# if let Some(e) = self.source() {\n# writeln!(f, \"\\nCaused by:\")?;\n# Display::fmt(&e, f)?;\n# }\n# }\n# Ok(())\n# }\n# }\n# # impl Debug for ChainError {\n# fn fmt(&self, f: &mut Formatter) -> Result {\n# #[cfg(not(feature = \"no-fileline\"))]\n# {\n# if let Some(o) = self.occurrence {\n# write!(f, \"{}:{}: \", o.1, o.0)?;\n# }\n# }\n# # if self.is_chain::() {\n# Display::fmt(&self.kind, f)?;\n# } else {\n# Debug::fmt(&self.kind, f)?;\n# }\n# # #[cfg(not(feature = \"no-debug-cause\"))]\n# {\n# if let Some(e) = self.source() {\n# writeln!(f, \"\\nCaused by:\")?;\n# Debug::fmt(&e, f)?;\n# }\n# }\n# Ok(())\n# }\n# }\n# # pub trait ChainErrorFrom: Sized {\n# fn chain_error_from(_: T, line_filename: Option<(u32, &'static str)>) -> ChainError;\n# }\n# # pub trait IntoChainError: Sized {\n# fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError;\n# }\n# # impl IntoChainError for T\n# where\n# U: ChainErrorFrom,\n# {\n# fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError {\n# U::chain_error_from(self, line_filename)\n# }\n# }\n# # impl ChainErrorFrom for U\n# where\n# T: Into,\n# U: 'static + Display + Debug,\n# {\n# fn chain_error_from(t: T, line_filename: Option<(u32, &'static str)>) -> ChainError {\n# let e: U = t.into();\n# ChainError::<_>::new(e, None, line_filename)\n# }\n# }\n# # #[macro_export]\n# macro_rules! minto_cherr {\n# ( ) => {\n# |e| e.into_chain_error(Some((line!(), file!())))\n# };\n# }\n# # #[macro_export]\n# macro_rules! into_cherr {\n# ( $t:expr ) => {\n# $t.into_chain_error(Some((line!(), file!())))\n# };\n# }\n# # /// Creates a new `ChainError`\n# ///\n# /// # Examples\n# ///\n# /// Create a new ChainError, where `FooError` must implement `Display` and `Debug`.\n# /// ~~~rust\n# /// # use chainerror::*;\n# /// #\n# /// # #[derive(Debug)]\n# /// enum FooError {\n# /// Bar,\n# /// Baz(&'static str),\n# /// }\n# /// #\n# /// # impl ::std::fmt::Display for FooError {\n# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# /// # match self {\n# /// # FooError::Bar => write!(f, \"Bar Error\"),\n# /// # FooError::Baz(s) => write!(f, \"Baz Error: '{}'\", s),\n# /// # }\n# /// # }\n# /// # }\n# ///\n# /// // impl ::std::fmt::Display for FooError\n# ///\n# /// fn do_some_stuff() -> bool {\n# /// false\n# /// }\n# ///\n# /// fn func() -> ChainResult<(), FooError> {\n# /// if ! do_some_stuff() {\n# /// Err(cherr!(FooError::Baz(\"Error\")))?;\n# /// }\n# /// Ok(())\n# /// }\n# /// #\n# /// # pub fn main() {\n# /// # match func().unwrap_err().kind() {\n# /// # FooError::Baz(s) if s == &\"Error\" => {},\n# /// # _ => panic!(),\n# /// # }\n# /// # }\n# /// ~~~\n# ///\n# /// Additionally an error cause can be added.\n# ///\n# /// ~~~rust\n# /// # use chainerror::*;\n# /// # use std::io;\n# /// # use std::error::Error;\n# /// #\n# /// # #[derive(Debug)]\n# /// # enum FooError {\n# /// # Bar,\n# /// # Baz(&'static str),\n# /// # }\n# /// #\n# /// # impl ::std::fmt::Display for FooError {\n# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# /// # match self {\n# /// # FooError::Bar => write!(f, \"Bar Error\"),\n# /// # FooError::Baz(s) => write!(f, \"Baz Error: '{}'\", s),\n# /// # }\n# /// # }\n# /// # }\n# /// #\n# /// fn do_some_stuff() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// fn func() -> ChainResult<(), FooError> {\n# /// do_some_stuff().map_err(\n# /// |e| cherr!(e, FooError::Baz(\"Error\"))\n# /// )?;\n# /// Ok(())\n# /// }\n# /// #\n# /// # pub fn main() {\n# /// # match func().unwrap_err().kind() {\n# /// # FooError::Baz(s) if s == &\"Error\" => {},\n# /// # _ => panic!(),\n# /// # }\n# /// # }\n# /// ~~~\n# #[macro_export]\n# macro_rules! cherr {\n# ( $k:expr ) => ({\n# ChainError::<_>::new($k, None, Some((line!(), file!())))\n# });\n# ( None, $k:expr ) => ({\n# ChainError::<_>::new($k, None, Some((line!(), file!())))\n# });\n# ( None, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!(None, format!($fmt, $($arg)+ ))\n# });\n# ( None, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!(None, format!($fmt, $($arg)+ ))\n# });\n# ( $e:ident, $k:expr ) => ({\n# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))\n# });\n# ( $e:path, $k:expr ) => ({\n# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))\n# });\n# ( $e:ident, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!($e, format!($fmt, $($arg)+ ))\n# });\n# ( $e:path, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!($e, format!($fmt, $($arg)+ ))\n# });\n# # }\n# # /// Convenience macro for `|e| cherr!(e, format!(…))`\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// #\n# /// # fn do_some_io() -> Result<(), Box> {\n# /// # Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// # Ok(())\n# /// # }\n# /// #\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?;\n# /// Ok(())\n# /// }\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().map_err(mstrerr!(\"func1 error\"))?;\n# /// Ok(())\n# /// }\n# ///\n# /// # fn main() {\n# /// # if let Err(e) = func1() {\n# /// # #[cfg(not(windows))]\n# /// # assert_eq!(\n# /// # format!(\"\\n{:?}\\n\", e), r#\"\n# /// # src/lib.rs:20: func1 error\n# /// # Caused by:\n# /// # src/lib.rs:15: Error reading 'foo.txt'\n# /// # Caused by:\n# /// # Kind(NotFound)\n# /// # \"#\n# /// # );\n# /// # } else {\n# /// # unreachable!();\n# /// # }\n# /// # }\n# /// ~~~\n# ///\n# /// `mstrerr!()` can also be used to map a new `ChainError`, where T was defined with\n# /// `derive_str_cherr!(T)`\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// #\n# /// # fn do_some_io() -> Result<(), Box> {\n# /// # Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// # Ok(())\n# /// # }\n# /// #\n# /// derive_str_cherr!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().map_err(mstrerr!(Func2Error, \"Error reading '{}'\", filename))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_cherr!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().map_err(mstrerr!(Func1Error, \"func1 error\"))?;\n# /// Ok(())\n# /// }\n# /// #\n# /// # fn main() {\n# /// # if let Err(e) = func1() {\n# /// # if let Some(f1err) = e.downcast_chain_ref::() {\n# /// # assert!(f1err.find_cause::>().is_some());\n# /// # assert!(f1err.find_chain_cause::().is_some());\n# /// # } else {\n# /// # panic!();\n# /// # }\n# /// # } else {\n# /// # unreachable!();\n# /// # }\n# /// # }\n# /// ~~~\n# #[macro_export]\n# macro_rules! mstrerr {\n# ( $t:ident, $msg:expr ) => ({\n# |e| cherr!(e, $t ($msg.to_string()))\n# });\n# ( $t:path, $msg:expr ) => ({\n# |e| cherr!(e, $t ($msg.to_string()))\n# });\n# ( $t:ident, $msg:expr, ) => ({\n# |e| cherr!(e, $t ($msg.to_string()))\n# });\n# ( $t:path, $msg:expr, ) => ({\n# |e| cherr!(e, $t ($msg.to_string()))\n# });\n# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({\n# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))\n# });\n# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({\n# |e| cherr!(e, $t (format!($fmt, $($arg)+ )))\n# });\n# ($msg:expr) => ({\n# |e| cherr!(e, $msg.to_string())\n# });\n# ($msg:expr, ) => ({\n# |e| cherr!(e, $msg.to_string())\n# });\n# ($fmt:expr, $($arg:tt)+) => ({\n# |e| cherr!(e, format!($fmt, $($arg)+ ))\n# });\n# }\n# # /// Convenience macro for `cherr!(T(format!(…)))` where `T(String)`\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::result::Result;\n# /// #\n# /// derive_str_cherr!(Func2Error);\n# ///\n# /// fn func2() -> ChainResult<(), Func2Error> {\n# /// let filename = \"foo.txt\";\n# /// Err(strerr!(Func2Error, \"Error reading '{}'\", filename))\n# /// }\n# ///\n# /// derive_str_cherr!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().map_err(mstrerr!(Func1Error, \"func1 error\"))?;\n# /// Ok(())\n# /// }\n# /// #\n# /// # fn main() {\n# /// # if let Err(e) = func1() {\n# /// # if let Some(f1err) = e.downcast_chain_ref::() {\n# /// # assert!(f1err.find_cause::>().is_some());\n# /// # assert!(f1err.find_chain_cause::().is_some());\n# /// # } else {\n# /// # panic!();\n# /// # }\n# /// # } else {\n# /// # unreachable!();\n# /// # }\n# /// # }\n# /// ~~~\n# #[macro_export]\n# macro_rules! strerr {\n# ( $t:ident, $msg:expr ) => ({\n# cherr!($t ($msg.to_string()))\n# });\n# ( $t:path, $msg:expr ) => ({\n# cherr!($t ($msg.to_string()))\n# });\n# ( $t:ident, $msg:expr, ) => ({\n# cherr!($t ($msg.to_string()))\n# });\n# ( $t:path, $msg:expr, ) => ({\n# cherr!($t ($msg.to_string()))\n# });\n# ( $t:ident, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!($t (format!($fmt, $($arg)+ )))\n# });\n# ( $t:path, $fmt:expr, $($arg:tt)+ ) => ({\n# cherr!($t (format!($fmt, $($arg)+ )))\n# });\n# ($msg:expr) => ({\n# cherr!($msg.to_string())\n# });\n# ($msg:expr, ) => ({\n# cherr!($msg.to_string())\n# });\n# ($fmt:expr, $($arg:tt)+) => ({\n# cherr!(format!($fmt, $($arg)+ ))\n# });\n# }\n# # /// Convenience macro to create a \"new type\" T(String) and implement Display + Debug for T\n# ///\n# /// # Examples\n# ///\n# /// ~~~rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// #\n# /// # fn do_some_io() -> Result<(), Box> {\n# /// # Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// # Ok(())\n# /// # }\n# /// #\n# /// derive_str_cherr!(Func2Error);\n# ///\n# /// fn func2() -> ChainResult<(), Func2Error> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().map_err(mstrerr!(Func2Error, \"Error reading '{}'\", filename))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_cherr!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().map_err(mstrerr!(Func1Error, \"func1 error\"))?;\n# /// Ok(())\n# /// }\n# /// #\n# /// # fn main() {\n# /// # if let Err(e) = func1() {\n# /// # if let Some(f1err) = e.downcast_chain_ref::() {\n# /// # assert!(f1err.find_cause::>().is_some());\n# /// # assert!(f1err.find_chain_cause::().is_some());\n# /// # } else {\n# /// # panic!();\n# /// # }\n# /// # } else {\n# /// # unreachable!();\n# /// # }\n# /// # }\n# /// ~~~\n# #[macro_export]\n# macro_rules! derive_str_cherr {\n# ($e:ident) => {\n# pub struct $e(pub String);\n# impl ::std::fmt::Display for $e {\n# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# write!(f, \"{}\", self.0)\n# }\n# }\n# impl ::std::fmt::Debug for $e {\n# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# write!(f, \"{}({})\", stringify!($e), self.0)\n# }\n# }\n# impl ::std::error::Error for $e {}\n# };\n# }\n# }","breadcrumbs":"The root cause of all Errors","id":"10","title":"The root cause of all Errors"},"11":{"body":"To distinguish the errors occuring in various places, we can define named string errors with the \"new type\" pattern. derive_str_cherr!(Func2Error);\nderive_str_cherr!(Func1Error); Instead of ChainError we now have struct Func1Error(String) and ChainError . In the main function you can see, how we can match the different errors. Also see: if let Some(f2err) = f1err.find_chain_cause::() { as a shortcut to if let Some(f2err) = f1err.find_cause::>() { hiding the ChainError implementation detail. use crate::chainerror::*;\nuse std::error::Error;\nuse std::io;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(())\n} derive_str_cherr!(Func2Error); fn func2() -> Result<(), Box> { let filename = \"foo.txt\"; do_some_io().map_err(mstrerr!(Func2Error, \"Error reading '{}'\", filename))?; Ok(())\n} derive_str_cherr!(Func1Error); fn func1() -> Result<(), Box> { func2().map_err(mstrerr!(Func1Error, \"func1 error\"))?; Ok(())\n} fn main() -> Result<(), Box> { if let Err(e) = func1() { if let Some(f1err) = e.downcast_chain_ref::() { eprintln!(\"Func1Error: {}\", f1err); if let Some(f2err) = f1err.find_cause::>() { eprintln!(\"Func2Error: {}\", f2err); } if let Some(f2err) = f1err.find_chain_cause::() { eprintln!(\"Debug Func2Error:\\n{:?}\", f2err); } } } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your\n# //! binaries, you still have the error backtrace.\n# //!\n# //! `chainerror` has no dependencies!\n# //!\n# //! `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.\n# //! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.\n# //!\n# //! Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing.\n# //!\n# //! ## Features\n# //!\n# //! `no-fileline`\n# //! : completely turn off storing filename and line\n# //!\n# //! `display-cause`\n# //! : turn on printing a backtrace of the errors in `Display`\n# //!\n# //! `no-debug-cause`\n# //! : turn off printing a backtrace of the errors in `Debug`\n# //!\n# //!\n# //! # Tutorial\n# //!\n# //! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)\n# //!\n# //! # Examples\n# //!\n# //! ~~~rust\n# //! use chainerror::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func2() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func1() -> Result<(), Box> {\n# //! func2().map_err(mstrerr!(\"func1 error\"))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e), r#\"\n# //! src/lib.rs:20: func1 error\n# //! Caused by:\n# //! src/lib.rs:15: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! }\n# //! ~~~\n# //!\n# //!\n# //! ~~~rust\n# //! use chainerror::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func3() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().map_err(mstrerr!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! derive_str_cherr!(Func2Error);\n# //!\n# //! fn func2() -> ChainResult<(), Func2Error> {\n# //! func3().map_err(mstrerr!(Func2Error, \"func2 error: calling func3\"))?;\n# //! Ok(())\n# //! }\n# //!\n# //! enum Func1Error {\n# //! Func2,\n# //! IO(String),\n# //! }\n# //!\n# //! impl ::std::fmt::Display for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! match self {\n# //! Func1Error::Func2 => write!(f, \"func1 error calling func2\"),\n# //! Func1Error::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# //! }\n# //! }\n# //! }\n# //!\n# //! impl ::std::fmt::Debug for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! write!(f, \"{}\", self)\n# //! }\n# //! }\n# //!\n# //! fn func1() -> ChainResult<(), Func1Error> {\n# //! func2().map_err(|e| cherr!(e, Func1Error::Func2))?;\n# //! let filename = String::from(\"bar.txt\");\n# //! do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! assert!(\n# //! match e.kind() {\n# //! Func1Error::Func2 => {\n# //! eprintln!(\"Main Error Report: func1 error calling func2\");\n# //! true\n# //! }\n# //! Func1Error::IO(filename) => {\n# //! eprintln!(\"Main Error Report: func1 error reading '{}'\", filename);\n# //! false\n# //! }\n# //! }\n# //! );\n# //!\n# //! assert!(e.find_chain_cause::().is_some());\n# //!\n# //! if let Some(e) = e.find_chain_cause::() {\n# //! eprintln!(\"\\nError reported by Func2Error: {}\", e)\n# //! }\n# //!\n# //!\n# //! assert!(e.root_cause().is_some());\n# //!\n# //! if let Some(e) = e.root_cause() {\n# //! let ioerror = e.downcast_ref::().unwrap();\n# //! eprintln!(\"\\nThe root cause was: std::io::Error: {:#?}\", ioerror);\n# //! }\n# //!\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e), r#\"\n# //! src/lib.rs:47: func1 error calling func2\n# //! Caused by:\n# //! src/lib.rs:22: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! src/lib.rs:15: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! }\n# //! ~~~\n# # use std::any::TypeId;\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# # /// chains an inner error kind `T` with a causing error\n# pub struct ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\n# occurrence: Option<(u32, &'static str)>,\n# kind: T,\n# error_cause: Option>,\n# }\n# # /// convenience type alias\n# pub type ChainResult = std::result::Result>;\n# # impl