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