pub const fn msb0_mask(width: u32, ranges: &[(u8, u8)]) -> u128 {
let mut mask = 0u128;
let mut i = 0;
while i < ranges.len() {
let (start, end) = ranges[i];
let mut bit = start;
while bit <= end {
mask |= 1u128 << (width - 1 - bit as u32);
bit += 1;
}
i += 1;
}
mask
}
pub const fn lsb0_mask(ranges: &[(u8, u8)]) -> u128 {
let mut mask = 0u128;
let mut i = 0;
while i < ranges.len() {
let (start, end) = ranges[i];
let mut bit = start;
while bit <= end {
mask |= 1u128 << bit;
bit += 1;
}
i += 1;
}
mask
}
#[doc(hidden)]
#[macro_export]
macro_rules! __bits_pairs {
(@acc [$($pairs:tt)*]) => {
[$($pairs)*]
};
(@acc [$($pairs:tt)*] $s:literal ..= $e:literal, $($rest:tt)*) => {
$crate::__bits_pairs!(@acc [$($pairs)* ($s as u8, $e as u8),] $($rest)*)
};
(@acc [$($pairs:tt)*] $s:literal ..= $e:literal) => {
$crate::__bits_pairs!(@acc [$($pairs)* ($s as u8, $e as u8),])
};
(@acc [$($pairs:tt)*] $bit:literal, $($rest:tt)*) => {
$crate::__bits_pairs!(@acc [$($pairs)* ($bit as u8, $bit as u8),] $($rest)*)
};
(@acc [$($pairs:tt)*] $bit:literal) => {
$crate::__bits_pairs!(@acc [$($pairs)* ($bit as u8, $bit as u8),])
};
($($tokens:tt)*) => {
$crate::__bits_pairs!(@acc [] $($tokens)*)
};
}
#[inline]
pub fn extract_mask<T: crate::BitField>(ranges: &[(u8, u8)]) -> T::Storage {
let raw = if T::IS_MSB0 {
msb0_mask(<T::Storage as crate::BitStorage>::BITS, ranges)
} else {
lsb0_mask(ranges)
};
<T::Storage as crate::BitStorage>::from_u128(raw)
}
#[inline]
pub fn extract_bits_auto<T>(val: T, ranges: &[(u8, u8)]) -> T
where
T: crate::BitField,
T: core::ops::BitAnd<T::Storage, Output = T>,
{
val & extract_mask::<T>(ranges)
}
#[macro_export]
macro_rules! extract_bits {
(msb0 $ty:ty; $val:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::mask::msb0_mask(
<$ty>::BITS,
&$crate::__bits_pairs!($($specs)*),
) as $ty;
($val) & MASK
}};
(lsb0 $ty:ty; $val:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::mask::lsb0_mask(
&$crate::__bits_pairs!($($specs)*),
) as $ty;
($val) & MASK
}};
($val:expr; $($specs:tt)*) => {
$crate::mask::extract_bits_auto($val, &$crate::__bits_pairs!($($specs)*))
};
}