bitable 0.1.0

An all-const, compile-time checked, safe bit handling library with zero runtime overhead
Documentation
use super::common::*;

/// A generic set of bits of type `Type`
pub const trait Set<Type, const OFFSET: u8, const SIZE: u8>
where Type: const CastFromUReg
{
    const ASSERT_FLAG: () = { assert_flag::<Type>(OFFSET); };
    const ASSERT_FIELD: () = { assert_field::<Type>(OFFSET, SIZE); };
    const ASSERT_MASK: () = { assert_mask::<Type>(SIZE); };
    const ASSERT_ARRAY: () = {};

    fn read(&self) -> UReg;
    fn read_at(&self, idx: usize) -> UReg;
    // fn write(&mut self, mask: &Mask<Type>, value: Type);
}

// ---------------------------------------------------------------------------
// Core target implementations: plain types
// ---------------------------------------------------------------------------

impl<const OFFSET: u8, const SIZE: u8>
const Set<bool, OFFSET, SIZE> for u8 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}
impl<const OFFSET: u8, const SIZE: u8>
const Set<bool, OFFSET, SIZE> for u16 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}
impl<const OFFSET: u8, const SIZE: u8>
const Set<bool, OFFSET, SIZE> for u32 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}

impl<const OFFSET: u8, const SIZE: u8>
const Set<u8, OFFSET, SIZE> for u8 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}

impl<const OFFSET: u8, const SIZE: u8>
const Set<u16, OFFSET, SIZE> for u16 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}

impl<const OFFSET: u8, const SIZE: u8>
const Set<u32, OFFSET, SIZE> for u32 {
    fn read(&self) -> UReg {
        *self as UReg
    }
    fn read_at(&self, _idx: usize) -> UReg {
        *self as UReg
    }
}

// ---------------------------------------------------------------------------
// Core target implementations: [u8; N] arrays
// ---------------------------------------------------------------------------

impl<const OFFSET: u8, const SIZE: u8, const N: usize>
const Set<bool, OFFSET, SIZE> for [u8; N] {
    const ASSERT_ARRAY: () = {
        // Compute how many total bits our field requires
        let required_bits = OFFSET + SIZE;
        // Compute how many bits this array physically holds
        let available_bits = N * 8;

        assert!(
            required_bits as usize <= available_bits,
            "Bitfield out of bounds for the provided array storage!"
        );
    };

    fn read(&self) -> UReg {
        // Automatically cast the array into a slice and call the slice method
        // <[u8] as Set<u16, OFFSET, SIZE>>::read(self)
        // u16::from_be_bytes(*self) as UInt
        <[u8; N] as Set<u8, OFFSET, SIZE>>::read_at(self, 0)
    }
    fn read_at(&self, idx: usize) -> UReg {
        self[idx] as UReg
    }
}

impl<const OFFSET: u8, const SIZE: u8, const N: usize>
const Set<u8, OFFSET, SIZE> for [u8; N] {
    const ASSERT_ARRAY: () = {
        // Compute how many total bits our field requires
        let required_bits = OFFSET + SIZE;
        // Compute how many bits this array physically holds
        let available_bits = N * 8;

        assert!(
            required_bits as usize <= available_bits,
            "Bitfield out of bounds for the provided array storage!"
        );
    };

    fn read(&self) -> UReg {
        // Automatically cast the array into a slice and call the slice method
        // <[u8] as Set<u16, OFFSET, SIZE>>::read(self)
        // u16::from_be_bytes(*self) as UInt
        <[u8; N] as Set<u8, OFFSET, SIZE>>::read_at(self, 0)
    }
    fn read_at(&self, idx: usize) -> UReg {
        self[idx] as UReg
    }
}

impl<const OFFSET: u8, const SIZE: u8, const N: usize>
const Set<u16, OFFSET, SIZE> for [u8; N] {
    const ASSERT_ARRAY: () = {
        // Compute how many total bits our field requires
        let required_bits = OFFSET + SIZE;
        // Compute how many bits this array physically holds
        let available_bits = N * 8;

        assert!(
            required_bits as usize <= available_bits,
            "Bitfield out of bounds for the provided array storage!"
        );
    };

    fn read(&self) -> UReg {
        // Automatically cast the array into a slice and call the slice method
        // <[u8] as Set<u16, OFFSET, SIZE>>::read(self)
        // u16::from_be_bytes(*self) as UInt
        <[u8; N] as Set<u16, OFFSET, SIZE>>::read_at(self, 0)
    }
    fn read_at(&self, idx: usize) -> UReg {
        let b0 = self[idx] as u32;
        let b1 = self[idx + 1] as u32;
        b0 << 8 | b1
    }
}

impl<const OFFSET: u8, const SIZE: u8, const N: usize>
const Set<u32, OFFSET, SIZE> for [u8; N] {
    const ASSERT_ARRAY: () = {
        // Compute how many total bits our field requires
        let required_bits = OFFSET + SIZE;
        // Compute how many bits this array physically holds
        let available_bits = N * 8;

        assert!(
            required_bits as usize <= available_bits,
            "Bitfield out of bounds for the provided array storage!"
        );
    };
    fn read(&self) -> u32 {
        <[u8; N] as Set<u32, OFFSET, SIZE>>::read_at(self, 0)
    }
    fn read_at(&self, idx: usize) -> u32 {
        // let safe_self = core::hint::black_box(self);
        let b0 = self[idx] as u32;
        let b1 = self[idx + 1] as u32;
        let b2 = self[idx + 2] as u32;
        let b3 = self[idx + 3] as u32;
        b0 << 24 | b1 << 16 | b2 << 8 |  b3
    }
}