1use crate::checksum::{Checksum, Crc32};
2use crate::decode::{Decode, DecodeError};
3use crate::encode::Encode;
4
5use super::{StreamDecodeError, StreamFlags};
6
7const MAGIC_BYTES_LEN: usize = 2;
8const MAGIC_BYTES: [u8; MAGIC_BYTES_LEN] = [0x59, 0x5A];
9
10#[derive(Debug, Clone)]
11pub struct StreamFooter {
12 pub backward_size: u32,
13 pub flags: StreamFlags,
14}
15
16impl Encode for StreamFooter {
17 fn encoding(&self) -> Vec<u8> {
18 let mut crc_32 = Crc32::new();
19
20 let backward_size = self.backward_size.to_le_bytes();
21 crc_32.process_words(&backward_size);
22
23 let flags = self.flags.encoding();
24 crc_32.process_words(&flags);
25
26 let crc_32 = crc_32.result().to_le_bytes();
27
28 crc_32
29 .into_iter()
30 .chain(backward_size)
31 .chain(flags)
32 .chain(MAGIC_BYTES)
33 .collect()
34 }
35}
36
37impl Decode for StreamFooter {
38 fn decode<R: std::io::Read>(src: &mut R) -> Result<Self, DecodeError> {
39 let err = |e| Err(DecodeError::from(e));
40 use StreamDecodeError::*;
41
42 let mut bytes = [0u8; 12];
43 src.read_exact(&mut bytes)?;
44 if bytes[10..] != MAGIC_BYTES {
45 return err(InvalidFooter);
46 }
47
48 let backward_size = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
49
50 let flags = StreamFlags::try_from(&[bytes[8], bytes[9]])?;
51
52 let mut crc_32 = Crc32::new();
53 crc_32.process_words(&bytes[4..10]);
54 if bytes[..4] != crc_32.result().to_le_bytes() {
55 return err(InvalidFooter);
56 }
57
58 Ok(Self {
59 backward_size,
60 flags,
61 })
62 }
63}