Skip to content

Commit

Permalink
Add a way to get the deepest Whatever error backtrace
Browse files Browse the repository at this point in the history
  • Loading branch information
shepmaster committed May 3, 2021
1 parent 76e93f9 commit a7dccef
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
20 changes: 20 additions & 0 deletions compatibility-tests/backtrace-shim/tests/whatever_nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use snafu::{whatever, ResultExt, Whatever};

fn inner_outer() -> Result<(), Whatever> {
not_a_whatever().with_whatever_context(|_| format!("Outer failure"))
}

fn not_a_whatever() -> Result<(), Box<dyn std::error::Error>> {
inner_whatever().map_err(Into::into)
}

fn inner_whatever() -> Result<(), Whatever> {
whatever!("Inner failure");
}

#[test]
fn backtrace_method_delegates_to_nested_whatever() {
let e = inner_outer().unwrap_err();
let bt = e.backtrace().expect("Must have a backtrace");
assert!(bt.to_string().contains("::inner_whatever::"));
}
32 changes: 32 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,18 @@ impl GenerateBacktrace for Backtrace {
/// ```
///
/// See [`whatever!`][] for detailed usage instructions.
///
/// ## Limitations
///
/// When wrapping errors, only the backtrace from the shallowest
/// function is guaranteed to be available. If you need the deepest
/// possible trace, consider creating a custom error type and [using
/// `#[snafu(backtrace)]` on the `source`
/// field](Snafu#controlling-backtraces). If a best-effort attempt is
/// sufficient, see the [`backtrace`] method.
///
/// When the standard library stabilizes backtrace support, this
/// behavior may change.
#[derive(Debug, Snafu)]
#[snafu(crate_root(crate))]
#[snafu(whatever)]
Expand All @@ -1121,3 +1133,23 @@ pub struct Whatever {
message: String,
backtrace: Backtrace,
}

#[cfg(any(feature = "std", test))]
impl Whatever {
/// Gets the backtrace from the deepest `Whatever` error. If none
/// of the underlying errors are `Whatever`, returns the backtrace
/// from when this instance was created.
pub fn backtrace(&self) -> Option<&Backtrace> {
let mut best_backtrace = &self.backtrace;

let mut source = self.source();
while let Some(s) = source {
if let Some(this) = s.downcast_ref::<Self>() {
best_backtrace = &this.backtrace;
}
source = s.source();
}

Some(best_backtrace)
}
}

0 comments on commit a7dccef

Please sign in to comment.