mirror of
https://github.com/haraldh/chainerror.git
synced 2025-02-23 08:44:20 +01:00
deploy: 1003671be3
This commit is contained in:
parent
10db06b469
commit
4d8e0bf76f
247
index.html
247
index.html
|
@ -169,199 +169,78 @@
|
||||||
<h1><a class="header" href="#chainerror" id="chainerror">chainerror</a></h1>
|
<h1><a class="header" href="#chainerror" id="chainerror">chainerror</a></h1>
|
||||||
<p><code>chainerror</code> provides an error backtrace without doing a real backtrace, so even after you <code>strip</code> your
|
<p><code>chainerror</code> provides an error backtrace without doing a real backtrace, so even after you <code>strip</code> your
|
||||||
binaries, you still have the error backtrace.</p>
|
binaries, you still have the error backtrace.</p>
|
||||||
<p><code>chainerror</code> has no dependencies!</p>
|
<p>Having nested function returning errors, the output doesn't tell where the error originates from.</p>
|
||||||
|
<pre><pre class="playground"><code class="language-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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre></pre>
|
||||||
|
<p>This gives the output:</p>
|
||||||
|
<pre><code class="language-console">Error:
|
||||||
|
Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</code></pre>
|
||||||
|
<p>and you have no idea where it comes from.</p>
|
||||||
|
<p>With <code>chainerror</code>, you can supply a context and get a nice error backtrace:</p>
|
||||||
|
<pre><pre class="playground"><code class="language-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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre></pre>
|
||||||
|
<p>with the output:</p>
|
||||||
|
<pre><code class="language-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" }
|
||||||
|
</code></pre>
|
||||||
<p><code>chainerror</code> uses <code>.source()</code> of <code>std::error::Error</code> along with <code>#[track_caller]</code> and <code>Location</code> to provide a nice debug error backtrace.
|
<p><code>chainerror</code> uses <code>.source()</code> of <code>std::error::Error</code> along with <code>#[track_caller]</code> and <code>Location</code> to provide a nice debug error backtrace.
|
||||||
It encapsulates all types, which have <code>Display + Debug</code> and can store the error cause internally.</p>
|
It encapsulates all types, which have <code>Display + Debug</code> and can store the error cause internally.</p>
|
||||||
<p>Along with the <code>ChainError<T></code> struct, <code>chainerror</code> comes with some useful helper macros to save a lot of typing.</p>
|
<p>Along with the <code>ChainError<T></code> struct, <code>chainerror</code> comes with some useful helper macros to save a lot of typing.</p>
|
||||||
|
<p><code>chainerror</code> has no dependencies!</p>
|
||||||
<p>Debug information is worth it!</p>
|
<p>Debug information is worth it!</p>
|
||||||
<h3><a class="header" href="#features" id="features">Features</a></h3>
|
<h3><a class="header" href="#features" id="features">Features</a></h3>
|
||||||
<p><code>display-cause</code>
|
<p><code>display-cause</code>
|
||||||
: turn on printing a backtrace of the errors in <code>Display</code></p>
|
: turn on printing a backtrace of the errors in <code>Display</code></p>
|
||||||
<h2><a class="header" href="#tutorial" id="tutorial">Tutorial</a></h2>
|
<h2><a class="header" href="#tutorial" id="tutorial">Tutorial</a></h2>
|
||||||
<p>Read the <a href="https://haraldh.github.io/chainerror/tutorial1.html">Tutorial</a></p>
|
<p>Read the <a href="https://haraldh.github.io/chainerror/tutorial1.html">Tutorial</a></p>
|
||||||
<h2><a class="header" href="#examples" id="examples">Examples</a></h2>
|
|
||||||
<p>examples/example.rs:</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust">// […]
|
|
||||||
fn main() {
|
|
||||||
if let Err(e) = func1() {
|
|
||||||
eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
// […]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre></pre>
|
|
||||||
<pre><code class="language-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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<pre><pre class="playground"><code class="language-rust">
|
|
||||||
<span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>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)
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
<span class="boring">}
|
|
||||||
</span></code></pre></pre>
|
|
||||||
<pre><pre class="playground"><code class="language-rust">
|
|
||||||
<span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>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)
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
<span class="boring">}
|
|
||||||
</span></code></pre></pre>
|
|
||||||
<h2><a class="header" href="#license" id="license">License</a></h2>
|
<h2><a class="header" href="#license" id="license">License</a></h2>
|
||||||
<p>Licensed under either of</p>
|
<p>Licensed under either of</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
3571
print.html
3571
print.html
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
277
tutorial10.html
277
tutorial10.html
|
@ -233,13 +233,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -250,200 +333,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial11.html
277
tutorial11.html
|
@ -246,13 +246,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -263,200 +346,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial12.html
277
tutorial12.html
|
@ -244,13 +244,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -261,200 +344,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial13.html
277
tutorial13.html
|
@ -170,13 +170,96 @@ have to change much or anything.</p>
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -187,200 +270,10 @@ have to change much or anything.</p>
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial2.html
277
tutorial2.html
|
@ -196,13 +196,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -213,200 +296,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial3.html
277
tutorial3.html
|
@ -194,13 +194,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -211,200 +294,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial4.html
277
tutorial4.html
|
@ -195,13 +195,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -212,200 +295,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial5.html
277
tutorial5.html
|
@ -200,13 +200,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -217,200 +300,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial6.html
277
tutorial6.html
|
@ -212,13 +212,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -229,200 +312,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial7.html
277
tutorial7.html
|
@ -224,13 +224,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -241,200 +324,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial8.html
277
tutorial8.html
|
@ -221,13 +221,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -238,200 +321,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
277
tutorial9.html
277
tutorial9.html
|
@ -224,13 +224,96 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
</span><span class="boring">//! `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
</span><span class="boring">//! binaries, you still have the error backtrace.
|
</span><span class="boring">//! binaries, you still have the error backtrace.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` has no dependencies!
|
</span><span class="boring">//! Having nested function returning errors, the output doesn't tell where the error originates from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path)?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into())?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! This gives the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//! and you have no idea where it comes from.
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! With `chainerror`, you can supply a context and get a nice error backtrace:
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! ```rust
|
||||||
|
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
||||||
|
</span><span class="boring">//! use std::path::PathBuf;
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
</span><span class="boring">//! fn read_config_file(path: PathBuf) -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = std::fs::read_to_string(&path).context(format!("Reading file: {:?}", &path))?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn process_config_file() -> Result<(), BoxedError> {
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! let _buf = read_config_file("foo.txt".into()).context("read the config file")?;
|
||||||
|
</span><span class="boring">//! // do stuff, return other errors
|
||||||
|
</span><span class="boring">//! Ok(())
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! fn main() {
|
||||||
|
</span><span class="boring">//! if let Err(e) = process_config_file() {
|
||||||
|
</span><span class="boring">//! eprintln!("Error:\n{:?}", e);
|
||||||
|
</span><span class="boring">//! # assert_eq!(
|
||||||
|
</span><span class="boring">//! # format!("{:?}\n", e),
|
||||||
|
</span><span class="boring">//! # "\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:16:51: read the config file\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # src/lib.rs:9:47: Reading file: \"foo.txt\"\n\
|
||||||
|
</span><span class="boring">//! # Caused by:\n\
|
||||||
|
</span><span class="boring">//! # Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\
|
||||||
|
</span><span class="boring">//! # ",
|
||||||
|
</span><span class="boring">//! # );
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! with the output:
|
||||||
|
</span><span class="boring">//! ```console
|
||||||
|
</span><span class="boring">//! Error:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:14:51: read the config file
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! examples/simple.rs:7:47: Reading file: "foo.txt"
|
||||||
|
</span><span class="boring">//! Caused by:
|
||||||
|
</span><span class="boring">//! Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||||
|
</span><span class="boring">//! ```
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
</span><span class="boring">//! `chainerror` uses `.source()` of `std::error::Error` along with `#[track_caller]` and `Location` to provide a nice debug error backtrace.
|
||||||
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
</span><span class="boring">//! It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
</span><span class="boring">//! Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
|
</span><span class="boring">//! `chainerror` has no dependencies!
|
||||||
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Debug information is worth it!
|
</span><span class="boring">//! Debug information is worth it!
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! ## Features
|
</span><span class="boring">//! ## Features
|
||||||
|
@ -241,200 +324,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
</span><span class="boring">//! # Tutorial
|
</span><span class="boring">//! # Tutorial
|
||||||
</span><span class="boring">//!
|
</span><span class="boring">//!
|
||||||
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
</span><span class="boring">//! Read the [Tutorial](https://haraldh.github.io/chainerror/tutorial1.html)
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! # Examples
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! examples/example.rs:
|
|
||||||
</span><span class="boring">//! ```rust,ignore
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! fn main() {
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nDebug Error {{:?}}:\n{:?}", e);
|
|
||||||
</span><span class="boring">//! eprintln!("\nAlternative Debug Error {{:#?}}:\n{:#?}\n", e);
|
|
||||||
</span><span class="boring">//! // […]
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```console
|
|
||||||
</span><span class="boring">//! $ cargo run -q --example example
|
|
||||||
</span><span class="boring">//! Debug Error {:?}:
|
|
||||||
</span><span class="boring">//! examples/example.rs:46:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:21:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! examples/example.rs:14:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! Alternative Debug Error {:#?}:
|
|
||||||
</span><span class="boring">//! ChainError<example::Func1Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:46:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: func1 error calling func2,
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<example::Func2Error> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:21:13",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: Func2Error(func2 error: calling func3),
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! ChainError<alloc::string::String> {
|
|
||||||
</span><span class="boring">//! occurrence: Some(
|
|
||||||
</span><span class="boring">//! "examples/example.rs:14:18",
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! kind: "Error reading \'foo.txt\'",
|
|
||||||
</span><span class="boring">//! source: Some(
|
|
||||||
</span><span class="boring">//! Kind(
|
|
||||||
</span><span class="boring">//! NotFound,
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! },
|
|
||||||
</span><span class="boring">//! ),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! func2().context("func1 error")?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:21:13: func1 error
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! ```rust
|
|
||||||
</span><span class="boring">//! use chainerror::prelude::v1::*;
|
|
||||||
</span><span class="boring">//! use std::error::Error;
|
|
||||||
</span><span class="boring">//! use std::io;
|
|
||||||
</span><span class="boring">//! use std::result::Result;
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! Err(io::Error::from(io::ErrorKind::NotFound))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
</span><span class="boring">//! let filename = "foo.txt";
|
|
||||||
</span><span class="boring">//! do_some_io().context(format!("Error reading '{}'", filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! derive_str_context!(Func2Error);
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func2() -> ChainResult<(), Func2Error> {
|
|
||||||
</span><span class="boring">//! func3().context(Func2Error("func2 error: calling func3".into()))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! enum Func1Error {
|
|
||||||
</span><span class="boring">//! Func2,
|
|
||||||
</span><span class="boring">//! IO(String),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Display for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! match self {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! impl ::std::fmt::Debug for Func1Error {
|
|
||||||
</span><span class="boring">//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
</span><span class="boring">//! write!(f, "{}", self)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! fn func1() -> ChainResult<(), Func1Error> {
|
|
||||||
</span><span class="boring">//! func2().context(Func1Error::Func2)?;
|
|
||||||
</span><span class="boring">//! let filename = String::from("bar.txt");
|
|
||||||
</span><span class="boring">//! do_some_io().context(Func1Error::IO(filename))?;
|
|
||||||
</span><span class="boring">//! Ok(())
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Err(e) = func1() {
|
|
||||||
</span><span class="boring">//! assert!(match e.kind() {
|
|
||||||
</span><span class="boring">//! Func1Error::Func2 => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error calling func2");
|
|
||||||
</span><span class="boring">//! true
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! Func1Error::IO(filename) => {
|
|
||||||
</span><span class="boring">//! eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
|
||||||
</span><span class="boring">//! false
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! });
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.find_chain_cause::<Func2Error>().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
|
||||||
</span><span class="boring">//! eprintln!("\nError reported by Func2Error: {}", e)
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! assert!(e.root_cause().is_some());
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! if let Some(e) = e.root_cause() {
|
|
||||||
</span><span class="boring">//! let io_error = e.downcast_ref::<io::Error>().unwrap();
|
|
||||||
</span><span class="boring">//! eprintln!("\nThe root cause was: std::io::Error: {:#?}", io_error);
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//!
|
|
||||||
</span><span class="boring">//! #[cfg(not(windows))]
|
|
||||||
</span><span class="boring">//! assert_eq!(
|
|
||||||
</span><span class="boring">//! format!("\n{:?}\n", e),
|
|
||||||
</span><span class="boring">//! r#"
|
|
||||||
</span><span class="boring">//! src/lib.rs:48:13: func1 error calling func2
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:23:13: Func2Error(func2 error: calling func3)
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! src/lib.rs:16:18: Error reading 'foo.txt'
|
|
||||||
</span><span class="boring">//! Caused by:
|
|
||||||
</span><span class="boring">//! Kind(NotFound)
|
|
||||||
</span><span class="boring">//! "#
|
|
||||||
</span><span class="boring">//! );
|
|
||||||
</span><span class="boring">//! }
|
|
||||||
</span><span class="boring">//! # else {
|
|
||||||
</span><span class="boring">//! # unreachable!();
|
|
||||||
</span><span class="boring">//! # }
|
|
||||||
</span><span class="boring">//! ```
|
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">#![deny(clippy::all)]
|
</span><span class="boring">#![deny(clippy::all)]
|
||||||
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
</span><span class="boring">#![deny(clippy::integer_arithmetic)]
|
||||||
|
</span><span class="boring">#![allow(clippy::needless_doctest_main)]
|
||||||
</span><span class="boring">#![deny(missing_docs)]
|
</span><span class="boring">#![deny(missing_docs)]
|
||||||
</span><span class="boring">
|
</span><span class="boring">
|
||||||
</span><span class="boring">use std::any::TypeId;
|
</span><span class="boring">use std::any::TypeId;
|
||||||
|
|
Loading…
Reference in a new issue