use crate::{
bitfld::{BitField, BitField2, BitsCast, DynBitField, PlainBitsCast},
int::{BasicInt, BasicUInt, PrimaryUInt},
repr::{PlainUncheckable, Uncheckable, Unchecked},
};
impl<const START: u32, const LAST: u32, STRUCT: PlainBitsCast<Bits: BasicUInt>, FLD: BitsCast + PlainBitsCast> BitField<STRUCT, FLD, START, LAST> {
#[inline(always)]
pub const fn const_read(&self) -> FLD {
unsafe { from_bits(FieldOp::<START, LAST>::read_bits(into_bits(self.raw))) }
}
#[must_use]
#[inline(always)]
pub const fn const_with(&self, fld: impl IntoBitField<FLD>) -> STRUCT {
unsafe { from_bits(FieldOp::<START, LAST>::with_fld(into_bits(self.raw), into_bit_field(fld))) }
}
}
impl<STRUCT: PlainBitsCast<Bits: BasicUInt>, FLD: BitsCast + PlainBitsCast> DynBitField<FLD, STRUCT> {
#[inline(always)]
pub const fn const_read(&self) -> FLD {
unsafe {
if <STRUCT::Bits as BasicInt>::Primary::BITS <= usize::BITS {
let unused_bits = const { usize::BITS.wrapping_sub(FLD::BITS) };
let left_unused_bits = unused_bits - self.start_bit();
force_truncate(usize_read_bits(int_cast_up(into_bits(*self.underlying())), left_unused_bits, unused_bits, FLD::Bits::SIGNED))
} else {
let unused_bits = const { u128::BITS.wrapping_sub(FLD::BITS) };
let left_unused_bits = unused_bits - self.start_bit();
force_truncate(u128_read_bits(int_cast_up(into_bits(*self.underlying())), left_unused_bits, unused_bits, FLD::Bits::SIGNED))
}
}
}
#[must_use]
#[inline(always)]
pub const fn const_with(&self, fld: impl IntoBitField<FLD>) -> STRUCT {
let src = unsafe { into_bits(*self.underlying()) };
let fld = unsafe { into_bit_field(fld) };
unsafe {
if <STRUCT::Bits as BasicInt>::Primary::BITS <= usize::BITS {
force_truncate(usize_with_fld(int_cast_up(src), int_cast_up(fld), const { usize::BITS.wrapping_sub(FLD::BITS) }, self.start_bit()))
} else {
force_truncate(u128_with_fld(int_cast_up(src), int_cast_up(fld), const { u128::BITS.wrapping_sub(FLD::BITS) }, self.start_bit()))
}
}
}
}
impl<STRUCT: PlainBitsCast<Bits: BasicUInt>, FLD: PlainBitsCast, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32>
BitField2<STRUCT, FLD, LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>
{
#[inline(always)]
pub const fn const_read(&self) -> FLD {
let () = Self::ASSERT;
unsafe { from_bits(Field2Op::<LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>::read_bits(into_bits(self.raw))) }
}
#[must_use]
#[inline(always)]
pub const fn const_with(&self, fld: impl IntoBitField<FLD>) -> STRUCT {
let () = Self::ASSERT;
unsafe { from_bits(Field2Op::<LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>::with_fld(into_bits(self.raw), into_bit_field(fld))) }
}
}
pub trait IntoBitField<Fld: BitsCast + PlainBitsCast>: Copy {
}
impl<Fld: BitsCast + PlainBitsCast> IntoBitField<Fld> for Fld {}
impl<Fld: Uncheckable<UncheckedRaw: BasicInt> + PlainUncheckable> IntoBitField<Unchecked<Fld>> for Fld {}
struct FieldOp<const START: u32, const LAST: u32>;
impl<const START: u32, const LAST: u32> FieldOp<START, LAST> {
const END: u32 = LAST + 1;
const BITS: u32 = Self::END - START;
#[inline(always)]
const unsafe fn read_bits<T: BasicUInt, Fld: BasicInt>(src: T) -> Fld {
unsafe {
if T::Primary::BITS <= usize::BITS {
let (left_unused_bits, unused_bits) = const { (usize::BITS.wrapping_sub(Self::END), usize::BITS.wrapping_sub(Self::BITS)) };
force_truncate(usize_read_bits(int_cast_up(src), left_unused_bits, unused_bits, Fld::SIGNED))
} else {
let (left_unused_bits, unused_bits) = const { (u128::BITS.wrapping_sub(Self::END), u128::BITS.wrapping_sub(Self::BITS)) };
force_truncate(u128_read_bits(int_cast_up(src), left_unused_bits, unused_bits, Fld::SIGNED))
}
}
}
#[inline(always)]
const unsafe fn with_fld<T: BasicUInt, Fld: BasicInt>(src: T, fld: Fld) -> T {
unsafe {
if T::Primary::BITS <= usize::BITS {
force_truncate(usize_with_fld(int_cast_up(src), int_cast_up(fld), const { usize::BITS.wrapping_sub(Self::BITS) }, START))
} else {
force_truncate(u128_with_fld(int_cast_up(src), int_cast_up(fld), const { u128::BITS.wrapping_sub(Self::BITS) }, START))
}
}
}
}
struct Field2Op<const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32>;
impl<const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> Field2Op<LOW_START, LOW_LAST, HIGH_START, HIGH_LAST> {
const LOW_END: u32 = LOW_LAST + 1;
const LOW_BITS: u32 = Self::LOW_END - LOW_START;
const HIGH_END: u32 = HIGH_LAST + 1;
const HIGH_BITS: u32 = Self::HIGH_END - HIGH_START;
#[inline(always)]
const unsafe fn read_bits<T: BasicUInt, Fld: BasicInt>(src: T) -> Fld {
unsafe {
if T::Primary::BITS <= usize::BITS {
let src = int_cast_up(src);
let (left_unused_bits, unused_bits) = const { (usize::BITS.wrapping_sub(Self::LOW_END), usize::BITS.wrapping_sub(Self::LOW_BITS)) };
let low = usize_read_bits(src, left_unused_bits, unused_bits, false);
let (left_unused_bits, unused_bits) = const { (usize::BITS.wrapping_sub(Self::HIGH_END), usize::BITS.wrapping_sub(Self::HIGH_BITS)) };
let high = usize_read_bits(src, left_unused_bits, unused_bits, Fld::SIGNED);
force_truncate(high << Self::LOW_BITS | low)
} else {
let src = int_cast_up(src);
let (left_unused_bits, unused_bits) = const { (u128::BITS.wrapping_sub(Self::LOW_END), u128::BITS.wrapping_sub(Self::LOW_BITS)) };
let low = u128_read_bits(src, left_unused_bits, unused_bits, false);
let (left_unused_bits, unused_bits) = const { (u128::BITS.wrapping_sub(Self::HIGH_END), u128::BITS.wrapping_sub(Self::HIGH_BITS)) };
let high = u128_read_bits(src, left_unused_bits, unused_bits, Fld::SIGNED);
force_truncate(high << Self::LOW_BITS | low)
}
}
}
#[inline(always)]
const unsafe fn with_fld<T: BasicUInt, Fld: BasicInt>(src: T, fld: Fld) -> T {
unsafe {
if T::Primary::BITS <= usize::BITS {
let fld = int_cast_up(fld);
let low = usize_with_fld(int_cast_up(src), fld, const { usize::BITS.wrapping_sub(Self::LOW_BITS) }, LOW_START);
force_truncate(usize_with_fld(low, fld >> Self::LOW_BITS, const { usize::BITS.wrapping_sub(Self::HIGH_BITS) }, HIGH_START))
} else {
let fld = int_cast_up(fld);
let low = u128_with_fld(int_cast_up(src), fld, const { u128::BITS.wrapping_sub(Self::LOW_BITS) }, LOW_START);
force_truncate(u128_with_fld(low, fld >> Self::LOW_BITS, const { u128::BITS.wrapping_sub(Self::HIGH_BITS) }, HIGH_START))
}
}
}
}
#[inline(always)]
const fn usize_read_bits(src: usize, left_unused_bits: u32, unused_bits: u32, signed: bool) -> usize {
let src = src << left_unused_bits;
if signed { ((src as isize) >> unused_bits) as usize } else { src >> unused_bits }
}
#[inline(always)]
const fn u128_read_bits(src: u128, left_unused_bits: u32, unused_bits: u32, signed: bool) -> u128 {
let src = src << left_unused_bits;
if signed { ((src as i128) >> unused_bits) as u128 } else { src >> unused_bits }
}
#[inline(always)]
const unsafe fn int_cast_up<Src: BasicInt, Tgt: PrimaryUInt>(src: Src) -> Tgt {
const { assert!(size_of::<Src>() <= size_of::<Tgt>()) }
let mut v = Tgt::ZERO;
unsafe { (&raw mut v as *mut Src).write(src) };
v
}
#[inline(always)]
const fn usize_with_fld(src: usize, fld: usize, remain_bits: u32, start: u32) -> usize {
let mask = usize::ALL_ONE >> remain_bits << start;
src & !mask | fld << start & mask
}
#[inline(always)]
const fn u128_with_fld(src: u128, fld: u128, remain_bits: u32, start: u32) -> u128 {
let mask = u128::ALL_ONE >> remain_bits << start;
src & !mask | fld << start & mask
}
#[inline(always)]
const unsafe fn force_truncate<Src: Copy, Tgt>(src: Src) -> Tgt {
const { assert!(size_of::<Src>() >= size_of::<Tgt>()) }
let ptr = &raw const src as *const Tgt;
unsafe { if align_of::<Src>() >= align_of::<Tgt>() { ptr.read() } else { ptr.read_unaligned() } }
}
#[inline(always)]
const unsafe fn from_bits<T: PlainBitsCast>(src: T::Bits) -> T {
let () = T::ASSERT;
unsafe { force_truncate(src) }
}
#[inline(always)]
const unsafe fn into_bits<T: PlainBitsCast>(src: T) -> T::Bits {
let () = T::ASSERT;
unsafe { force_truncate(src) }
}
#[inline(always)]
const unsafe fn into_bit_field<Fld: BitsCast + PlainBitsCast, T: IntoBitField<Fld>>(src: T) -> Fld::Bits {
let () = Fld::ASSERT;
unsafe { force_truncate(src) }
}