/* * Macro builder for bit masks * $collection: Name for the bit mask collection * $unsigned_type: Unsigned type for the data that the bit mask will be applied onto * ($name: name of a bit mask, $shift: shift of the bit field, $width: no. of bits in the bit field) * Note: All bit masks must concern a set of contiguous bits */ macro_rules! construct_bitmask { ($collection: ident; $unsigned_type: ty; $($name: ident, $shift: expr, $width: expr),+) => { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[allow(non_camel_case_types)] pub enum $collection { $( $name, )* } impl $collection { pub(crate) fn get_width(self) -> u8 { match self { $( $collection::$name => $width, )* } } pub(crate) fn get_shift(self) -> u8 { match self { $( $collection::$name => $shift, )* } } pub(crate) fn get_bitmask(self) -> $unsigned_type { let mut mask: $unsigned_type = 0; for bit in 0..self.get_width() { mask |= (1 << (self.get_shift() + bit) % ((size_of::<$unsigned_type>() as u8) * 8)); } mask } pub(crate) fn get_shifted_bits(self, arg: $unsigned_type) -> $unsigned_type { assert!(arg < (2 << self.get_width())); (arg << (self.get_shift() % ((size_of::<$unsigned_type>() as u8) * 8))) } #[allow(dead_code)] pub(crate) fn set_data_by_arg(self, data: &mut $unsigned_type, arg: $unsigned_type) { // Clear bits in field, then insert shifted argument *data &= (!self.get_bitmask()); *data |= self.get_shifted_bits(arg); } pub(crate) fn get_filtered_content(self, data: $unsigned_type) -> $unsigned_type { // Filter everything then shift bits ((data & self.get_bitmask()) >> (self.get_shift() % ((size_of::<$unsigned_type>() as u8) * 8))) } } } }