use crate::bit_io::BitWriter;
use crate::common::MAGIC_NUM;
use crate::encoding::util::{find_min_size, minify_val};
use alloc::vec::Vec;
#[derive(Debug)]
pub struct FrameHeader {
pub frame_content_size: Option<u64>,
pub single_segment: bool,
pub content_checksum: bool,
pub dictionary_id: Option<u64>,
pub window_size: Option<u64>,
}
impl FrameHeader {
pub fn serialize(self, output: &mut Vec<u8>) {
vprintln!("Serializing frame with header: {self:?}");
output.extend_from_slice(&MAGIC_NUM.to_le_bytes());
output.push(self.descriptor());
if !self.single_segment
&& let Some(window_size) = self.window_size
{
let log = window_size.next_power_of_two().ilog2();
let exponent = if log > 10 { log - 10 } else { 1 } as u8;
output.push(exponent << 3);
}
if let Some(id) = self.dictionary_id {
output.extend(minify_val(id));
}
if let Some(frame_content_size) = self.frame_content_size {
output.extend(minify_val_fcs(frame_content_size));
}
}
fn descriptor(&self) -> u8 {
let mut bw = BitWriter::new();
if let Some(id) = self.dictionary_id {
let flag_value: u8 = match find_min_size(id) {
0 => 0,
1 => 1,
2 => 2,
4 => 3,
_ => panic!(),
};
bw.write_bits(flag_value, 2);
} else {
bw.write_bits(0u8, 2);
}
if self.content_checksum {
bw.write_bits(1u8, 1);
} else {
bw.write_bits(0u8, 1);
}
bw.write_bits(0u8, 1);
bw.write_bits(0u8, 1);
if self.single_segment {
assert!(
self.frame_content_size.is_some(),
"if the `single_segment` flag is set to true, then a frame content size must be provided"
);
bw.write_bits(1u8, 1);
} else {
assert!(
self.window_size.is_some(),
"if the `single_segment` flag is set to false, then a window size must be provided"
);
bw.write_bits(0u8, 1);
}
if let Some(frame_content_size) = self.frame_content_size {
let field_size = find_min_size(frame_content_size);
let flag_value: u8 = match field_size {
1 => 0,
2 => 1,
4 => 2,
3 => 8,
_ => panic!(),
};
bw.write_bits(flag_value, 2);
} else {
bw.write_bits(0u8, 2);
}
bw.dump()[0]
}
}
fn minify_val_fcs(val: u64) -> Vec<u8> {
let new_size = find_min_size(val);
let mut val = val;
if new_size == 2 {
val -= 256;
}
val.to_le_bytes()[0..new_size].to_vec()
}
#[cfg(test)]
mod tests {
use super::FrameHeader;
use crate::decoding::frame::{FrameDescriptor, read_frame_header};
use alloc::vec::Vec;
#[test]
fn frame_header_descriptor_decode() {
let header = FrameHeader {
frame_content_size: Some(1),
single_segment: true,
content_checksum: false,
dictionary_id: None,
window_size: None,
};
let descriptor = header.descriptor();
let decoded_descriptor = FrameDescriptor(descriptor);
assert_eq!(decoded_descriptor.frame_content_size_bytes().unwrap(), 1);
assert!(!decoded_descriptor.content_checksum_flag());
assert_eq!(decoded_descriptor.dictionary_id_bytes().unwrap(), 0);
}
#[test]
fn frame_header_decode() {
let header = FrameHeader {
frame_content_size: Some(1),
single_segment: true,
content_checksum: false,
dictionary_id: None,
window_size: None,
};
let mut serialized_header = Vec::new();
header.serialize(&mut serialized_header);
let parsed_header = read_frame_header(serialized_header.as_slice()).unwrap().0;
assert!(parsed_header.dictionary_id().is_none());
assert_eq!(parsed_header.frame_content_size(), 1);
}
#[test]
#[should_panic]
fn catches_single_segment_no_fcs() {
let header = FrameHeader {
frame_content_size: None,
single_segment: true,
content_checksum: false,
dictionary_id: None,
window_size: Some(1),
};
let mut serialized_header = Vec::new();
header.serialize(&mut serialized_header);
}
#[test]
#[should_panic]
fn catches_single_segment_no_winsize() {
let header = FrameHeader {
frame_content_size: Some(7),
single_segment: false,
content_checksum: false,
dictionary_id: None,
window_size: None,
};
let mut serialized_header = Vec::new();
header.serialize(&mut serialized_header);
}
}