fray 0.1.2

A type-safe and ergonomic Rust library for working with bitfields.
Documentation
use crate::BitContainer;

use super::{BitIterableContainer, InnerType};
use core::ops::{BitAnd, Shl};

/// Describes a type that can be converted to and from an iterator of bits.
///
/// `BitConvert` is used by [`BitIterableContainer`] to store and retrieve values.
/// Implementors define how a type is transformed into an iterator over boolean values
/// (`bits`) and how it can be reconstructed from such an iterator.
///
/// # Usage
///
/// This trait allows any type to define a custom bit-level representation,
/// which can then be stored in a [`BitIterableContainer`] within a [`BitField`](crate::BitField).
pub trait BitConvert {
    /// An iterator yielding the individual bits (`bool`) of the value.
    type Bits: Iterator<Item = bool>;

    /// The number of bits used to represent the type.
    const SIZE: usize;

    /// Converts the value into an iterator of bits (`bool`).
    fn into_bits(self) -> Self::Bits;

    /// Constructs the value from an iterator of bits (`bool`).
    fn from_bits<I>(iter: I) -> Self
    where
        I: Iterator<Item = bool>;
}

#[derive(Debug, Clone)]
pub struct BitIter<T> {
    value: T,
    pos: usize,
    total: usize,
}

impl<T> Iterator for BitIter<T>
where
    T: From<bool>,
    T: Shl<usize, Output = T>,
    T: BitAnd<T, Output = T>,
    T: Copy,
    T: Eq,
{
    type Item = bool;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == self.total {
            return None;
        }

        let one = T::from(true);
        let zero = T::from(false);
        let mask = one << self.pos;
        let bit = self.value & mask;

        self.pos += 1;
        Some(bit != zero)
    }
}

macro_rules! impl_bitconvert {
    ($($t:ty),*) => {
        $(
            impl BitConvert for $t {
                type Bits = BitIter<$t>;
                const SIZE: usize = core::mem::size_of::<Self>() * 8;

                fn into_bits(self) -> Self::Bits {
                    BitIter {
                        value: self,
                        pos: 0,
                        total: Self::SIZE,
                    }
                }

                fn from_bits<I>(iter: I) -> Self
                where
                    I: Iterator<Item = bool>
                {
                    iter.take(Self::SIZE)
                        .enumerate()
                        .fold(0, |acc, (i, bit)| acc | (Self::from(bit) << i))
                }
            }
        )*
    };
}

impl_bitconvert!(u8, u16, u32, u64);

impl<U: InnerType> BitConvert for BitIterableContainer<U> {
    type Bits = U::Bits;
    const SIZE: usize = U::SIZE;

    #[inline]
    fn into_bits(self) -> Self::Bits {
        self.into_inner().into_bits()
    }
    #[inline]
    fn from_bits<I>(iter: I) -> Self
    where
        I: Iterator<Item = bool>,
    {
        U::from_bits(iter).into()
    }
}

impl BitConvert for bool {
    type Bits = core::iter::Once<bool>;
    const SIZE: usize = 1;

    fn into_bits(self) -> Self::Bits {
        core::iter::once(self)
    }

    fn from_bits<I>(mut iter: I) -> Self
    where
        I: Iterator<Item = bool>,
    {
        iter.next().is_some_and(|bool| bool)
    }
}

impl BitConvert for () {
    type Bits = core::iter::Empty<bool>;
    const SIZE: usize = 0;

    fn into_bits(self) -> Self::Bits {
        core::iter::empty()
    }

    fn from_bits<I>(_iter: I) -> Self
    where
        I: Iterator<Item = bool>,
    {
    }
}

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

    #[test]
    fn bit_iter_all_zeros() {
        let iter = BitIter {
            value: 0b0000_0000u8,
            pos: 0,
            total: 8,
        };
        assert_eq!(iter.collect::<Vec<bool>>(), vec![false; 8])
    }

    #[test]
    fn bit_iter_all_ones() {
        let iter = BitIter {
            value: 0b1111_1111u8,
            pos: 0,
            total: 8,
        };
        assert_eq!(iter.collect::<Vec<bool>>(), vec![true; 8])
    }

    #[test]
    fn bit_iter_mixed() {
        let iter = BitIter {
            value: 0b1010_1100u8,
            pos: 0,
            total: 8,
        };
        assert_eq!(
            iter.collect::<Vec<bool>>(),
            vec![false, false, true, true, false, true, false, true]
        )
    }

    #[test]
    fn bit_convert_unit_into_bits() {
        assert_eq!(().into_bits().count(), 0)
    }

    #[test]
    fn bit_convert_bool_into_bits() {
        assert_eq!(true.into_bits().collect::<Vec<bool>>(), vec![true]);
        assert_eq!(false.into_bits().collect::<Vec<bool>>(), vec![false])
    }

    #[test]
    fn bit_convert_bool_from_bits() {
        assert!(bool::from_bits([true].into_iter()));
        assert!(!bool::from_bits([false].into_iter()));
    }

    #[test]
    fn bit_convert_bool_from_bits_empty_ite() {
        assert!(!bool::from_bits([].into_iter()));
    }

    #[test]
    fn bit_convert_uint_into_bits() {
        let min: Vec<bool> = u8::MIN.into_bits().collect();
        assert_eq!(min, vec![false; 8]);

        let max: Vec<bool> = u8::MAX.into_bits().collect();
        assert_eq!(max, vec![true; 8]);

        let mixed: Vec<bool> = 0b1100_1001u8.into_bits().collect();
        let expected = vec![true, false, false, true, false, false, true, true];
        assert_eq!(mixed, expected);
    }
}