1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/// Defines an error type with a failure context and a kind.
///
/// The kind enum needs to be defined explicitly, and has to implement `Fail` already. This macro
/// then defines an error type that wraps the kind in a `failure::Context` which makes it carry a
/// backtrace and allows nesting errors, and also defines the following methods on the error type:
///
///  - `kind()`: Returns a reference to the error kind.
///  - `cause()`: Returns the causing error, if any.
///  - `backtrace()`: Returns the backtrace of this error (or the cause), if
///    `RUST_BACKTRACE` was set.
///
/// In addition to this, the following conversions are defined for the error type:
///  - `From<ErrorKind>`
///  - `From<Context<ErrorKind>>`
///
/// ## Example
///
/// ```rust
/// use failure::Fail;
/// # use symbolic_common::derive_failure;
/// #[derive(Debug, Fail)]
/// enum MyErrorKind {
///     #[fail(display = "some")] Something,
///     #[fail(display = "else")] Else,
/// }
///
/// derive_failure!(MyError, MyErrorKind);
///
/// fn something() -> Result<(), MyError> {
///     Err(MyErrorKind::Something.into())
/// }
/// ```
#[macro_export]
macro_rules! derive_failure {
    ($error:ident, $kind:ident $(, $meta:meta)* $(,)?) => {
        $(#[$meta])*
        #[derive(Debug)]
        pub struct $error {
            inner: ::failure::Context<$kind>,
        }

        impl ::failure::Fail for $error {
            fn cause(&self) -> Option<&dyn ::failure::Fail> {
                self.inner.cause()
            }

            fn backtrace(&self) -> Option<&::failure::Backtrace> {
                self.inner.backtrace()
            }
        }

        impl ::std::fmt::Display for $error {
            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
                self.inner.fmt(f)
            }
        }

        impl $error {
            /// Returns the error kind of this error.
            pub fn kind(&self) -> &$kind {
                &self.inner.get_context()
            }
        }

        impl From<$kind> for $error {
            fn from(kind: $kind) -> Self {
                $error {
                    inner: ::failure::Context::new(kind),
                }
            }
        }

        impl From<::failure::Context<$kind>> for $error {
            fn from(inner: ::failure::Context<$kind>) -> Self {
                $error { inner }
            }
        }
    };
}