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