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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/// Derives From<T> implementations for enums whose variants can be expressed by such foreign
/// types.
///
/// For example, this:
/// ```
/// mod serde_json {
///     pub struct Error;
/// }
///
/// enum MyError {
///     SerializationError(serde_json::Error),
/// }
///
/// impl From<serde_json::Error> for MyError {
///     fn from(e: serde_json::Error) -> Self {
///         Self::SerializationError(e)
///     }
/// }
/// ```
/// is condensed using convertable-errors into this:
/// ```
/// # use convertable_errors::convertable_error;
///
/// mod serde_json {
///     # #[derive(PartialEq, Debug, Clone, Copy)]
///     pub struct Error;
/// }
///
/// convertable_error! {
///     # #[derive(PartialEq, Debug)]
///     enum MyError {
///         (SerializationError(serde_json::Error), [(serde_json::Error, Self::SerializationError)])
///     }
/// }
/// #
/// # let err = serde_json::Error;
/// # let my_err: MyError = err.into();
/// # assert_eq!(my_err, MyError::SerializationError(err));
/// ```
/// 
/// The syntax for defining a convertable enum with convertable-errors is as follows:
/// - Each variant of an enum must be wrapped in a tuple: `enum MyError { (Variant(ForeignType)), (Variant1) }`
/// - The first member of the tuple represents your variant. At the moment, only tuple variants and
/// unit variants are supported bc I'm a lazy fuck.
/// - The second member of the tuple (optional) represents the types that can be converted into
/// that variant: `enum MyError { (Variant(ForeignType), [ ... ]), (Variant1) }`
/// - The members of the convertable types array are each tuples representing the foreign type that
/// can be converted into your enum and the closure or variant to apply the foreign value to:
/// `[(ForeignType, Self::Variant)]`. Internally, this second member can be a closure `|x|
/// Self::Variant(x)`, a unit variant closure `|_| Self::Variant1`, or simply a variant identifier
/// where the value of the foreign type will be stored: `Self::Variant`. In practice, you can use
/// this macro for any enum, but I find it most useful for Error-like enums.
///
/// NOTE: This isn't a serious project, I might have made some mistakes, so feel free to open a PR
/// :) This is just a helpful snippet that I use and felt like sharing.
#[macro_export]
macro_rules! convertable_error {
    // A variant can have foreign types it can be derived from. Each of these may have a converter
    (
        $(#[$supermeta:meta])*
        $v:vis enum $name:ident {
            $(
                $(#[$meta:meta])*
                ($variant:ident$(($($field:ty),*))?$(, $equivalents:tt)?)
            ),+$(,)?
        }
    ) => {
        $(#[$supermeta])*
        $v enum $name {
            $($(#[$meta])*$variant$(($($field),*))?),+
        }

        // Build From<Foreign> impls for each of the variants
        $(convertable_error!(@from $name, ($variant$(, $equivalents)?));)+
    };

    (@from $name:ident, ($variant:ident, [$(($ftype:ty, $converter:expr)),+])) => {
        $(impl From<$ftype> for $name {
            fn from(v: $ftype) -> Self {
                $converter(v)
            }
        })+
    };
    // function f(v: ForeignType) -> Self, or simply be type-to-type
    (@from $name:ident, ($variant:ident, [$($ftype:ty),+])) => {
        $(impl From<$ftype> for $name {
            fn from(v: $ftype) -> Self {
                Self::$variant(v)
            }
        })+
    };
    // A variant of an error without any equivalent foreign types needs no further computation.
    (@from $name:ident, ($variant:ident)) => {};
}