Crate derail

Crate derail 

Source
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§

CoreCompat
Wraps a core::error::Error type so that it implements Error.
VisitContext
Context provided to Visitor::visit.

Traits§

Error
Trait for types that represent an error condition.
ErrorExt
Extension trait that provides more methods for Errors.
Visitor
Trait for visiting Error forests.
VisitorExt
Extension trait that provides more methods for Visitors.