wrapping_error/
lib.rs

1//! An anti-boilerplate crate for errors that wrap errors.
2//!
3//! This crate only exports one item: the [`wrapping_error`] macro.
4//! See that for documentation.
5
6/// Creates an error that wraps other errors.
7///
8/// ## Example
9///
10/// ```
11/// use std::{env::VarError, io};
12///
13/// use wrapping_error::wrapping_error;
14///
15/// wrapping_error!(pub(crate) AppDataError {
16///     Var(VarError) => "could not get $HOME environment variable",
17///     Io(io::Error) => "failed to read/write app data",
18///     Postcard(postcard::Error) => "failed to serialize/deserialize app data",
19/// });
20/// ```
21#[macro_export]
22macro_rules! wrapping_error {
23    ($vis:vis $enum:ident { $($variant:ident($error:path)$( => $message:literal)?),+$(,)? }) => {
24        use std::{fmt, error};
25
26        #[derive(Debug)]
27        $vis enum $enum {
28            $($variant($error),)+
29        }
30
31        impl fmt::Display for $enum {
32            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33                match *self {
34                    // TODO: find a way to make $error optional and be able to tie (..) to whether it exists
35                    $($(Self::$variant(..) => write!(f, $message),)?)+
36                    ref err => err.fmt(f),
37                }
38            }
39        }
40
41        impl error::Error for $enum {
42            fn source(&self) -> Option<&(dyn error::Error + 'static)> {
43                match *self {
44                    ref err => Some(err),
45                }
46            }
47        }
48
49        $(
50            impl From<$error> for $enum {
51                fn from(err: $error) -> Self {
52                    Self::$variant(err)
53                }
54            }
55        )+
56    };
57}