Skip to main content

snafu/
whatever.rs

1use alloc::{boxed::Box, string::String};
2
3use crate::{Backtrace, ChainCompat, Snafu};
4
5/// A basic error type that you can use as a first step to better
6/// error handling.
7///
8/// You can use this type in your own application as a quick way to
9/// create errors or add basic context to another error. This can also
10/// be used in a library, but consider wrapping it in an
11/// [opaque](crate::guide::opaque) error to avoid putting the SNAFU
12/// crate in your public API.
13///
14/// ## Examples
15///
16/// ```rust
17/// use snafu::prelude::*;
18///
19/// type Result<T, E = snafu::Whatever> = std::result::Result<T, E>;
20///
21/// fn subtract_numbers(a: u32, b: u32) -> Result<u32> {
22///     if a > b {
23///         Ok(a - b)
24///     } else {
25///         whatever!("Can't subtract {a} - {b}")
26///     }
27/// }
28///
29/// fn complicated_math(a: u32, b: u32) -> Result<u32> {
30///     let val = subtract_numbers(a, b).whatever_context("Can't do the math")?;
31///     Ok(val * 2)
32/// }
33/// ```
34///
35/// See [`whatever!`][crate::whatever!] for detailed usage instructions.
36///
37/// ## Limitations
38///
39/// When wrapping errors, only the backtrace from the shallowest
40/// function is guaranteed to be available. If you need the deepest
41/// possible trace, consider creating a custom error type and [using
42/// `#[snafu(backtrace)]` on the `source`
43/// field](Snafu#controlling-backtraces). If a best-effort attempt is
44/// sufficient, see the [`backtrace`][Self::backtrace] method.
45///
46/// When the standard library stabilizes support for the
47/// [provide API](https://doc.rust-lang.org/std/error/trait.Error.html#method.provide),
48/// this behavior may change.
49///
50/// ## Thread Safety
51///
52/// This type requires that contained errors implement [`Send`][] and
53/// [`Sync`][]. If this is burdensome, you may also use
54/// [`WhateverLocal`][].
55#[derive(Debug, Snafu)]
56#[snafu(crate_root(crate))]
57#[snafu(whatever)]
58#[snafu(display("{message}"))]
59pub struct Whatever {
60    #[snafu(source(from(Box<dyn crate::Error + Send + Sync>, Some)))]
61    source: Option<Box<dyn crate::Error + Send + Sync>>,
62    message: String,
63    backtrace: Backtrace,
64}
65
66impl Whatever {
67    /// Gets the backtrace from the deepest [`Whatever`][] or
68    /// [`WhateverLocal`][] error. If none of the underlying errors
69    /// are one of these types, returns the backtrace from when this
70    /// instance was created.
71    pub fn backtrace(&self) -> &Backtrace {
72        known_whatevers_backtrace(self).unwrap_or(&self.backtrace)
73    }
74}
75
76/// A basic error type that you can use as a first step to better
77/// error handling when the error does not need to cross a thread
78/// boundary.
79///
80/// This type behaves the same as [`Whatever`][] except it does not
81/// require that the wrapped errors implement [`Send`][] or
82/// [`Sync`][]. See [`Whatever`][] and [`whatever!`][crate::whatever!] for detailed
83/// usage instructions.
84#[derive(Debug, Snafu)]
85#[snafu(crate_root(crate))]
86#[snafu(whatever)]
87#[snafu(display("{message}"))]
88pub struct WhateverLocal {
89    #[snafu(source(from(Box<dyn crate::Error>, Some)))]
90    source: Option<Box<dyn crate::Error>>,
91    message: String,
92    backtrace: Backtrace,
93}
94
95impl WhateverLocal {
96    /// Gets the backtrace from the deepest [`Whatever`][] or
97    /// [`WhateverLocal`][] error. If none of the underlying errors
98    /// are one of these types, returns the backtrace from when this
99    /// instance was created.
100    pub fn backtrace(&self) -> &Backtrace {
101        known_whatevers_backtrace(self).unwrap_or(&self.backtrace)
102    }
103}
104
105fn known_whatevers_backtrace<'a>(
106    root: &'a (dyn crate::Error + 'static),
107) -> Option<&'a crate::Backtrace> {
108    ChainCompat::new(root)
109        .skip(1)
110        .filter_map(|e| {
111            if let Some(e) = e.downcast_ref::<Whatever>() {
112                Some(&e.backtrace)
113            } else if let Some(e) = e.downcast_ref::<WhateverLocal>() {
114                Some(&e.backtrace)
115            } else {
116                None
117            }
118        })
119        .last()
120}