fray 0.1.2

A type-safe and ergonomic Rust library for working with bitfields.
Documentation
//! Contain the default [`BitContainer`] implementation.
//!
//! The `iterable` module provides [`BitIterableContainer`](self::BitIterableContainer),
//! a generic wrapper around a primitive integer type that
//! implements the [`BitContainer`] trait.
use super::{BitContainer, BitContainerFor};
use core::fmt::Debug;

mod bit_convert;
pub use bit_convert::BitConvert;

mod substitute;
use substitute::Substitute;

/// Default container implementation for [`BitContainer`].
///
/// `BitIterableContainer<U>` provides a low-level storage for bitfields
/// and implements [`BitContainer`]. It is generic over a primitive type `U`
/// (e.g., `u8`, `u16`, `u32`) and can store any type implementing [`BitConvert`],
/// which defines how a value can be converted to and from an iterator of bits (`bool`).
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BitIterableContainer<U: BitConvert>(U);

impl<U: InnerType> From<U> for BitIterableContainer<U> {
    fn from(value: U) -> Self {
        Self(value)
    }
}

/// Marker trait for types that can serve as the internal storage of a [`BitIterableContainer`].
///
/// `InnerType` is implemented generically for types that implement [`BitConvert`] and [`Copy`].
/// It is used purely as a constraint to ensure that the inner type of a [`BitIterableContainer`]
/// is suitable for bit-level storage and iteration.
pub trait InnerType
where
    Self: BitConvert,
    Self: Copy,
{
}

impl<T> InnerType for T
where
    Self: BitConvert,
    Self: Copy,
{
}

impl<T, U> BitContainerFor<T> for BitIterableContainer<U>
where
    T: BitConvert,
    U: InnerType,
{
    fn store_raw(&mut self, value: T, offset: usize, size: usize) {
        self.0 = U::from_bits(Substitute::new(
            self.0.into_bits(),
            value.into_bits(),
            offset..(offset + size),
        ));
    }

    fn retrieve_raw(&self, offset: usize, size: usize) -> T {
        T::from_bits(self.0.into_bits().skip(offset).take(size))
    }
}

impl<U: BitConvert> BitContainer for BitIterableContainer<U> {
    /// The internal type of [`BitIterableContainer`], requiring [`BitConvert`] and [`Copy`].
    type Inner = U;
    const SIZE: usize = ::core::mem::size_of::<U>() * 8;

    fn empty() -> Self {
        Self(U::from_bits(core::iter::repeat(false)))
    }

    fn into_inner(self) -> Self::Inner {
        self.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bit_iterable_container_into_inner() {
        let container: BitIterableContainer<u32> = BitIterableContainer(0b1010101010111100u32);

        assert_eq!(container.into_inner(), 0b1010101010111100u32)
    }

    #[test]
    fn bit_iterable_from_inner() {
        let container: BitIterableContainer<u32> =
            BitIterableContainer::from(0b1010101010111100u32);

        assert_eq!(container.0, 0b1010101010111100u32)
    }

    #[test]
    fn bit_iterable_container_empty() {
        let container: BitIterableContainer<u32> = BitIterableContainer::empty();

        assert_eq!(container.0, 0u32)
    }

    #[test]
    fn bit_iterable_container_store_basic() {
        let mut container: BitIterableContainer<u32> = BitIterableContainer(0);

        container.store(0b1011u8, 0, 4);
        assert_eq!(container.0, 0b1011u32)
    }

    #[test]
    fn bit_iterable_container_store_at_index() {
        let mut container: BitIterableContainer<u32> = BitIterableContainer(0);

        container.store(0b1011u8, 4, 4);
        assert_eq!(container.0, 0b1011_0000u32)
    }

    #[test]
    fn bit_iterable_container_store_max() {
        let mut container: BitIterableContainer<u32> = BitIterableContainer(0);

        container.store(u32::MAX, 0, 32);
        assert_eq!(container.0, u32::MAX)
    }

    #[test]
    fn bit_iterable_container_store_min() {
        let mut container: BitIterableContainer<u32> = BitIterableContainer(u32::MAX);

        container.store(0u32, 0, 32);
        assert_eq!(container.0, 0)
    }

    #[test]
    fn bit_iterable_container_store_overwrite() {
        let mut container: BitIterableContainer<u32> = BitIterableContainer(0b1011u32);

        container.store(0b100u8, 0, 3);
        assert_eq!(container.0, 0b1100u32);

        container.store(0b0u8, 0, 4);
        assert_eq!(container.0, 0u32);
    }

    #[test]
    fn bit_iterable_container_retrieve_basic() {
        let container: BitIterableContainer<u32> = BitIterableContainer(0b1011u32);

        assert_eq!(container.retrieve::<u32>(0, 4), 0b1011u32);
        assert_eq!(container.retrieve::<u32>(0, 2), 0b0011u32);
    }

    #[test]
    fn bit_iterable_container_retrieve_max() {
        let container: BitIterableContainer<u32> = BitIterableContainer(u32::MAX);

        assert_eq!(container.retrieve::<u32>(0, 32), u32::MAX);
    }

    #[test]
    fn bit_iterable_container_retrieve_at_index() {
        let container: BitIterableContainer<u32> = BitIterableContainer(0b1011u32);

        assert_eq!(container.retrieve::<u32>(2, 2), 0b0010u32);
        assert_eq!(container.retrieve::<u32>(2, 10), 0b0010u32);
    }
}