{"doc_urls":["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"],"index":{"documentStore":{"docInfo":{"0":{"body":63,"breadcrumbs":3,"title":3},"1":{"body":556,"breadcrumbs":4,"title":4},"10":{"body":603,"breadcrumbs":2,"title":2},"11":{"body":613,"breadcrumbs":2,"title":2},"2":{"body":45,"breadcrumbs":1,"title":1},"3":{"body":581,"breadcrumbs":2,"title":2},"4":{"body":567,"breadcrumbs":3,"title":3},"5":{"body":581,"breadcrumbs":2,"title":2},"6":{"body":564,"breadcrumbs":2,"title":2},"7":{"body":566,"breadcrumbs":3,"title":3},"8":{"body":558,"breadcrumbs":3,"title":3},"9":{"body":563,"breadcrumbs":3,"title":3}},"docs":{"0":{"body":"The most simplest of doing error handling in rust is by returning String as a Box . As you can see by running the example (the \"Play\" button in upper right of the code block), 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;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(\"do_some_io error\")?; Ok(())\n} fn func2() -> Result<(), Box> { if let Err(_) = do_some_io() { Err(\"func2 error\")?; } Ok(())\n} fn func1() -> Result<(), Box> { if let Err(_) = func2() { Err(\"func1 error\")?; } Ok(())\n} fn main() -> Result<(), Box> { func1()\n}","breadcrumbs":"Simple String Errors","id":"0","title":"Simple String Errors"},"1":{"body":"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::*;\nuse std::error::Error;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(\"do_some_io error\")?; Ok(())\n} fn func2() -> Result<(), Box> { if let Err(e) = do_some_io() { Err(cherr!(e, \"func2 error\"))?; } Ok(())\n} fn func1() -> Result<(), Box> { if let Err(e) = func2() { Err(cherr!(e, \"func1 error\"))?; } Ok(())\n} fn main() -> Result<(), Box> { func1()\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::result::Result as StdResult;\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# # pub type ChainResult = StdResult>;\n# # impl ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\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# 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# # pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# let mut cause = self as &(dyn Error + 'static);\n# while let Some(c) = cause.source() {\n# cause = c;\n# }\n# Some(cause)\n# }\n# # pub fn find_cause(&self) -> Option<&U> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::() {\n# return cause.downcast_ref::();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::>() {\n# return cause.downcast_ref::>();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn kind<'a>(&'a self) -> &'a T {\n# &self.kind\n# }\n# }\n# # pub trait ChainErrorDown {\n# fn is_chain(&self) -> bool;\n# fn downcast_chain_ref(&self) -> Option<&ChainError>;\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>;\n# }\n# # use std::any::TypeId;\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# unsafe { Some(&*(self as *const dyn Error as *const &ChainError)) }\n# } else {\n# None\n# }\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# if self.is_chain::() {\n# unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError)) }\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# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &mut ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\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# # Debug::fmt(&self.kind, f)?;\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# # #[macro_export]\n# macro_rules! cherr {\n# ( $k:expr ) => {\n# ChainError::<_>::new($k, None, Some((line!(), file!())))\n# };\n# ( $e:expr, $k:expr ) => {\n# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))\n# };\n# }\n# # #[macro_export]\n# macro_rules! mstrerr {\n# ( $t:ident, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $t:path, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, format!($v, $( $more , )* ))\n# };\n# }\n# # #[macro_export]\n# macro_rules! derive_str_cherr {\n# ($e:ident) => {\n# struct $e(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# # #[macro_export]\n# macro_rules! try_cherr_ref {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_ref::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_ref::>()\n# };\n# }\n# # #[macro_export]\n# macro_rules! try_cherr_mut {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_mut::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_mut::>()\n# };\n# }\n# }","breadcrumbs":"Simple Chained String Errors","id":"1","title":"Simple Chained String Errors"},"10":{"body":"[TBD] 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(Debug)]\nenum 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} 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() -> Result<(), Box> { 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!(\"Error reported by Func2Error: {}\", e) } eprintln!(\"\\nDebug Error:\\n{:?}\", e); } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::result::Result as StdResult;\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# # pub type ChainResult = StdResult>;\n# # impl ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\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# 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# # pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# let mut cause = self as &(dyn Error + 'static);\n# while let Some(c) = cause.source() {\n# cause = c;\n# }\n# Some(cause)\n# }\n# # pub fn find_cause(&self) -> Option<&U> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::() {\n# return cause.downcast_ref::();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::>() {\n# return cause.downcast_ref::>();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn kind<'a>(&'a self) -> &'a T {\n# &self.kind\n# }\n# }\n# # pub trait ChainErrorDown {\n# fn is_chain(&self) -> bool;\n# fn downcast_chain_ref(&self) -> Option<&ChainError>;\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>;\n# }\n# # use std::any::TypeId;\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# unsafe { Some(&*(self as *const dyn Error as *const &ChainError)) }\n# } else {\n# None\n# }\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# if self.is_chain::() {\n# unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError)) }\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# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &mut ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\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# # Debug::fmt(&self.kind, f)?;\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# # #[macro_export]\n# macro_rules! cherr {\n# ( $k:expr ) => {\n# ChainError::<_>::new($k, None, Some((line!(), file!())))\n# };\n# ( $e:expr, $k:expr ) => {\n# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))\n# };\n# }\n# # #[macro_export]\n# macro_rules! mstrerr {\n# ( $t:ident, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $t:path, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, format!($v, $( $more , )* ))\n# };\n# }\n# # #[macro_export]\n# macro_rules! derive_str_cherr {\n# ($e:ident) => {\n# struct $e(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# # #[macro_export]\n# macro_rules! try_cherr_ref {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_ref::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_ref::>()\n# };\n# }\n# # #[macro_export]\n# macro_rules! try_cherr_mut {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_mut::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_mut::>()\n# };\n# }\n# }","breadcrumbs":"ErrorKind to the rescue","id":"10","title":"ErrorKind to the rescue"},"11":{"body":"[TBD] 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} 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() -> Result<(), Box> { 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!(\"Error reported by Func2Error: {}\", e) } eprintln!(\"\\nDebug Error:\\n{:?}\", e); } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::result::Result as StdResult;\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# # pub type ChainResult = StdResult>;\n# # impl ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\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# 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# # pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# let mut cause = self as &(dyn Error + 'static);\n# while let Some(c) = cause.source() {\n# cause = c;\n# }\n# Some(cause)\n# }\n# # pub fn find_cause(&self) -> Option<&U> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::() {\n# return cause.downcast_ref::();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::>() {\n# return cause.downcast_ref::>();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn kind<'a>(&'a self) -> &'a T {\n# &self.kind\n# }\n# }\n# # pub trait ChainErrorDown {\n# fn is_chain(&self) -> bool;\n# fn downcast_chain_ref(&self) -> Option<&ChainError>;\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>;\n# }\n# # use std::any::TypeId;\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# unsafe { Some(&*(self as *const dyn Error as *const &ChainError)) }\n# } else {\n# None\n# }\n# }\n# # fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# if self.is_chain::() {\n# unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError)) }\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# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\n# }\n# }\n# # impl Error for &mut ChainError {\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# if let Some(ref e) = self.error_cause {\n# Some(e.as_ref())\n# } else {\n# None\n# }\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# # Debug::fmt(&self.kind, f)?;\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# # #[macro_export]\n# macro_rules! cherr {\n# ( $k:expr ) => {\n# ChainError::<_>::new($k, None, Some((line!(), file!())))\n# };\n# ( $e:expr, $k:expr ) => {\n# ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))\n# };\n# }\n# # #[macro_export]\n# macro_rules! mstrerr {\n# ( $t:ident, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $t:path, $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, $t (format!($v, $( $more , )* )))\n# };\n# ( $v:expr $(, $more:expr)* ) => {\n# |e| cherr!(e, format!($v, $( $more , )* ))\n# };\n# }\n# # #[macro_export]\n# macro_rules! derive_str_cherr {\n# ($e:ident) => {\n# struct $e(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# # #[macro_export]\n# macro_rules! try_cherr_ref {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_ref::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_ref::>()\n# };\n# }\n# # #[macro_export]\n# macro_rules! try_cherr_mut {\n# ( $e:expr, $t:ident ) => {\n# $e.downcast_mut::>()\n# };\n# ( $e:expr, $t:path ) => {\n# $e.downcast_mut::>()\n# };\n# }\n# }","breadcrumbs":"Debug for the ErrorKind","id":"11","title":"Debug for the ErrorKind"},"2":{"body":"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) as a result. The Debug implementation of ChainError (which is returned by cherr!() ) prints the Debug of T prefixed with the stored filename and line number. ChainError is in our case ChainError .","breadcrumbs":"What did we do here?","id":"2","title":"What did we do here?"},"3":{"body":"Now let's get more rust idiomatic by using .map_err() . use crate::chainerror::*;\nuse std::error::Error;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(\"do_some_io error\")?; Ok(())\n} fn func2() -> Result<(), Box> { do_some_io().map_err(|e| cherr!(e, \"func2 error\"))?; Ok(())\n} fn func1() -> Result<(), Box> { func2().map_err(|e| cherr!(e, \"func1 error\"))?; Ok(())\n} fn main() -> Result<(), Box> { if let Err(e) = func1() { eprintln!(\"{:?}\", e); } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::result::Result as StdResult;\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# # pub type ChainResult = StdResult>;\n# # impl ChainError {\n# #[cfg(not(feature = \"no-fileline\"))]\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# 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# # pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# let mut cause = self as &(dyn Error + 'static);\n# while let Some(c) = cause.source() {\n# cause = c;\n# }\n# Some(cause)\n# }\n# # pub fn find_cause(&self) -> Option<&U> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::() {\n# return cause.downcast_ref::();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# let mut cause = self as &(dyn Error + 'static);\n# loop {\n# if cause.is::>() {\n# return cause.downcast_ref::>();\n# }\n# # match cause.source() {\n# Some(c) => cause = c,\n# None => return None,\n# }\n# }\n# }\n# # pub fn kind<'a>(&'a self) -> &'a T {\n# &self.kind\n# }\n# }\n# # pub trait ChainErrorDown {\n# fn is_chain(&self) -> bool;\n# fn downcast_chain_ref