thistrace 0.1.0

Callsite provenance (file/line/col) for thiserror #[from] conversions via #[track_caller]
Documentation
use thistrace::{origin, traceable, DisplayTrace, HasTrace, OneLineTrace};

#[derive(thiserror::Error, Debug)]
#[error("leaf boom")]
struct LeafError;

#[traceable]
#[derive(thiserror::Error, Debug)]
enum MidError {
    #[error("mid")]
    Mid(#[from] thistrace::Origin<LeafError>),
}

#[traceable]
#[derive(thiserror::Error, Debug)]
enum TopError {
    #[error("top")]
    Top(#[from] thistrace::Bubbled<MidError>),
}

fn inner() -> Result<(), thistrace::Origin<LeafError>> {
    Err(origin(LeafError))
}

fn mid() -> Result<(), MidError> {
    inner()?;
    Ok(())
}

fn top() -> Result<(), TopError> {
    mid().map_err(thistrace::bubble_err!())?;
    Ok(())
}

#[test]
fn origin_custom_error_multiple_bubbles_appends_frames() {
    let err = top().unwrap_err();
    let t = err.trace().expect("top error should have trace");

    // origin frame + mid bubble + top bubble
    assert_eq!(t.frames().len(), 3);
    assert!(t.frames()[2].file.ends_with("origin_custom_multiple_bubbles.rs"));

    let pretty = format!("{}", DisplayTrace::new(&err));
    println!("{}", pretty);
    assert!(pretty.matches("\n  at ").count() >= 3);

    let one_line = format!("{}", OneLineTrace::new(&err));
    println!("{}", one_line);
    assert!(!one_line.contains('\n'));
}