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}