#[macro_export]
macro_rules! bitenum {
(
$(#[$meta:meta])*
$vis:vis enum $enum_name:ident (u $bits:expr) {
$(
$variant:ident = $val:expr
),* $(,)?
}
) => {
$crate::bitenum! {
@impl_unsigned_enum
[ $($meta)* ]
$vis $enum_name $bits,
{ $($variant = $val),* }
}
};
(
$(#[$meta:meta])*
$vis:vis enum $enum_name:ident (i $bits:expr) {
$(
$variant:ident = $val:expr
),* $(,)?
}
) => {
$crate::bitenum! {
@impl_signed_enum
[ $($meta)* ]
$vis $enum_name $bits,
{ $($variant = $val),* }
}
};
(
$(#[$meta:meta])*
$vis:vis enum $enum_name:ident ($bits:expr) {
$(
$variant:ident = $val:expr
),* $(,)?
}
) => {
$crate::bitenum! {
@impl_unsigned_enum
[ $($meta)* ]
$vis $enum_name $bits,
{ $($variant = $val),* }
}
};
(
@impl_unsigned_enum
[ $($meta:meta)* ]
$vis:vis $enum_name:ident $bits:expr,
{
$(
$variant:ident = $val:expr
),* $(,)?
}
) => {
$(#[$meta])*
#[derive(Copy, Clone, PartialEq, Eq, Default)]
#[derive($crate::bytemuck::Pod, $crate::bytemuck::Zeroable)]
#[repr(transparent)]
$vis struct $enum_name(pub <$crate::Bits<$bits> as $crate::BitenumType>::Prim);
impl core::fmt::Debug for $enum_name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let s = match self.0 {
$(
$val => stringify!($variant),
)*
_ => "UNKNOWN",
};
write!(f, "{}({})::{}", stringify!($enum_name), self.0, s)
}
}
impl $enum_name {
$(
#[allow(non_upper_case_globals, dead_code)]
#[doc = concat!("Enumeration variant for `", stringify!($variant), "` with raw value `", stringify!($val), "`.")]
pub const $variant: Self = Self($val);
)*
#[allow(dead_code)]
pub const BITS: usize = $bits;
#[allow(dead_code)]
pub const MASK: <$crate::Bits<$bits> as $crate::BitenumType>::Prim = {
type Prim = <$crate::Bits<$bits> as $crate::BitenumType>::Prim;
#[allow(dead_code)]
const TOTAL_BITS: usize = <Prim as $crate::BitLength>::BITS;
(!0 as Prim) >> (TOTAL_BITS - $bits)
};
#[inline(always)]
#[allow(dead_code)]
pub const fn is_defined(self) -> bool {
match self.0 {
$( $val => true, )*
_ => false,
}
}
#[inline(always)]
#[allow(dead_code)]
pub const fn to_bits(self) -> <$crate::Bits<$bits> as $crate::BitenumType>::Prim { self.0 }
#[inline(always)]
#[allow(dead_code)]
pub const fn from_bits(val: <$crate::Bits<$bits> as $crate::BitenumType>::Prim) -> Self {
debug_assert!(val <= Self::MASK, "Value overflows allocated bit width for this enumeration");
Self(val)
}
#[inline(always)]
#[allow(dead_code)]
pub const fn try_from_bits(val: <$crate::Bits<$bits> as $crate::BitenumType>::Prim) -> Result<Self, $crate::BitstructError> {
let s = Self(val);
if s.is_defined() {
Ok(s)
} else {
Err($crate::BitstructError::InvalidVariant { value: val as u128, enum_name: stringify!($enum_name) })
}
}
}
impl $crate::ValidField for $enum_name {
const ASSERT_VALID: () = ();
}
const _: () = {
type Prim = <$crate::Bits<$bits> as $crate::BitenumType>::Prim;
$(
assert!(
($val as Prim) <= ((!0 as Prim) >> (<Prim as $crate::BitLength>::BITS - $bits)),
"Enum variant exceeds the maximum value for the allocated bit width"
);
)*
};
};
(
@impl_signed_enum
[ $($meta:meta)* ]
$vis:vis $enum_name:ident $bits:expr,
{
$(
$variant:ident = $val:expr
),* $(,)?
}
) => {
$(#[$meta])*
#[derive(Copy, Clone, PartialEq, Eq, Default)]
#[derive($crate::bytemuck::Pod, $crate::bytemuck::Zeroable)]
#[repr(transparent)]
$vis struct $enum_name(pub <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim);
impl core::fmt::Debug for $enum_name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let s = match self.0 {
$(
$val => stringify!($variant),
)*
_ => "UNKNOWN",
};
write!(f, "{}({})::{}", stringify!($enum_name), self.0, s)
}
}
impl $enum_name {
$(
#[allow(non_upper_case_globals, dead_code)]
#[doc = concat!("Enumeration variant for `", stringify!($variant), "` with raw value `", stringify!($val), "`.")]
pub const $variant: Self = Self($val);
)*
#[allow(dead_code)]
pub const BITS: usize = $bits;
#[allow(dead_code)]
pub const MIN: <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim = (!0 as <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim) << ($bits - 1);
#[allow(dead_code)]
pub const MAX: <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim = !Self::MIN;
#[inline(always)]
#[allow(dead_code)]
pub const fn is_defined(self) -> bool {
match self.0 {
$( $val => true, )*
_ => false,
}
}
#[inline(always)]
#[allow(dead_code)]
pub const fn to_bits(self) -> <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim { self.0 }
#[inline(always)]
#[allow(dead_code)]
pub const fn from_bits(mut val: <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim) -> Self {
const SHIFT_UP: usize = <<$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim as $crate::BitLength>::BITS - $bits;
val = (val << SHIFT_UP) >> SHIFT_UP;
debug_assert!(val >= Self::MIN && val <= Self::MAX, "Value overflows allocated bit width for this signed enumeration");
Self(val)
}
#[inline(always)]
#[allow(dead_code)]
pub const fn try_from_bits(mut val: <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim) -> Result<Self, $crate::BitstructError> {
const SHIFT_UP: usize = <<$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim as $crate::BitLength>::BITS - $bits;
val = (val << SHIFT_UP) >> SHIFT_UP;
let s = Self(val);
if s.is_defined() {
Ok(s)
} else {
Err($crate::BitstructError::InvalidVariant { value: (val as i128) as u128, enum_name: stringify!($enum_name) })
}
}
}
impl $crate::ValidField for $enum_name {
const ASSERT_VALID: () = ();
}
const _: () = {
type Prim = <$crate::Bits<$bits> as $crate::SignedBitenumType>::Prim;
$(
assert!(
($val as Prim) >= ((!0 as Prim) << ($bits - 1)) && ($val as Prim) <= !((!0 as Prim) << ($bits - 1)),
"Enum variant exceeds the maximum bounds for the allocated signed bit width"
);
)*
};
};
}