diff --git a/src/lib.rs b/src/lib.rs index e89a848..547e4f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,182 +1,177 @@ -/*! - -`chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your -binaries, you still have the error backtrace. - -`chainerror` has no dependencies! - -`chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace. -It encapsulates all types, which have `Display + Debug` and can store the error cause internally. - -Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing. - -## Features - -`no-fileline` -: completely turn off storing filename and line - -`display-cause` -: turn on printing a backtrace of the errors in `Display` - -`no-debug-cause` -: turn off printing a backtrace of the errors in `Debug` - - -# Tutorial - -Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html) - -# Examples - -~~~rust -use chainerror::*; -use std::error::Error; -use std::io; -use std::result::Result; - -fn do_some_io() -> Result<(), Box> { - Err(io::Error::from(io::ErrorKind::NotFound))?; - Ok(()) -} - -fn func2() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; - Ok(()) -} - -fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!("func1 error"))?; - Ok(()) -} - -fn main() { - if let Err(e) = func1() { - #[cfg(not(windows))] - assert_eq!( - format!("\n{:?}\n", e), r#" -src/lib.rs:20: func1 error -Caused by: -src/lib.rs:15: Error reading 'foo.txt' -Caused by: -Kind(NotFound) -"# - ); - } -# else { -# unreachable!(); -# } -} -~~~ - - -~~~rust -use chainerror::*; -use std::error::Error; -use std::io; -use std::result::Result; - -fn do_some_io() -> Result<(), Box> { - Err(io::Error::from(io::ErrorKind::NotFound))?; - Ok(()) -} - -fn func3() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; - Ok(()) -} - -derive_str_cherr!(Func2Error); - -fn func2() -> ChainResult<(), Func2Error> { - func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?; - Ok(()) -} - -enum Func1Error { - Func2, - IO(String), -} - -impl ::std::fmt::Display for Func1Error { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - match self { - Func1Error::Func2 => write!(f, "func1 error calling func2"), - Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename), - } - } -} - -impl ::std::fmt::Debug for Func1Error { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", self) - } -} - -fn func1() -> ChainResult<(), Func1Error> { - func2().map_err(|e| cherr!(e, Func1Error::Func2))?; - let filename = String::from("bar.txt"); - do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?; - Ok(()) -} - -fn main() { - if let Err(e) = func1() { - assert!( - match e.kind() { - Func1Error::Func2 => { - eprintln!("Main Error Report: func1 error calling func2"); - true - } - Func1Error::IO(filename) => { - eprintln!("Main Error Report: func1 error reading '{}'", filename); - false - } - } - ); - - assert!(e.find_chain_cause::().is_some()); - - if let Some(e) = e.find_chain_cause::() { - eprintln!("\nError reported by Func2Error: {}", e) - } - - - assert!(e.root_cause().is_some()); - - if let Some(e) = e.root_cause() { - let ioerror = e.downcast_ref::().unwrap(); - eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror); - } - - #[cfg(not(windows))] - assert_eq!( - format!("\n{:?}\n", e), r#" -src/lib.rs:47: func1 error calling func2 -Caused by: -src/lib.rs:22: Func2Error(func2 error: calling func3) -Caused by: -src/lib.rs:15: Error reading 'foo.txt' -Caused by: -Kind(NotFound) -"# - ); - } -# else { -# unreachable!(); -# } -} -~~~ - -!*/ +//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your +//! binaries, you still have the error backtrace. +//! +//! `chainerror` has no dependencies! +//! +//! `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace. +//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally. +//! +//! Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing. +//! +//! ## Features +//! +//! `no-fileline` +//! : completely turn off storing filename and line +//! +//! `display-cause` +//! : turn on printing a backtrace of the errors in `Display` +//! +//! `no-debug-cause` +//! : turn off printing a backtrace of the errors in `Debug` +//! +//! +//! # Tutorial +//! +//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html) +//! +//! # Examples +//! +//! ~~~rust +//! use chainerror::*; +//! use std::error::Error; +//! use std::io; +//! use std::result::Result; +//! +//! fn do_some_io() -> Result<(), Box> { +//! Err(io::Error::from(io::ErrorKind::NotFound))?; +//! Ok(()) +//! } +//! +//! fn func2() -> Result<(), Box> { +//! let filename = "foo.txt"; +//! do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; +//! Ok(()) +//! } +//! +//! fn func1() -> Result<(), Box> { +//! func2().map_err(mstrerr!("func1 error"))?; +//! Ok(()) +//! } +//! +//! fn main() { +//! if let Err(e) = func1() { +//! #[cfg(not(windows))] +//! assert_eq!( +//! format!("\n{:?}\n", e), r#" +//! src/lib.rs:20: func1 error +//! Caused by: +//! src/lib.rs:15: Error reading 'foo.txt' +//! Caused by: +//! Kind(NotFound) +//! "# +//! ); +//! } +//! # else { +//! # unreachable!(); +//! # } +//! } +//! ~~~ +//! +//! +//! ~~~rust +//! use chainerror::*; +//! use std::error::Error; +//! use std::io; +//! use std::result::Result; +//! +//! fn do_some_io() -> Result<(), Box> { +//! Err(io::Error::from(io::ErrorKind::NotFound))?; +//! Ok(()) +//! } +//! +//! fn func3() -> Result<(), Box> { +//! let filename = "foo.txt"; +//! do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; +//! Ok(()) +//! } +//! +//! derive_str_cherr!(Func2Error); +//! +//! fn func2() -> ChainResult<(), Func2Error> { +//! func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?; +//! Ok(()) +//! } +//! +//! enum Func1Error { +//! Func2, +//! IO(String), +//! } +//! +//! impl ::std::fmt::Display for Func1Error { +//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +//! match self { +//! Func1Error::Func2 => write!(f, "func1 error calling func2"), +//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename), +//! } +//! } +//! } +//! +//! impl ::std::fmt::Debug for Func1Error { +//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +//! write!(f, "{}", self) +//! } +//! } +//! +//! fn func1() -> ChainResult<(), Func1Error> { +//! func2().map_err(|e| cherr!(e, Func1Error::Func2))?; +//! let filename = String::from("bar.txt"); +//! do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?; +//! Ok(()) +//! } +//! +//! fn main() { +//! if let Err(e) = func1() { +//! assert!( +//! match e.kind() { +//! Func1Error::Func2 => { +//! eprintln!("Main Error Report: func1 error calling func2"); +//! true +//! } +//! Func1Error::IO(filename) => { +//! eprintln!("Main Error Report: func1 error reading '{}'", filename); +//! false +//! } +//! } +//! ); +//! +//! assert!(e.find_chain_cause::().is_some()); +//! +//! if let Some(e) = e.find_chain_cause::() { +//! eprintln!("\nError reported by Func2Error: {}", e) +//! } +//! +//! +//! assert!(e.root_cause().is_some()); +//! +//! if let Some(e) = e.root_cause() { +//! let ioerror = e.downcast_ref::().unwrap(); +//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror); +//! } +//! +//! #[cfg(not(windows))] +//! assert_eq!( +//! format!("\n{:?}\n", e), r#" +//! src/lib.rs:47: func1 error calling func2 +//! Caused by: +//! src/lib.rs:22: Func2Error(func2 error: calling func3) +//! Caused by: +//! src/lib.rs:15: Error reading 'foo.txt' +//! Caused by: +//! Kind(NotFound) +//! "# +//! ); +//! } +//! # else { +//! # unreachable!(); +//! # } +//! } +//! ~~~ use std::any::TypeId; use std::error::Error; use std::fmt::{Debug, Display, Formatter, Result}; -/** chains an inner error kind `T` with a causing error -**/ +/// chains an inner error kind `T` with a causing error pub struct ChainError { #[cfg(not(feature = "no-fileline"))] occurrence: Option<(u32, &'static str)>, @@ -217,73 +212,70 @@ impl ChainError { self.iter().last() } - /** find the first error cause of type U, if any exists - - # Examples - - ~~~rust - # use crate::chainerror::*; - # use std::error::Error; - # use std::io; - # use std::result::Result; - # - fn do_some_io() -> Result<(), Box> { - Err(io::Error::from(io::ErrorKind::NotFound))?; - Ok(()) - } - - derive_str_cherr!(Func2Error); - - fn func2() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; - Ok(()) - } - - derive_str_cherr!(Func1Error); - - fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!(Func1Error, "func1 error"))?; - Ok(()) - } - - fn main() { - if let Err(e) = func1() { - if let Some(f1err) = e.downcast_chain_ref::() { - - assert!(f1err.find_cause::().is_some()); - - assert!(f1err.find_chain_cause::().is_some()); - } - # else { - # panic!(); - # } - } - # else { - # unreachable!(); - # } - } - ~~~ - **/ + /// Find the first error cause of type U, if any exists + /// + /// # Examples + /// + /// ~~~rust + /// # use crate::chainerror::*; + /// # use std::error::Error; + /// # use std::io; + /// # use std::result::Result; + /// # + /// fn do_some_io() -> Result<(), Box> { + /// Err(io::Error::from(io::ErrorKind::NotFound))?; + /// Ok(()) + /// } + /// + /// derive_str_cherr!(Func2Error); + /// + /// fn func2() -> Result<(), Box> { + /// let filename = "foo.txt"; + /// do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; + /// Ok(()) + /// } + /// + /// derive_str_cherr!(Func1Error); + /// + /// fn func1() -> Result<(), Box> { + /// func2().map_err(mstrerr!(Func1Error, "func1 error"))?; + /// Ok(()) + /// } + /// + /// fn main() { + /// if let Err(e) = func1() { + /// if let Some(f1err) = e.downcast_chain_ref::() { + /// + /// assert!(f1err.find_cause::().is_some()); + /// + /// assert!(f1err.find_chain_cause::().is_some()); + /// } + /// # else { + /// # panic!(); + /// # } + /// } + /// # else { + /// # unreachable!(); + /// # } + /// } + /// ~~~ pub fn find_cause(&self) -> Option<&U> { self.iter().filter_map(Error::downcast_ref::).next() } - /** find the first error cause of type ChainError, if any exists - - Same as `find_cause`, but hides the `ChainError` implementation internals - - # Examples - - ~~~rust,ignore - /// Instead of writing - err.find_cause::>(); - - /// leave out the ChainError implementation detail - err.find_chain_cause::(); - ~~~ - - **/ + /// Find the first error cause of type ChainError, if any exists + /// + /// Same as `find_cause`, but hides the `ChainError` implementation internals + /// + /// # Examples + /// + /// ~~~rust,ignore + /// // Instead of writing + /// err.find_cause::>(); + /// + /// // leave out the ChainError implementation detail + /// err.find_chain_cause::(); + /// ~~~ pub fn find_chain_cause(&self) -> Option<&ChainError> { self.iter() .filter_map(Error::downcast_ref::>) @@ -300,65 +292,63 @@ impl ChainError { .next() } - /** return a reference to T of `ChainError` - - # Examples - - ~~~rust - # use crate::chainerror::*; - # use std::error::Error; - # use std::io; - # use std::result::Result; - # - fn do_some_io() -> Result<(), Box> { - Err(io::Error::from(io::ErrorKind::NotFound))?; - Ok(()) - } - - derive_str_cherr!(Func2Error); - - fn func2() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; - Ok(()) - } - - #[derive(Debug)] - enum Func1ErrorKind { - Func2, - IO(String), - } - - // impl ::std::fmt::Display for Func1ErrorKind {…} - # impl ::std::fmt::Display for Func1ErrorKind { - # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - # match self { - # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"), - # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename), - # } - # } - # } - - fn func1() -> ChainResult<(), Func1ErrorKind> { - func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?; - do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?; - Ok(()) - } - - fn main() { - if let Err(e) = func1() { - match e.kind() { - Func1ErrorKind::Func2 => {}, - Func1ErrorKind::IO(filename) => panic!(), - } - } - # else { - # unreachable!(); - # } - } - ~~~ - - **/ + /// Return a reference to T of `ChainError` + /// + /// # Examples + /// + /// ~~~rust + /// # use crate::chainerror::*; + /// # use std::error::Error; + /// # use std::io; + /// # use std::result::Result; + /// # + /// fn do_some_io() -> Result<(), Box> { + /// Err(io::Error::from(io::ErrorKind::NotFound))?; + /// Ok(()) + /// } + /// + /// derive_str_cherr!(Func2Error); + /// + /// fn func2() -> Result<(), Box> { + /// let filename = "foo.txt"; + /// do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; + /// Ok(()) + /// } + /// + /// #[derive(Debug)] + /// enum Func1ErrorKind { + /// Func2, + /// IO(String), + /// } + /// + /// /// impl ::std::fmt::Display for Func1ErrorKind {…} + /// # impl ::std::fmt::Display for Func1ErrorKind { + /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + /// # match self { + /// # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"), + /// # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename), + /// # } + /// # } + /// # } + /// + /// fn func1() -> ChainResult<(), Func1ErrorKind> { + /// func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?; + /// do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?; + /// Ok(()) + /// } + /// + /// fn main() { + /// if let Err(e) = func1() { + /// match e.kind() { + /// Func1ErrorKind::Func2 => {}, + /// Func1ErrorKind::IO(filename) => panic!(), + /// } + /// } + /// # else { + /// # unreachable!(); + /// # } + /// } + /// ~~~ pub fn kind(&self) -> &T { &self.kind } @@ -384,17 +374,13 @@ impl<'a> Iterator for ErrorIter<'a> { } } -/** convenience trait to hide the `ChainError` implementation internals -**/ +/// Convenience trait to hide the `ChainError` implementation internals pub trait ChainErrorDown { - /** test if of type `ChainError` - **/ + /// Test if of type `ChainError` fn is_chain(&self) -> bool; - /** downcast to a reference of `ChainError` - **/ + /// Downcast to a reference of `ChainError` fn downcast_chain_ref(&self) -> Option<&ChainError>; - /** downcast to a mutable reference of `ChainError` - **/ + /// Downcast to a mutable reference of `ChainError` fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>; } @@ -569,93 +555,91 @@ macro_rules! into_cherr { }; } -/** creates a new `ChainError` - -# Examples - -Create a new ChainError, where `FooError` must implement `Display` and `Debug`. -~~~rust -# use chainerror::*; -# -# #[derive(Debug)] -enum FooError { - Bar, - Baz(&'static str), -} -# -# impl ::std::fmt::Display for FooError { -# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { -# match self { -# FooError::Bar => write!(f, "Bar Error"), -# FooError::Baz(s) => write!(f, "Baz Error: '{}'", s), -# } -# } -# } - -// impl ::std::fmt::Display for FooError - -fn do_some_stuff() -> bool { - false -} - -fn func() -> ChainResult<(), FooError> { - if ! do_some_stuff() { - Err(cherr!(FooError::Baz("Error")))?; - } - Ok(()) -} -# -# pub fn main() { -# match func().unwrap_err().kind() { -# FooError::Baz(s) if s == &"Error" => {}, -# _ => panic!(), -# } -# } -~~~ - -Additionally an error cause can be added. - -~~~rust -# use chainerror::*; -# use std::io; -# use std::error::Error; -# -# #[derive(Debug)] -# enum FooError { -# Bar, -# Baz(&'static str), -# } -# -# impl ::std::fmt::Display for FooError { -# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { -# match self { -# FooError::Bar => write!(f, "Bar Error"), -# FooError::Baz(s) => write!(f, "Baz Error: '{}'", s), -# } -# } -# } -# -fn do_some_stuff() -> Result<(), Box> { - Err(io::Error::from(io::ErrorKind::NotFound))?; - Ok(()) -} - -fn func() -> ChainResult<(), FooError> { - do_some_stuff().map_err( - |e| cherr!(e, FooError::Baz("Error")) - )?; - Ok(()) -} -# -# pub fn main() { -# match func().unwrap_err().kind() { -# FooError::Baz(s) if s == &"Error" => {}, -# _ => panic!(), -# } -# } -~~~ - -**/ +/// Creates a new `ChainError` +/// +/// # Examples +/// +/// Create a new ChainError, where `FooError` must implement `Display` and `Debug`. +/// ~~~rust +/// # use chainerror::*; +/// # +/// # #[derive(Debug)] +/// enum FooError { +/// Bar, +/// Baz(&'static str), +/// } +/// # +/// # impl ::std::fmt::Display for FooError { +/// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +/// # match self { +/// # FooError::Bar => write!(f, "Bar Error"), +/// # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s), +/// # } +/// # } +/// # } +/// +/// // impl ::std::fmt::Display for FooError +/// +/// fn do_some_stuff() -> bool { +/// false +/// } +/// +/// fn func() -> ChainResult<(), FooError> { +/// if ! do_some_stuff() { +/// Err(cherr!(FooError::Baz("Error")))?; +/// } +/// Ok(()) +/// } +/// # +/// # pub fn main() { +/// # match func().unwrap_err().kind() { +/// # FooError::Baz(s) if s == &"Error" => {}, +/// # _ => panic!(), +/// # } +/// # } +/// ~~~ +/// +/// Additionally an error cause can be added. +/// +/// ~~~rust +/// # use chainerror::*; +/// # use std::io; +/// # use std::error::Error; +/// # +/// # #[derive(Debug)] +/// # enum FooError { +/// # Bar, +/// # Baz(&'static str), +/// # } +/// # +/// # impl ::std::fmt::Display for FooError { +/// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +/// # match self { +/// # FooError::Bar => write!(f, "Bar Error"), +/// # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s), +/// # } +/// # } +/// # } +/// # +/// fn do_some_stuff() -> Result<(), Box> { +/// Err(io::Error::from(io::ErrorKind::NotFound))?; +/// Ok(()) +/// } +/// +/// fn func() -> ChainResult<(), FooError> { +/// do_some_stuff().map_err( +/// |e| cherr!(e, FooError::Baz("Error")) +/// )?; +/// Ok(()) +/// } +/// # +/// # pub fn main() { +/// # match func().unwrap_err().kind() { +/// # FooError::Baz(s) if s == &"Error" => {}, +/// # _ => panic!(), +/// # } +/// # } +/// ~~~ #[macro_export] macro_rules! cherr { ( $k:expr ) => ({ @@ -685,93 +669,92 @@ macro_rules! cherr { } -/** convenience macro for |e| cherr!(e, format!(…)) - -# Examples - -~~~rust -# use crate::chainerror::*; -# use std::error::Error; -# use std::io; -# use std::result::Result; -# -# fn do_some_io() -> Result<(), Box> { -# Err(io::Error::from(io::ErrorKind::NotFound))?; -# Ok(()) -# } -# -fn func2() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; - Ok(()) -} - -fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!("func1 error"))?; - Ok(()) -} - -# fn main() { -# if let Err(e) = func1() { -# #[cfg(not(windows))] -# assert_eq!( -# format!("\n{:?}\n", e), r#" -# src/lib.rs:20: func1 error -# Caused by: -# src/lib.rs:15: Error reading 'foo.txt' -# Caused by: -# Kind(NotFound) -# "# -# ); -# } else { -# unreachable!(); -# } -# } -~~~ - -`mstrerr!()` can also be used to map a new `ChainError`, where T was defined with -`derive_str_cherr!(T)` - -~~~rust -# use crate::chainerror::*; -# use std::error::Error; -# use std::io; -# use std::result::Result; -# -# fn do_some_io() -> Result<(), Box> { -# Err(io::Error::from(io::ErrorKind::NotFound))?; -# Ok(()) -# } -# -derive_str_cherr!(Func2Error); - -fn func2() -> Result<(), Box> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; - Ok(()) -} - -derive_str_cherr!(Func1Error); - -fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!(Func1Error, "func1 error"))?; - Ok(()) -} -# -# fn main() { -# if let Err(e) = func1() { -# if let Some(f1err) = e.downcast_chain_ref::() { -# assert!(f1err.find_cause::>().is_some()); -# assert!(f1err.find_chain_cause::().is_some()); -# } else { -# panic!(); -# } -# } else { -# unreachable!(); -# } -# } -~~~ -**/ +/// Convenience macro for `|e| cherr!(e, format!(…))` +/// +/// # Examples +/// +/// ~~~rust +/// # use crate::chainerror::*; +/// # use std::error::Error; +/// # use std::io; +/// # use std::result::Result; +/// # +/// # fn do_some_io() -> Result<(), Box> { +/// # Err(io::Error::from(io::ErrorKind::NotFound))?; +/// # Ok(()) +/// # } +/// # +/// fn func2() -> Result<(), Box> { +/// let filename = "foo.txt"; +/// do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; +/// Ok(()) +/// } +/// +/// fn func1() -> Result<(), Box> { +/// func2().map_err(mstrerr!("func1 error"))?; +/// Ok(()) +/// } +/// +/// # fn main() { +/// # if let Err(e) = func1() { +/// # #[cfg(not(windows))] +/// # assert_eq!( +/// # format!("\n{:?}\n", e), r#" +/// # src/lib.rs:20: func1 error +/// # Caused by: +/// # src/lib.rs:15: Error reading 'foo.txt' +/// # Caused by: +/// # Kind(NotFound) +/// # "# +/// # ); +/// # } else { +/// # unreachable!(); +/// # } +/// # } +/// ~~~ +/// +/// `mstrerr!()` can also be used to map a new `ChainError`, where T was defined with +/// `derive_str_cherr!(T)` +/// +/// ~~~rust +/// # use crate::chainerror::*; +/// # use std::error::Error; +/// # use std::io; +/// # use std::result::Result; +/// # +/// # fn do_some_io() -> Result<(), Box> { +/// # Err(io::Error::from(io::ErrorKind::NotFound))?; +/// # Ok(()) +/// # } +/// # +/// derive_str_cherr!(Func2Error); +/// +/// fn func2() -> Result<(), Box> { +/// let filename = "foo.txt"; +/// do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; +/// Ok(()) +/// } +/// +/// derive_str_cherr!(Func1Error); +/// +/// fn func1() -> Result<(), Box> { +/// func2().map_err(mstrerr!(Func1Error, "func1 error"))?; +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # if let Err(e) = func1() { +/// # if let Some(f1err) = e.downcast_chain_ref::() { +/// # assert!(f1err.find_cause::>().is_some()); +/// # assert!(f1err.find_chain_cause::().is_some()); +/// # } else { +/// # panic!(); +/// # } +/// # } else { +/// # unreachable!(); +/// # } +/// # } +/// ~~~ #[macro_export] macro_rules! mstrerr { ( $t:ident, $msg:expr ) => ({ @@ -803,41 +786,42 @@ macro_rules! mstrerr { }); } -/** convenience macro for cherr!(T(format!(…))) where T(String) -~~~rust -# use crate::chainerror::*; -# use std::error::Error; -# use std::result::Result; -# -derive_str_cherr!(Func2Error); - -fn func2() -> ChainResult<(), Func2Error> { - let filename = "foo.txt"; - Err(strerr!(Func2Error, "Error reading '{}'", filename)) -} - -derive_str_cherr!(Func1Error); - -fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!(Func1Error, "func1 error"))?; - Ok(()) -} -# -# fn main() { -# if let Err(e) = func1() { -# if let Some(f1err) = e.downcast_chain_ref::() { -# assert!(f1err.find_cause::>().is_some()); -# assert!(f1err.find_chain_cause::().is_some()); -# } else { -# panic!(); -# } -# } else { -# unreachable!(); -# } -# } -~~~ - -**/ +/// Convenience macro for `cherr!(T(format!(…)))` where `T(String)` +/// +/// # Examples +/// +/// ~~~rust +/// # use crate::chainerror::*; +/// # use std::error::Error; +/// # use std::result::Result; +/// # +/// derive_str_cherr!(Func2Error); +/// +/// fn func2() -> ChainResult<(), Func2Error> { +/// let filename = "foo.txt"; +/// Err(strerr!(Func2Error, "Error reading '{}'", filename)) +/// } +/// +/// derive_str_cherr!(Func1Error); +/// +/// fn func1() -> Result<(), Box> { +/// func2().map_err(mstrerr!(Func1Error, "func1 error"))?; +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # if let Err(e) = func1() { +/// # if let Some(f1err) = e.downcast_chain_ref::() { +/// # assert!(f1err.find_cause::>().is_some()); +/// # assert!(f1err.find_chain_cause::().is_some()); +/// # } else { +/// # panic!(); +/// # } +/// # } else { +/// # unreachable!(); +/// # } +/// # } +/// ~~~ #[macro_export] macro_rules! strerr { ( $t:ident, $msg:expr ) => ({ @@ -869,49 +853,49 @@ macro_rules! strerr { }); } -/** convenience macro to create a "new type" T(String) and implement Display + Debug for T - -~~~rust -# use crate::chainerror::*; -# use std::error::Error; -# use std::io; -# use std::result::Result; -# -# fn do_some_io() -> Result<(), Box> { -# Err(io::Error::from(io::ErrorKind::NotFound))?; -# Ok(()) -# } -# -derive_str_cherr!(Func2Error); - -fn func2() -> ChainResult<(), Func2Error> { - let filename = "foo.txt"; - do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; - Ok(()) -} - -derive_str_cherr!(Func1Error); - -fn func1() -> Result<(), Box> { - func2().map_err(mstrerr!(Func1Error, "func1 error"))?; - Ok(()) -} -# -# fn main() { -# if let Err(e) = func1() { -# if let Some(f1err) = e.downcast_chain_ref::() { -# assert!(f1err.find_cause::>().is_some()); -# assert!(f1err.find_chain_cause::().is_some()); -# } else { -# panic!(); -# } -# } else { -# unreachable!(); -# } -# } -~~~ - -**/ +/// Convenience macro to create a "new type" T(String) and implement Display + Debug for T +/// +/// # Examples +/// +/// ~~~rust +/// # use crate::chainerror::*; +/// # use std::error::Error; +/// # use std::io; +/// # use std::result::Result; +/// # +/// # fn do_some_io() -> Result<(), Box> { +/// # Err(io::Error::from(io::ErrorKind::NotFound))?; +/// # Ok(()) +/// # } +/// # +/// derive_str_cherr!(Func2Error); +/// +/// fn func2() -> ChainResult<(), Func2Error> { +/// let filename = "foo.txt"; +/// do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; +/// Ok(()) +/// } +/// +/// derive_str_cherr!(Func1Error); +/// +/// fn func1() -> Result<(), Box> { +/// func2().map_err(mstrerr!(Func1Error, "func1 error"))?; +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # if let Err(e) = func1() { +/// # if let Some(f1err) = e.downcast_chain_ref::() { +/// # assert!(f1err.find_cause::>().is_some()); +/// # assert!(f1err.find_chain_cause::().is_some()); +/// # } else { +/// # panic!(); +/// # } +/// # } else { +/// # unreachable!(); +/// # } +/// # } +/// ~~~ #[macro_export] macro_rules! derive_str_cherr { ($e:ident) => {