[][src]Crate adhocerr

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
        })
}

Re-exports

pub use err as format_err;

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

wrap

Thinly wrap an error by defining a hidden error type and returning a closure to construct it