#![no_std]
use core::ops::{Add, BitAnd, BitAndAssign, BitOrAssign, BitXorAssign, Not, RangeBounds, Shl, Shr, Sub};
pub mod helper_traits;
use helper_traits::{One, Zero, BitSize};
#[doc(inline)]
pub use macros::bitfield;
trait BitFieldRequisites:
BitOrAssign<Self> + BitXorAssign<Self> +
Shl<Self, Output = Self> + Shr<Self, Output = Self> +
BitAnd<Self, Output = Self> + BitAndAssign<Self> +
Sub<Self, Output = Self> + Add<Self, Output = Self> +
Not<Output = Self> +
PartialEq<Self> + Default + Copy +
One + Zero + BitSize
{}
impl<T> BitFieldRequisites for T
where
T:
BitOrAssign<T> + BitXorAssign<T> +
Shl<T, Output = T> + Shr<T, Output = T> +
BitAnd<T, Output = Self> + BitAndAssign<T> +
Sub<T, Output = Self> + Add<T, Output = Self> +
Not<Output = T> +
PartialEq<T> + Default + Copy +
One + Zero + BitSize
{}
#[allow(private_bounds)]
pub trait BitField<T: BitFieldRequisites> {
fn set_bit(&mut self, i: T);
fn clear_bit(&mut self, i: T);
fn toggle_bit(&mut self, i: T);
fn get_bit(&self, i: T) -> bool;
fn set_bit_range(&mut self, range: impl RangeBounds<T>, b: T);
fn get_bit_range(&self, range: impl RangeBounds<T>) -> T;
}
fn range_convrt<T>(range: impl RangeBounds<T>) -> (T, T)
where
T: Sub<Output = T> + One + Zero + BitSize + Copy,
{
use core::ops::Bound;
let start = match range.start_bound() {
Bound::Included(n) => *n,
Bound::Excluded(n) => *n - T::one(),
Bound::Unbounded => T::zero(),
};
let end = match range.end_bound() {
Bound::Included(n) => *n,
Bound::Excluded(n) => *n - T::one(),
Bound::Unbounded => T::bit_size(),
};
(start, end)
}
impl<T: BitFieldRequisites> BitField<T> for T {
fn set_bit(&mut self, i: T) {
(*self) |= T::one() << i;
}
fn clear_bit(&mut self, i: T) {
(*self) &= !(T::one() << i);
}
fn get_bit(&self, i: T) -> bool {
( ( *self & (T::one() << i) ) >> i ) != T::zero()
}
fn toggle_bit(&mut self, i: T) {
(*self) ^= T::one() << i;
}
fn set_bit_range(&mut self, range: impl RangeBounds<T>, b: T) {
let (start, end) = range_convrt(range);
let mut mask = (!T::zero()) << (end - start + T::one());
mask = !mask;
(*self) &= !(mask << start);
(*self) |= (b & mask) << start;
}
fn get_bit_range(&self, range: impl RangeBounds<T>) -> T {
let (start, end) = range_convrt(range);
let mut mask = (!T::zero()) << (end - start + T::one());
mask = !mask << start;
let elem = *self & mask;
elem >> start
}
}
#[doc(hidden)]
#[expect(unused)]
fn check_numeric_types() {
macro_rules! check {
($($t:ty),*) => {
$( assert!(!<$t as BitField<$t>>::get_bit(&0, 0)); )*
};
}
check!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
}