[go: up one dir, main page]

Crate adhocerr

Source
Expand description

A library for the construction of efficient static/dynamic single use error types per callsite.

[dependencies]
adhocerr = "0.1"

§Examples

Creating a root cause error:

use adhocerr::err;

fn get_git_root(start: &Path) -> Result<PathBuf, impl Error + 'static> {
    start
        .ancestors()
        .find(|a| a.join(".git").is_dir())
        .map(Path::to_owned)
        .ok_or(err!("Unable to find .git/ in parent directories"))
}

Wrapping another Error:

use adhocerr::wrap;

fn record_success() -> Result<(), impl Error + 'static> {
    std::fs::write(".success", "true").map_err(wrap!("Failed to save results of script"))
}

§Details

This crate provides two primary macros. err! and wrap!. The former, err!, is used to create ad-hoc error types without a root cause from strings. wrap! on the other hand is used to create new errors with a source member.

Both of these macros have two versions, and they generate completely different code, depending on whether or not string interopoation (format!-like code) is used in the error message. When the error message is a fixed string, the macro declares a new struct in line that has the string itself inserted into its Display implementation. This way no memory is used or allocations made to hold the error when they are not needed.

For err! this means that your error type is a Zero Sized Type (ZST), for wrap! this means that your Wrapper error is the same size as the original error you’re wrapping.

When runtime interpolation is used and a String allocation is necessary it uses pre defined Error types to wrap the String to avoid declaring new types unnecessarily, but hides them behind an impl Trait boundary.

§Expanded

The Expanded version of the example above would look like this:

fn get_git_root(start: &Path) -> Result<PathBuf, impl Error + 'static> {
    start
        .ancestors()
        .find(|a| a.join(".git").is_dir())
        .map(Path::to_owned)
        .ok_or({
            #[derive(Debug)]
            struct AdhocError;

            impl std::error::Error for AdhocError {
                fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
                    None
                }
            }

            impl core::fmt::Display for AdhocError {
                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                    f.write_str("Unable to find .git/ in parent directories")
                }
            }

            AdhocError
        })
}

Macros§

bail
Return an ad-hoc error immediately
ensure
Return early with an error if a condition is not satisfied.
err
Create an ad-hoc error type with zero size if none is needed
format_err
Create an ad-hoc error type with zero size if none is needed
wrap
Thinly wrap an error by defining a hidden error type and returning a closure to construct it