# traced_result ## An proof-of-concept to automatically backtrace errors propagated with the `?` operator# **Note**: This crate relies on the unstable [`try_trait_v2`](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html) language feature. This means it can only be used with the `nightly` toolchain, may break at any time, and is thus not recommended for use in production code until this feature is stabilized. ## Usage `traced_result` differs from crates like [`trace_error`](https://crates.io/crates/trace_error) in that it does not use macros to trace call stacks, but instead uses the (currently unstable) `Try` trait to be as consistent with regular `Result`s as possible. The two types at the core of this crate are `TracedResult`, designed to work like `std::result::Result`, and `TracedError`, which is simply a wrapper around `E` and a `Vec<&'static Location<'static>>`. To get started, simply replace `Result` with `TracedResult`: ```rust // From fn foo() -> Result { // ... return Err(Baz(/*...*/)); } // To fn foo() -> TracedResult { // ... return TracedResult::Err(TracedError::new(Baz(/*...*/))) } ``` `TracedResult` and `TracedError` also come with convenient `From` implementations, allowing you to write something like ```rust return TracedResult::Err(Baz(/*...*/).into()) ``` or even ```rust return Err(Baz(/*...*/)).into() ``` Now, whenever a `TracedResult` is propagated with the `?` operator, `TracedResult`'s `Try` impl will store the location of the operators usage to the errors call stack, if any: ```rust fn foo() -> TracedResult { Err(Baz(/*...*/)).into() } fn do_something() -> TracedResult<(), Baz> { let value = foo()?; Ok(()) } fn main() { if let TracedResult::Err(error) = do_something() { println!("{}", error) // Baz at (40:21) in file example.rs // at (2:26) in file example.rs } } ``` ## `Result` methods `TracedResult` currently has its the following methods: - `unwrap()` and all related methods, including the `unchecked` methods - `is_ok()` and `is_err()` - `map()` and all related methods - conversion to an `std::result::Result>` using `into_result()` or the `From` trait for compatibility any remaining methods – note that subsequent uses of the `?` operator will no longer be tracked. To discard the call stack completely, you can also use `TracedResult::discard_call_stack()` to get a `Result` without the `TracedError` wrapper around `E`. ## Note: the `#[track_caller]` attribute Internally, `TracedResult` uses the `#[track_caller]` attribute to get the location at which the `?` operator was used. This means that if the result is propagated from a function which itself is annotated with `#[track_caller]`, the `Location` added to the call stack will be that of the function's caller, not that of the `Try` operator itself.