#error #library #ergonomic

snafu

An ergonomic error handling library

17 unstable releases (3 breaking)

0.4.1 May 19, 2019
0.3.1 May 11, 2019
0.2.3 Apr 24, 2019
0.2.0 Mar 26, 2019
0.1.0 Jan 28, 2019

#49 in Rust patterns

Download history 155/week @ 2019-03-25 21/week @ 2019-04-01 10/week @ 2019-04-08 47/week @ 2019-04-15 92/week @ 2019-04-22 201/week @ 2019-04-29 281/week @ 2019-05-06 374/week @ 2019-05-13 395/week @ 2019-05-20 547/week @ 2019-05-27 602/week @ 2019-06-03 374/week @ 2019-06-10 953/week @ 2019-06-17 539/week @ 2019-06-24 487/week @ 2019-07-01

834 downloads per month
Used in 28 crates (24 directly)

MIT/Apache

75KB
807 lines

SNAFU

Situation Normal: All Fouled Up

crates.io Documentation Build Status

SNAFU is a library to easily assign underlying errors into domain-specific errors while adding context. Please see the documentation and the user's guide for a full description.


lib.rs:

SNAFU

SNAFU is a library to easily assign underlying errors into domain-specific errors while adding context. For detailed information, please see the user's guide.

Quick example

This example mimics a (very poor) authentication process that opens a file, writes to a file, and checks the user's ID. While two of our operations involve an io::Error, these are different conceptual errors to us.

SNAFU creates context selectors mirroring each error variant. These are used with the context method to provide ergonomic error handling.

use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu};
use std::{
    fs,
    path::{Path, PathBuf},
};

#[derive(Debug, Snafu)]
enum Error {
    #[snafu(display("Could not open config from {}: {}", filename.display(), source))]
    OpenConfig {
        filename: PathBuf,
        source: std::io::Error,
    },
    #[snafu(display("Could not save config to {}: {}", filename.display(), source))]
    SaveConfig {
        filename: PathBuf,
        source: std::io::Error,
    },
    #[snafu(display("The user id {} is invalid", user_id))]
    UserIdInvalid { user_id: i32, backtrace: Backtrace },
}

type Result<T, E = Error> = std::result::Result<T, E>;

fn log_in_user<P>(config_root: P, user_id: i32) -> Result<bool>
where
    P: AsRef<Path>,
{
    let config_root = config_root.as_ref();
    let filename = &config_root.join("config.toml");

    let config = fs::read(filename).context(OpenConfig { filename })?;
    // Perform updates to config
    fs::write(filename, config).context(SaveConfig { filename })?;

    ensure!(user_id == 42, UserIdInvalid { user_id });

    Ok(true)
}

# const CONFIG_DIRECTORY: &str = "/does/not/exist";
# const USER_ID: i32 = 0;
fn log_in() {
    match log_in_user(CONFIG_DIRECTORY, USER_ID) {
        Ok(true) => println!("Logged in!"),
        Ok(false) => println!("Not logged in!"),
        Err(e) => {
            eprintln!("An error occurred: {}", e);
            if let Some(backtrace) = ErrorCompat::backtrace(&e) {
                println!("{}", backtrace);
            }
        }
    }
}

Dependencies

~1MB
~22K SLoC