itybity 0.3.3

An itty bitty crate providing bit iterators and bit iterator accessories.
Documentation
use crate::{BitIterable, BitLength, FromBitIterator, GetBit, Lsb0, Msb0, SetBit};

macro_rules! impl_int_from_bits {
    ($typ:ty) => {
        impl FromBitIterator for $typ {
            fn from_lsb0_iter(iter: impl IntoIterator<Item = bool>) -> Self {
                let mut iter = iter.into_iter();

                let mut value = <$typ>::default();
                for i in 0..<$typ>::BITS {
                    if let Some(bit) = iter.next() {
                        value |= (bit as $typ) << i;
                    } else {
                        return value;
                    }
                }

                value
            }

            fn from_msb0_iter(iter: impl IntoIterator<Item = bool>) -> Self {
                let mut iter = iter.into_iter();

                let mut value = <$typ>::default();
                for i in 0..<$typ>::BITS {
                    if let Some(bit) = iter.next() {
                        value |= (bit as $typ) << ((<$typ>::BITS - 1) - i);
                    } else {
                        return value;
                    }
                }

                value
            }
        }
    };
}

impl_int_from_bits!(u8);
impl_int_from_bits!(u16);
impl_int_from_bits!(u32);
impl_int_from_bits!(u64);
impl_int_from_bits!(u128);
impl_int_from_bits!(usize);
impl_int_from_bits!(i8);
impl_int_from_bits!(i16);
impl_int_from_bits!(i32);
impl_int_from_bits!(i64);
impl_int_from_bits!(i128);
impl_int_from_bits!(isize);

macro_rules! impl_get_bit_int {
    ($ty:ty) => {
        impl BitLength for $ty {
            const BITS: usize = <$ty>::BITS as usize;
        }

        impl GetBit<Lsb0> for $ty {
            #[inline]
            fn get_bit(&self, index: usize) -> bool {
                assert!(index < <$ty>::BITS as usize);
                self & (1 << index) != 0
            }
        }

        impl GetBit<Msb0> for $ty {
            #[inline]
            fn get_bit(&self, index: usize) -> bool {
                assert!(index < <$ty>::BITS as usize);
                self & (1 << ((<$ty>::BITS as usize - 1) - index)) != 0
            }
        }

        impl SetBit<Lsb0> for $ty {
            #[inline]
            fn set_bit(&mut self, index: usize, value: bool) {
                assert!(index < <$ty>::BITS as usize);
                let mask = (1 as $ty) << index;
                if value {
                    *self |= mask;
                } else {
                    *self &= !mask;
                }
            }
        }

        impl SetBit<Msb0> for $ty {
            #[inline]
            fn set_bit(&mut self, index: usize, value: bool) {
                assert!(index < <$ty>::BITS as usize);
                let mask = (1 as $ty) << ((<$ty>::BITS as usize - 1) - index);
                if value {
                    *self |= mask;
                } else {
                    *self &= !mask;
                }
            }
        }

        impl BitIterable for $ty {}
    };
}

impl_get_bit_int!(u8);
impl_get_bit_int!(u16);
impl_get_bit_int!(u32);
impl_get_bit_int!(u64);
impl_get_bit_int!(u128);
impl_get_bit_int!(usize);
impl_get_bit_int!(i8);
impl_get_bit_int!(i16);
impl_get_bit_int!(i32);
impl_get_bit_int!(i64);
impl_get_bit_int!(i128);
impl_get_bit_int!(isize);

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

    macro_rules! set_bit_test {
        ($name:ident, $ty:ty) => {
            #[rstest]
            fn $name() {
                let bits = <$ty>::BITS as usize;

                for i in 0..bits {
                    let mut v: $ty = 0;
                    SetBit::<Lsb0>::set_bit(&mut v, i, true);
                    assert_eq!(v, (1 as $ty) << i);
                    assert!(GetBit::<Lsb0>::get_bit(&v, i));
                    SetBit::<Lsb0>::set_bit(&mut v, i, false);
                    assert_eq!(v, 0);

                    let mut v: $ty = 0;
                    SetBit::<Msb0>::set_bit(&mut v, i, true);
                    assert_eq!(v, (1 as $ty) << (bits - 1 - i));
                    assert!(GetBit::<Msb0>::get_bit(&v, i));
                    SetBit::<Msb0>::set_bit(&mut v, i, false);
                    assert_eq!(v, 0);
                }

                let mut v: $ty = !0;
                SetBit::<Lsb0>::set_bit(&mut v, 0, false);
                assert_eq!(v, !0 & !(1 as $ty));
                SetBit::<Lsb0>::set_bit(&mut v, 0, true);
                assert_eq!(v, !0);
            }
        };
    }

    set_bit_test!(set_bit_u8, u8);
    set_bit_test!(set_bit_u16, u16);
    set_bit_test!(set_bit_u32, u32);
    set_bit_test!(set_bit_u64, u64);
    set_bit_test!(set_bit_u128, u128);
    set_bit_test!(set_bit_usize, usize);
    set_bit_test!(set_bit_i8, i8);
    set_bit_test!(set_bit_i16, i16);
    set_bit_test!(set_bit_i32, i32);
    set_bit_test!(set_bit_i64, i64);
    set_bit_test!(set_bit_i128, i128);
    set_bit_test!(set_bit_isize, isize);

    #[test]
    #[should_panic]
    fn set_bit_lsb0_out_of_bounds() {
        let mut v: u8 = 0;
        SetBit::<Lsb0>::set_bit(&mut v, 8, true);
    }

    #[test]
    #[should_panic]
    fn set_bit_msb0_out_of_bounds() {
        let mut v: u8 = 0;
        SetBit::<Msb0>::set_bit(&mut v, 8, true);
    }
}