ex3_node_error/
util.rs

1//! Error-related macros
2
3/// Compare two errors.
4///
5/// NOTE: Used for testing only!
6/// Refer to: https://github.com/nervosnetwork/ckb/blob/develop/error/src/util.rs
7#[doc(hidden)]
8#[macro_export]
9macro_rules! assert_error_eq {
10    ($left:expr, $right:expr) => {
11        assert_eq!(
12            Into::<$crate::Error>::into($left).to_string(),
13            Into::<$crate::Error>::into($right).to_string(),
14        );
15    };
16    ($left:expr, $right:expr,) => {
17        $crate::assert_error_eq!($left, $right);
18    };
19    ($left:expr, $right:expr, $($arg:tt)+) => {
20        assert_eq!(
21            Into::<$crate::Error>::into($left).to_string(),
22            Into::<$crate::Error>::into($right).to_string(),
23            $($arg)+
24        );
25    }
26}
27
28/// A macro to implement conversion from source type to target type with an implicit error kind.
29///
30/// ## Examples
31///
32/// ```text
33/// impl_error_conversion_with_kind!(SourceType, error_kind, TargetType)
34/// ```
35///
36/// the expanded code:
37///
38/// ```text
39/// impl From<SourceType> for TargetType {
40///     fn from(source: SourceType) -> TargetType {
41///         TargetType {
42///             kind: error_kind,
43///             inner: source.into(),
44///         }
45///     }
46/// }
47/// ```
48#[doc(hidden)]
49#[macro_export]
50macro_rules! impl_error_conversion_with_kind {
51    ($source:ty, $kind:expr, $target:ty) => {
52        impl ::std::convert::From<$source> for $target {
53            fn from(error: $source) -> Self {
54                $kind.because(error)
55            }
56        }
57    };
58}
59
60/// A macro to implement conversion from source type to target type based on an implicit middle adaptor.
61///
62/// ## Examples
63///
64/// ```text
65/// impl_error_conversion_with_adaptor!(SourceType, AdaptorType, TargetType)
66/// ```
67///
68/// the expanded code:
69///
70/// ```text
71/// impl From<SourceType> for TargetType {
72///     fn from(source: SourceType) -> TargetType {
73///         let adaptor: AdaptorType = source.into();
74///         let target: TargetType = adaptor.into();
75///         target
76///     }
77/// }
78/// ```
79#[doc(hidden)]
80#[macro_export]
81macro_rules! impl_error_conversion_with_adaptor {
82    ($source:ty, $adaptor:ty, $target:ty) => {
83        impl ::std::convert::From<$source> for $target {
84            fn from(error: $source) -> Self {
85                ::std::convert::Into::<$adaptor>::into(error).into()
86            }
87        }
88    };
89}
90
91#[doc(hidden)]
92#[macro_export]
93macro_rules! def_error_base_on_kind {
94    ($error:ident, $error_kind:ty, $comment_error:expr, $comment_because:expr, $comment_simple:expr) => {
95        #[doc = $comment_error]
96        #[derive(Error, Debug, Clone)]
97        pub struct $error {
98            kind: $error_kind,
99            inner: $crate::AnyError,
100        }
101
102        impl ::std::fmt::Display for $error {
103            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
104                if let Some(err) = self.cause() {
105                    if f.alternate() {
106                        write!(f, "{:?}: {:?}", self.kind(), err)
107                    } else {
108                        write!(f, "{:?}({:?})", self.kind(), err)
109                    }
110                } else {
111                    write!(f, "{:?}", self.kind())
112                }
113            }
114        }
115
116        impl ::std::convert::From<$error_kind> for $error {
117            fn from(kind: $error_kind) -> Self {
118                kind.because($crate::SilentError)
119            }
120        }
121
122        impl $error_kind {
123            #[doc = $comment_because]
124            pub fn because<E>(self, reason: E) -> $error
125            where
126                E: ::std::error::Error + Send + Sync + 'static,
127            {
128                $error {
129                    kind: self,
130                    inner: reason.into(),
131                }
132            }
133
134            #[doc = $comment_simple]
135            pub fn other<T>(self, reason: T) -> $error
136            where
137                T: ::std::fmt::Display,
138            {
139                $error {
140                    kind: self,
141                    inner: $crate::OtherError::new(reason.to_string()).into(),
142                }
143            }
144        }
145
146        impl $error {
147            /// Returns the general category of this error.
148            pub fn kind(&self) -> $error_kind {
149                self.kind
150            }
151
152            /// Downcast this error object by reference.
153            pub fn downcast_ref<E>(&self) -> Option<&E>
154            where
155                E: ::std::fmt::Display + ::std::fmt::Debug + Send + Sync + 'static,
156            {
157                self.inner.downcast_ref::<E>()
158            }
159
160            /// The lowest level cause of this error — this error's cause's cause's cause etc.
161            pub fn root_cause(&self) -> &(dyn ::std::error::Error + 'static) {
162                self.inner.root_cause()
163            }
164
165            /// The lower-level source of this error, if any.
166            pub fn cause(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
167                self.inner.chain().next()
168            }
169        }
170    };
171    ($error:ident, $error_kind:ty, $comment_error:expr) => {
172        def_error_base_on_kind!(
173            $error,
174            $error_kind,
175            $comment_error,
176            concat!(
177                "Creates `",
178                stringify!($error),
179                "` base on `",
180                stringify!($error_kind),
181                "` with an error as the reason."
182            ),
183            concat!(
184                "Creates `",
185                stringify!($error),
186                "` base on `",
187                stringify!($error_kind),
188                "` with a simple string as the reason."
189            )
190        );
191    };
192    ($error:ident, $error_kind:ty) => {
193        def_error_base_on_kind!($error, $error_kind, "/// TODO(doc): @witter");
194    };
195}