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!(usize);
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[test]
fn test_bit_size() {
assert_eq!(8, u8::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]),
#[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());
}
}