use std::ops::{BitAnd, Shr};
use std::slice;
use num_traits::Num;
use crate::common::{Endianness, SerializerError};
use crate::num_traits::SerializableInt;
pub struct Serializer<'a, T: std::io::Write> {
data: &'a mut T,
endianness: Endianness,
offset_in_bits: usize,
buffer: u8,
}
impl<'a, T: std::io::Write> Serializer<'a, T> {
pub fn new(data: &'a mut T, endianness: Endianness) -> Serializer<'a, T> {
Self {
data,
endianness,
offset_in_bits: 0,
buffer: 0,
}
}
pub fn offset_in_bits(&self) -> usize {
self.offset_in_bits
}
fn write_u8(&mut self, value: u8, bit_size: u8) -> Result<(), SerializerError> {
if bit_size == 8 && self.offset_in_bits % 8 == 0 {
self.data.write_all(slice::from_ref(&value))?;
self.offset_in_bits += bit_size as usize;
Ok(())
} else {
for i in 0..bit_size {
let bit_set_maskx: u8 = 1 << (7 - ((i as usize + self.offset_in_bits) % 8));
let bit_maskx: u8 = 0x80 >> (i + (8 - bit_size));
if (value & bit_maskx) != 0 {
self.buffer |= bit_set_maskx;
} else {
self.buffer &= !bit_set_maskx;
}
if (i as usize + self.offset_in_bits) % 8 == 7 {
self.data.write_all(slice::from_ref(&self.buffer))?;
}
}
self.offset_in_bits += bit_size as usize;
Ok(())
}
}
pub fn write<V>(&mut self, value: V, bit_size: u8) -> Result<(), SerializerError>
where
V: SerializableInt + Shr<V, Output = V> + BitAnd<V, Output = V> + Copy + Num,
{
if bit_size > 128 || bit_size as u32 > V::bit_size() {
return Err(SerializerError::TooManyBits);
} else if bit_size == 0 {
return Err(SerializerError::TooFewBits);
} else if value.min_bit_count() > bit_size as u32 {
return Err(SerializerError::ValueOutOfRange);
}
let num_byte_bits: u8 = (bit_size / 8) * 8;
match self.endianness {
Endianness::LittleEndian => {
for i in (0..num_byte_bits).step_by(8) {
self.write_u8((value.shr_to_u32(i) & 0xFF) as u8, 8)?;
}
if bit_size % 8 != 0 {
self.write_u8((value.shr_to_u32(num_byte_bits) & 0xFF) as u8, bit_size % 8)?;
}
Ok(())
}
Endianness::BigEndian => {
if bit_size % 8 != 0 {
self.write_u8((value.shr_to_u32(num_byte_bits) & 0xFF) as u8, bit_size % 8)?;
}
for i in (8..=num_byte_bits).step_by(8) {
self.write_u8((value.shr_to_u32(num_byte_bits - i) & 0xFF) as u8, 8)?;
}
Ok(())
}
}
}
}
#[cfg(test)]
mod tests {
use super::{Endianness, Serializer, SerializerError};
#[test]
fn aligned_u8_write() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(0b00000000_u8, 8)?;
serializer.write(0b10101010_u8, 8)?;
serializer.write(0b01010101_u8, 8)?;
serializer.write(0b11111111_u8, 8)?;
serializer.write(0b00001111_u8, 8)?;
serializer.write(0b11110000_u8, 8)?;
assert_eq!(
v,
vec![0b00000000, 0b10101010, 0b01010101, 0b11111111, 0b00001111, 0b11110000]
);
Ok(())
}
#[test]
fn write_all_types() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(0b00000000_u8, 8)?;
serializer.write(0b10101010_u16, 8)?;
serializer.write(0b01010101_u32, 8)?;
serializer.write(0b11111111_u64, 8)?;
serializer.write(0b00001111_u128, 8)?;
serializer.write(0b00000000_i8, 8)?;
serializer.write(0b01101010_i16, 8)?;
serializer.write(0b01010101_i32, 8)?;
serializer.write(0b01111111_i64, 8)?;
serializer.write(0b00001111_i128, 8)?;
assert_eq!(
v,
vec![
0b00000000, 0b10101010, 0b01010101, 0b11111111, 0b00001111, 0b00000000, 0b01101010,
0b01010101, 0b01111111, 0b00001111
]
);
Ok(())
}
#[test]
fn unaligned_u8_write() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(0b01010_u8, 5)?;
serializer.write(0b10101_u8, 5)?;
serializer.write(0b010_u8, 3)?;
serializer.write(0b1_u8, 1)?;
serializer.write(0b01_u8, 2)?;
assert_eq!(v, vec![0b01010101, 0b01010101]);
Ok(())
}
#[test]
fn big_endian_different_unsigned_sizes() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(0b0101_u8, 4)?;
serializer.write(0b0101_u16, 4)?;
serializer.write(0b0101_u32, 4)?;
serializer.write(0b0101_u64, 4)?;
serializer.write(0b0101_u128, 4)?;
serializer.write(0b0101_u128, 4)?;
assert_eq!(v, vec![0b01010101, 0b01010101, 0b01010101]);
Ok(())
}
#[test]
fn big_endian_different_signed_sizes() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(-6_i8, 4)?;
serializer.write(-6_i16, 4)?;
serializer.write(-6_i32, 4)?;
serializer.write(-6_i64, 4)?;
serializer.write(-6_i128, 4)?;
serializer.write(-6_i128, 4)?;
assert_eq!(v, vec![0b10101010, 0b10101010, 0b10101010]);
Ok(())
}
#[test]
fn little_endian_different_signed_sizes() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::LittleEndian);
serializer.write(-6_i8, 4)?;
serializer.write(-6_i16, 4)?;
serializer.write(-6_i32, 4)?;
serializer.write(-6_i64, 4)?;
serializer.write(-6_i128, 4)?;
serializer.write(-6_i128, 4)?;
assert_eq!(v, vec![0b10101010, 0b10101010, 0b10101010]);
Ok(())
}
#[test]
fn big_endian_multibyte() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write(0xFF00_u16, 16)?;
serializer.write(0xFF00AA55_u32, 32)?;
serializer.write(0xFF00AA5533CCF00F_u64, 64)?;
serializer.write(-256i16, 16)?; serializer.write(-16733611i32, 32)?; serializer.write(-71870311119917041i64, 64)?;
let expected_v = vec![
0xFF, 0x00, 0xFF, 0x00, 0xAA, 0x55, 0xFF, 0x00, 0xAA, 0x55, 0x33, 0xCC, 0xF0, 0x0F,
0xFF, 0x00, 0xFF, 0x00, 0xAA, 0x55, 0xFF, 0x00, 0xAA, 0x55, 0x33, 0xCC, 0xF0, 0x0F,
];
assert_eq!(v, expected_v);
Ok(())
}
#[test]
fn little_endian_multibyte() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::LittleEndian);
serializer.write(0xFF00_u16, 16)?;
serializer.write(0xFF00AA55_u32, 32)?;
serializer.write(0xFF00AA5533CCF00F_u64, 64)?;
serializer.write(-256i16, 16)?; serializer.write(-16733611i32, 32)?; serializer.write(-71870311119917041i64, 64)?;
let expected_v = vec![
0x00, 0xFF, 0x55, 0xAA, 0x00, 0xFF, 0x0F, 0xF0, 0xCC, 0x33, 0x55, 0xAA, 0x00, 0xFF,
0x00, 0xFF, 0x55, 0xAA, 0x00, 0xFF, 0x0F, 0xF0, 0xCC, 0x33, 0x55, 0xAA, 0x00, 0xFF,
];
assert_eq!(v, expected_v);
Ok(())
}
#[test]
fn size_bigger_than_data() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
assert_eq!(
serializer.write(0b1010_u8, 9).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_u16, 17).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_u32, 33).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_u64, 65).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_u128, 129).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_i8, 9).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_i16, 17).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_i32, 33).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_i64, 65).unwrap_err(),
SerializerError::TooManyBits
);
assert_eq!(
serializer.write(0b1010_i128, 129).unwrap_err(),
SerializerError::TooManyBits
);
Ok(())
}
#[test]
fn size_fits_data() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
assert!(serializer.write(0b1010_u8, 8).is_ok());
assert!(serializer.write(0b1010_u16, 16).is_ok());
assert!(serializer.write(0b1010_u32, 32).is_ok());
assert!(serializer.write(0b1010_u64, 64).is_ok());
assert!(serializer.write(0b1010_u128, 128).is_ok());
assert!(serializer.write(0b1010_i8, 8).is_ok());
assert!(serializer.write(0b1010_i16, 16).is_ok());
assert!(serializer.write(0b1010_i32, 32).is_ok());
assert!(serializer.write(0b1010_i64, 64).is_ok());
assert!(serializer.write(0b1010_i128, 128).is_ok());
Ok(())
}
#[test]
fn aligned_offset_in_bits() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write_u8(0b00000000, 8)?;
serializer.write_u8(0b10101010, 8)?;
serializer.write_u8(0b01010101, 8)?;
serializer.write_u8(0b11111111, 8)?;
serializer.write_u8(0b00001111, 8)?;
serializer.write_u8(0b11110000, 8)?;
assert_eq!(serializer.offset_in_bits(), 48);
Ok(())
}
#[test]
fn unaligned_offset_in_bits() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
serializer.write_u8(0b01010, 5)?;
serializer.write_u8(0b10101, 5)?;
serializer.write_u8(0b010, 3)?;
serializer.write_u8(0b1, 1)?;
serializer.write_u8(0b01, 2)?;
assert_eq!(serializer.offset_in_bits(), 16);
Ok(())
}
#[test]
fn zero_bits_cannot_be_serialized() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
assert_eq!(
serializer.write(0b1010_u8, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_u16, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_u32, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_u64, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_u128, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_i8, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_i16, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_i32, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_i64, 0).unwrap_err(),
SerializerError::TooFewBits
);
assert_eq!(
serializer.write(0b1010_i128, 0).unwrap_err(),
SerializerError::TooFewBits
);
Ok(())
}
#[test]
fn value_out_of_range() -> Result<(), SerializerError> {
let mut v: Vec<u8> = Vec::new();
let mut serializer = Serializer::new(&mut v, Endianness::BigEndian);
assert_eq!(
serializer.write(0b1010_u8, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_u16, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_u32, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_u64, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_u128, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_i8, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_i16, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_i32, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_i64, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
assert_eq!(
serializer.write(0b1010_i128, 1).unwrap_err(),
SerializerError::ValueOutOfRange
);
Ok(())
}
}