Crate bherror

Source
Expand description

This crate provides an error handling system used across all of the TBTL’s Rust code.

The errors constructed are automatically logged as warnings. Errors also carry the backtrace of source errors with them, along with extra context if any.

§Details

Use std::result::Result<T, bherror::Error<E>>, or equivalently bherror::Result<T, E> as the return type for functions which may return an error.

The error type E in bherror::Error<E> must implement the BhError trait. Therefore, all of our concrete error types must implement BhError.

Constructing the initial, root error is done via the Error::root method. This will also log a warning.

Error types that are not defined by us, i.e. don’t implement BhError but do implement std::error::Error we name as “foreign errors”. These errors can be converted & propagated to bherror::Error<E> via the ForeignError trait.

Propagating bherror::Error<E> types is done via the PropagateError trait, instead of using ?. This way we preserve the trace of source errors.

Additional context can be attached to an error using the Error::ctx method. As a convenience, we also offer ErrorContext trait which extends the Result type with the same method.

The crate also offers some additional features.

  • ErrorDyn for cases when you want to type-erase the concrete BhError type.
  • Loggable trait which extends the Result with a method for logging errors at the error level. Note, we log all constructed errors as warnings regardless.
  • adapters module for easier integration with other libraries & frameworks.

§Examples

use bherror::traits::{ErrorContext, ForeignError, PropagateError};

enum MyErrors {
    NumberIsNegativeError,
    NumberParseError,
}

impl std::fmt::Display for MyErrors {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MyErrors::NumberIsNegativeError => write!(f, "MyErrors::NumberIsNegativeError"),
            MyErrors::NumberParseError => write!(f, "MyErrors::NumberParseError"),
        }
    }
}

impl bherror::BhError for MyErrors {}

fn my_function(s: &str) -> bherror::Result<i32, MyErrors> {
    let num = s
        .parse()
        // Propagate a "foreign error" and log it as a warning.
        .foreign_err(|| MyErrors::NumberParseError)
        // Add some additional context to the error.
        .ctx(|| format!("parsing {s}"))?;
    if num < 0 {
        // Return the root error and log it as a warning.
        Err(bherror::Error::root(MyErrors::NumberIsNegativeError))
    } else {
        Ok(num)
    }
}

struct AnotherError;

impl std::fmt::Display for AnotherError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "AnotherError")
    }
}

impl bherror::BhError for AnotherError {}

fn another_function() -> bherror::Result<(), AnotherError> {
    // Propagate `MyErrors` as the source error for `AnotherError`
    my_function("blah").with_err(|| AnotherError)?;
    Ok(())
}

Modules§

adapters
This module provides various adapters for making our crate::Error<BhError> types work with other libraries and frameworks.
traits
This module provides various extension traits which provide convenience for working with our error handling system.

Structs§

Error
A struct that should be used for all errors in our projects.

Traits§

BhError
The trait needed for compatibility with the Error functionality.
BhErrorAny
Hacky trait to enable downcasting from trait objects of it.

Type Aliases§

ErrorDyn
Error containing type-erased BhError.
Result
The std::result::Result wrapper that wraps the error object into Error.