Skip to main content

naia_serde/
file_bit_writer.rs

1use crate::BitWrite;
2
3// FileBitWriter — heap-backed writer for files/snapshots, no MTU cap.
4// Uses the same u32-scratch word-aligned approach as BitWriter.
5pub struct FileBitWriter {
6    scratch: u32,
7    scratch_bits: u32,
8    buffer: Vec<u8>,
9}
10
11impl FileBitWriter {
12    #[allow(clippy::new_without_default)]
13    pub fn new() -> Self {
14        Self {
15            scratch: 0,
16            scratch_bits: 0,
17            buffer: Vec::new(),
18        }
19    }
20
21    fn flush_word(&mut self) {
22        self.buffer.extend_from_slice(&self.scratch.to_le_bytes());
23        self.scratch = 0;
24        self.scratch_bits = 0;
25    }
26
27    fn finalize(&mut self) {
28        if self.scratch_bits > 0 {
29            let remaining_bytes = (self.scratch_bits as usize).div_ceil(8);
30            let word = self.scratch.to_le_bytes();
31            self.buffer.extend_from_slice(&word[..remaining_bytes]);
32        }
33    }
34
35    pub fn to_bytes(mut self) -> Box<[u8]> {
36        self.finalize();
37        Box::from(self.buffer)
38    }
39
40    pub fn to_vec(mut self) -> Vec<u8> {
41        self.finalize();
42        self.buffer
43    }
44}
45
46impl BitWrite for FileBitWriter {
47    #[inline(always)]
48    fn write_bit(&mut self, bit: bool) {
49        self.scratch |= (bit as u32) << self.scratch_bits;
50        self.scratch_bits += 1;
51        if self.scratch_bits == 32 {
52            self.flush_word();
53        }
54    }
55
56    #[inline(always)]
57    fn write_byte(&mut self, byte: u8) {
58        let available = 32 - self.scratch_bits;
59        if available >= 8 {
60            self.scratch |= (byte as u32) << self.scratch_bits;
61            self.scratch_bits += 8;
62            if self.scratch_bits == 32 {
63                self.flush_word();
64            }
65        } else {
66            let lo = (byte as u32) & ((1 << available) - 1);
67            self.scratch |= lo << self.scratch_bits;
68            self.flush_word();
69            self.scratch = (byte as u32) >> available;
70            self.scratch_bits = 8 - available;
71        }
72    }
73
74    fn count_bits(&mut self, _: u32) {
75        panic!("This method should not be called for FileBitWriter!");
76    }
77
78    fn is_counter(&self) -> bool {
79        panic!("This method should not be called for FileBitWriter!");
80    }
81}