relay_common/
macros.rs

1/// Helper macro to implement string based serialization.
2///
3/// If a type implements `Display` then this automatically
4/// implements a serializer for that type that dispatches
5/// appropriately.
6#[macro_export]
7macro_rules! impl_str_ser {
8    ($type:ty) => {
9        impl ::serde::ser::Serialize for $type {
10            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11            where
12                S: ::serde::ser::Serializer,
13            {
14                serializer.collect_str(self)
15            }
16        }
17    };
18}
19
20/// Helper macro to implement string based deserialization.
21///
22/// If a type implements `FromStr` then this automatically
23/// implements a deserializer for that type that dispatches
24/// appropriately.
25#[macro_export]
26macro_rules! impl_str_de {
27    ($type:ty, $expectation:expr) => {
28        impl<'de> ::serde::de::Deserialize<'de> for $type {
29            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30            where
31                D: ::serde::de::Deserializer<'de>,
32            {
33                struct V;
34
35                impl<'de> ::serde::de::Visitor<'de> for V {
36                    type Value = $type;
37
38                    fn expecting(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> fmt::Result {
39                        formatter.write_str($expectation)
40                    }
41
42                    fn visit_str<E>(self, value: &str) -> Result<$type, E>
43                    where
44                        E: ::serde::de::Error,
45                    {
46                        value.parse().map_err(|_| {
47                            ::serde::de::Error::invalid_value(
48                                ::serde::de::Unexpected::Str(value),
49                                &self,
50                            )
51                        })
52                    }
53                }
54
55                deserializer.deserialize_str(V)
56            }
57        }
58    };
59}
60
61/// Helper macro to implement string based serialization and deserialization.
62///
63/// If a type implements `FromStr` and `Display` then this automatically
64/// implements a serializer/deserializer for that type that dispatches
65/// appropriately.
66#[macro_export]
67macro_rules! impl_str_serde {
68    ($type:ty, $expectation:expr) => {
69        $crate::impl_str_ser!($type);
70        $crate::impl_str_de!($type, $expectation);
71    };
72}
73
74/// Implements FromStr and Display on a flat/C-like enum such that strings roundtrip correctly and
75/// all variants can be FromStr'd.
76///
77///
78/// Usage:
79///
80/// ```
81/// use relay_common::derive_fromstr_and_display;
82///
83/// // derive fail for this or whatever you need. The type must be ZST though.
84/// struct ValueTypeError;
85///
86/// enum ValueType {
87///     Foo,
88///     Bar,
89/// }
90///
91/// derive_fromstr_and_display!(ValueType, ValueTypeError, {
92///     ValueType::Foo => "foo" | "foo2",  // fromstr will recognize foo/foo2, display will use foo.
93///     ValueType::Bar => "bar",
94/// });
95/// ```
96#[macro_export]
97macro_rules! derive_fromstr_and_display {
98    ($type:ty, $error_type:tt, { $($variant:path => $($name:literal)|*),+ $(,)? }) => {
99        impl $type {
100            /// Returns the string representation of this enum variant.
101            pub fn as_str(&self) -> &'static str {
102                match *self {
103                    $(
104                        $variant => ($($name, )*).0
105                    ),*
106                }
107            }
108        }
109
110        impl ::std::fmt::Display for $type {
111            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
112                write!(f, "{}", self.as_str())
113            }
114        }
115
116        impl ::std::str::FromStr for $type {
117            type Err = $error_type;
118
119            fn from_str(s: &str) -> Result<Self, Self::Err> {
120                Ok(match s {
121                    $(
122                        $($name)|* => $variant,
123                    )*
124                    _ => return Err($error_type)
125                })
126            }
127        }
128    }
129}