docs: use new names

Signed-off-by: Harald Hoyer <harald@hoyer.xyz>
This commit is contained in:
Harald Hoyer 2023-07-28 16:21:22 +02:00
parent 55c16d7867
commit 82257c881a
Signed by: harald
GPG key ID: 900F3C4971086004
27 changed files with 74 additions and 76 deletions

View file

@ -46,7 +46,7 @@ and you have no idea where it comes from.
With `chainerror`, you can supply a context and get a nice error backtrace: With `chainerror`, you can supply a context and get a nice error backtrace:
```rust ```rust
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::path::PathBuf; use std::path::PathBuf;
type BoxedError = Box<dyn std::error::Error + Send + Sync>; type BoxedError = Box<dyn std::error::Error + Send + Sync>;

1
booksrc/LICENSE-APACHE Symbolic link
View file

@ -0,0 +1 @@
../LICENSE-APACHE

1
booksrc/LICENSE-MIT Symbolic link
View file

@ -0,0 +1 @@
../LICENSE-MIT

View file

@ -1,6 +1,6 @@
# ErrorKind to the rescue # ErrorKind to the rescue
To cope with different kind of errors, we introduce the kind of an error `Func1ErrorKind` with an enum. To cope with different kind of errors, we introduce the `kind` of an error `Func1ErrorKind` with an enum.
Because we derive `Debug` and implement `Display` our `Func1ErrorKind` enum, this enum can be used as Because we derive `Debug` and implement `Display` our `Func1ErrorKind` enum, this enum can be used as
a `std::error::Error`. a `std::error::Error`.
@ -8,10 +8,9 @@ a `std::error::Error`.
Only returning `Func1ErrorKind` in `func1()` now let us get rid of `Result<(), Box<Error + Send + Sync>>` and we can Only returning `Func1ErrorKind` in `func1()` now let us get rid of `Result<(), Box<Error + Send + Sync>>` and we can
use `ChainResult<(), Func1ErrorKind>`. use `ChainResult<(), Func1ErrorKind>`.
In `main` we can now directly use the methods of `ChainError<T>` without downcasting the error first. In `main` we can now directly use the methods of `chainerror::Error<T>` without downcasting the error first.
Also a nice `match` on `ChainError<T>.kind()` is now possible, which returns `&T`, meaning Also, a nice `match` on `chainerror::Error<T>.kind()` is now possible, which returns `&T`, meaning `&Func1ErrorKind` here.
`&Func1ErrorKind` here.
~~~rust ~~~rust
{{#include ../examples/tutorial10.rs}} {{#include ../examples/tutorial10.rs}}

View file

@ -21,7 +21,7 @@ which gives us a lot more detail.
To create your own Errors, you might find [crates](https://crates.io) which create enum `Display+Debug` via derive macros. To create your own Errors, you might find [crates](https://crates.io) which create enum `Display+Debug` via derive macros.
Also noteworthy is [custom_error](https://crates.io/crates/custom_error) to define your custom errors, Also, noteworthy is [custom_error](https://crates.io/crates/custom_error) to define your custom errors,
which can then be used with `chainerror`. which can then be used with `chainerror`.
~~~rust ~~~rust

View file

@ -1,6 +1,6 @@
# Deref for the ErrorKind # Deref for the ErrorKind
Because ChainError<T> implements Deref to &T, we can also match on `*e` instead of `e.kind()` Because chainerror::Error<T> implements Deref to &T, we can also match on `*e` instead of `e.kind()`
or call a function with `&e` or call a function with `&e`
~~~rust ~~~rust
{{#include ../examples/tutorial12.rs}} {{#include ../examples/tutorial12.rs}}

View file

@ -1,6 +1,6 @@
# Writing a library # Writing a library
I would advise to only expose an `mycrate::ErrorKind` and type alias `mycrate::Error` to `ChainError<mycrate::ErrorKind>` I would advise to only expose an `mycrate::ErrorKind` and type alias `mycrate::Error` to `chainerror::Error<mycrate::ErrorKind>`
so you can tell your library users to use the `.kind()` method as `std::io::Error` does. so you can tell your library users to use the `.kind()` method as `std::io::Error` does.
If you later decide to make your own `Error` implementation, your library users don't If you later decide to make your own `Error` implementation, your library users don't

View file

@ -25,7 +25,7 @@ along with the `Location` of the `context()` call and returns `Err(newerror)`.
`?` then returns the inner error applying `.into()`, so that we `?` then returns the inner error applying `.into()`, so that we
again have a `Err(Box<Error + Send + Sync>)` as a result. again have a `Err(Box<Error + Send + Sync>)` as a result.
The `Debug` implementation of `ChainError<T>` (which is returned by `context()`) The `Debug` implementation of `chainerror::Error<T>` (which is returned by `context()`)
prints the `Debug` of `T` prefixed with the stored filename and line number. prints the `Debug` of `T` prefixed with the stored filename and line number.
`ChainError<T>` in our case is `ChainError<&str>`. `chainerror::Error<T>` in our case is `chainerror::Error<&str>`.

View file

@ -14,13 +14,13 @@ If you compare the output to the previous example, you will see,
that: that:
~~~ ~~~
Error: src/main.rs:19: "func1 error" Error: examples/tutorial2.rs:20:16: func1 error
~~~ ~~~
changed to just: changed to just:
~~~ ~~~
src/main.rs:16: "func1 error" examples/tutorial3.rs:17:13: func1 error
~~~ ~~~
This is, because we caught the error of `func1()` in `main()` and print it out ourselves. This is, because we caught the error of `func1()` in `main()` and print it out ourselves.

View file

@ -14,5 +14,4 @@ Sometimes you want to inspect the `source()` of an `Error`.
Note, that because we changed the output of the error in `main()` from Note, that because we changed the output of the error in `main()` from
`Debug` to `Display`, we don't see the error backtrace with filename and line number. `Debug` to `Display`, 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`. To use the `Display` backtrace, you have to use the alternative display format output `{:#}`.

View file

@ -4,15 +4,15 @@
~~~rust,ignore ~~~rust,ignore
fn is_chain<T: 'static + Display + Debug>(&self) -> bool fn is_chain<T: 'static + Display + Debug>(&self) -> bool
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&chainerror::Error<T>>
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut chainerror::Error<T>>
fn root_cause(&self) -> Option<&(dyn Error + 'static)> fn root_cause(&self) -> Option<&(dyn Error + 'static)>
fn find_cause<U: Error + 'static>(&self) -> Option<&U> fn find_cause<U: Error + 'static>(&self) -> Option<&U>
fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> fn find_chain_cause<U: Error + 'static>(&self) -> Option<&chainerror::Error<U>>
fn kind<'a>(&'a self) -> &'a T fn kind<'a>(&'a self) -> &'a T
~~~ ~~~
Using `downcast_chain_ref::<String>()` gives a `ChainError<String>`, which can be used Using `downcast_chain_ref::<String>()` gives a `chainerror::Error<String>`, which can be used
to call `.find_cause::<io::Error>()`. to call `.find_cause::<io::Error>()`.
~~~rust,ignore ~~~rust,ignore

View file

@ -1,14 +1,14 @@
# Finding an Error cause # Finding an Error cause
To distinguish the errors occuring in various places, we can define named string errors with the To distinguish the errors occurring in various places, we can define named string errors with the
"new type" pattern. "new type" pattern.
~~~rust,ignore ~~~rust,ignore
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
derive_str_context!(Func1Error); chainerror::str_context!(Func1Error);
~~~ ~~~
Instead of `ChainError<String>` we now have `struct Func1Error(String)` and `ChainError<Func1Error>`. Instead of `chainerror::Error<String>` we now have `struct Func1Error(String)` and `chainerror::Error<Func1Error>`.
In the `main` function you can see, how we can match the different errors. In the `main` function you can see, how we can match the different errors.
@ -18,9 +18,9 @@ Also see:
~~~ ~~~
as a shortcut to as a shortcut to
~~~rust,ignore ~~~rust,ignore
if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() { if let Some(f2err) = f1err.find_cause::<chainerror::Error<Func2Error>>() {
~~~ ~~~
hiding the `ChainError<T>` implementation detail. hiding the `chainerror::Error<T>` implementation detail.
~~~rust ~~~rust
{{#include ../examples/tutorial8.rs}} {{#include ../examples/tutorial8.rs}}

View file

@ -1,8 +1,7 @@
use chainerror::prelude::v2::*;
use std::error::Error; use std::error::Error;
use std::fmt;
use std::io; use std::io;
use std::result::Result;
use chainerror::prelude::v1::*;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
@ -15,9 +14,9 @@ fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> ChainResult<(), Func2Error> { fn func2() -> chainerror::Result<(), Func2Error> {
func3().context(Func2Error("func2 error: calling func3".to_string()))?; func3().context(Func2Error("func2 error: calling func3".to_string()))?;
Ok(()) Ok(())
} }
@ -27,8 +26,8 @@ enum Func1Error {
IO(String), IO(String),
} }
impl ::std::fmt::Display for Func1Error { impl fmt::Display for Func1Error {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Func1Error::Func2 => write!(f, "func1 error calling func2"), Func1Error::Func2 => write!(f, "func1 error calling func2"),
Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename), Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
@ -36,13 +35,13 @@ impl ::std::fmt::Display for Func1Error {
} }
} }
impl ::std::fmt::Debug for Func1Error { impl fmt::Debug for Func1Error {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self) write!(f, "{}", self)
} }
} }
fn func1() -> ChainResult<(), Func1Error> { fn func1() -> chainerror::Result<(), Func1Error> {
func2().context(Func1Error::Func2)?; func2().context(Func1Error::Func2)?;
let filename = String::from("bar.txt"); let filename = String::from("bar.txt");
do_some_io().context(Func1Error::IO(filename))?; do_some_io().context(Func1Error::IO(filename))?;

View file

@ -3,7 +3,6 @@
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,14 +1,14 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> Result<(), Box<dyn Error + Send + Sync>> { fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -32,7 +32,7 @@ impl ::std::fmt::Display for Func1ErrorKind {
} }
impl ::std::error::Error for Func1ErrorKind {} impl ::std::error::Error for Func1ErrorKind {}
fn func1() -> ChainResult<(), Func1ErrorKind> { fn func1() -> chainerror::Result<(), Func1ErrorKind> {
func2().context(Func1ErrorKind::Func2)?; func2().context(Func1ErrorKind::Func2)?;
let filename = String::from("bar.txt"); let filename = String::from("bar.txt");
do_some_io().context(Func1ErrorKind::IO(filename))?; do_some_io().context(Func1ErrorKind::IO(filename))?;

View file

@ -1,14 +1,14 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> Result<(), Box<dyn Error + Send + Sync>> { fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -38,7 +38,7 @@ impl ::std::fmt::Debug for Func1ErrorKind {
impl ::std::error::Error for Func1ErrorKind {} impl ::std::error::Error for Func1ErrorKind {}
fn func1() -> ChainResult<(), Func1ErrorKind> { fn func1() -> chainerror::Result<(), Func1ErrorKind> {
func2().context(Func1ErrorKind::Func2)?; func2().context(Func1ErrorKind::Func2)?;
let filename = String::from("bar.txt"); let filename = String::from("bar.txt");
do_some_io().context(Func1ErrorKind::IO(filename))?; do_some_io().context(Func1ErrorKind::IO(filename))?;

View file

@ -1,14 +1,14 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> Result<(), Box<dyn Error + Send + Sync>> { fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -38,7 +38,7 @@ impl ::std::fmt::Debug for Func1ErrorKind {
impl ::std::error::Error for Func1ErrorKind {} impl ::std::error::Error for Func1ErrorKind {}
fn func1() -> ChainResult<(), Func1ErrorKind> { fn func1() -> chainerror::Result<(), Func1ErrorKind> {
func2().context(Func1ErrorKind::Func2)?; func2().context(Func1ErrorKind::Func2)?;
let filename = String::from("bar.txt"); let filename = String::from("bar.txt");
do_some_io().context(Func1ErrorKind::IO(filename))?; do_some_io().context(Func1ErrorKind::IO(filename))?;

View file

@ -2,7 +2,8 @@
#![allow(clippy::redundant_pattern_matching)] #![allow(clippy::redundant_pattern_matching)]
pub mod mycrate { pub mod mycrate {
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::io; use std::io;
fn do_some_io() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> { fn do_some_io() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
@ -10,7 +11,7 @@ pub mod mycrate {
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> { fn func2() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -24,7 +25,7 @@ pub mod mycrate {
IO(String), IO(String),
} }
derive_err_kind!(Error, ErrorKind); chainerror::err_kind!(Error, ErrorKind);
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;

View file

@ -2,7 +2,8 @@
#![allow(clippy::redundant_pattern_matching)] #![allow(clippy::redundant_pattern_matching)]
pub mod mycrate { pub mod mycrate {
use chainerror::prelude::v1::*; use chainerror::{Context as _, ErrorDown as _};
use std::io; use std::io;
fn do_some_io(_f: &str) -> std::result::Result<(), io::Error> { fn do_some_io(_f: &str) -> std::result::Result<(), io::Error> {
@ -10,7 +11,7 @@ pub mod mycrate {
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> { fn func2() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -26,7 +27,7 @@ pub mod mycrate {
Unknown, Unknown,
} }
derive_err_kind!(Error, ErrorKind); chainerror::err_kind!(Error, ErrorKind);
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
impl std::fmt::Display for ErrorKind { impl std::fmt::Display for ErrorKind {

View file

@ -1,8 +1,7 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,8 +1,7 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,7 +1,7 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,7 +1,7 @@
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,10 +1,10 @@
#![allow(clippy::single_match)] #![allow(clippy::single_match)]
#![allow(clippy::redundant_pattern_matching)] #![allow(clippy::redundant_pattern_matching)]
use chainerror::prelude::v1::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,10 +1,10 @@
#![allow(clippy::single_match)] #![allow(clippy::single_match)]
#![allow(clippy::redundant_pattern_matching)] #![allow(clippy::redundant_pattern_matching)]
use chainerror::prelude::v1::*; use chainerror::{Context as _, ErrorDown as _};
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;

View file

@ -1,14 +1,14 @@
use chainerror::prelude::v1::*; use chainerror::{Context as _, ErrorDown as _};
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> Result<(), Box<dyn Error + Send + Sync>> { fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -16,7 +16,7 @@ fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(()) Ok(())
} }
derive_str_context!(Func1Error); chainerror::str_context!(Func1Error);
fn func1() -> Result<(), Box<dyn Error + Send + Sync>> { fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
func2().context(Func1Error("func1 error".to_string()))?; func2().context(Func1Error("func1 error".to_string()))?;
@ -28,7 +28,7 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() { if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
eprintln!("Func1Error: {}", f1err); eprintln!("Func1Error: {}", f1err);
if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() { if let Some(f2err) = f1err.find_cause::<chainerror::Error<Func2Error>>() {
eprintln!("Func2Error: {}", f2err); eprintln!("Func2Error: {}", f2err);
} }

View file

@ -1,14 +1,14 @@
use chainerror::prelude::v1::*; use chainerror::{Context as _, ErrorDown};
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::result::Result;
fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> { fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Err(io::Error::from(io::ErrorKind::NotFound))?; Err(io::Error::from(io::ErrorKind::NotFound))?;
Ok(()) Ok(())
} }
derive_str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> Result<(), Box<dyn Error + Send + Sync>> { fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
@ -16,8 +16,8 @@ fn func2() -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(()) Ok(())
} }
derive_str_context!(Func1ErrorFunc2); chainerror::str_context!(Func1ErrorFunc2);
derive_str_context!(Func1ErrorIO); chainerror::str_context!(Func1ErrorIO);
fn func1() -> Result<(), Box<dyn Error + Send + Sync>> { fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
func2().context(Func1ErrorFunc2("func1 error calling func2".to_string()))?; func2().context(Func1ErrorFunc2("func1 error calling func2".to_string()))?;
@ -28,7 +28,7 @@ fn func1() -> Result<(), Box<dyn Error + Send + Sync>> {
fn main() -> Result<(), Box<dyn Error + Send + Sync>> { fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
if let Err(e) = func1() { if let Err(e) = func1() {
if let Some(s) = e.downcast_ref::<ChainError<Func1ErrorIO>>() { if let Some(s) = e.downcast_ref::<chainerror::Error<Func1ErrorIO>>() {
eprintln!("Func1ErrorIO:\n{:?}", s); eprintln!("Func1ErrorIO:\n{:?}", s);
} }