byteflow 0.2.1

Library for reading/writing non-byte-aligned numeric types
Documentation
pub trait SerializableInt: ::num_traits::ToBytes + ::num_traits::Zero {
    fn min_bit_count(&self) -> u32;
    fn shr_to_u32(&self, shift_amount: u8) -> u32;
    fn bit_size() -> u32;
    fn from_u8(value: u8) -> Self;
}

macro_rules! serializable_unsigned_int_impl {
    ($($t:ty)*) => ($(
        impl SerializableInt for $t {
            fn min_bit_count(&self) -> u32 {
                <$t>::BITS - self.leading_zeros()
            }
            fn shr_to_u32(&self, shift_amount: u8) -> u32 {
                self.checked_shr(shift_amount as u32).unwrap_or(0) as u32
            }
            fn bit_size() -> u32 {
                <$t>::BITS
            }
            fn from_u8(value: u8) -> Self {
                value as $t
            }
        }
    )*);
}

macro_rules! serializable_signed_int_impl {
    ($($t:ty)*) => ($(
        impl SerializableInt for $t {
            fn min_bit_count(&self) -> u32 {
                if self < &mut <$t as num_traits::Zero>::zero() {
                    <$t>::BITS - self.leading_ones() + 1
                } else {
                    <$t>::BITS - self.leading_zeros() + 1
                }
            }
            fn shr_to_u32(&self, shift_amount: u8) -> u32 {
                self.checked_shr(shift_amount as u32).unwrap_or(0) as u32
            }
            fn bit_size() -> u32 {
                <$t>::BITS
            }
            fn from_u8(value: u8) -> Self {
                value as $t
            }
        }
    )*)
}

serializable_unsigned_int_impl!(u16 u32 u64 u128 usize);
serializable_signed_int_impl!(i16 i32 i64 i128 isize);

impl SerializableInt for u8 {
    fn min_bit_count(&self) -> u32 {
        u8::BITS - self.leading_zeros()
    }
    fn shr_to_u32(&self, shift_amount: u8) -> u32 {
        (*self as u32).checked_shr(shift_amount as u32).unwrap_or(0)
    }
    fn bit_size() -> u32 {
        u8::BITS
    }
    fn from_u8(value: u8) -> Self {
        value
    }
}

impl SerializableInt for i8 {
    fn min_bit_count(&self) -> u32 {
        if *self < 0 {
            i8::BITS - self.leading_ones() + 1
        } else {
            i8::BITS - self.leading_zeros() + 1
        }
    }
    fn shr_to_u32(&self, shift_amount: u8) -> u32 {
        (*self as u32).checked_shr(shift_amount as u32).unwrap_or(0)
    }
    fn bit_size() -> u32 {
        i8::BITS
    }
    fn from_u8(value: u8) -> Self {
        value as i8
    }
}

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

    #[test]
    fn min_bit_count() {
        for i in u8::MIN..u8::MAX {
            assert_eq!(
                i.min_bit_count(),
                8 - i.leading_zeros(),
                "Minimum bit count for u8 '{}' is not correct",
                i
            );
        }

        assert_eq!(
            (0_i8).min_bit_count(),
            1,
            "Minimum bit count for i8 '0' is not correct"
        );
        assert_eq!(
            (-2_i8).min_bit_count(),
            2,
            "Minimum bit count for i8 '-2' is not correct"
        );
        assert_eq!(
            (2_i8).min_bit_count(),
            3,
            "Minimum bit count for i8 '2' is not correct"
        );
        assert_eq!(
            (i8::MIN).min_bit_count(),
            i8::BITS,
            "Minimum bit count for i8 '{}' is not correct",
            i8::MIN
        );
        assert_eq!(
            (i8::MAX).min_bit_count(),
            i8::BITS,
            "Minimum bit count for i8 '{}' is not correct",
            i8::MAX
        );

        assert_eq!(
            (0_i16).min_bit_count(),
            1,
            "Minimum bit count for i16 '0' is not correct"
        );
        assert_eq!(
            (-2_i16).min_bit_count(),
            2,
            "Minimum bit count for i16 '-2' is not correct"
        );
        assert_eq!(
            (2_i16).min_bit_count(),
            3,
            "Minimum bit count for i16 '2' is not correct"
        );
        assert_eq!(
            (i16::MIN).min_bit_count(),
            i16::BITS,
            "Minimum bit count for i16 '{}' is not correct",
            i16::MIN
        );
        assert_eq!(
            (i16::MAX).min_bit_count(),
            i16::BITS,
            "Minimum bit count for i16 '{}' is not correct",
            i16::MAX
        );

        assert_eq!(
            (0_i32).min_bit_count(),
            1,
            "Minimum bit count for i32 '0' is not correct"
        );
        assert_eq!(
            (-2_i32).min_bit_count(),
            2,
            "Minimum bit count for i32 '-2' is not correct"
        );
        assert_eq!(
            (2_i32).min_bit_count(),
            3,
            "Minimum bit count for i32 '2' is not correct"
        );
        assert_eq!(
            (i32::MIN).min_bit_count(),
            i32::BITS,
            "Minimum bit count for i32 '{}' is not correct",
            i32::MIN
        );
        assert_eq!(
            (i32::MAX).min_bit_count(),
            i32::BITS,
            "Minimum bit count for i32 '{}' is not correct",
            i32::MAX
        );

        assert_eq!(
            (0_i64).min_bit_count(),
            1,
            "Minimum bit count for i64 '0' is not correct"
        );
        assert_eq!(
            (-2_i64).min_bit_count(),
            2,
            "Minimum bit count for i64 '-2' is not correct"
        );
        assert_eq!(
            (2_i64).min_bit_count(),
            3,
            "Minimum bit count for i64 '2' is not correct"
        );
        assert_eq!(
            (i64::MIN).min_bit_count(),
            i64::BITS,
            "Minimum bit count for i64 '{}' is not correct",
            i64::MIN
        );
        assert_eq!(
            (i64::MAX).min_bit_count(),
            i64::BITS,
            "Minimum bit count for i64 '{}' is not correct",
            i64::MAX
        );

        assert_eq!(
            (0_i128).min_bit_count(),
            1,
            "Minimum bit count for i128 '0' is not correct"
        );
        assert_eq!(
            (-2_i128).min_bit_count(),
            2,
            "Minimum bit count for i128 '-2' is not correct"
        );
        assert_eq!(
            (2_i128).min_bit_count(),
            3,
            "Minimum bit count for i128 '2' is not correct"
        );
        assert_eq!(
            (i128::MIN).min_bit_count(),
            i128::BITS,
            "Minimum bit count for i128 '{}' is not correct",
            i128::MIN
        );
        assert_eq!(
            (i128::MAX).min_bit_count(),
            i128::BITS,
            "Minimum bit count for i128 '{}' is not correct",
            i128::MAX
        );

        assert_eq!(
            (0_isize).min_bit_count(),
            1,
            "Minimum bit count for isize '0' is not correct"
        );
        assert_eq!(
            (-2_isize).min_bit_count(),
            2,
            "Minimum bit count for isize '-2' is not correct"
        );
        assert_eq!(
            (2_isize).min_bit_count(),
            3,
            "Minimum bit count for isize '2' is not correct"
        );
        assert_eq!(
            (isize::MIN).min_bit_count(),
            isize::BITS,
            "Minimum bit count for isize '{}' is not correct",
            isize::MIN
        );
        assert_eq!(
            (isize::MAX).min_bit_count(),
            isize::BITS,
            "Minimum bit count for isize '{}' is not correct",
            isize::MAX
        );

        assert_eq!(
            (0_u8).min_bit_count(),
            0,
            "Minimum bit count for u8 '0' is not correct"
        );
        assert_eq!(
            (2_u8).min_bit_count(),
            2,
            "Minimum bit count for u8 '2' is not correct"
        );
        assert_eq!(
            (u8::MAX).min_bit_count(),
            u8::BITS,
            "Minimum bit count for u8 '{}' is not correct",
            u8::MAX
        );

        assert_eq!(
            (0_u16).min_bit_count(),
            0,
            "Minimum bit count for u16 '0' is not correct"
        );
        assert_eq!(
            (2_u16).min_bit_count(),
            2,
            "Minimum bit count for u16 '2' is not correct"
        );
        assert_eq!(
            (u16::MAX).min_bit_count(),
            u16::BITS,
            "Minimum bit count for u16 '{}' is not correct",
            u16::MAX
        );

        assert_eq!(
            (0_u32).min_bit_count(),
            0,
            "Minimum bit count for u32 '0' is not correct"
        );
        assert_eq!(
            (2_u32).min_bit_count(),
            2,
            "Minimum bit count for u32 '2' is not correct"
        );
        assert_eq!(
            (u32::MAX).min_bit_count(),
            u32::BITS,
            "Minimum bit count for u32 '{}' is not correct",
            u32::MAX
        );

        assert_eq!(
            (0_u64).min_bit_count(),
            0,
            "Minimum bit count for u64 '0' is not correct"
        );
        assert_eq!(
            (2_u64).min_bit_count(),
            2,
            "Minimum bit count for u64 '2' is not correct"
        );
        assert_eq!(
            (u64::MAX).min_bit_count(),
            u64::BITS,
            "Minimum bit count for u64 '{}' is not correct",
            u64::MAX
        );

        assert_eq!(
            (0_u128).min_bit_count(),
            0,
            "Minimum bit count for u128 '0' is not correct"
        );
        assert_eq!(
            (2_u128).min_bit_count(),
            2,
            "Minimum bit count for u128 '2' is not correct"
        );
        assert_eq!(
            (u128::MAX).min_bit_count(),
            u128::BITS,
            "Minimum bit count for u128 '{}' is not correct",
            u128::MAX
        );

        assert_eq!(
            (0_usize).min_bit_count(),
            0,
            "Minimum bit count for usize '0' is not correct"
        );
        assert_eq!(
            (2_usize).min_bit_count(),
            2,
            "Minimum bit count for usize '2' is not correct"
        );
        assert_eq!(
            (usize::MAX).min_bit_count(),
            usize::BITS,
            "Minimum bit count for usize '{}' is not correct",
            usize::MAX
        );
    }
}