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;