Crate errify

source ·
Expand description

§errify

This library provides the macros that provide error context for the entire function.

§Features

§Context provider

There are two macros errify and errify_with that provide immediate and lazy context creation respectively. The error type must implement the WrapErr trait for use in macros.

Macros also support async functions.

§Immediate context

To get started, add the attribute macro to the function for which you want to add error context and implement WrapErr for your error:

use errify::errify;

struct CustomError {
    // ...
}
impl errify::WrapErr for CustomError {
    fn wrap_err<C>(self, context: C) -> Self
    where
        C: std::fmt::Display + Send + Sync + 'static,
    {
        // ...
    }
}

#[errify("Custom error context, with argument capturing {arg} = {}", arg)]
fn func(arg: i32) -> Result<(), CustomError> {
    // ...
}

This code expands into something like this:

fn func(arg: i32) -> Result<(), CustomError> {
    let cx = std::borrow::Cow::<'static, str>::Owned(format!("Custom error context, with argument capturing {arg} = {}", arg));
    let res = {
        let f = move || {
            // ...
        };
        let f_res: Result<(), CustomError> = (f)();
        f_res
    };
    match res {
        Ok(v) => Ok(v),
        Err(err) => Err(errify::WrapErr::wrap_err(err, cx)),
    }
}

Note that after desugaring your original function converts into closure and move all arguments into it. This is mean that context is created before call this function because of arguments, and it could lead to unnecessary allocation even for the success branch.

The context can be either the format string or any expression that fits constraint T: Display + Send + Sync + 'static:

use errify::errify;

#[errify(String::from("Hello context from String"))]
fn func(arg: i32) -> Result<(), CustomError> {
    // ...
}

§Lazy context

If you need lazy initialization of the context, there is another macro:

use errify::errify_with;

#[errify_with(|| format!("Wow, context from lambda, and it can also capture arguments {arg}"))]
fn func(arg: i32) -> Result<(), CustomError> {
    // ...
}

The constraint looks similar F: FnOnce() -> impl Display + Send + Sync + 'static.

You can use either a lambda or define free function:

use std::fmt::Display;
use errify::errify_with;

fn ctx() -> impl Display {
    "context from free function"
}

#[errify_with(ctx)]
fn func(arg: i32) -> Result<(), CustomError> {
    // ...
}

Traits§

  • Provides the wrap_err method for the error type.

Attribute Macros§

  • Macro that provides error context on entire function. Supports async functions.
  • Macro that provides lazy error context on entire function. Supports async functions.