This commit is contained in:
Harald Hoyer 2018-12-20 15:14:21 +01:00
parent e0c2eadae0
commit 4d2d807332
13 changed files with 115 additions and 5 deletions

View file

@ -1,2 +1,13 @@
# chainerror # chainerror
Read the [Tutorial](https://haraldh.github.io/chainerror/)
`chainerror` provides an error backtrace like `failure` without doing a real backtrace, so even after you `strip` your
binaries, you still have the error backtrace.
`chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
Debug information is worth it!
For an introduction read the [Tutorial](https://haraldh.github.io/chainerror/)

View file

@ -1,3 +1,11 @@
## Simple String Errors
The most simplest of doing error handling in rust is by returning `String` as a `Box<Error>`.
As you can see by running the example, this only prints out the last `Error`.
If the rust `main` function returns an Err(), this Err() will be displayed with `std::fmt::Debug`.
~~~rust ~~~rust
{{#include ../examples/tutorial1.rs:2:}} {{#include ../examples/tutorial1.rs:2:}}
~~~ ~~~

View file

@ -1,3 +1,7 @@
## ErrorKind to the rescue
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial10.rs:2:}} {{#include ../examples/tutorial10.rs:2:}}

View file

@ -1,3 +1,7 @@
## Debug for the ErrorKind
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial11.rs:2:}} {{#include ../examples/tutorial11.rs:2:}}

View file

@ -1,3 +1,9 @@
## Simple Chained String Errors
Now with the help of the `chainerror` crate, we can have a nicer output.
Press the play button in the upper right corner and see the nice debug output.
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial2.rs:2:}} {{#include ../examples/tutorial2.rs:2:}}
@ -5,4 +11,21 @@ use crate::chainerror::*;
# mod chainerror { # mod chainerror {
{{#includecomment ../src/lib.rs}} {{#includecomment ../src/lib.rs}}
# } # }
~~~ ~~~
### What did we do here?
~~~rust,ignore
{{#include ../examples/tutorial2.rs:11:13}}
~~~
The macro `cherr!(cause, newerror)` stores `cause` as the source/cause of `newerror` and returns
`newerror`, along with the filename (`file!()`) and line number (`line!()`).
`Err(e)?` then returns the error `e` applying `e.into()`, so that we
again have a `Err(Box<Error>)` as a result.
The `Debug` implementation of `ChainError<T>` (which is returned by `cherr!()`)
prints the `Debug` of `T` prefixed with the stored filename and line number.
`ChainError<T>` is in our case `ChainError<String>`.

View file

@ -1,3 +1,7 @@
## Mapping Errors
Now let's get more rust idiomatic by using `.map_err()`.
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial3.rs:2:}} {{#include ../examples/tutorial3.rs:2:}}
@ -5,4 +9,22 @@ use crate::chainerror::*;
# mod chainerror { # mod chainerror {
{{#includecomment ../src/lib.rs}} {{#includecomment ../src/lib.rs}}
# } # }
~~~ ~~~
If you compare the output to the previous example, you will see,
that:
~~~
Error: src/main.rs:19: "func1 error"
~~~
changed to just:
~~~
src/main.rs:16: "func1 error"
~~~
This is, because we caught the error of `func1()` in `main()` and print it out ourselves.
We can now control, whether to output in `Debug` or `Display` mode.
Maybe depending on `--debug` as a CLI argument.

View file

@ -1,3 +1,13 @@
## Saving coding chars
Because decorating an error with more information should not
let you jump through hoops, `chainerror` has a quick macro for that.
`mstrerror!()` fits right into `.map_err()` letting you quickly add
more debug strings.
`mstrerror!()` even understands `format!()` syntax like `println!()`.
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial4.rs:2:}} {{#include ../examples/tutorial4.rs:2:}}

View file

@ -1,3 +1,8 @@
## The source() of Errors
Sometimes you want to inspect the `source()` of an `Error`.
`chainerror` implements `std::error::Error::source()`, so you can get the cause of an error.
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial5.rs:2:}} {{#include ../examples/tutorial5.rs:2:}}
@ -5,4 +10,10 @@ use crate::chainerror::*;
# mod chainerror { # mod chainerror {
{{#includecomment ../src/lib.rs}} {{#includecomment ../src/lib.rs}}
# } # }
~~~ ~~~
Note, that we changed the output of the error in `main()` from `Debug` to `Display`, so we don't see
the error backtrace with filename and line number.
To enable the `Display` backtrace, you have to enable the feature `display-cause` for `chainerror`.

View file

@ -1,3 +1,7 @@
## Downcast the Errors
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial6.rs:2:}} {{#include ../examples/tutorial6.rs:2:}}

View file

@ -1,3 +1,7 @@
## The root cause of all Errors
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial7.rs:2:}} {{#include ../examples/tutorial7.rs:2:}}

View file

@ -1,3 +1,7 @@
## Finding an Error cause
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial8.rs:2:}} {{#include ../examples/tutorial8.rs:2:}}

View file

@ -1,3 +1,7 @@
## Selective Error Handling
[TBD]
~~~rust ~~~rust
use crate::chainerror::*; use crate::chainerror::*;
{{#include ../examples/tutorial9.rs:2:}} {{#include ../examples/tutorial9.rs:2:}}

View file

@ -8,7 +8,8 @@ fn do_some_io() -> Result<(), Box<Error>> {
} }
fn func2() -> Result<(), Box<Error>> { fn func2() -> Result<(), Box<Error>> {
do_some_io().map_err(mstrerr!("func2 error"))?; let filename = "foo.txt";
do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
Ok(()) Ok(())
} }