error_support/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5// kinda abusing features here, but features "override" builtin support.
6pub use tracing_support::{debug, error, info, trace, warn, Level};
7
8#[cfg(feature = "testing")]
9pub use tracing_support::{init_for_tests, init_for_tests_with_level};
10
11mod macros;
12
13#[cfg(feature = "backtrace")]
14/// Re-export of the `backtrace` crate for use in macros and
15/// to ensure the needed version is kept in sync in dependents.
16pub use backtrace;
17
18#[cfg(not(feature = "backtrace"))]
19/// A compatibility shim for `backtrace`.
20pub mod backtrace {
21    use std::fmt;
22
23    pub struct Backtrace;
24
25    impl Backtrace {
26        pub fn new() -> Self {
27            Backtrace
28        }
29    }
30
31    impl Default for Backtrace {
32        fn default() -> Self {
33            Self::new()
34        }
35    }
36
37    impl fmt::Debug for Backtrace {
38        #[cold]
39        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40            write!(f, "Not available")
41        }
42    }
43}
44
45mod redact;
46pub use redact::*;
47
48mod error_tracing;
49pub use error_tracing::{report_breadcrumb, report_error_to_app};
50
51pub use error_support_macros::handle_error;
52
53mod handling;
54pub use handling::{convert_log_report_error, ErrorHandling, ErrorReporting, GetErrorHandling};
55
56/// XXX - Most of this is now considered deprecated - only FxA uses it, and
57/// should be replaced with the facilities in the `handling` module.
58///
59/// Define a wrapper around the the provided ErrorKind type.
60/// See also `define_error` which is more likely to be what you want.
61#[macro_export]
62macro_rules! define_error_wrapper {
63    ($Kind:ty) => {
64        pub type Result<T, E = Error> = std::result::Result<T, E>;
65        struct ErrorData {
66            kind: $Kind,
67            backtrace: Option<std::sync::Mutex<$crate::backtrace::Backtrace>>,
68        }
69
70        impl ErrorData {
71            #[cold]
72            fn new(kind: $Kind) -> Self {
73                ErrorData {
74                    kind,
75                    #[cfg(feature = "backtrace")]
76                    backtrace: Some(std::sync::Mutex::new(
77                        $crate::backtrace::Backtrace::new_unresolved(),
78                    )),
79                    #[cfg(not(feature = "backtrace"))]
80                    backtrace: None,
81                }
82            }
83
84            #[cfg(feature = "backtrace")]
85            #[cold]
86            fn get_backtrace(&self) -> Option<&std::sync::Mutex<$crate::backtrace::Backtrace>> {
87                self.backtrace.as_ref().map(|mutex| {
88                    mutex.lock().unwrap().resolve();
89                    mutex
90                })
91            }
92
93            #[cfg(not(feature = "backtrace"))]
94            #[cold]
95            fn get_backtrace(&self) -> Option<&std::sync::Mutex<$crate::backtrace::Backtrace>> {
96                None
97            }
98        }
99
100        impl std::fmt::Debug for ErrorData {
101            #[cfg(feature = "backtrace")]
102            #[cold]
103            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
104                let mut bt = self.backtrace.as_ref().unwrap().lock().unwrap();
105                bt.resolve();
106                write!(f, "{:?}\n\n{}", bt, self.kind)
107            }
108
109            #[cfg(not(feature = "backtrace"))]
110            #[cold]
111            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112                write!(f, "{}", self.kind)
113            }
114        }
115
116        #[derive(Debug, thiserror::Error)]
117        pub struct Error(Box<ErrorData>);
118        impl Error {
119            #[cold]
120            pub fn kind(&self) -> &$Kind {
121                &self.0.kind
122            }
123
124            #[cold]
125            pub fn backtrace(&self) -> Option<&std::sync::Mutex<$crate::backtrace::Backtrace>> {
126                self.0.get_backtrace()
127            }
128        }
129
130        impl std::fmt::Display for Error {
131            #[cold]
132            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133                std::fmt::Display::fmt(self.kind(), f)
134            }
135        }
136
137        impl From<$Kind> for Error {
138            // Cold to optimize in favor of non-error cases.
139            #[cold]
140            fn from(ctx: $Kind) -> Error {
141                Error(Box::new(ErrorData::new(ctx)))
142            }
143        }
144    };
145}
146
147/// Define a set of conversions from external error types into the provided
148/// error kind. Use `define_error` to do this at the same time as
149/// `define_error_wrapper`.
150#[macro_export]
151macro_rules! define_error_conversions {
152    ($Kind:ident { $(($variant:ident, $type:ty)),* $(,)? }) => ($(
153        impl From<$type> for Error {
154            // Cold to optimize in favor of non-error cases.
155            #[cold]
156            fn from(e: $type) -> Self {
157                Error::from($Kind::$variant(e))
158            }
159        }
160    )*);
161}
162
163/// All the error boilerplate (okay, with a couple exceptions in some cases) in
164/// one place.
165#[macro_export]
166macro_rules! define_error {
167    ($Kind:ident { $(($variant:ident, $type:ty)),* $(,)? }) => {
168        $crate::define_error_wrapper!($Kind);
169        $crate::define_error_conversions! {
170            $Kind {
171                $(($variant, $type)),*
172            }
173        }
174    };
175}
176
177uniffi::setup_scaffolding!("errorsupport");