1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Deku is a data-to-struct serialization/deserialization library supporting bit level granularity,
//! Makes use of the [bitvec](https://crates.io/crates/bitvec) crate as the "Reader" and “Writer”

use bitvec::prelude::*;
pub use deku_derive::*;
pub mod error;
pub mod prelude;
use crate::error::DekuError;

pub trait BitsSize {
    fn bit_size() -> usize;
}

pub trait BitsReader: BitsSize {
    fn read(
        input: &BitSlice<Msb0, u8>,
        len: usize,
    ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError>
    where
        Self: Sized;
}

pub trait BitsWriter: BitsSize {
    fn write(self) -> Vec<u8>;
    fn swap_endian(self) -> Self;
}

macro_rules! ImplDekuTraits {
    ($typ:ty) => {
        impl BitsSize for $typ {
            fn bit_size() -> usize {
                std::mem::size_of::<$typ>() * 8
            }
        }

        impl BitsReader for $typ {
            fn read(
                input: &BitSlice<Msb0, u8>,
                len: usize,
            ) -> Result<(&BitSlice<Msb0, u8>, Self), DekuError> {
                if input.len() < len {
                    return Err(DekuError::Parse(format!("not enough data")));
                }

                let (bits, rest) = input.split_at(len);

                if len > <$typ>::bit_size() {
                    return Err(DekuError::Parse(format!("too much data")));
                }

                #[cfg(target_endian = "little")]
                let value: $typ = bits.load_be();

                #[cfg(target_endian = "big")]
                let value: $typ = bits.load_le();

                Ok((rest, value))
            }
        }

        impl BitsWriter for $typ {
            fn write(self) -> Vec<u8> {
                #[cfg(target_endian = "little")]
                let res = self.to_be_bytes();

                #[cfg(target_endian = "big")]
                let res = self.to_le_bytes();

                res.to_vec()
            }

            fn swap_endian(self) -> $typ {
                self.swap_bytes()
            }
        }
    };
}

ImplDekuTraits!(u8);
ImplDekuTraits!(u16);
ImplDekuTraits!(u32);
ImplDekuTraits!(u64);
// ImplDekuTraits!(u128);
ImplDekuTraits!(usize);

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

    use rstest::rstest;

    #[test]
    fn test_bit_size() {
        assert_eq!(8, u8::bit_size());
        // assert_eq!(128, u128::bit_size());
    }

    #[rstest(input,read_bits,expected,expected_rest,
        case::normal([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), 32, 0xAABBCCDD, bits![Msb0, u8;]),
        case::normal_offset([0b1001_0110, 0b1110_0000, 0xCC, 0xDD].as_ref(), 12, 0b1001_0110_1110, bits![Msb0, u8; 0,0,0,0, 1,1,0,0,1,1,0,0, 1,1,0,1,1,1,0,1]),
        case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF].as_ref(), 32, 0xAABBCCDD, bits![Msb0, u8; 1,1,1,0,1,1,1,0, 1,1,1,1,1,1,1,1]),

        // TODO: Better error message for these
        #[should_panic(expected="Parse(\"not enough data\")")]
        case::not_enough_data([].as_ref(), 32, 0xFF, bits![Msb0, u8;]),
        #[should_panic(expected="Parse(\"not enough data\")")]
        case::not_enough_data([0xAA, 0xBB].as_ref(), 32, 0xFF, bits![Msb0, u8;]),
        #[should_panic(expected="Parse(\"too much data\")")]
        case::not_enough_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), 64, 0xFF, bits![Msb0, u8;]),
    )]
    fn test_bit_read(
        input: &[u8],
        read_bits: usize,
        expected: u32,
        expected_rest: &BitSlice<Msb0, u8>,
    ) {
        let bit_slice = input.bits::<Msb0>();

        let (rest, res_read) = u32::read(bit_slice, read_bits).unwrap();
        assert_eq!(expected, res_read);
        assert_eq!(expected_rest, rest);
    }

    #[rstest(input,expected,
        case::normal(0xAABBCCDD, vec![0xAA, 0xBB, 0xCC, 0xDD]),
    )]
    fn test_bit_write(input: u32, expected: Vec<u8>) {
        let res_write = input.write();
        assert_eq!(expected, res_write);
    }

    #[rstest(input,read_bits,expected,expected_rest,expected_write,
        case::normal([0xAA, 0xBB, 0xCC, 0xDD].as_ref(), 32, 0xAABBCCDD, bits![Msb0, u8;], vec![0xAA, 0xBB, 0xCC, 0xDD]),
    )]
    fn test_bit_read_write(
        input: &[u8],
        read_bits: usize,
        expected: u32,
        expected_rest: &BitSlice<Msb0, u8>,
        expected_write: Vec<u8>,
    ) {
        let bit_slice = input.bits::<Msb0>();

        let (rest, res_read) = u32::read(bit_slice, read_bits).unwrap();
        assert_eq!(expected, res_read);
        assert_eq!(expected_rest, rest);

        let res_write = res_read.write();
        assert_eq!(expected_write, res_write);

        assert_eq!(input[..expected_write.len()].to_vec(), expected_write);
    }

    #[test]
    fn test_swap_endian() {
        let input = 0xAABBCCDDu32;
        assert_eq!(0xDDCCBBAA, input.swap_endian());
    }
}