use crate::error::Overflow;
#[allow(clippy::len_without_is_empty)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BitField<T> {
start: u32,
len: u32,
mask: T,
}
macro_rules! impl_bitfield {
($($ty:ty),*) => {
$(
impl BitField<$ty> {
#[inline]
pub const fn new(start: u32, len: u32) -> Self {
assert!(len > 0, "field length must be > 0");
assert!(start + len <= <$ty>::BITS, "field exceeds integer bounds");
let unshifted = if len == <$ty>::BITS {
!0
} else {
(1 << len) - 1
};
let mask = unshifted << start;
Self { start, len, mask }
}
#[inline]
pub const fn start(self) -> u32 {
self.start
}
#[inline]
pub const fn len(self) -> u32 {
self.len
}
#[inline]
pub const fn mask(self) -> $ty {
self.mask
}
#[inline]
pub const fn max_value(self) -> $ty {
self.mask >> self.start
}
#[inline]
pub const fn get(self, val: $ty) -> $ty {
(val & self.mask) >> self.start
}
#[inline]
pub const fn set(self, val: $ty, field_val: $ty) -> Result<$ty, Overflow<$ty>> {
let max = self.max_value();
if field_val > max {
return Err(Overflow { value: field_val, max });
}
Ok(self.set_unchecked(val, field_val))
}
#[inline]
pub const fn set_unchecked(self, val: $ty, field_val: $ty) -> $ty {
let cleared = val & !self.mask;
cleared | ((field_val << self.start) & self.mask)
}
#[inline]
pub const fn clear(self, val: $ty) -> $ty {
val & !self.mask
}
}
)*
};
}
impl_bitfield!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);