devela/code/util/
enumset.rs

1// devela::code::util::enumset
2//
3//! An enum with an associated bitfield.
4//
5
6/// Defines an enum and an associated type set of its variants.
7///
8/// It uses the [`bitfield!`][crate::data::bitfield] macro to create the associated set.
9///
10/// You have to give unique names both to the enum and to the associated set.
11///
12/// # Features
13/// This macro depends on enabling any of the `_bit` features. E.g. `_bit_u8`.
14///
15/// # Examples
16/// See also the [enumset][crate::_info::examples::enumset] example.
17///
18/// ```
19/// # use devela::enumset;
20/// enumset! {
21///     pub enum MyEnum(pub MyEnumSet: u8) {
22///         Variant1,
23///         Variant2(bool),
24///         Variant3{a: u8, b: u16},
25///     }
26/// }
27/// assert_eq![3, MyEnum::ENUM_VARIANTS];
28/// let mut eset = MyEnumSet::default();
29/// assert![eset.is_empty()];
30/// eset.mut_set_field_variant1();
31/// assert![eset.is_field_variant1()];
32/// ```
33#[doc(hidden)]
34#[macro_export]
35macro_rules! _enumset {
36    (
37        // $enum_attr: the attributes of the enum.
38        // $enum_vis:  the visibility of the enum.
39        // $enum_name: the name of the new enum.
40        // $set_attr:  the attributes of the set.
41        // $set_vis:   the visibility of the set.
42        // $set_name:  the name of the associated set.
43        // $set_ty:    the inner integer primitive type for the bitfield (u8, i32, …).
44        $( #[$enum_attr:meta] )*
45        $enum_vis:vis enum $enum_name:ident
46            $( < $($gen:tt),* $(,)? > )? // optional generics and lifetimes
47            // attributes, visibility, name and inner type of the set, between ():
48            ( $( #[$set_attr:meta] )* $set_vis:vis $set_name:ident: $set_ty:ty )
49            $([where $($where:tt)+ $(,)? ] $(,)? )? // optional where clauses, between []
50        {
51            $(
52                $( #[$variant_attr:meta] )*
53                $variant_name:ident
54                $(( $($tuple_type:ty),* $(,)? ))?
55                $({ $( $( #[$field_attr:meta] )* $field_name:ident : $field_type:ty),* $(,)? })?
56                $(= $discriminant:expr)?
57                $(,)?
58            )*
59        }
60    ) => { $crate::paste! {
61        /* define enum */
62
63        $( #[$enum_attr] )*
64        // #[doc = "\n\nSee also the associated type set of variants [`" $set_name "`]."]
65        $enum_vis enum $enum_name $( < $($gen),* > )? $(where $($where)+)? {
66            $(
67                $( #[$variant_attr] )*
68                $variant_name
69                $(( $($tuple_type),* ))?
70                $({ $( $( #[$field_attr] )* $field_name : $field_type),* })?
71                $(= $discriminant)?
72            ),*
73        }
74
75        /* define the associated bitfield */
76
77        #[allow(non_snake_case)]
78        mod [<_$enum_name _private>] {
79            pub(super) const ENUM_VARIANTS: usize = $crate::ident_total!($($variant_name)*);
80            $crate::ident_const_index!(pub(super), ENUM_VARIANTS; $($variant_name)*);
81        }
82
83        /// # `enumset` methods
84        #[allow(dead_code)]
85        impl $( < $($gen),* > )? $enum_name $( < $($gen),* > )? $( where $($where)* )? {
86            /// Returns the total number of variants.
87            $set_vis const ENUM_VARIANTS: usize = [<_$enum_name _private>]::ENUM_VARIANTS;
88
89            /// Returns the total number of variants.
90            $set_vis const fn enum_variants(&self) -> usize { Self::ENUM_VARIANTS }
91
92            /// Returns the associated empty set.
93            $set_vis const fn new_empty_set() -> $set_name {
94                $set_name::without_fields()
95            }
96            /// Returns the associated full set.
97            $set_vis const fn new_full_set() -> $set_name {
98                $set_name::with_all_fields()
99            }
100        }
101
102        $crate::data::bitfield! { // NOTE: need the long path
103            $( #[$set_attr] )*
104            // #[doc = "Represents a set of [`" $enum_name "`] variants."]
105            $set_vis struct $set_name($set_ty) {
106                $(
107                    #[doc = "The bit index that corresponds to `" $enum_name "::`[`"
108                        $variant_name "`][" $enum_name "::" $variant_name "]."]
109
110                    #[allow(non_upper_case_globals)]
111                    $variant_name: [<_$enum_name _private>]::$variant_name as u32;
112                )*
113            }
114        }
115    }};
116}
117#[doc(inline)]
118#[cfg_attr(feature = "nightly_doc", doc(cfg(_bit_·)))]
119pub use _enumset as enumset;