diff --git a/index.html b/index.html
index 49e601f..8bc20a5 100644
--- a/index.html
+++ b/index.html
@@ -169,199 +169,78 @@
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!
+Having nested function returning errors, the output doesn't tell where the error originates from.
+use std::path::PathBuf;
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = std::fs::read_to_string(&path)?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn process_config_file() -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = read_config_file("foo.txt".into())?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = process_config_file() {
+ eprintln!("Error:\n{:?}", e);
+ }
+}
+
+This gives the output:
+Error:
+Os { code: 2, kind: NotFound, message: "No such file or directory" }
+
+and you have no idea where it comes from.
+With chainerror
, you can supply a context and get a nice error backtrace:
+use chainerror::prelude::v1::*;
+use std::path::PathBuf;
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn process_config_file() -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = process_config_file() {
+ eprintln!("Error:\n{:?}", e);
+ }
+}
+
+with the output:
+Error:
+examples/simple.rs:14:51: read the config file
+Caused by:
+examples/simple.rs:7:47: Reading file: "foo.txt"
+Caused by:
+Os { code: 2, kind: NotFound, message: "No such file or directory" }
+
chainerror
uses .source()
of std::error::Error
along with #[track_caller]
and Location
to provide a nice debug error backtrace.
It encapsulates all types, which have Display + Debug
and can store the error cause internally.
Along with the ChainError<T>
struct, chainerror
comes with some useful helper macros to save a lot of typing.
+chainerror
has no dependencies!
Debug information is worth it!
display-cause
: turn on printing a backtrace of the errors in Display
Read the Tutorial
-
-examples/example.rs:
-// […]
-fn main() {
- if let Err(e) = func1() {
- eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
- eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
- // […]
- }
-}
-
-$ cargo run -q --example example
-Debug Error {:?}:
-examples/example.rs:46:13: func1 error calling func2
-Caused by:
-examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-Caused by:
-examples/example.rs:14:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-
-Alternative Debug Error {:#?}:
-ChainError<example::Func1Error> {
- occurrence: Some(
- "examples/example.rs:46:13",
- ),
- kind: func1 error calling func2,
- source: Some(
- ChainError<example::Func2Error> {
- occurrence: Some(
- "examples/example.rs:21:13",
- ),
- kind: Func2Error(func2 error: calling func3),
- source: Some(
- ChainError<alloc::string::String> {
- occurrence: Some(
- "examples/example.rs:14:18",
- ),
- kind: "Error reading \'foo.txt\'",
- source: Some(
- Kind(
- NotFound,
- ),
- ),
- },
- ),
- },
- ),
-}
-
-
-#![allow(unused)]
-fn main() {
-use chainerror::prelude::v1::*;
-use std::error::Error;
-use std::io;
-use std::result::Result;
-
-fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
- Err(io::Error::from(io::ErrorKind::NotFound))?;
- Ok(())
-}
-
-fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
- let filename = "foo.txt";
- do_some_io().context(format!("Error reading '{}'", filename))?;
- Ok(())
-}
-
-fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
- func2().context("func1 error")?;
- Ok(())
-}
-
-if let Err(e) = func1() {
- #[cfg(not(windows))]
- assert_eq!(
- format!("\n{:?}\n", e),
- r#"
-src/lib.rs:21:13: func1 error
-Caused by:
-src/lib.rs:16:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-"#
- );
-}
-}
-
-
-#![allow(unused)]
-fn main() {
-use chainerror::prelude::v1::*;
-use std::error::Error;
-use std::io;
-use std::result::Result;
-
-fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
- Err(io::Error::from(io::ErrorKind::NotFound))?;
- Ok(())
-}
-
-fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
- let filename = "foo.txt";
- do_some_io().context(format!("Error reading '{}'", filename))?;
- Ok(())
-}
-
-derive_str_context!(Func2Error);
-
-fn func2() -> ChainResult<(), Func2Error> {
- func3().context(Func2Error("func2 error: calling func3".into()))?;
- 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().context(Func1Error::Func2)?;
- let filename = String::from("bar.txt");
- do_some_io().context(Func1Error::IO(filename))?;
- Ok(())
-}
-
-if let Err(e) = func1() {
- assert!(match e.kind() {
- Func1Error::Func2 => {
- eprintln!("Main Error Report: func1 error calling func2");
- true
- }
- Func1Error::IO(filename) => {
- eprintln!("Main Error Report: func1 error reading '{}'", filename);
- false
- }
- });
-
- assert!(e.find_chain_cause::<Func2Error>().is_some());
-
- if let Some(e) = e.find_chain_cause::<Func2Error>() {
- eprintln!("\nError reported by Func2Error: {}", e)
- }
-
- assert!(e.root_cause().is_some());
-
- if let Some(e) = e.root_cause() {
- let io_error = e.downcast_ref::<io::Error>().unwrap();
- eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
- }
-
- #[cfg(not(windows))]
- assert_eq!(
- format!("\n{:?}\n", e),
- r#"
-src/lib.rs:48:13: func1 error calling func2
-Caused by:
-src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-Caused by:
-src/lib.rs:16:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-"#
- );
-}
-}
-
Licensed under either of
diff --git a/print.html b/print.html
index d79fcd9..c55bde7 100644
--- a/print.html
+++ b/print.html
@@ -171,199 +171,78 @@
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!
+Having nested function returning errors, the output doesn't tell where the error originates from.
+
use std::path::PathBuf;
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = std::fs::read_to_string(&path)?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn process_config_file() -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = read_config_file("foo.txt".into())?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = process_config_file() {
+ eprintln!("Error:\n{:?}", e);
+ }
+}
+
+This gives the output:
+Error:
+Os { code: 2, kind: NotFound, message: "No such file or directory" }
+
+and you have no idea where it comes from.
+With chainerror
, you can supply a context and get a nice error backtrace:
+use chainerror::prelude::v1::*;
+use std::path::PathBuf;
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn process_config_file() -> Result<(), BoxedError> {
+ // do stuff, return other errors
+ let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+ // do stuff, return other errors
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = process_config_file() {
+ eprintln!("Error:\n{:?}", e);
+ }
+}
+
+with the output:
+Error:
+examples/simple.rs:14:51: read the config file
+Caused by:
+examples/simple.rs:7:47: Reading file: "foo.txt"
+Caused by:
+Os { code: 2, kind: NotFound, message: "No such file or directory" }
+
chainerror
uses .source()
of std::error::Error
along with #[track_caller]
and Location
to provide a nice debug error backtrace.
It encapsulates all types, which have Display + Debug
and can store the error cause internally.
Along with the ChainError<T>
struct, chainerror
comes with some useful helper macros to save a lot of typing.
+chainerror
has no dependencies!
Debug information is worth it!
display-cause
: turn on printing a backtrace of the errors in Display
Read the Tutorial
-
-examples/example.rs:
-// […]
-fn main() {
- if let Err(e) = func1() {
- eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
- eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
- // […]
- }
-}
-
-$ cargo run -q --example example
-Debug Error {:?}:
-examples/example.rs:46:13: func1 error calling func2
-Caused by:
-examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-Caused by:
-examples/example.rs:14:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-
-Alternative Debug Error {:#?}:
-ChainError<example::Func1Error> {
- occurrence: Some(
- "examples/example.rs:46:13",
- ),
- kind: func1 error calling func2,
- source: Some(
- ChainError<example::Func2Error> {
- occurrence: Some(
- "examples/example.rs:21:13",
- ),
- kind: Func2Error(func2 error: calling func3),
- source: Some(
- ChainError<alloc::string::String> {
- occurrence: Some(
- "examples/example.rs:14:18",
- ),
- kind: "Error reading \'foo.txt\'",
- source: Some(
- Kind(
- NotFound,
- ),
- ),
- },
- ),
- },
- ),
-}
-
-
-#![allow(unused)]
-fn main() {
-use chainerror::prelude::v1::*;
-use std::error::Error;
-use std::io;
-use std::result::Result;
-
-fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
- Err(io::Error::from(io::ErrorKind::NotFound))?;
- Ok(())
-}
-
-fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
- let filename = "foo.txt";
- do_some_io().context(format!("Error reading '{}'", filename))?;
- Ok(())
-}
-
-fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
- func2().context("func1 error")?;
- Ok(())
-}
-
-if let Err(e) = func1() {
- #[cfg(not(windows))]
- assert_eq!(
- format!("\n{:?}\n", e),
- r#"
-src/lib.rs:21:13: func1 error
-Caused by:
-src/lib.rs:16:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-"#
- );
-}
-}
-
-
-#![allow(unused)]
-fn main() {
-use chainerror::prelude::v1::*;
-use std::error::Error;
-use std::io;
-use std::result::Result;
-
-fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
- Err(io::Error::from(io::ErrorKind::NotFound))?;
- Ok(())
-}
-
-fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
- let filename = "foo.txt";
- do_some_io().context(format!("Error reading '{}'", filename))?;
- Ok(())
-}
-
-derive_str_context!(Func2Error);
-
-fn func2() -> ChainResult<(), Func2Error> {
- func3().context(Func2Error("func2 error: calling func3".into()))?;
- 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().context(Func1Error::Func2)?;
- let filename = String::from("bar.txt");
- do_some_io().context(Func1Error::IO(filename))?;
- Ok(())
-}
-
-if let Err(e) = func1() {
- assert!(match e.kind() {
- Func1Error::Func2 => {
- eprintln!("Main Error Report: func1 error calling func2");
- true
- }
- Func1Error::IO(filename) => {
- eprintln!("Main Error Report: func1 error reading '{}'", filename);
- false
- }
- });
-
- assert!(e.find_chain_cause::<Func2Error>().is_some());
-
- if let Some(e) = e.find_chain_cause::<Func2Error>() {
- eprintln!("\nError reported by Func2Error: {}", e)
- }
-
- assert!(e.root_cause().is_some());
-
- if let Some(e) = e.root_cause() {
- let io_error = e.downcast_ref::<io::Error>().unwrap();
- eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
- }
-
- #[cfg(not(windows))]
- assert_eq!(
- format!("\n{:?}\n", e),
- r#"
-src/lib.rs:48:13: func1 error calling func2
-Caused by:
-src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-Caused by:
-src/lib.rs:16:18: Error reading 'foo.txt'
-Caused by:
-Kind(NotFound)
-"#
- );
-}
-}
-
Licensed under either of
@@ -454,13 +333,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -471,200 +433,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -1465,13 +1237,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -1482,200 +1337,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -2475,13 +2140,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -2492,200 +2240,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -3480,13 +3038,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -3497,200 +3138,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -4500,13 +3951,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -4517,200 +4051,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -5529,13 +4873,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -5546,200 +4973,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -6555,13 +5792,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -6572,200 +5892,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -7584,13 +6714,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -7601,200 +6814,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -8622,13 +7645,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -8639,200 +7745,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -9673,13 +8589,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -9690,200 +8689,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -10722,13 +9531,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -10739,200 +9631,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
@@ -11697,13 +10399,96 @@ have to change much or anything.
//! `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!
+//! Having nested function returning errors, the output doesn't tell where the error originates from.
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path)?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into())?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! }
+//! }
+//! ```
+//!
+//! This gives the output:
+//! ```console
+//! Error:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
+//! and you have no idea where it comes from.
+//!
+//!
+//! With `chainerror`, you can supply a context and get a nice error backtrace:
+//!
+//! ```rust
+//! use chainerror::prelude::v1::*;
+//! use std::path::PathBuf;
+//!
+//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn process_config_file() -> Result<(), BoxedError> {
+//! // do stuff, return other errors
+//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
+//! // do stuff, return other errors
+//! Ok(())
+//! }
+//!
+//! fn main() {
+//! if let Err(e) = process_config_file() {
+//! eprintln!("Error:\n{:?}", e);
+//! # assert_eq!(
+//! # format!("{:?}\n", e),
+//! # "\
+//! # src/lib.rs:16:51: read the config file\n\
+//! # Caused by:\n\
+//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
+//! # Caused by:\n\
+//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
+//! # ",
+//! # );
+//! }
+//! }
+//! ```
+//!
+//! with the output:
+//! ```console
+//! Error:
+//! examples/simple.rs:14:51: read the config file
+//! Caused by:
+//! examples/simple.rs:7:47: Reading file: "foo.txt"
+//! Caused by:
+//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
+//! ```
//!
//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
//!
//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
//!
+//! `chainerror` has no dependencies!
+//!
//! Debug information is worth it!
//!
//! ## Features
@@ -11714,200 +10499,10 @@ have to change much or anything.
//! # Tutorial
//!
//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
-//!
-//! # Examples
-//!
-//! examples/example.rs:
-//! ```rust,ignore
-//! // […]
-//! fn main() {
-//! if let Err(e) = func1() {
-//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
-//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
-//! // […]
-//! }
-//! }
-//! ```
-//!
-//! ```console
-//! $ cargo run -q --example example
-//! Debug Error {:?}:
-//! examples/example.rs:46:13: func1 error calling func2
-//! Caused by:
-//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! examples/example.rs:14:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//!
-//! Alternative Debug Error {:#?}:
-//! ChainError<example::Func1Error> {
-//! occurrence: Some(
-//! "examples/example.rs:46:13",
-//! ),
-//! kind: func1 error calling func2,
-//! source: Some(
-//! ChainError<example::Func2Error> {
-//! occurrence: Some(
-//! "examples/example.rs:21:13",
-//! ),
-//! kind: Func2Error(func2 error: calling func3),
-//! source: Some(
-//! ChainError<alloc::string::String> {
-//! occurrence: Some(
-//! "examples/example.rs:14:18",
-//! ),
-//! kind: "Error reading \'foo.txt\'",
-//! source: Some(
-//! Kind(
-//! NotFound,
-//! ),
-//! ),
-//! },
-//! ),
-//! },
-//! ),
-//! }
-//! ```
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! func2().context("func1 error")?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:21:13: func1 error
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
-//!
-//!
-//! ```rust
-//! use chainerror::prelude::v1::*;
-//! use std::error::Error;
-//! use std::io;
-//! use std::result::Result;
-//!
-//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! Err(io::Error::from(io::ErrorKind::NotFound))?;
-//! Ok(())
-//! }
-//!
-//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
-//! let filename = "foo.txt";
-//! do_some_io().context(format!("Error reading '{}'", filename))?;
-//! Ok(())
-//! }
-//!
-//! derive_str_context!(Func2Error);
-//!
-//! fn func2() -> ChainResult<(), Func2Error> {
-//! func3().context(Func2Error("func2 error: calling func3".into()))?;
-//! 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().context(Func1Error::Func2)?;
-//! let filename = String::from("bar.txt");
-//! do_some_io().context(Func1Error::IO(filename))?;
-//! Ok(())
-//! }
-//!
-//! if let Err(e) = func1() {
-//! assert!(match e.kind() {
-//! Func1Error::Func2 => {
-//! eprintln!("Main Error Report: func1 error calling func2");
-//! true
-//! }
-//! Func1Error::IO(filename) => {
-//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
-//! false
-//! }
-//! });
-//!
-//! assert!(e.find_chain_cause::<Func2Error>().is_some());
-//!
-//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
-//! eprintln!("\nError reported by Func2Error: {}", e)
-//! }
-//!
-//! assert!(e.root_cause().is_some());
-//!
-//! if let Some(e) = e.root_cause() {
-//! let io_error = e.downcast_ref::<io::Error>().unwrap();
-//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
-//! }
-//!
-//! #[cfg(not(windows))]
-//! assert_eq!(
-//! format!("\n{:?}\n", e),
-//! r#"
-//! src/lib.rs:48:13: func1 error calling func2
-//! Caused by:
-//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
-//! Caused by:
-//! src/lib.rs:16:18: Error reading 'foo.txt'
-//! Caused by:
-//! Kind(NotFound)
-//! "#
-//! );
-//! }
-//! # else {
-//! # unreachable!();
-//! # }
-//! ```
#![deny(clippy::all)]
#![deny(clippy::integer_arithmetic)]
+#![allow(clippy::needless_doctest_main)]
#![deny(missing_docs)]
use std::any::TypeId;
diff --git a/searchindex.js b/searchindex.js
index 5891ed4..4fcce87 100644
--- a/searchindex.js
+++ b/searchindex.js
@@ -1 +1 @@
-Object.assign(window.search, {"doc_urls":["index.html#chainerror","index.html#features","index.html#tutorial","index.html#examples","index.html#license","index.html#contribution","tutorial1.html#simple-string-errors","tutorial2.html#simple-chained-string-errors","tutorial2.html#what-did-we-do-here","tutorial3.html#mapping-errors","tutorial4.html#more-information","tutorial5.html#the-source-of-errors","tutorial6.html#downcast-the-errors","tutorial7.html#the-root-cause-of-all-errors","tutorial8.html#finding-an-error-cause","tutorial9.html#selective-error-handling","tutorial10.html#errorkind-to-the-rescue","tutorial11.html#debug-for-the-errorkind","tutorial12.html#deref-for-the-errorkind","tutorial13.html#writing-a-library","tutorial14.html#going-back-to-std","end.html#the-end"],"index":{"documentStore":{"docInfo":{"0":{"body":66,"breadcrumbs":1,"title":1},"1":{"body":7,"breadcrumbs":1,"title":1},"10":{"body":1739,"breadcrumbs":2,"title":2},"11":{"body":1767,"breadcrumbs":2,"title":2},"12":{"body":1779,"breadcrumbs":2,"title":2},"13":{"body":1812,"breadcrumbs":3,"title":3},"14":{"body":1777,"breadcrumbs":3,"title":3},"15":{"body":1792,"breadcrumbs":3,"title":3},"16":{"body":1833,"breadcrumbs":2,"title":2},"17":{"body":1846,"breadcrumbs":2,"title":2},"18":{"body":1828,"breadcrumbs":2,"title":2},"19":{"body":1845,"breadcrumbs":2,"title":2},"2":{"body":2,"breadcrumbs":1,"title":1},"20":{"body":348,"breadcrumbs":3,"title":3},"21":{"body":18,"breadcrumbs":1,"title":1},"3":{"body":275,"breadcrumbs":1,"title":1},"4":{"body":16,"breadcrumbs":1,"title":1},"5":{"body":21,"breadcrumbs":1,"title":1},"6":{"body":106,"breadcrumbs":3,"title":3},"7":{"body":1747,"breadcrumbs":4,"title":4},"8":{"body":41,"breadcrumbs":1,"title":1},"9":{"body":1767,"breadcrumbs":2,"title":2}},"docs":{"0":{"body":"Crate Rust Documentation Coverage Status Workflow Status Average time to resolve an issue Percentage of issues still open Maintenance 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 #[track_caller] and Location to provide a nice debug error backtrace. It encapsulates all types, which have Display + Debug and can store the error cause internally. Along with the ChainError struct, chainerror comes with some useful helper macros to save a lot of typing. Debug information is worth it!","breadcrumbs":"chainerror","id":"0","title":"chainerror"},"1":{"body":"display-cause : turn on printing a backtrace of the errors in Display","breadcrumbs":"Features","id":"1","title":"Features"},"10":{"body":"To give more context to the error, you want to use format! to extend the information in the context string. use chainerror::prelude::v1::*;\nuse std::error::Error;\nuse std::io;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(())\n} fn func2() -> Result<(), Box> { let filename = \"foo.txt\"; do_some_io().context(format!(\"Error reading '{}'\", filename))?; Ok(())\n} fn func1() -> Result<(), Box> { func2().context(\"func1 error\")?; Ok(())\n} fn main() -> Result<(), Box> { if let Err(e) = func1() { eprintln!(\"{:?}\", e); std::process::exit(1); } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your\n# //! binaries, you still have the error backtrace.\n# //!\n# //! `chainerror` has no dependencies!\n# //!\n# //! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.\n# //! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.\n# //!\n# //! Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing.\n# //!\n# //! Debug information is worth it!\n# //!\n# //! ## Features\n# //!\n# //! `display-cause`\n# //! : turn on printing a backtrace of the errors in `Display`\n# //!\n# //! # Tutorial\n# //!\n# //! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)\n# //!\n# //! # Examples\n# //!\n# //! examples/example.rs:\n# //! ```rust,ignore\n# //! // […]\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! eprintln!(\"\\nDebug Error {{:?}}:\\n{:?}\", e);\n# //! eprintln!(\"\\nAlternative Debug Error {{:#?}}:\\n{:#?}\\n\", e);\n# //! // […]\n# //! }\n# //! }\n# //! ```\n# //!\n# //! ```console\n# //! $ cargo run -q --example example\n# //! Debug Error {:?}:\n# //! examples/example.rs:46:13: func1 error calling func2\n# //! Caused by:\n# //! examples/example.rs:21:13: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! examples/example.rs:14:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //!\n# //! Alternative Debug Error {:#?}:\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:46:13\",\n# //! ),\n# //! kind: func1 error calling func2,\n# //! source: Some(\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:21:13\",\n# //! ),\n# //! kind: Func2Error(func2 error: calling func3),\n# //! source: Some(\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:14:18\",\n# //! ),\n# //! kind: \"Error reading \\'foo.txt\\'\",\n# //! source: Some(\n# //! Kind(\n# //! NotFound,\n# //! ),\n# //! ),\n# //! },\n# //! ),\n# //! },\n# //! ),\n# //! }\n# //! ```\n# //!\n# //! ```rust\n# //! use chainerror::prelude::v1::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func2() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().context(format!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func1() -> Result<(), Box> {\n# //! func2().context(\"func1 error\")?;\n# //! Ok(())\n# //! }\n# //!\n# //! if let Err(e) = func1() {\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e),\n# //! r#\"\n# //! src/lib.rs:21:13: func1 error\n# //! Caused by:\n# //! src/lib.rs:16:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! ```\n# //!\n# //!\n# //! ```rust\n# //! use chainerror::prelude::v1::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func3() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().context(format!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! derive_str_context!(Func2Error);\n# //!\n# //! fn func2() -> ChainResult<(), Func2Error> {\n# //! func3().context(Func2Error(\"func2 error: calling func3\".into()))?;\n# //! Ok(())\n# //! }\n# //!\n# //! enum Func1Error {\n# //! Func2,\n# //! IO(String),\n# //! }\n# //!\n# //! impl ::std::fmt::Display for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! match self {\n# //! Func1Error::Func2 => write!(f, \"func1 error calling func2\"),\n# //! Func1Error::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# //! }\n# //! }\n# //! }\n# //!\n# //! impl ::std::fmt::Debug for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! write!(f, \"{}\", self)\n# //! }\n# //! }\n# //!\n# //! fn func1() -> ChainResult<(), Func1Error> {\n# //! func2().context(Func1Error::Func2)?;\n# //! let filename = String::from(\"bar.txt\");\n# //! do_some_io().context(Func1Error::IO(filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! if let Err(e) = func1() {\n# //! assert!(match e.kind() {\n# //! Func1Error::Func2 => {\n# //! eprintln!(\"Main Error Report: func1 error calling func2\");\n# //! true\n# //! }\n# //! Func1Error::IO(filename) => {\n# //! eprintln!(\"Main Error Report: func1 error reading '{}'\", filename);\n# //! false\n# //! }\n# //! });\n# //!\n# //! assert!(e.find_chain_cause::().is_some());\n# //!\n# //! if let Some(e) = e.find_chain_cause::() {\n# //! eprintln!(\"\\nError reported by Func2Error: {}\", e)\n# //! }\n# //!\n# //! assert!(e.root_cause().is_some());\n# //!\n# //! if let Some(e) = e.root_cause() {\n# //! let io_error = e.downcast_ref::().unwrap();\n# //! eprintln!(\"\\nThe root cause was: std::io::Error: {:#?}\", io_error);\n# //! }\n# //!\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e),\n# //! r#\"\n# //! src/lib.rs:48:13: func1 error calling func2\n# //! Caused by:\n# //! src/lib.rs:23:13: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! src/lib.rs:16:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! ```\n# # #![deny(clippy::all)]\n# #![deny(clippy::integer_arithmetic)]\n# #![deny(missing_docs)]\n# # use std::any::TypeId;\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::panic::Location;\n# # pub mod prelude {\n# //! convenience prelude\n# pub mod v1 {\n# //! convenience prelude\n# pub use super::super::ChainErrorDown as _;\n# pub use super::super::ResultTrait as _;\n# pub use super::super::{ChainError, ChainResult};\n# pub use crate::{derive_err_kind, derive_str_context};\n# }\n# }\n# # /// chains an inner error kind `T` with a causing error\n# pub struct ChainError {\n# occurrence: Option,\n# kind: T,\n# error_cause: Option>,\n# }\n# # /// convenience type alias\n# pub type ChainResult = std::result::Result>;\n# # impl ChainError {\n# /// Use the `context()` or `map_context()` Result methods instead of calling this directly\n# #[inline]\n# pub fn new(\n# kind: T,\n# error_cause: Option>,\n# occurrence: Option,\n# ) -> Self {\n# Self {\n# occurrence,\n# kind,\n# error_cause,\n# }\n# }\n# # /// return the root cause of the error chain, if any exists\n# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# self.iter().last()\n# }\n# # /// Find the first error cause of type U, if any exists\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// use chainerror::prelude::v1::*;\n# /// use std::error::Error;\n# /// use std::io;\n# ///\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().context(Func2Error(format!(\"Error reading '{}'\", filename)))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().context(Func1Error(\"func1 error\".into()))?;\n# /// Ok(())\n# /// }\n# ///\n# /// if let Err(e) = func1() {\n# /// if let Some(f1err) = e.downcast_chain_ref::() {\n# /// assert!(f1err.find_cause::().is_some());\n# ///\n# /// assert!(f1err.find_chain_cause::().is_some());\n# /// }\n# /// # else {\n# /// # panic!();\n# /// # }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// ```\n# #[inline]\n# pub fn find_cause(&self) -> Option<&U> {\n# self.iter().filter_map(Error::downcast_ref::).next()\n# }\n# # /// Find the first error cause of type `ChainError`, if any exists\n# ///\n# /// Same as `find_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// # use chainerror::prelude::v1::*;\n# /// # derive_str_context!(FooError);\n# /// # let err = ChainError::new(String::new(), None, None);\n# /// // Instead of writing\n# /// err.find_cause::>();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_chain_cause::();\n# /// ```\n# #[inline]\n# pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# self.iter()\n# .filter_map(Error::downcast_ref::>)\n# .next()\n# }\n# # /// Find the first error cause of type `ChainError` or `U`, if any exists and return `U`\n# ///\n# /// Same as `find_cause` and `find_chain_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// # use chainerror::prelude::v1::*;\n# /// # derive_str_context!(FooErrorKind);\n# /// # let err = ChainError::new(String::new(), None, None);\n# /// // Instead of writing\n# /// err.find_cause::>();\n# /// // and/or\n# /// err.find_chain_cause::();\n# /// // and/or\n# /// err.find_cause::();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_kind_or_cause::();\n# /// ```\n# #[inline]\n# pub fn find_kind_or_cause(&self) -> Option<&U> {\n# self.iter()\n# .filter_map(|e| {\n# e.downcast_ref::>()\n# .map(|e| e.kind())\n# .or_else(|| e.downcast_ref::())\n# })\n# .next()\n# }\n# # /// Return a reference to T of `ChainError`\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// use chainerror::prelude::v1::*;\n# /// use std::error::Error;\n# /// use std::io;\n# ///\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().context(Func2Error(format!(\"Error reading '{}'\", filename)))?;\n# /// Ok(())\n# /// }\n# ///\n# /// #[derive(Debug)]\n# /// enum Func1ErrorKind {\n# /// Func2,\n# /// IO(String),\n# /// }\n# ///\n# /// /// impl ::std::fmt::Display for Func1ErrorKind {…}\n# /// # impl ::std::fmt::Display for Func1ErrorKind {\n# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# /// # match self {\n# /// # Func1ErrorKind::Func2 => write!(f, \"func1 error calling func2\"),\n# /// # Func1ErrorKind::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# /// # }\n# /// # }\n# /// # }\n# ///\n# /// fn func1() -> ChainResult<(), Func1ErrorKind> {\n# /// func2().context(Func1ErrorKind::Func2)?;\n# /// do_some_io().context(Func1ErrorKind::IO(\"bar.txt\".into()))?;\n# /// Ok(())\n# /// }\n# ///\n# /// if let Err(e) = func1() {\n# /// match e.kind() {\n# /// Func1ErrorKind::Func2 => {}\n# /// Func1ErrorKind::IO(filename) => panic!(),\n# /// }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// ```\n# #[inline]\n# pub fn kind(&self) -> &T {\n# &self.kind\n# }\n# # /// Returns an Iterator over all error causes/sources\n# ///\n# /// # Example\n# #[inline]\n# pub fn iter(&self) -> impl Iterator- {\n# ErrorIter {\n# current: Some(self),\n# }\n# }\n# }\n# # /// Convenience methods for `Result<>` to turn the error into a decorated ChainError\n# pub trait ResultTrait>> {\n# /// Decorate the error with a `kind` of type `T` and the source `Location`\n# fn context(\n# self,\n# kind: T,\n# ) -> std::result::Result>;\n# # /// Decorate the `error` with a `kind` of type `T` produced with a `FnOnce(&error)` and the source `Location`\n# fn map_context T>(\n# self,\n# op: F,\n# ) -> std::result::Result>;\n# }\n# # impl>> ResultTrait\n# for std::result::Result\n# {\n# #[track_caller]\n# fn context(\n# self,\n# kind: T,\n# ) -> std::result::Result> {\n# match self {\n# Ok(t) => Ok(t),\n# Err(error_cause) => Err(ChainError::new(\n# kind,\n# Some(error_cause.into()),\n# Some(Location::caller().to_string()),\n# )),\n# }\n# }\n# # #[track_caller]\n# fn map_context T>(\n# self,\n# op: F,\n# ) -> std::result::Result> {\n# match self {\n# Ok(t) => Ok(t),\n# Err(error_cause) => {\n# let kind = op(&error_cause);\n# Err(ChainError::new(\n# kind,\n# Some(error_cause.into()),\n# Some(Location::caller().to_string()),\n# ))\n# }\n# }\n# }\n# }\n# # /// An iterator over all error causes/sources\n# pub struct ErrorIter<'a> {\n# current: Option<&'a (dyn Error + 'static)>,\n# }\n# # impl<'a> Iterator for ErrorIter<'a> {\n# type Item = &'a (dyn Error + 'static);\n# # #[inline]\n# fn next(&mut self) -> Option {\n# let current = self.current;\n# self.current = self.current.and_then(Error::source);\n# current\n# }\n# }\n# # impl std::ops::Deref for ChainError {\n# type Target = T;\n# # #[inline]\n# fn deref(&self) -> &Self::Target {\n# &self.kind\n# }\n# }\n# # /// Convenience trait to hide the `ChainError` implementation internals\n# pub trait ChainErrorDown {\n# /// Test if of type `ChainError`\n# fn is_chain(&self) -> bool;\n# /// Downcast to a reference of `ChainError`\n# fn downcast_chain_ref(&self) -> Option<&ChainError>;\n# /// Downcast to a mutable reference of `ChainError`\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError>;\n# /// Downcast to T of `ChainError`\n# fn downcast_inner_ref(&self) -> Option<&T>;\n# /// Downcast to T mutable reference of `ChainError`\n# fn downcast_inner_mut(&mut self) -> Option<&mut T>;\n# }\n# # impl ChainErrorDown for ChainError {\n# #[inline]\n# fn is_chain(&self) -> bool {\n# TypeId::of::() == TypeId::of::()\n# }\n# # #[inline]\n# fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# #[allow(trivial_casts)]\n# Some(&*(self as *const dyn Error as *const &ChainError))\n# }\n# } else {\n# None\n# }\n# }\n# # #[inline]\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# #[allow(trivial_casts)]\n# Some(&mut *(self as *mut dyn Error as *mut &mut ChainError))\n# }\n# } else {\n# None\n# }\n# }\n# #[inline]\n# fn downcast_inner_ref(&self) -> Option<&T> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# #[allow(trivial_casts)]\n# Some(&(*(self as *const dyn Error as *const &ChainError)).kind)\n# }\n# } else {\n# None\n# }\n# }\n# # #[inline]\n# fn downcast_inner_mut(&mut self) -> Option<&mut T> {\n# if self.is_chain::() {\n# #[allow(clippy::cast_ptr_alignment)]\n# unsafe {\n# #[allow(trivial_casts)]\n# Some(&mut (*(self as *mut dyn Error as *mut &mut ChainError)).kind)\n# }\n# } else {\n# None\n# }\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static {\n# #[inline]\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # #[inline]\n# fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # #[inline]\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# # #[inline]\n# fn downcast_inner_ref(&self) -> Option<&T> {\n# self.downcast_ref::()\n# .or_else(|| self.downcast_ref::>().map(|e| e.kind()))\n# }\n# # #[inline]\n# fn downcast_inner_mut(&mut self) -> Option<&mut T> {\n# if self.is::() {\n# return self.downcast_mut::();\n# }\n# # self.downcast_mut::>()\n# .and_then(|e| e.downcast_inner_mut::())\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static + Send {\n# #[inline]\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # #[inline]\n# fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # #[inline]\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# # #[inline]\n# fn downcast_inner_ref(&self) -> Option<&T> {\n# self.downcast_ref::()\n# .or_else(|| self.downcast_ref::>().map(|e| e.kind()))\n# }\n# # #[inline]\n# fn downcast_inner_mut(&mut self) -> Option<&mut T> {\n# if self.is::() {\n# return self.downcast_mut::();\n# }\n# # self.downcast_mut::>()\n# .and_then(|e| e.downcast_inner_mut::())\n# }\n# }\n# # impl ChainErrorDown for dyn Error + 'static + Send + Sync {\n# #[inline]\n# fn is_chain(&self) -> bool {\n# self.is::>()\n# }\n# # #[inline]\n# fn downcast_chain_ref(&self) -> Option<&ChainError> {\n# self.downcast_ref::>()\n# }\n# # #[inline]\n# fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> {\n# self.downcast_mut::>()\n# }\n# # #[inline]\n# fn downcast_inner_ref(&self) -> Option<&T> {\n# self.downcast_ref::()\n# .or_else(|| self.downcast_ref::>().map(|e| e.kind()))\n# }\n# # #[inline]\n# fn downcast_inner_mut(&mut self) -> Option<&mut T> {\n# if self.is::() {\n# return self.downcast_mut::();\n# }\n# # self.downcast_mut::>()\n# .and_then(|e| e.downcast_inner_mut::())\n# }\n# }\n# # impl Error for ChainError {\n# #[inline]\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause\n# .as_ref()\n# .map(|e| e.as_ref() as &(dyn Error + 'static))\n# }\n# }\n# # impl Error for &ChainError {\n# #[inline]\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause\n# .as_ref()\n# .map(|e| e.as_ref() as &(dyn Error + 'static))\n# }\n# }\n# # impl Error for &mut ChainError {\n# #[inline]\n# fn source(&self) -> Option<&(dyn Error + 'static)> {\n# self.error_cause\n# .as_ref()\n# .map(|e| e.as_ref() as &(dyn Error + 'static))\n# }\n# }\n# # impl Display for ChainError {\n# #[inline]\n# fn fmt(&self, f: &mut Formatter<'_>) -> Result {\n# write!(f, \"{}\", self.kind)?;\n# # #[cfg(feature = \"display-cause\")]\n# {\n# if let Some(e) = self.source() {\n# writeln!(f, \"\\nCaused by:\")?;\n# Display::fmt(&e, f)?;\n# }\n# }\n# Ok(())\n# }\n# }\n# # impl Debug for ChainError {\n# #[inline]\n# fn fmt(&self, f: &mut Formatter<'_>) -> Result {\n# if f.alternate() {\n# let mut f = f.debug_struct(&format!(\"ChainError<{}>\", std::any::type_name::()));\n# # let f = f\n# .field(\"occurrence\", &self.occurrence)\n# .field(\"kind\", &self.kind)\n# .field(\"source\", &self.source());\n# # f.finish()\n# } else {\n# if let Some(ref o) = self.occurrence {\n# write!(f, \"{}: \", o)?;\n# }\n# # if TypeId::of::() == TypeId::of::()\n# || TypeId::of::<&str>() == TypeId::of::()\n# {\n# Display::fmt(&self.kind, f)?;\n# } else {\n# Debug::fmt(&self.kind, f)?;\n# }\n# # if let Some(e) = self.source() {\n# writeln!(f, \"\\nCaused by:\")?;\n# Debug::fmt(&e, f)?;\n# }\n# Ok(())\n# }\n# }\n# }\n# # /// `ChainErrorFrom` is similar to `From`\n# pub trait ChainErrorFrom: Sized {\n# /// similar to From::from()\n# fn chain_error_from(from: T, line_filename: Option) -> ChainError;\n# }\n# # /// `IntoChainError` is similar to `Into`\n# pub trait IntoChainError: Sized {\n# /// similar to Into::into()\n# fn into_chain_error(self, line_filename: Option) -> ChainError;\n# }\n# # impl IntoChainError for T\n# where\n# U: ChainErrorFrom,\n# {\n# #[inline]\n# fn into_chain_error(self, line_filename: Option) -> ChainError {\n# U::chain_error_from(self, line_filename)\n# }\n# }\n# # impl ChainErrorFrom for U\n# where\n# T: Into,\n# U: 'static + Display + Debug,\n# {\n# #[inline]\n# fn chain_error_from(t: T, line_filename: Option) -> ChainError {\n# let e: U = t.into();\n# ChainError::new(e, None, line_filename)\n# }\n# }\n# # /// Convenience macro to create a \"new type\" T(String) and implement Display + Debug for T\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// # use crate::chainerror::*;\n# /// # use std::error::Error;\n# /// # use std::io;\n# /// # use std::result::Result;\n# /// # fn do_some_io() -> Result<(), Box> {\n# /// # Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// # Ok(())\n# /// # }\n# /// derive_str_context!(Func2Error);\n# ///\n# /// fn func2() -> ChainResult<(), Func2Error> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().context(Func2Error(format!(\"Error reading '{}'\", filename)))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().context(Func1Error(\"func1 error\".into()))?;\n# /// Ok(())\n# /// }\n# /// # if let Err(e) = func1() {\n# /// # if let Some(f1err) = e.downcast_chain_ref::() {\n# /// # assert!(f1err.find_cause::>().is_some());\n# /// # assert!(f1err.find_chain_cause::().is_some());\n# /// # } else {\n# /// # panic!();\n# /// # }\n# /// # } else {\n# /// # unreachable!();\n# /// # }\n# /// ```\n# #[macro_export]\n# macro_rules! derive_str_context {\n# ($e:ident) => {\n# #[derive(Clone)]\n# pub struct $e(pub String);\n# impl ::std::fmt::Display for $e {\n# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# write!(f, \"{}\", self.0)\n# }\n# }\n# impl ::std::fmt::Debug for $e {\n# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# write!(f, \"{}({})\", stringify!($e), self.0)\n# }\n# }\n# impl ::std::error::Error for $e {}\n# };\n# }\n# # /// Derive an Error for an ErrorKind, which wraps a `ChainError` and implements a `kind()` method\n# ///\n# /// It basically hides `ChainError` to the outside and only exposes the `kind()`\n# /// method.\n# ///\n# /// Error::kind() returns the ErrorKind\n# /// Error::source() returns the parent error\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// use chainerror::prelude::v1::*;\n# /// use std::io;\n# ///\n# /// fn do_some_io(_f: &str) -> std::result::Result<(), io::Error> {\n# /// return Err(io::Error::from(io::ErrorKind::NotFound));\n# /// }\n# ///\n# /// #[derive(Debug, Clone)]\n# /// pub enum ErrorKind {\n# /// IO(String),\n# /// FatalError(String),\n# /// Unknown,\n# /// }\n# ///\n# /// derive_err_kind!(Error, ErrorKind);\n# ///\n# /// impl std::fmt::Display for ErrorKind {\n# /// fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {\n# /// match self {\n# /// ErrorKind::FatalError(e) => write!(f, \"fatal error {}\", e),\n# /// ErrorKind::Unknown => write!(f, \"unknown error\"),\n# /// ErrorKind::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# /// }\n# /// }\n# /// }\n# ///\n# /// impl ErrorKind {\n# /// fn from_io_error(e: &io::Error, f: String) -> Self {\n# /// match e.kind() {\n# /// io::ErrorKind::BrokenPipe => panic!(\"Should not happen\"),\n# /// io::ErrorKind::ConnectionReset => {\n# /// ErrorKind::FatalError(format!(\"While reading `{}`: {}\", f, e))\n# /// }\n# /// _ => ErrorKind::IO(f),\n# /// }\n# /// }\n# /// }\n# ///\n# /// impl From<&io::Error> for ErrorKind {\n# /// fn from(e: &io::Error) -> Self {\n# /// ErrorKind::IO(format!(\"{}\", e))\n# /// }\n# /// }\n# ///\n# /// pub fn func1() -> std::result::Result<(), Error> {\n# /// let filename = \"bar.txt\";\n# ///\n# /// do_some_io(filename).map_context(|e| ErrorKind::from_io_error(e, filename.into()))?;\n# /// do_some_io(filename).map_context(|e| ErrorKind::IO(filename.into()))?;\n# /// do_some_io(filename).map_context(|e| ErrorKind::from(e))?;\n# /// Ok(())\n# /// }\n# /// ```\n# #[macro_export]\n# macro_rules! derive_err_kind {\n# ($e:ident, $k:ident) => {\n# pub struct $e($crate::ChainError<$k>);\n# # impl $e {\n# pub fn kind(&self) -> &$k {\n# self.0.kind()\n# }\n# }\n# # impl From<$k> for $e {\n# fn from(e: $k) -> Self {\n# $e($crate::ChainError::new(e, None, None))\n# }\n# }\n# # impl From> for $e {\n# fn from(e: $crate::ChainError<$k>) -> Self {\n# $e(e)\n# }\n# }\n# # impl From<&$e> for $k\n# where\n# $k: Clone,\n# {\n# fn from(e: &$e) -> Self {\n# e.kind().clone()\n# }\n# }\n# # impl std::error::Error for $e {\n# fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n# self.0.source()\n# }\n# }\n# # impl std::fmt::Display for $e {\n# fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n# std::fmt::Display::fmt(&self.0, f)\n# }\n# }\n# # impl std::fmt::Debug for $e {\n# fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n# std::fmt::Debug::fmt(&self.0, f)\n# }\n# }\n# };\n# }\n# }","breadcrumbs":"More information","id":"10","title":"More information"},"11":{"body":"Sometimes you want to inspect the source() of an Error. chainerror implements std::error::Error::source(), so you can get the cause of an error. use chainerror::prelude::v1::*;\nuse std::error::Error;\nuse std::io;\nuse std::result::Result; fn do_some_io() -> Result<(), Box> { Err(io::Error::from(io::ErrorKind::NotFound))?; Ok(())\n} fn func2() -> Result<(), Box> { let filename = \"foo.txt\"; do_some_io().context(format!(\"Error reading '{}'\", filename))?; Ok(())\n} fn func1() -> Result<(), Box> { if let Err(e) = func2() { if let Some(s) = e.source() { eprintln!(\"func2 failed because of '{}'\", s); Err(e).context(\"func1 error\")?; } } Ok(())\n} fn main() -> Result<(), Box> { if let Err(e) = func1() { eprintln!(\"{}\", e); std::process::exit(1); } Ok(())\n}\n# #[allow(dead_code)]\n# mod chainerror {\n# //! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your\n# //! binaries, you still have the error backtrace.\n# //!\n# //! `chainerror` has no dependencies!\n# //!\n# //! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.\n# //! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.\n# //!\n# //! Along with the `ChainError` struct, `chainerror` comes with some useful helper macros to save a lot of typing.\n# //!\n# //! Debug information is worth it!\n# //!\n# //! ## Features\n# //!\n# //! `display-cause`\n# //! : turn on printing a backtrace of the errors in `Display`\n# //!\n# //! # Tutorial\n# //!\n# //! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)\n# //!\n# //! # Examples\n# //!\n# //! examples/example.rs:\n# //! ```rust,ignore\n# //! // […]\n# //! fn main() {\n# //! if let Err(e) = func1() {\n# //! eprintln!(\"\\nDebug Error {{:?}}:\\n{:?}\", e);\n# //! eprintln!(\"\\nAlternative Debug Error {{:#?}}:\\n{:#?}\\n\", e);\n# //! // […]\n# //! }\n# //! }\n# //! ```\n# //!\n# //! ```console\n# //! $ cargo run -q --example example\n# //! Debug Error {:?}:\n# //! examples/example.rs:46:13: func1 error calling func2\n# //! Caused by:\n# //! examples/example.rs:21:13: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! examples/example.rs:14:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //!\n# //! Alternative Debug Error {:#?}:\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:46:13\",\n# //! ),\n# //! kind: func1 error calling func2,\n# //! source: Some(\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:21:13\",\n# //! ),\n# //! kind: Func2Error(func2 error: calling func3),\n# //! source: Some(\n# //! ChainError {\n# //! occurrence: Some(\n# //! \"examples/example.rs:14:18\",\n# //! ),\n# //! kind: \"Error reading \\'foo.txt\\'\",\n# //! source: Some(\n# //! Kind(\n# //! NotFound,\n# //! ),\n# //! ),\n# //! },\n# //! ),\n# //! },\n# //! ),\n# //! }\n# //! ```\n# //!\n# //! ```rust\n# //! use chainerror::prelude::v1::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func2() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().context(format!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func1() -> Result<(), Box> {\n# //! func2().context(\"func1 error\")?;\n# //! Ok(())\n# //! }\n# //!\n# //! if let Err(e) = func1() {\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e),\n# //! r#\"\n# //! src/lib.rs:21:13: func1 error\n# //! Caused by:\n# //! src/lib.rs:16:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! ```\n# //!\n# //!\n# //! ```rust\n# //! use chainerror::prelude::v1::*;\n# //! use std::error::Error;\n# //! use std::io;\n# //! use std::result::Result;\n# //!\n# //! fn do_some_io() -> Result<(), Box> {\n# //! Err(io::Error::from(io::ErrorKind::NotFound))?;\n# //! Ok(())\n# //! }\n# //!\n# //! fn func3() -> Result<(), Box> {\n# //! let filename = \"foo.txt\";\n# //! do_some_io().context(format!(\"Error reading '{}'\", filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! derive_str_context!(Func2Error);\n# //!\n# //! fn func2() -> ChainResult<(), Func2Error> {\n# //! func3().context(Func2Error(\"func2 error: calling func3\".into()))?;\n# //! Ok(())\n# //! }\n# //!\n# //! enum Func1Error {\n# //! Func2,\n# //! IO(String),\n# //! }\n# //!\n# //! impl ::std::fmt::Display for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! match self {\n# //! Func1Error::Func2 => write!(f, \"func1 error calling func2\"),\n# //! Func1Error::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# //! }\n# //! }\n# //! }\n# //!\n# //! impl ::std::fmt::Debug for Func1Error {\n# //! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# //! write!(f, \"{}\", self)\n# //! }\n# //! }\n# //!\n# //! fn func1() -> ChainResult<(), Func1Error> {\n# //! func2().context(Func1Error::Func2)?;\n# //! let filename = String::from(\"bar.txt\");\n# //! do_some_io().context(Func1Error::IO(filename))?;\n# //! Ok(())\n# //! }\n# //!\n# //! if let Err(e) = func1() {\n# //! assert!(match e.kind() {\n# //! Func1Error::Func2 => {\n# //! eprintln!(\"Main Error Report: func1 error calling func2\");\n# //! true\n# //! }\n# //! Func1Error::IO(filename) => {\n# //! eprintln!(\"Main Error Report: func1 error reading '{}'\", filename);\n# //! false\n# //! }\n# //! });\n# //!\n# //! assert!(e.find_chain_cause::().is_some());\n# //!\n# //! if let Some(e) = e.find_chain_cause::() {\n# //! eprintln!(\"\\nError reported by Func2Error: {}\", e)\n# //! }\n# //!\n# //! assert!(e.root_cause().is_some());\n# //!\n# //! if let Some(e) = e.root_cause() {\n# //! let io_error = e.downcast_ref::().unwrap();\n# //! eprintln!(\"\\nThe root cause was: std::io::Error: {:#?}\", io_error);\n# //! }\n# //!\n# //! #[cfg(not(windows))]\n# //! assert_eq!(\n# //! format!(\"\\n{:?}\\n\", e),\n# //! r#\"\n# //! src/lib.rs:48:13: func1 error calling func2\n# //! Caused by:\n# //! src/lib.rs:23:13: Func2Error(func2 error: calling func3)\n# //! Caused by:\n# //! src/lib.rs:16:18: Error reading 'foo.txt'\n# //! Caused by:\n# //! Kind(NotFound)\n# //! \"#\n# //! );\n# //! }\n# //! # else {\n# //! # unreachable!();\n# //! # }\n# //! ```\n# # #![deny(clippy::all)]\n# #![deny(clippy::integer_arithmetic)]\n# #![deny(missing_docs)]\n# # use std::any::TypeId;\n# use std::error::Error;\n# use std::fmt::{Debug, Display, Formatter, Result};\n# use std::panic::Location;\n# # pub mod prelude {\n# //! convenience prelude\n# pub mod v1 {\n# //! convenience prelude\n# pub use super::super::ChainErrorDown as _;\n# pub use super::super::ResultTrait as _;\n# pub use super::super::{ChainError, ChainResult};\n# pub use crate::{derive_err_kind, derive_str_context};\n# }\n# }\n# # /// chains an inner error kind `T` with a causing error\n# pub struct ChainError {\n# occurrence: Option,\n# kind: T,\n# error_cause: Option>,\n# }\n# # /// convenience type alias\n# pub type ChainResult = std::result::Result>;\n# # impl ChainError {\n# /// Use the `context()` or `map_context()` Result methods instead of calling this directly\n# #[inline]\n# pub fn new(\n# kind: T,\n# error_cause: Option>,\n# occurrence: Option,\n# ) -> Self {\n# Self {\n# occurrence,\n# kind,\n# error_cause,\n# }\n# }\n# # /// return the root cause of the error chain, if any exists\n# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {\n# self.iter().last()\n# }\n# # /// Find the first error cause of type U, if any exists\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// use chainerror::prelude::v1::*;\n# /// use std::error::Error;\n# /// use std::io;\n# ///\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().context(Func2Error(format!(\"Error reading '{}'\", filename)))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func1Error);\n# ///\n# /// fn func1() -> Result<(), Box> {\n# /// func2().context(Func1Error(\"func1 error\".into()))?;\n# /// Ok(())\n# /// }\n# ///\n# /// if let Err(e) = func1() {\n# /// if let Some(f1err) = e.downcast_chain_ref::() {\n# /// assert!(f1err.find_cause::().is_some());\n# ///\n# /// assert!(f1err.find_chain_cause::().is_some());\n# /// }\n# /// # else {\n# /// # panic!();\n# /// # }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// ```\n# #[inline]\n# pub fn find_cause(&self) -> Option<&U> {\n# self.iter().filter_map(Error::downcast_ref::).next()\n# }\n# # /// Find the first error cause of type `ChainError`, if any exists\n# ///\n# /// Same as `find_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// # use chainerror::prelude::v1::*;\n# /// # derive_str_context!(FooError);\n# /// # let err = ChainError::new(String::new(), None, None);\n# /// // Instead of writing\n# /// err.find_cause::>();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_chain_cause::();\n# /// ```\n# #[inline]\n# pub fn find_chain_cause(&self) -> Option<&ChainError> {\n# self.iter()\n# .filter_map(Error::downcast_ref::>)\n# .next()\n# }\n# # /// Find the first error cause of type `ChainError` or `U`, if any exists and return `U`\n# ///\n# /// Same as `find_cause` and `find_chain_cause`, but hides the `ChainError` implementation internals\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// # use chainerror::prelude::v1::*;\n# /// # derive_str_context!(FooErrorKind);\n# /// # let err = ChainError::new(String::new(), None, None);\n# /// // Instead of writing\n# /// err.find_cause::>();\n# /// // and/or\n# /// err.find_chain_cause::();\n# /// // and/or\n# /// err.find_cause::();\n# ///\n# /// // leave out the ChainError implementation detail\n# /// err.find_kind_or_cause::();\n# /// ```\n# #[inline]\n# pub fn find_kind_or_cause(&self) -> Option<&U> {\n# self.iter()\n# .filter_map(|e| {\n# e.downcast_ref::>()\n# .map(|e| e.kind())\n# .or_else(|| e.downcast_ref::())\n# })\n# .next()\n# }\n# # /// Return a reference to T of `ChainError`\n# ///\n# /// # Examples\n# ///\n# /// ```rust\n# /// use chainerror::prelude::v1::*;\n# /// use std::error::Error;\n# /// use std::io;\n# ///\n# /// fn do_some_io() -> Result<(), Box> {\n# /// Err(io::Error::from(io::ErrorKind::NotFound))?;\n# /// Ok(())\n# /// }\n# ///\n# /// derive_str_context!(Func2Error);\n# ///\n# /// fn func2() -> Result<(), Box> {\n# /// let filename = \"foo.txt\";\n# /// do_some_io().context(Func2Error(format!(\"Error reading '{}'\", filename)))?;\n# /// Ok(())\n# /// }\n# ///\n# /// #[derive(Debug)]\n# /// enum Func1ErrorKind {\n# /// Func2,\n# /// IO(String),\n# /// }\n# ///\n# /// /// impl ::std::fmt::Display for Func1ErrorKind {…}\n# /// # impl ::std::fmt::Display for Func1ErrorKind {\n# /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {\n# /// # match self {\n# /// # Func1ErrorKind::Func2 => write!(f, \"func1 error calling func2\"),\n# /// # Func1ErrorKind::IO(filename) => write!(f, \"Error reading '{}'\", filename),\n# /// # }\n# /// # }\n# /// # }\n# ///\n# /// fn func1() -> ChainResult<(), Func1ErrorKind> {\n# /// func2().context(Func1ErrorKind::Func2)?;\n# /// do_some_io().context(Func1ErrorKind::IO(\"bar.txt\".into()))?;\n# /// Ok(())\n# /// }\n# ///\n# /// if let Err(e) = func1() {\n# /// match e.kind() {\n# /// Func1ErrorKind::Func2 => {}\n# /// Func1ErrorKind::IO(filename) => panic!(),\n# /// }\n# /// }\n# /// # else {\n# /// # unreachable!();\n# /// # }\n# /// ```\n# #[inline]\n# pub fn kind(&self) -> &T {\n# &self.kind\n# }\n# # /// Returns an Iterator over all error causes/sources\n# ///\n# /// # Example\n# #[inline]\n# pub fn iter(&self) -> impl Iterator
- {\n# ErrorIter {\n# current: Some(self),\n# }\n# }\n# }\n# # /// Convenience methods for `Result<>` to turn the error into a decorated ChainError\n# pub trait ResultTrait>> {\n# /// Decorate the error with a `kind` of type `T` and the source `Location`\n# fn context(\n# self,\n# kind: T,\n# ) -> std::result::Result>;\n# # /// Decorate the `error` with a `kind` of type `T` produced with a `FnOnce(&error)` and the source `Location`\n# fn map_context