binary_codec/bitstream/
writer.rs

1use std::cmp::min;
2
3use crate::encoding::fixed_int::FixedInt;
4
5pub struct BitStreamWriter<'a> {
6    buffer: &'a mut Vec<u8>,
7    bit_pos: usize,
8}
9
10impl<'a> BitStreamWriter<'a> {
11    /// Create a new LSB-first writer
12    pub fn new(buffer: &'a mut Vec<u8>) -> Self {
13        Self { buffer, bit_pos: 0 }
14    }
15
16    /// Get byte position of writer
17    pub fn byte_pos(&self) -> usize {
18        self.bit_pos / 8
19    }
20
21    /// Write a single bit
22    pub fn write_bit(&mut self, val: bool) {
23        self.write_small(val as u8, 1);
24    }
25
26    /// Write 1-8 bits (LSB-first)
27    pub fn write_small(&mut self, mut val: u8, mut bits: u8) {
28        assert!(bits > 0 && bits < 8);
29
30        while bits > 0 {
31            self.ensure_byte();
32
33            // Determine the current bit position inside the current byte (0..7)
34            let bit_offset = self.bit_pos % 8;
35
36            // Determine how many bytes left to read. Min(bits left in this byte, bits to write)
37            let bits_in_current_byte = min(8 - bit_offset as u8, bits);
38
39            // Create a mask for the bits we are going to modify.
40            // Example: bit_offset = 2, bits_in_current_byte = 3
41            // mask = 00011100 (we will only touch bits 2,3,4)
42            let mask = ((1 << bits_in_current_byte) - 1) << bit_offset;
43
44            // Prepare the bits to write:
45            // 1️⃣ Take only the lowest 'bits_in_current_byte' bits from val
46            // 2️⃣ Shift them left by bit_offset to align inside the byte
47            // Example: val = 0b110101, bits_in_current_byte = 3, bit_offset = 2
48            // Step 1: val & 0b111 = 0b101
49            // Step 2: 0b101 << 2 = 0b10100 → shifted_val
50            let shifted_val = (val & ((1 << bits_in_current_byte) - 1)) << bit_offset;
51
52            let byte_pos = self.byte_pos();
53
54            // Clear the bits in this byte where we will write
55            self.buffer[byte_pos] &= !mask;
56
57            // Write the new bits into the cleared positions
58            self.buffer[byte_pos] |= shifted_val & mask;
59
60            // Decrease the number of bits remaining to write
61            bits -= bits_in_current_byte;
62
63            // Shift val right to remove the bits we've already written
64            val >>= bits_in_current_byte;
65
66            self.bit_pos += bits_in_current_byte as usize;
67        }
68    }
69
70    /// Write a full byte, starting at the next byte boundary
71    pub fn write_byte(&mut self, byte: u8) {
72        self.align_byte();
73        self.ensure_byte();
74
75        let byte_pos = self.byte_pos();
76        self.buffer[byte_pos] = byte;
77        self.bit_pos += 8;
78    }
79
80    /// Write a slice of bytes, starting at the next byte boundary
81    pub fn write_bytes(&mut self, data: &[u8]) {
82        self.align_byte();
83        self.buffer.extend_from_slice(data);
84        self.bit_pos += 8 * data.len();
85    }
86
87    /// Write a dynamic int, starting at the next byte bounary
88    /// The last bit is used as a continuation flag for the next byte
89    pub fn write_dyn_int(&mut self, mut val: u128) {
90        while val > 0 {
91            let mut encoded = val % 128;
92            val /= 128;
93            if val > 0 {
94                encoded |= 128;
95            }
96            self.write_byte(encoded as u8);
97        }
98    }
99
100    /// Write a integer of fixed size to the buffer
101    pub fn write_fixed_int<const S: usize, T: FixedInt<S>>(&mut self, val: T) {
102        self.write_bytes(&val.serialize());
103    }
104
105    /// Ensure the buffer has at least `byte_pos + 1` bytes
106    fn ensure_byte(&mut self) {
107        let byte_pos = self.byte_pos();
108        if byte_pos >= self.buffer.len() {
109            self.buffer.resize(byte_pos + 1, 0);
110        }
111    }
112
113    /// Align the stream to the next byte boundary
114    pub fn align_byte(&mut self) {
115        let rem = self.bit_pos % 8;
116        if rem != 0 {
117            self.bit_pos += 8 - rem;
118        }
119    }
120
121    /// Reset writing position
122    pub fn reset(&mut self) {
123        self.bit_pos = 0;
124    }
125
126    /// Get buffer length
127    pub fn len(&self) -> usize {
128        self.buffer.len()
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::BitStreamWriter;
135
136    /// Helper to format buffer as binary strings
137    fn buffer_to_bin(buffer: &[u8]) -> Vec<String> {
138        buffer.iter().map(|b| format!("{:08b}", b)).collect()
139    }
140
141    #[test]
142    fn test_write_bit() {
143        let mut buf = Vec::new();
144        let mut stream = BitStreamWriter::new(&mut buf);
145
146        stream.write_bit(true);
147        stream.write_bit(false);
148        stream.write_bit(true);
149        stream.write_bit(true); // 4 bits
150
151        assert_eq!(buf.len(), 1);
152        assert_eq!(buf[0], 0b00001101); // LSB-first: first bit is lowest
153    }
154
155    #[test]
156    fn test_write_small() {
157        let mut buf = Vec::new();
158        let mut stream = BitStreamWriter::new(&mut buf);
159
160        stream.write_small(0b101, 3); // write 3 bits
161        stream.write_small(0b11, 2); // write 2 bits
162        stream.write_small(0b111, 3); // write 3 bits
163
164        assert_eq!(buf.len(), 1);
165        assert_eq!(buf[0], 0b11111101); // bits packed LSB-first
166    }
167
168    #[test]
169    fn test_write_cross_byte() {
170        let mut buf = Vec::new();
171        let mut stream = BitStreamWriter::new(&mut buf);
172
173        // write 11 bits: first 7 bits fill almost one byte, next 3 bits spill into second byte
174        stream.write_small(0b00101011, 7);
175        stream.write_small(0b1101, 4);
176
177        assert_eq!(buf.len(), 2);
178        assert_eq!(buf[0], 0b10101011);
179        assert_eq!(buf[1], 0b00000110);
180    }
181
182    #[test]
183    fn test_write_byte() {
184        let mut buf = Vec::new();
185        let mut stream = BitStreamWriter::new(&mut buf);
186
187        stream.write_bit(true); // 1 bit
188        stream.write_byte(0xAA); // should align and write full byte
189
190        assert_eq!(buf.len(), 2);
191        assert_eq!(buf[0], 0b00000001); // first bit written, rest padded
192        assert_eq!(buf[1], 0xAA); // full byte
193    }
194
195    #[test]
196    fn test_write_bytes() {
197        let mut buf = Vec::new();
198        let mut stream = BitStreamWriter::new(&mut buf);
199
200        stream.write_bit(true); // 1 bit
201        stream.write_bytes(&[0xAA, 0xBB, 0xCC]); // align and write slice
202
203        assert_eq!(buf.len(), 4);
204        assert_eq!(buf[0], 0b00000001); // padding of first bit
205        assert_eq!(buf[1], 0xAA);
206        assert_eq!(buf[2], 0xBB);
207        assert_eq!(buf[3], 0xCC);
208    }
209
210    #[test]
211    fn test_alignment() {
212        let mut buf = Vec::new();
213        let mut stream = BitStreamWriter::new(&mut buf);
214
215        stream.write_small(0b11, 2); // 2 bits
216        stream.align_byte();
217        stream.write_byte(0xFF);
218
219        assert_eq!(buf.len(), 2);
220        assert_eq!(buf[0], 0b00000011); // 2 bits written, rest padded
221        assert_eq!(buf[1], 0xFF);
222    }
223
224    #[test]
225    fn test_multiple_operations() {
226        let mut buf = Vec::new();
227        let mut stream = BitStreamWriter::new(&mut buf);
228
229        stream.write_bit(true);
230        stream.write_small(0b101, 3);
231        stream.write_byte(0xAA);
232        stream.write_bytes(&[0xBB, 0xCC]);
233        stream.write_small(0b11, 2);
234
235        let bin = buffer_to_bin(&buf);
236        println!("{:?}", bin);
237
238        assert_eq!(buf.len(), 5);
239        assert_eq!(buf[0], 0b00001011); // first 4 bits
240        assert_eq!(buf[1], 0xAA); // write_byte
241        assert_eq!(buf[2], 0xBB);
242        assert_eq!(buf[3], 0xCC);
243        assert_eq!(buf[4], 0b00000011); // last 2 bits
244    }
245
246    #[test]
247    fn test_write_dyn_int() {
248        let mut buf = Vec::new();
249        let mut stream = BitStreamWriter::new(&mut buf);
250
251        stream.write_dyn_int(127);
252        assert_eq!(1, stream.len());
253
254        stream.write_dyn_int(128); // Crossed 127 = boundary of first byte
255        assert_eq!(3, stream.len());
256
257        stream.write_dyn_int(268435455); // 4 bytes boundary
258        assert_eq!(7, stream.len());
259
260        assert_eq!(vec![127, 128, 1, 255, 255, 255, 127], buf);
261    }
262
263    #[test]
264    fn test_write_fixed_int() {
265        let mut buf = Vec::new();
266        let mut stream = BitStreamWriter::new(&mut buf);
267
268        stream.write_fixed_int(1u8);
269        stream.write_fixed_int(1i8);
270        stream.write_fixed_int(2u16);
271        stream.write_fixed_int(2i16);
272        stream.write_fixed_int(3u32);
273        stream.write_fixed_int(3i32);
274        stream.write_fixed_int(4u64);
275        stream.write_fixed_int(4i64);
276        stream.write_fixed_int(5u128);
277        stream.write_fixed_int(5i128);
278
279        assert_eq!(
280            vec![
281                1, 2, 0, 2, 0, 4, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,
282                0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283                0, 0, 0, 0, 0, 10
284            ],
285            buf
286        );
287    }
288}