#[macro_export]
#[doc(hidden)]
macro_rules! check_field_mask {
(bool, $mask:expr, $name:ident) => {
assert!(
$mask != 0,
concat!("Mask for field ", stringify!($name), " is zero.")
);
assert!(
($mask as usize).is_power_of_two(),
concat!(
"Field ",
stringify!($name),
" is of type boolean, but it's mask isn't a power of two."
)
);
};
($field_type:ty, $mask:expr, $name:ident) => {
assert!(
$mask != 0,
concat!("Mask for field ", stringify!($name), " is zero.")
);
assert!(
(($mask >> 1 ^ $mask) as usize).count_ones() <= 2,
concat!("Mask for field ", stringify!($name), " is discontinous.")
);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! read_field {
(bool, $representation:ty, $shifted_value:expr) => {
$shifted_value != 0
};
(u8, $representation:ty, $shifted_value:expr) => {
$shifted_value as u8
};
(i8, $representation:ty, $shifted_value:expr) => {
$shifted_value as i8
};
(u16, $representation:ty, $shifted_value:expr) => {
$shifted_value as u16
};
(i16, $representation:ty, $shifted_value:expr) => {
$shifted_value as i16
};
(u32, $representation:ty, $shifted_value:expr) => {
$shifted_value as u32
};
(i32, $representation:ty, $shifted_value:expr) => {
$shifted_value as i32
};
(u64, $representation:ty, $shifted_value:expr) => {
$shifted_value as u64
};
(i64, $representation:ty, $shifted_value:expr) => {
$shifted_value as i64
};
(u128, $representation:ty, $shifted_value:expr) => {
$shifted_value as u128
};
(i128, $representation:ty, $shifted_value:expr) => {
$shifted_value as i128
};
($field_type:ty, $representation:ty, $shifted_value:expr) => {
<$field_type as From<$representation>>::from($shifted_value)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! write_field {
(bool, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(u8, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(i8, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(u16, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(i16, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(u32, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(i32, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(u64, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(i64, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(u128, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
(i128, $representation:ty, $shifted_value:expr) => {
$shifted_value as $representation
};
($field_type:ty, $representation:ty, $shifted_value:expr) => {
<$representation as From<$field_type>>::from($shifted_value)
};
}
#[macro_export]
macro_rules! bitfield {
(
$(#[$attr:meta])*
$struct_vis:vis struct $struct_name:ident : $struct_representation:ty {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_type:ty => $field_mask:expr
),*
}
) => {
::macro_bits::defile::defile! {
$(#[$attr])*
$struct_vis struct $struct_name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_type
),*
}
impl $struct_name {
const _BITFIELD_PROOF: () = {
assert!(
($($field_mask)^+) == $($field_mask)|+,
"Masks are overlapping."
);
$(
assert!(
$field_mask <= <$struct_representation>::MAX,
concat!("Mask for field ",
stringify!($field_name),
" is larger than the representation type."
)
);
)*
$(
::macro_bits::check_field_mask!($field_type, $field_mask, $field_name);
)*
};
pub fn from_representation(value: $struct_representation) -> Self {
$(
let $field_name =
::macro_bits::read_field!(
$field_type,
$struct_representation,
(value & $field_mask) >> ($field_mask as usize).trailing_zeros()
);
)+
Self {
$(
$field_name,
)+
}
}
pub fn to_representation(self) -> $struct_representation {
let mut data: $struct_representation = 0;
$(
data |= (
(
::macro_bits::write_field!(
$field_type,
$struct_representation,
self.$field_name
)
) << ($field_mask as usize).trailing_zeros()
) & $field_mask;
)*
data
}
}
::macro_bits::generate_conversions!($struct_representation, $struct_representation, $struct_name);
}
};
}