snafu 0.4.4

An ergonomic error handling library
Documentation
extern crate snafu;

use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu};

type AnotherError = Box<dyn std::error::Error>;

#[derive(Debug, Snafu)]
enum Error {
    #[snafu(display = r#"("Invalid user {}:\n{}", user_id, backtrace)"#)]
    InvalidUser { user_id: i32, backtrace: Backtrace },
    WithSource {
        source: AnotherError,
        backtrace: Backtrace,
    },
    WithSourceAndOtherInfo {
        user_id: i32,
        source: AnotherError,
        backtrace: Backtrace,
    },
}

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

fn check_less_than(user_id: i32) -> Result<()> {
    ensure!(user_id >= 42, InvalidUser { user_id });
    Ok(())
}

fn check_greater_than(user_id: i32) -> Result<()> {
    ensure!(user_id <= 42, InvalidUser { user_id });
    Ok(())
}

fn example(user_id: i32) -> Result<()> {
    check_less_than(user_id)?;
    check_greater_than(user_id)?;

    Ok(())
}

#[test]
fn has_a_backtrace() {
    let e = example(0).unwrap_err();
    let text = ErrorCompat::backtrace(&e)
        .map(ToString::to_string)
        .unwrap_or_default();
    assert!(text.contains("check_less_than"));
}

#[test]
fn display_can_access_backtrace() {
    let e = example(0).unwrap_err();
    let text = e.to_string();
    assert!(text.contains("check_less_than"));
}

fn trigger() -> Result<(), AnotherError> {
    Err("boom".into())
}

#[test]
fn errors_with_sources_can_have_backtraces() {
    let _e: Error = trigger().context(WithSource).unwrap_err();
}

#[test]
fn errors_with_sources_and_other_info_can_have_backtraces() {
    let _e: Error = trigger()
        .context(WithSourceAndOtherInfo { user_id: 42 })
        .unwrap_err();
}