Scoped Error: Yet another error handling crate, but this time it makes sense to me
This project is inspired by using the great exn crate in my projects.
Example:
use scoped_error::{Error, expect_error};
fn read_config() -> Result<String, Error> {
expect_error("read config file", || {
let raw = std::fs::read_to_string("config.toml")?;
Ok(raw)
})
}
fn complex_method() -> Result<(), Error> {
expect_error("failed to do complex thing", || {
let cfg = read_config()?;
parse(cfg)?;
Ok(())
})
}
The core idea is simple: attach context exactly once. Not at every call site, not at every failure point, just between caller and logic. I want per-module Error types without manual conversion at every step.
expect_error() has three responsibilities: prepare context for future errors, force inner errors into a boxed type to type-erase the inner error, and wrap the outer error with the inner as its source.
The result: a clean, readable declaration of fallible operations. A default Error type is provided, but any std Error implementing WithContext works too.