neli/consts/
macros.rs

1/// For generating a marker trait that flags a new enum as usable in a
2/// field that accepts a generic type. This way, the type parameter
3/// can be constrained by a trait bound to only accept enums that
4/// implement the marker trait.
5///
6/// # Usage
7///
8/// ```
9/// use neli::neli_enum;
10///
11/// /// Define an enum
12/// #[neli_enum(serialized_type = "u16")]
13/// pub enum MyFamilyEnum {
14///     One = 1,
15///     Two = 2,
16///     Three = 3
17/// }
18///
19/// /// Define another enum
20/// #[neli_enum(serialized_type = "u16")]
21/// pub enum MyOtherFamilyEnum {
22///     Four = 4,
23///     Five = 5,
24///     Six = 6,
25/// }
26///
27/// /// Define a marker trait and implement it for MyFamilyEnum and
28/// /// MyOtherFamilyEnum.
29/// neli::impl_trait!(
30///     MyMarkerTrait,
31///     u16,
32///     MyFamilyWrapperType,
33///     MyFamilyEnum,
34///     MyOtherFamilyEnum
35/// );
36/// ```
37///
38/// The result of the example above will be:
39/// * One enum called `MyFamilyEnum`.
40/// * Another called `MyOtherFamilyEnum`.
41/// * A marker trait called `MyMarkerTrait`. This can be used to
42///   constain type parameter so that only `MyFamilyEnum` and
43///   `MyOtherFamilyEnum` variants can be passed in as a value.
44/// * A wrapper enum called `MyFamilyWrapperType`. The definition is
45///   as follows:
46/// ```
47/// enum MyFamilyEnum {
48///     One,
49///     Two,
50///     Three,
51/// }
52///
53/// enum MyOtherFamilyEnum {
54///     Four,
55///     Five,
56///     Six,
57/// }
58///
59/// enum MyFamilyWrapperType {
60///     MyFamilyEnum(MyFamilyEnum),
61///     MyOtherFamilyEnum(MyOtherFamilyEnum),
62/// }
63/// ```
64/// If you are unsure of which type will be passed back, the wrapper
65/// type can be used to automatically determine this for you when
66/// deserializing and accept all values defined across both enums.
67#[macro_export]
68macro_rules! impl_trait {
69    (
70        $(#[$outer:meta])*
71        $vis_trait:vis $trait_name:ident,
72        $to_from_ty:ty,
73        $(
74            #[$wrapper_outer:meta]
75        )*
76        $vis_enum:vis $wrapper_type:ident,
77        $( $const_enum:ident ),+
78        $(,)?
79    ) => {
80        $(#[$outer])*
81        $vis_trait trait $trait_name: PartialEq
82            + Clone
83            + From<$to_from_ty>
84            + Into<$to_from_ty>
85            + Copy
86            + $crate::Size
87            + $crate::TypeSize
88            + $crate::FromBytes
89            + $crate::ToBytes
90            + std::fmt::Debug
91        {}
92
93        impl $trait_name for $to_from_ty {}
94
95        $(
96            impl $trait_name for $const_enum {}
97        )+
98
99        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
100        $(
101            #[$wrapper_outer]
102        )*
103        $vis_enum enum $wrapper_type {
104            $(
105                #[allow(missing_docs)]
106                $const_enum($const_enum),
107            )+
108            /// Constant could not be parsed into a type
109            UnrecognizedConst($to_from_ty),
110        }
111
112        impl $crate::Size for $wrapper_type {
113            fn unpadded_size(&self) -> usize {
114                std::mem::size_of::<$to_from_ty>()
115            }
116        }
117
118        impl $crate::TypeSize for $wrapper_type {
119            fn type_size() -> usize {
120                std::mem::size_of::<$to_from_ty>()
121            }
122        }
123
124        impl $crate::ToBytes for $wrapper_type {
125            fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), $crate::err::SerError> {
126                Ok(match self {
127                    $(
128                        $wrapper_type::$const_enum(val) => val.to_bytes(buffer)?,
129                    )*
130                    $wrapper_type::UnrecognizedConst(val) => val.to_bytes(buffer)?,
131                })
132            }
133        }
134
135        impl $crate::FromBytes for $wrapper_type {
136            fn from_bytes(buffer: &mut std::io::Cursor<impl AsRef<[u8]>>) -> Result<Self, $crate::err::DeError> {
137                Ok($wrapper_type::from(<$to_from_ty as $crate::FromBytes>::from_bytes(
138                    buffer
139                )?))
140            }
141        }
142
143        impl $trait_name for $wrapper_type {}
144
145        $(
146            impl From<$const_enum> for $wrapper_type {
147                fn from(e: $const_enum) -> Self {
148                    $wrapper_type::$const_enum(e)
149                }
150            }
151        )+
152
153        impl From<$wrapper_type> for $to_from_ty {
154            fn from(w: $wrapper_type) -> Self {
155                match w {
156                    $(
157                        $wrapper_type::$const_enum(inner) => inner.into(),
158                    )+
159                    $wrapper_type::UnrecognizedConst(v) => v,
160                }
161            }
162        }
163
164        impl From<&$wrapper_type> for $to_from_ty {
165            fn from(w: &$wrapper_type) -> Self {
166                match w {
167                    $(
168                        $wrapper_type::$const_enum(inner) => inner.into(),
169                    )+
170                    $wrapper_type::UnrecognizedConst(v) => *v,
171                }
172            }
173        }
174
175        impl From<$to_from_ty> for $wrapper_type {
176            fn from(v: $to_from_ty) -> Self {
177                $(
178                    let var = $const_enum::from(v);
179                    if !var.is_unrecognized() {
180                        return $wrapper_type::$const_enum(var);
181                    }
182                )*
183                $wrapper_type::UnrecognizedConst(v)
184            }
185        }
186    };
187}
188
189/// Implement a container for bit flag enums using the [`bitflags`][bitflags] crate.
190///
191/// # Usage
192///
193/// ```
194/// use neli::neli_enum;
195///
196/// neli::impl_flags!(
197///     pub MyFlags: u16 {
198///         ThisFlag = 1,
199///         ThatFlag = 2,
200///     }
201/// );
202/// ```
203///
204/// See [here][bitflags] for the methods that are autogenerated by `bitflags` on
205/// the struct.
206#[macro_export]
207macro_rules! impl_flags {
208    ($(#[$outer:meta])* $vis:vis $name:ident: $bin_type:ty {
209        $($(#[$inner:ident $($tt:tt)*])* $var:ident = $const:expr),*
210        $(,)?
211    }) => {
212        #[derive(Debug, Clone, Copy, Eq, PartialEq, neli_proc_macros::Size, neli_proc_macros::FromBytes, neli_proc_macros::ToBytes)]
213        $(#[$outer])*
214        $vis struct $name($bin_type);
215
216        bitflags::bitflags! {
217            impl $name: $bin_type {
218                $(
219                    $(#[$inner $($tt)*])*
220                    #[allow(missing_docs)]
221                    const $var = $const;
222                )*
223            }
224        }
225
226        impl From<$bin_type> for $name {
227            fn from(bin: $bin_type) ->  Self {
228                $name::from_bits_truncate(bin)
229            }
230        }
231
232        impl From<$name> for $bin_type {
233            fn from(ty: $name) ->  Self {
234                ty.bits()
235            }
236        }
237
238        impl $crate::TypeSize for $name {
239            fn type_size() -> usize {
240                <$bin_type as $crate::TypeSize>::type_size()
241            }
242        }
243    };
244}