use core::{marker::PhantomData, mem::transmute};
use bytemuck::{Pod, Zeroable};
use crate::{
bitfld::{BitsCast, PlainBitsCast, sealed::IntoBitField},
int::{BasicInt, BasicUInt, BitsOp},
};
#[repr(transparent)]
pub struct BitField2<STRUCT, FLD, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> {
pub(super) raw: STRUCT,
mark: PhantomData<FLD>,
}
impl<STRUCT, FLD, 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>
{
pub const fn bind_ref(raw: &STRUCT) -> &Self {
unsafe { transmute(raw) }
}
pub const fn bind_mut(raw: &mut STRUCT) -> &mut Self {
unsafe { transmute(raw) }
}
}
impl<STRUCT, FLD, 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>
{
pub const LOW_START: u32 = LOW_START;
pub const LOW_LAST: u32 = LOW_LAST;
pub const LOW_BITS: u32 = LOW_LAST - LOW_START + 1;
pub const HIGH_START: u32 = HIGH_START;
pub const HIGH_LAST: u32 = HIGH_LAST;
pub const HIGH_BITS: u32 = HIGH_LAST - HIGH_START + 1;
pub const BITS: u32 = Self::LOW_BITS + Self::HIGH_BITS;
pub const fn bits(_: fn(&STRUCT) -> &Self) -> u32 {
Self::BITS
}
pub const fn low_bits_start(_: fn(&STRUCT) -> &Self) -> u32 {
LOW_START
}
pub const fn low_bits_last(_: fn(&STRUCT) -> &Self) -> u32 {
LOW_LAST
}
pub const fn high_bits_start(_: fn(&STRUCT) -> &Self) -> u32 {
HIGH_START
}
pub const fn high_bits_last(_: fn(&STRUCT) -> &Self) -> u32 {
HIGH_LAST
}
}
impl<STRUCT: PlainBitsCast<Bits: BasicUInt>, FLD, 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>
{
fn raw(&self) -> <STRUCT::Bits as BasicInt>::Primary {
STRUCT::into_underlying(self.raw)
}
}
impl<STRUCT: PlainBitsCast<Bits: BasicUInt>, FLD: BitsCast, 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>
{
pub(super) const ASSERT: () =
assert!(Self::BITS == FLD::BITS && LOW_START <= LOW_LAST && HIGH_START <= HIGH_LAST && (HIGH_START > LOW_LAST || LOW_START > HIGH_LAST));
pub fn read(&self) -> FLD {
let () = Self::ASSERT;
let under = self.raw();
FLD::from_underlying(under >> HIGH_START << Self::LOW_BITS | under.read_bits::<LOW_START, LOW_LAST>().cast_as())
}
#[must_use]
pub fn with(&self, fld: impl IntoBitField<FLD>) -> STRUCT {
let () = Self::ASSERT;
let fld: <STRUCT::Bits as BasicInt>::Primary = IntoBitField::into_bit_field(fld);
STRUCT::from_underlying(
self.raw().with_bits::<LOW_START, LOW_LAST>(fld.cast_as()).with_bits::<HIGH_START, HIGH_LAST>((fld >> Self::LOW_BITS).cast_as()),
)
}
pub fn write(&mut self, fld: impl IntoBitField<FLD>) {
self.raw = self.with(fld);
}
}
impl<STRUCT: Copy, FLD, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> Copy
for BitField2<STRUCT, FLD, LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>
{
}
impl<STRUCT: Clone, FLD, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> Clone
for BitField2<STRUCT, FLD, LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>
{
fn clone(&self) -> Self {
Self { raw: self.raw.clone(), mark: PhantomData }
}
}
unsafe impl<STRUCT: Zeroable, FLD, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> Zeroable
for BitField2<STRUCT, FLD, LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>
{
}
unsafe impl<STRUCT: Pod, FLD: 'static, const LOW_START: u32, const LOW_LAST: u32, const HIGH_START: u32, const HIGH_LAST: u32> Pod
for BitField2<STRUCT, FLD, LOW_START, LOW_LAST, HIGH_START, HIGH_LAST>
{
}