sharkyflac 0.2.0

A pure rust FLAC decoder and encoder
Documentation
#![allow(clippy::must_use_candidate, trivial_numeric_casts)]

pub trait Bitset {
    const ZERO: Self;
    const ONE: Self;

    /// Get the bit at `idx` relative to the most significant bit.
    ///
    /// ```rust
    /// use sharkyflac::bits::Bitset;
    ///
    /// assert_eq!(0b1010_1111_u8.get_bit_msb(2), true);
    /// ```
    #[must_use]
    fn get_bit_msb(self, idx: u32) -> bool;
    #[must_use]
    fn get_bit_range_msb(self, start: u32, len: u32) -> Self;
    #[must_use]
    fn get_bit_range_lsb(self, start: u8, len: u8) -> Self;

    #[must_use]
    fn set_bit_msb(self, idx: u32) -> Self;
    #[must_use]
    fn unset_bit_msb(self, idx: u32) -> Self;

    #[must_use]
    fn set_bit_range_msb(self, start: u8, len: u8) -> Self;
    #[must_use]
    fn set_bit_range_lsb(self, start: u8, len: u8) -> Self;
    #[must_use]
    fn unset_bit_range_msb(self, start: u32, len: u32) -> Self;
}

macro_rules! impl_bitset {
    ($($type:ty),+) => {
        $(
            impl Bitset for $type {
                const ZERO: Self = 0 as $type;
                const ONE: Self = 1 as $type;

                #[inline]
                fn get_bit_msb(self, idx: u32) -> bool {
                    (self.rotate_left(idx + 1) & 1) == 1
                }

                #[inline]
                fn get_bit_range_msb(self, start: u32, len: u32) -> Self {
                    self.unbounded_shl(start).unbounded_shr(<$type>::BITS - len)
                }

                #[inline]
                fn get_bit_range_lsb(self, start: u8, len: u8) -> Self {
                    self.unbounded_shl(u32::from(<$type>::BITS as u8 - (start + len))).unbounded_shr(u32::from(<$type>::BITS as u8- len))
                }

                #[inline]
                fn set_bit_msb(self, idx: u32) -> Self {
                    self | (((1 << 1) - 1) << Self::BITS - idx - 1)
                }

                #[inline]
                fn unset_bit_msb(self, idx: u32) -> Self {
                    self & !(((1 << 1) - 1) << Self::BITS - idx - 1)
                }

                #[inline]
                fn set_bit_range_msb(self, start: u8, len: u8) -> Self {
                    self | (((1 << len) - 1) << Self::BITS as u8 - start - len)
                }

                #[inline]
                fn set_bit_range_lsb(self, start: u8, len: u8) -> Self {
                    let mask = (Self::ONE.overflowing_shl(len.into()).0).wrapping_sub(1);
                    self | (mask << start)
                }

                #[inline]
                fn unset_bit_range_msb(self, start: u32, len: u32) -> Self {
                    self & !(((1 << len) - 1) << Self::BITS  - start - len)
                }
            }
        )+
    };
}

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

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

    #[test]
    fn get_bit_msb() {
        assert!(0b1010_1111_u8.get_bit_msb(0));
        assert!(!0b1010_1111_u8.get_bit_msb(1));
        assert!(0b1010_1111_u8.get_bit_msb(2));
        assert!(!0b1010_1111_u8.get_bit_msb(3));
        assert!(0b1010_1111_u8.get_bit_msb(4));
    }

    #[test]
    fn set_bit_msb() {
        assert_eq!(0x00.set_bit_msb(0), 0b1000_0000_u8);
        assert_eq!(0x00.set_bit_msb(7), 0b0000_0001_u8);
    }

    #[test]
    fn set_bit_range_lsb() {
        assert_eq!(0x00.set_bit_range_lsb(1, 2), 0b0000_0110_u8);
        //     assert_eq!(0x00.set_bit_range_lsb(0), 0b1000_0000_u8);
        //     assert_eq!(0x00.set_bit_range_lsb(0), 0b1000_0000_u8);
        //     assert_eq!(0x00.set_bit_range_lsb(7), 0b0000_0001_u8);
    }

    #[test]
    fn unset_bit_msb() {
        assert_eq!(0b1111_1111_u8.unset_bit_msb(0), 0b0111_1111_u8);
        assert_eq!(0b1111_1111_u8.unset_bit_msb(7), 0b1111_1110_u8);
    }

    #[test]
    fn get_bit_range_msb() {
        assert_eq!(0xAAAA_AAAAu32.get_bit_range_msb(0, 4), 0b1010);
    }

    #[test]
    fn msb_set_range() {
        let input: u8 = 0b0000_0000;
        let result = input.set_bit_range_msb(1, 3);
        assert_eq!(result, 0x70, "Failed to set MSB range 1..4 on u8");

        let input_32: u32 = 0;
        let result_32 = input_32.set_bit_range_msb(0, 4);
        assert_eq!(result_32, 0xF000_0000);
    }

    #[test]
    fn msb_unset_range() {
        let input: u8 = 0b1111_1111;
        let result = input.unset_bit_range_msb(4, 4);
        assert_eq!(result, 0xF0, "Failed to unset MSB range 4..8 on u8");

        let input_16: u16 = 0xFFFF;
        let result_16 = input_16.unset_bit_range_msb(4, 8);
        assert_eq!(result_16, 0xF00F);
    }
}