Expand description
std::error::Error
extensions
This crate encourages usage of the std::error::Error
trait for
describing errors, providing the following utilities:
- Error creation: The
errors::new
,errors::wrap
, anderrors::opaque
functions ease the creation of simple error values. - Error inspection: Error source chains can be easily iterated with
errors::iter
iterators to find the error you’re looking for. - Error formatting: The error values created with this crate provide
simple yet powerful control over the formatting of errors and their
source chains, and the
errors::fmt
adapter allows foreign error values to follow along.
§Creating Errors
When an error condition has nothing special about besides a message, you
can create one easily with errors::new
:
let err = errors::new("out of memory");
Library authors are encouraged to make distinct error types that may offer domain-specific ways of describing and inspecting details of a certain error case. For example:
use std::fmt;
#[derive(Debug)]
struct TimedOut;
impl fmt::Display for TimedOut {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("operation timed out")
}
}
impl std::error::Error for TimedOut {}
§Inspecting Errors
Errors tend to wrap others to provide more context. At times, we may wish
to programatically inspect the error and try to handle them depending on
what failed. We can do this by inspecting the source chain of an error with
the tools in errors::iter
.
Say we wanted to check for timeout errors and retry them:
if let Err(e) = do_the_thing() {
if errors::is::<TimedOut>(&*e) {
do_the_thing(); // again!
}
}
On the other hand, sometimes we want to wrap an error so that it can help users debug the problem, but we don’t want them to programmatically react to the error.
Say after trying to do_the_thing
repeated after 3 timeouts, we wanted to
include that information, but prevent the user from thinking the error is
still a Timeout
?
This can be easily done with errors::opaque
:
let mut cnt = 0;
loop {
if let Err(e) = do_the_thing() {
if errors::is::<TimedOut>(&*e) {
if cnt < 3 {
cnt += 1;
continue; // again!
}
// stop retrying
return Err(errors::wrap("too many attempts", errors::opaque(e)).into());
}
// something else went boom
return Err(e);
}
return Ok(()); // success!
}
§Formatting Errors
This crate defines a way for a user to specify how to easily format an
error along with its source chain. All the error values created with this
crate follow this spec, and any other errors can be adapted with the handy
errors::fmt
adapter.
§Output options:
-
Top message only
ship exploded
-
Top message + message of source chain
ship exploded: cat hair in generator
-
Top message + message of source chain + trace/frame
ship exploded at main.rs:55 at ship.rs:89 Caused by: cat hair in generator at ship::parts::generator.rs:33 at ship::parts::engine.rs:789 at ship.rs:89 at main.rs:55
§Format Flags
- Default (
{}
): Print only the top-level message. This is inline with the recommendation forError
- Example:
println!("top only = {}", err)
outputstop only = ship exploded
. - Alternative: This could also be achieved and possibly clearer by setting the “precision” flag to 0, such as
println!("top only: {:.0}", err)
.
- Example:
- Message chain (
{:+}
): Prints the message, and the message of each source, joined by": "
.- Example:
println!("chain = {:+}", err)
outputschain = ship exploded: cat hair in generator
.
- Example:
- With trace/frame (
{:#}
): Prints the message and stack trace/frame- Example:
println!("top trace = {:#}", err)
outputstop trace = ship exploded\n at ship.rs:89
.
- Example:
- Message chain with trace/frame (
{:+#}
): Prints the message and stack trace/frame, and message and trace for each source, joined by\nCaused by:
.
§errors::Main
Newer versions of Rust allow returning a Result
from the main
function
and it will be formatted and printed to the user. Using the
errors::Main
type, you can easily convert any application errors
such that the full source chain will be printed in a useful format.
fn main() -> Result<(), errors::Main> {
do_the_first_thing()?;
do_the_second()?;
Ok(())
}
// These even have different error types!
fn do_the_first_thing() -> Result<(), TimedOut> {
// ...
}
fn do_the_second() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// ...
}
Re-exports§
Modules§
- iter
- Iterating error source chains
Structs§
- Main
- An adapter to pretty-print an error source chain.