error_chain/
error_chain.rs

1#[doc(hidden)]
2#[macro_export]
3#[cfg(not(has_error_source))]
4macro_rules! impl_error_chain_cause_or_source {
5    (
6        types {
7            $error_kind_name:ident
8        }
9
10        foreign_links {
11            $( $foreign_link_variant:ident ( $foreign_link_error_path:path )
12               $( #[$meta_foreign_links:meta] )*; )*
13        }
14    ) => {
15        #[allow(unknown_lints, renamed_and_removed_lints)]
16        #[allow(unused_doc_comment, unused_doc_comments)]
17        fn cause(&self) -> Option<&::std::error::Error> {
18            match self.1.next_error {
19                Some(ref c) => Some(&**c),
20                None => {
21                    match self.0 {
22                        $(
23                            $(#[$meta_foreign_links])*
24                            $error_kind_name::$foreign_link_variant(ref foreign_err) => {
25                                foreign_err.cause()
26                            }
27                        ) *
28                        _ => None
29                    }
30                }
31            }
32        }
33    };
34}
35
36#[cfg(has_error_source)]
37#[doc(hidden)]
38#[macro_export]
39macro_rules! impl_error_chain_cause_or_source {
40    (
41        types {
42             $error_kind_name:ident
43        }
44
45        foreign_links {
46            $( $foreign_link_variant:ident ( $foreign_link_error_path:path )
47               $( #[$meta_foreign_links:meta] )*; )*
48        }
49    ) => {
50            #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)]
51            #[allow(unused_doc_comment, unused_doc_comments)]
52            fn source(&self) -> Option<&(std::error::Error + 'static)> {
53                match self.1.next_error {
54                    Some(ref c) => Some(&**c),
55                    None => {
56                        match self.0 {
57                        $(
58                            $(#[$meta_foreign_links])*
59                            $error_kind_name::$foreign_link_variant(ref foreign_err) => {
60                                foreign_err.source()
61                            }
62                        ) *
63                            _ => None
64                        }
65                    }
66                }
67            }
68        };
69}
70
71/// Conditional usage of deprecated Error::description
72#[doc(hidden)]
73#[cfg(has_error_description_deprecated)]
74#[macro_export(local_inner_macros)]
75macro_rules! call_to_deprecated_description {
76    ($e:ident) => {
77        ""
78    };
79}
80
81#[doc(hidden)]
82#[cfg(not(has_error_description_deprecated))]
83#[macro_export(local_inner_macros)]
84macro_rules! call_to_deprecated_description {
85    ($e:ident) => {
86        ::std::error::Error::description($e)
87    };
88}
89
90/// Prefer to use `error_chain` instead of this macro.
91#[doc(hidden)]
92#[macro_export(local_inner_macros)]
93macro_rules! impl_error_chain_processed {
94    // Default values for `types`.
95    (
96        types {}
97        $( $rest: tt )*
98    ) => {
99        impl_error_chain_processed! {
100            types {
101                Error, ErrorKind, ResultExt, Result;
102            }
103            $( $rest )*
104        }
105    };
106    // With `Result` wrapper.
107    (
108        types {
109            $error_name:ident, $error_kind_name:ident,
110            $result_ext_name:ident, $result_name:ident;
111        }
112        $( $rest: tt )*
113    ) => {
114        impl_error_chain_processed! {
115            types {
116                $error_name, $error_kind_name,
117                $result_ext_name;
118            }
119            $( $rest )*
120        }
121        /// Convenient wrapper around `std::Result`.
122        #[allow(unused)]
123        pub type $result_name<T> = ::std::result::Result<T, $error_name>;
124    };
125
126    // With `Msg` variant.
127    (
128        types {
129            $error_name:ident, $error_kind_name:ident, $($types:tt)*
130        }
131        links $links:tt
132        foreign_links $foreign_links:tt
133        errors { $($errors:tt)* }
134    ) => {
135        impl_error_chain_processed! {
136            types {
137                $error_name, $error_kind_name, $($types)*
138            }
139            skip_msg_variant
140            links $links
141            foreign_links $foreign_links
142            errors {
143                /// A convenient variant for String.
144                Msg(s: String) {
145                    description(&s)
146                    display("{}", s)
147                }
148
149                $($errors)*
150            }
151        }
152
153        impl<'a> From<&'a str> for $error_kind_name {
154            fn from(s: &'a str) -> Self {
155                $error_kind_name::Msg(s.into())
156            }
157        }
158
159        impl From<String> for $error_kind_name {
160            fn from(s: String) -> Self {
161                $error_kind_name::Msg(s)
162            }
163        }
164
165        impl<'a> From<&'a str> for $error_name {
166            fn from(s: &'a str) -> Self {
167                Self::from_kind(s.into())
168            }
169        }
170
171        impl From<String> for $error_name {
172            fn from(s: String) -> Self {
173                Self::from_kind(s.into())
174            }
175        }
176    };
177
178    // Without `Result` wrapper or `Msg` variant.
179    (
180        types {
181            $error_name:ident, $error_kind_name:ident,
182            $result_ext_name:ident;
183        }
184
185        skip_msg_variant
186
187        links {
188            $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path )
189               $( #[$meta_links:meta] )*; ) *
190        }
191
192        foreign_links {
193            $( $foreign_link_variant:ident ( $foreign_link_error_path:path )
194               $( #[$meta_foreign_links:meta] )*; )*
195        }
196
197        errors {
198            $( $error_chunks:tt ) *
199        }
200
201    ) => {
202        /// The Error type.
203        ///
204        /// This tuple struct is made of two elements:
205        ///
206        /// - an `ErrorKind` which is used to determine the type of the error.
207        /// - An internal `State`, not meant for direct use outside of `error_chain`
208        ///   internals, containing:
209        ///   - a backtrace, generated when the error is created.
210        ///   - an error chain, used for the implementation of `Error::cause()`.
211        #[derive(Debug)]
212        pub struct $error_name(
213            // The members must be `pub` for `links`.
214            /// The kind of the error.
215            pub $error_kind_name,
216            /// Contains the error chain and the backtrace.
217            #[doc(hidden)]
218            pub $crate::State,
219        );
220
221        impl $crate::ChainedError for $error_name {
222            type ErrorKind = $error_kind_name;
223
224            fn new(kind: $error_kind_name, state: $crate::State) -> $error_name {
225                $error_name(kind, state)
226            }
227
228            fn from_kind(kind: Self::ErrorKind) -> Self {
229                Self::from_kind(kind)
230            }
231
232            fn with_chain<E, K>(error: E, kind: K)
233                -> Self
234                where E: ::std::error::Error + Send + 'static,
235                      K: Into<Self::ErrorKind>
236            {
237                Self::with_chain(error, kind)
238            }
239
240            fn kind(&self) -> &Self::ErrorKind {
241                self.kind()
242            }
243
244            fn iter(&self) -> $crate::Iter {
245                $crate::Iter::new(Some(self))
246            }
247
248            fn chain_err<F, EK>(self, error: F) -> Self
249                where F: FnOnce() -> EK,
250                      EK: Into<$error_kind_name> {
251                self.chain_err(error)
252            }
253
254            fn backtrace(&self) -> Option<&$crate::Backtrace> {
255                self.backtrace()
256            }
257
258            impl_extract_backtrace!($error_name
259                                    $error_kind_name
260                                    $([$link_error_path, $(#[$meta_links])*])*);
261        }
262
263        #[allow(dead_code)]
264        impl $error_name {
265            /// Constructs an error from a kind, and generates a backtrace.
266            pub fn from_kind(kind: $error_kind_name) -> $error_name {
267                $error_name(
268                    kind,
269                    $crate::State::default(),
270                )
271            }
272
273            /// Constructs a chained error from another error and a kind, and generates a backtrace.
274            pub fn with_chain<E, K>(error: E, kind: K)
275                -> $error_name
276                where E: ::std::error::Error + Send + 'static,
277                      K: Into<$error_kind_name>
278            {
279                $error_name::with_boxed_chain(Box::new(error), kind)
280            }
281
282            /// Construct a chained error from another boxed error and a kind, and generates a backtrace
283            #[allow(unknown_lints, bare_trait_objects)]
284            pub fn with_boxed_chain<K>(error: Box<::std::error::Error + Send>, kind: K)
285                -> $error_name
286                where K: Into<$error_kind_name>
287            {
288                $error_name(
289                    kind.into(),
290                    $crate::State::new::<$error_name>(error, ),
291                )
292            }
293
294            /// Returns the kind of the error.
295            pub fn kind(&self) -> &$error_kind_name {
296                &self.0
297            }
298
299            /// Iterates over the error chain.
300            pub fn iter(&self) -> $crate::Iter {
301                $crate::ChainedError::iter(self)
302            }
303
304            /// Returns the backtrace associated with this error.
305            pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
306                self.1.backtrace()
307            }
308
309            /// Extends the error chain with a new entry.
310            pub fn chain_err<F, EK>(self, error: F) -> $error_name
311                where F: FnOnce() -> EK, EK: Into<$error_kind_name> {
312                $error_name::with_chain(self, Self::from_kind(error().into()))
313            }
314
315            /// A short description of the error.
316            /// This method is identical to [`Error::description()`](https://doc.rust-lang.org/nightly/std/error/trait.Error.html#tymethod.description)
317            pub fn description(&self) -> &str {
318                self.0.description()
319            }
320        }
321
322        impl ::std::error::Error for $error_name {
323            #[cfg(not(has_error_description_deprecated))]
324            fn description(&self) -> &str {
325                self.description()
326            }
327
328            impl_error_chain_cause_or_source!{
329                types {
330                    $error_kind_name
331                }
332                foreign_links {
333                    $( $foreign_link_variant ( $foreign_link_error_path )
334                    $( #[$meta_foreign_links] )*; )*
335                }
336            }
337        }
338
339        impl ::std::fmt::Display for $error_name {
340            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
341                ::std::fmt::Display::fmt(&self.0, f)
342            }
343        }
344
345        $(
346            $(#[$meta_links])*
347            impl From<$link_error_path> for $error_name {
348                fn from(e: $link_error_path) -> Self {
349                    $error_name(
350                        $error_kind_name::$link_variant(e.0),
351                        e.1,
352                    )
353                }
354            }
355        ) *
356
357        $(
358            $(#[$meta_foreign_links])*
359            impl From<$foreign_link_error_path> for $error_name {
360                fn from(e: $foreign_link_error_path) -> Self {
361                    $error_name::from_kind(
362                        $error_kind_name::$foreign_link_variant(e)
363                    )
364                }
365            }
366        ) *
367
368        impl From<$error_kind_name> for $error_name {
369            fn from(e: $error_kind_name) -> Self {
370                $error_name::from_kind(e)
371            }
372        }
373
374        // The ErrorKind type
375        // --------------
376
377        impl_error_chain_kind! {
378            /// The kind of an error.
379            #[derive(Debug)]
380            pub enum $error_kind_name {
381                $(
382                    $(#[$meta_links])*
383                    $link_variant(e: $link_kind_path) {
384                        description(e.description())
385                        display("{}", e)
386                    }
387                ) *
388
389                $(
390                    $(#[$meta_foreign_links])*
391                    $foreign_link_variant(err: $foreign_link_error_path) {
392                        description(call_to_deprecated_description!(err))
393                        display("{}", err)
394                    }
395                ) *
396
397                $($error_chunks)*
398            }
399        }
400
401        $(
402            $(#[$meta_links])*
403            impl From<$link_kind_path> for $error_kind_name {
404                fn from(e: $link_kind_path) -> Self {
405                    $error_kind_name::$link_variant(e)
406                }
407            }
408        ) *
409
410        impl From<$error_name> for $error_kind_name {
411            fn from(e: $error_name) -> Self {
412                e.0
413            }
414        }
415
416        // The ResultExt trait defines the `chain_err` method.
417
418        /// Additional methods for `Result`, for easy interaction with this crate.
419        pub trait $result_ext_name<T> {
420            /// If the `Result` is an `Err` then `chain_err` evaluates the closure,
421            /// which returns *some type that can be converted to `ErrorKind`*, boxes
422            /// the original error to store as the cause, then returns a new error
423            /// containing the original error.
424            fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
425                where F: FnOnce() -> EK,
426                      EK: Into<$error_kind_name>;
427        }
428
429        impl<T, E> $result_ext_name<T> for ::std::result::Result<T, E> where E: ::std::error::Error + Send + 'static {
430            fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
431                where F: FnOnce() -> EK,
432                      EK: Into<$error_kind_name> {
433                self.map_err(move |e| {
434                    let state = $crate::State::new::<$error_name>(Box::new(e), );
435                    $crate::ChainedError::new(callback().into(), state)
436                })
437            }
438        }
439
440        impl<T> $result_ext_name<T> for ::std::option::Option<T> {
441            fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
442                where F: FnOnce() -> EK,
443                      EK: Into<$error_kind_name> {
444                self.ok_or_else(move || {
445                    $crate::ChainedError::from_kind(callback().into())
446                })
447            }
448        }
449
450
451    };
452}
453
454/// Internal macro used for reordering of the fields.
455#[doc(hidden)]
456#[macro_export(local_inner_macros)]
457macro_rules! error_chain_processing {
458    (
459        ({}, $($rest:tt)*)
460        types $content:tt
461        $( $tail:tt )*
462    ) => {
463        error_chain_processing! {
464            ($content, $($rest)*)
465            $($tail)*
466        }
467    };
468
469    (
470        ($a:tt, {}, $($rest:tt)*)
471        links $content:tt
472        $( $tail:tt )*
473    ) => {
474        error_chain_processing! {
475            ($a, $content, $($rest)*)
476            $($tail)*
477        }
478    };
479
480    (
481        ($a:tt, $b:tt, {}, $($rest:tt)*)
482        foreign_links $content:tt
483        $( $tail:tt )*
484    ) => {
485        error_chain_processing! {
486            ($a, $b, $content, $($rest)*)
487            $($tail)*
488        }
489    };
490
491    (
492        ($a:tt, $b:tt, $c:tt, {}, $($rest:tt)*)
493        errors $content:tt
494        $( $tail:tt )*
495    ) => {
496        error_chain_processing! {
497            ($a, $b, $c, $content, $($rest)*)
498            $($tail)*
499        }
500    };
501
502    (
503        ($a:tt, $b:tt, $c:tt, $d:tt, {}, $($rest:tt)*)
504        skip_msg_variant
505        $( $tail:tt )*
506    ) => {
507        error_chain_processing! {
508            ($a, $b, $c, $d, {skip_msg_variant}, $($rest)*)
509            $($tail)*
510        }
511    };
512
513    ( ($a:tt, $b:tt, $c:tt, $d:tt, {$($e:tt)*},) ) => {
514        impl_error_chain_processed! {
515            types $a
516            $($e)*
517            links $b
518            foreign_links $c
519            errors $d
520        }
521    };
522}
523
524/// Macro for generating error types and traits. See crate level documentation for details.
525#[macro_export(local_inner_macros)]
526macro_rules! error_chain {
527    ( $($args:tt)* ) => {
528        error_chain_processing! {
529            ({}, {}, {}, {}, {},)
530            $($args)*
531        }
532    };
533}
534
535/// Macro used to manage the `backtrace` feature.
536///
537/// See
538/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3
539/// for more details.
540#[macro_export]
541#[doc(hidden)]
542macro_rules! impl_extract_backtrace {
543    ($error_name: ident
544     $error_kind_name: ident
545     $([$link_error_path: path, $(#[$meta_links: meta])*])*) => {
546        #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)]
547        #[allow(unused_doc_comment, unused_doc_comments)]
548        fn extract_backtrace(e: &(::std::error::Error + Send + 'static))
549            -> Option<$crate::InternalBacktrace> {
550            if let Some(e) = e.downcast_ref::<$error_name>() {
551                return Some(e.1.backtrace.clone());
552            }
553            $(
554                $( #[$meta_links] )*
555                {
556                    if let Some(e) = e.downcast_ref::<$link_error_path>() {
557                        return Some(e.1.backtrace.clone());
558                    }
559                }
560            ) *
561            None
562        }
563    }
564}