ecore 0.10.0

no_std bit-level integer types, bitfield structs/enums, ranged integers, and enum maps
Documentation
use core::{marker::PhantomData, mem::transmute};

use bytemuck::{Pod, Zeroable};

use crate::{
    bitfld::{BitsCast, PlainBitsCast, sealed::IntoBitField},
    int::{BasicInt, BasicUInt, BitsOp},
};

/// Bit-field type that concatenates bit ranges `LOW_START..=LOW_LAST` and `HIGH_START..=HIGH_LAST`
/// of bit-struct `STRUCT` with field type `FLD`. This object is typically not constructed directly,
/// but rather bound as a reference from the bit-struct. It is primarily auto-generated by
/// `#[bitfld(..)]` and generally not defined manually.
#[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>
{
    /// Reinterprets a shared reference to the bit-struct as a shared reference to this two-segment bit-field.
    pub const fn bind_ref(raw: &STRUCT) -> &Self {
        unsafe { transmute(raw) }
    }
    /// Reinterprets a mutable reference to the bit-struct as a mutable reference to this two-segment bit-field.
    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())
    }

    /// gen new bit struct value from origin bit struct value with new field value
    #[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>
{
}