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)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __const_mask {
(msb0 $ty:ty; $($specs:tt)*) => {
$crate::mask::msb0_mask(<$ty>::BITS, &$crate::__bits_pairs!($($specs)*)) as $ty
};
(lsb0 $ty:ty; $($specs:tt)*) => {
$crate::mask::lsb0_mask(&$crate::__bits_pairs!($($specs)*)) as $ty
};
}
#[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)
}
#[inline]
pub fn insert_bits_auto<T>(dst: T, src: T::Storage, ranges: &[(u8, u8)]) -> T
where
T: crate::BitField
+ core::ops::BitAnd<T::Storage, Output = T>
+ core::ops::BitOr<T::Storage, Output = T>,
T::Storage: core::ops::BitAnd<Output = T::Storage> + core::ops::Not<Output = T::Storage>,
{
let mask = extract_mask::<T>(ranges);
(dst & !mask) | (src & mask)
}
#[inline]
pub fn place_bits_auto<T>(dst: T, lo: u8, hi: u8, val: T::Storage) -> T
where
T: crate::BitField
+ core::ops::BitAnd<T::Storage, Output = T>
+ core::ops::BitOr<T::Storage, Output = T>,
T::Storage: core::ops::BitAnd<Output = T::Storage>
+ core::ops::Not<Output = T::Storage>
+ core::ops::Shl<u32, Output = T::Storage>,
{
let shift = if T::IS_MSB0 {
<T::Storage as crate::BitStorage>::BITS - 1 - hi as u32
} else {
lo as u32
};
insert_bits_auto(dst, val << shift, &[(lo, hi)])
}
#[macro_export]
macro_rules! extract_bits {
(msb0 $ty:ty; $val:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::__const_mask!(msb0 $ty; $($specs)*);
($val) & MASK
}};
(lsb0 $ty:ty; $val:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::__const_mask!(lsb0 $ty; $($specs)*);
($val) & MASK
}};
($val:expr; $($specs:tt)*) => {
$crate::mask::extract_bits_auto($val, &$crate::__bits_pairs!($($specs)*))
};
}
#[macro_export]
macro_rules! insert_bits {
(msb0 $ty:ty; $dst:expr; $src:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::__const_mask!(msb0 $ty; $($specs)*);
(($dst) & !MASK) | (($src) & MASK)
}};
(lsb0 $ty:ty; $dst:expr; $src:expr; $($specs:tt)*) => {{
const MASK: $ty = $crate::__const_mask!(lsb0 $ty; $($specs)*);
(($dst) & !MASK) | (($src) & MASK)
}};
($dst:expr; $src:expr; $($specs:tt)*) => {
$crate::mask::insert_bits_auto($dst, ($src as _), &$crate::__bits_pairs!($($specs)*))
};
}
#[macro_export]
macro_rules! place_bits {
(msb0 $ty:ty; $dst:expr; $lo:literal ..= $hi:literal; $val:expr) => {{
const MASK: $ty = $crate::__const_mask!(msb0 $ty; $lo ..= $hi);
const SHIFT: u32 = <$ty>::BITS - 1 - ($hi as u32);
(($dst) & !MASK) | ((($val as $ty) << SHIFT) & MASK)
}};
(lsb0 $ty:ty; $dst:expr; $lo:literal ..= $hi:literal; $val:expr) => {{
const MASK: $ty = $crate::__const_mask!(lsb0 $ty; $lo ..= $hi);
const SHIFT: u32 = $lo as u32;
(($dst) & !MASK) | ((($val as $ty) << SHIFT) & MASK)
}};
($dst:expr; $lo:literal ..= $hi:literal; $val:expr) => {
$crate::mask::place_bits_auto($dst, $lo, $hi, ($val as _))
};
(msb0 $ty:ty; $dst:expr; $bit:literal; $val:expr) => {
$crate::place_bits!(msb0 $ty; $dst; $bit ..= $bit; $val)
};
(lsb0 $ty:ty; $dst:expr; $bit:literal; $val:expr) => {
$crate::place_bits!(lsb0 $ty; $dst; $bit ..= $bit; $val)
};
($dst:expr; $bit:literal; $val:expr) => {
$crate::place_bits!($dst; $bit ..= $bit; $val)
};
}