Expand description
An alternative to core::error::Error.
While core::error::Errors are only capable of having zero or one cause (via
core::error::Error::source), derail::Errors are capable of having zero
or many causes (via derail::Error::accept). In graph theory terms, this
means a single core::error::Error can represent a path graph of causes
with itself as the root, and a single derail::Error can represent a tree
of causes with itself as the root.
The typical entrypoint for traversing derail::Errors and their causes
is VisitorExt::visit_many. This method accepts an IntoIterator
of derail::Errors, which means that forests of errors and their
causes are also supported. In practical terms, this means it’s reasonable
and well-supported for a fallible function to return either a single
derail::Error or a collection of them.
Because a path graph is a special case of a tree, CoreCompat is provided
to allow converting a core::error::Error into a derail::Error. No
convenient mechanism is provided for the reverse conversion, as it would
necessarily be lossy.
Additionally, while core::error::Error does not (yet) have a mechanism for
accessing arbitrary data stored in an error in a generic context, derail
provides the derail::Error::details function which
returns the derail::Error::Details associated
type to allow for this. It is also possible to write derail::Errors that
are caused by other derail::Errors with mismatched concrete types for
derail::Error::Details.
derail is #![no_std]-compatible, though it depends on
alloc
by default. Disable the alloc feature if this is undesirable.
§Examples
Here is an example that shows some of derail’s functionality:
use std::{io, iter};
use derail::CoreCompat;
use derail_macros::Error;
use derail_report::{HeapFactory, multiline};
#[derive(Debug, Error)]
#[derail(type Details = ())]
enum ConfigError {
#[derail(display("failed to parse configuration"))]
Parse,
#[derail(display("failed to validate configuration"))]
Validate(#[derail(children)] Vec<ValidationError>),
}
#[derive(Debug, Error)]
#[derail(type Details = ())]
enum ValidationError {
#[derail(display("{_0}"))]
Simple(&'static str),
#[derail(display("failed to read imported configuration file"))]
Import(#[derail(child)] CoreCompat<io::Error>),
}
let error = ConfigError::Validate(vec![
ValidationError::Simple("number out of bounds for option A"),
ValidationError::Import(CoreCompat(io::ErrorKind::NotFound.into())),
ValidationError::Simple("string not long enough for option B"),
]);
let actual = format!(
"Errors:\n{}\n",
multiline::<_, _, HeapFactory>(iter::once(&error)),
);
let expected = indoc::indoc! {"
Errors:
╰─► failed to validate configuration
├─► number out of bounds for option A
├─► failed to read imported configuration file
│ ╰─► entity not found
╰─► string not long enough for option B
"};
assert_eq!(expected, actual);Structs§
- Core
Compat - Wraps a
core::error::Errortype so that it implementsError. - Visit
Context - Context provided to
Visitor::visit.