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}