mirror of
https://github.com/haraldh/chainerror.git
synced 2025-06-06 16:14:43 +02:00
deploy: 1003671be3
This commit is contained in:
parent
10db06b469
commit
4d8e0bf76f
16 changed files with 2168 additions and 4978 deletions
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">//! binaries, you still have the error backtrace.
|
||||
</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">//! `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">//!
|
||||
</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">//! `chainerror` has no dependencies!
|
||||
</span><span class="boring">//!
|
||||
</span><span class="boring">//! Debug information is worth it!
|
||||
</span><span class="boring">//!
|
||||
</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">//!
|
||||
</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">#![deny(clippy::all)]
|
||||
</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">
|
||||
</span><span class="boring">use std::any::TypeId;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue