use super::*;
pub(crate) fn encode_integer(
value: u32,
flags: u8,
prefix_size: u8,
dst: &mut Vec<u8>,
) -> Result<(), EncoderError> {
if prefix_size < 1 || prefix_size > 8 {
return Err(EncoderError::InvalidPrefix);
}
let mask = ((1 << prefix_size) - 1) as u8; let flags = flags & 255 - mask as u8;
if value < mask as u32 { dst.push(flags | value as u8);
return Ok(());
}
let mut value = value - mask as u32;
dst.push(flags | mask as u8); while value >= 128 {
dst.push(0b10000000 | value as u8); value >>= 7;
}
dst.push(value as u8); Ok(())
}
pub(crate) fn encode_string(
data: Vec<u8>,
huffman: bool,
dst: &mut Vec<u8>,
) -> Result<(), EncoderError> {
let (flags, bytes) = if huffman {
let mut dst = Vec::new();
httlib_huffman::encode(&data, &mut dst)?;
(0x80, dst) } else {
(0, data.to_vec()) };
let len = bytes.len();
if len > u32::MAX as usize {
return Err(EncoderError::IntegerOverflow);
}
encode_integer(len as u32, flags, 7, dst)?; dst.append(&mut bytes.to_vec());
return Ok(());
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn encodes_integer() {
let examples = vec![
(10, 0, 5, vec![10]), (1337, 0, 5, vec![31, 154, 10]), (42, 0, 8, vec![0b00101010]), (127, 0, 7, vec![127, 0]),
(255, 0, 8, vec![255, 0]),
(254, 0, 8, vec![254]),
(1, 0, 8, vec![1]),
(0, 0, 8, vec![0]),
(255, 0, 7, vec![127, 128, 1]),
(10, 0b10000000, 5, vec![0b10001010]), (10, 0b01000000, 5, vec![0b01001010]), (10, 0b00010000, 5, vec![0b00001010]), (1337, 0b01000000, 5, vec![0b01011111, 0b10011010, 0b00001010]), ];
for (value, flags, prefix, res) in examples {
let mut dst = Vec::new();
encode_integer(value, flags, prefix, &mut dst).unwrap();
assert_eq!(dst, res);
}
}
#[test]
fn encodes_string() {
let examples = vec![
(b"foo".to_vec(), false, vec![3, 102, 111, 111]), (b"foo".to_vec(), true, vec![130, 148, 231]), ];
for (value, huffman, bytes) in examples {
let mut dst = Vec::new();
encode_string(value, huffman, &mut dst).unwrap();
assert_eq!(dst, bytes);
}
}
}