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            + for<'a> $crate::FromBytes<'a>
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<'lt> $crate::FromBytes<'lt> for $wrapper_type {
136            fn from_bytes(buffer: &mut std::io::Cursor<&'lt [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<$to_from_ty> for $wrapper_type {
165            fn from(v: $to_from_ty) -> Self {
166                $(
167                    let var = $const_enum::from(v);
168                    if !var.is_unrecognized() {
169                        return $wrapper_type::$const_enum(var);
170                    }
171                )*
172                $wrapper_type::UnrecognizedConst(v)
173            }
174        }
175    };
176}
177
178/// Implement a container for bit flag enums where the set of flags
179/// will be condensed into a single value.
180///
181/// # Usage
182///
183/// ```
184/// use neli::neli_enum;
185///
186/// #[neli_enum(serialized_type = "u16")]
187/// pub enum MyFlags {
188///     ThisFlag = 1,
189///     ThatFlag = 2,
190/// }
191///
192/// neli::impl_flags!(
193///     MyFlagSet,
194///     MyFlags,
195///     u16
196/// );
197/// ```
198///
199/// This creates a struct called `MyFlagSet` that has the following
200/// autogenerated methods:
201/// * `fn empty() -> Self`
202/// * `fn new(flags: &[MyFlags]) -> Self`
203/// * `fn set(&mut self, flag: MyFlags)`
204/// * `fn unset(&mut self, flag: &MyFlags)`
205/// * `fn contains(&self, flag: &MyFlags) -> bool`
206/// * `fn from_bitmask(bitmask: &IntType) -> Self`
207///
208/// When the following example is serialized, all flags contained in
209/// the set at the time of serialization will be converted into
210/// `u16`s and bitwise or-ed.
211#[macro_export]
212macro_rules! impl_flags {
213    ($(#[$outer:meta])* $vis:vis $name:ident, $type:ty, $bin_type:ty $(,)?) => {
214        #[derive(Debug, PartialEq, Eq, neli_proc_macros::Size, neli_proc_macros::FromBytes, neli_proc_macros::ToBytes)]
215        $(#[$outer])*
216        $vis struct $name($crate::types::FlagBuffer::<$bin_type, $type>);
217
218        impl $name {
219            /// Create an empty flag container
220            pub fn empty() -> Self {
221                $name($crate::types::FlagBuffer::<$bin_type, $type>::empty())
222            }
223
224            /// Create a flag container from a bitmask.
225            pub fn from_bitmask(bitmask: $bin_type) -> Self {
226                $name($crate::types::FlagBuffer::<$bin_type, $type>::from_bitmask(bitmask))
227            }
228
229            /// Initialize a flag container with the given flags
230            pub fn new(flags: &[$type]) -> Self {
231                $name(<$crate::types::FlagBuffer::<$bin_type, $type> as From<&[$type]>>::from(flags))
232            }
233
234            /// Add a flag
235            pub fn set(&mut self, flag: &$type) {
236                $crate::types::FlagBuffer::<$bin_type, $type>::set(&mut self.0, flag)
237            }
238
239            /// Add a flag
240            pub fn unset(&mut self, flag: &$type) {
241                $crate::types::FlagBuffer::<$bin_type, $type>::unset(&mut self.0, &flag)
242            }
243
244            /// Contains a flag
245            pub fn contains(&self, flag: &$type) -> bool {
246                $crate::types::FlagBuffer::<$bin_type, $type>::contains(&self.0, &flag)
247            }
248        }
249
250        impl $crate::TypeSize for $name {
251            fn type_size() -> usize {
252                <$crate::types::FlagBuffer::<$bin_type, $type> as $crate::TypeSize>::type_size()
253            }
254        }
255    };
256}