oxideav_bitstream/bit_writer.rs
1//! Shared MSB-first bit writer — the inverse of [`BitReader`].
2//!
3//! [`BitWriter`] accumulates bits MSB-first into an internal byte
4//! buffer so that a value written with [`BitWriter::write_bits`] and
5//! then read back with [`crate::bit_reader::BitReader::u`] at the same
6//! bit offset round-trips exactly. The Exp-Golomb writers
7//! ([`BitWriter::write_ue`] / [`BitWriter::write_se`]) are the inverses
8//! of [`crate::bit_reader::BitReader::ue`] /
9//! [`crate::bit_reader::BitReader::se`].
10//!
11//! # Conventions
12//!
13//! - Bits are packed MSB-first inside each byte, matching
14//! [`BitReader`](crate::bit_reader::BitReader).
15//! - The buffer grows one byte at a time; partial trailing bits are
16//! left-aligned (the unused low bits of the final byte are zero).
17//! - [`BitWriter::finish`] returns the accumulated bytes. Trailing
18//! zero-padding is implicit: if you wrote 11 bits you get 2 bytes
19//! with the low 5 bits of the second byte zero.
20//!
21//! # Clean-room
22//!
23//! This is an original primitive. No external bit-IO source was
24//! consulted; it is defined purely as the algebraic inverse of the
25//! in-crate [`BitReader`].
26
27use crate::BitstreamError;
28
29/// MSB-first bit writer accumulating into an owned `Vec<u8>`.
30#[derive(Debug, Default, Clone)]
31pub struct BitWriter {
32 bytes: Vec<u8>,
33 /// Number of valid bits in the buffer (≤ `bytes.len() * 8`).
34 bit_pos: usize,
35}
36
37impl BitWriter {
38 /// Create an empty writer.
39 pub fn new() -> Self {
40 Self::default()
41 }
42
43 /// Number of bits written so far.
44 pub fn bit_pos(&self) -> usize {
45 self.bit_pos
46 }
47
48 /// True if the next write would start on a byte boundary.
49 pub fn byte_aligned(&self) -> bool {
50 self.bit_pos % 8 == 0
51 }
52
53 /// Append a single bit (only bit 0 of `bit` is used).
54 pub fn write_bit(&mut self, bit: u32) {
55 let byte_idx = self.bit_pos / 8;
56 if byte_idx >= self.bytes.len() {
57 self.bytes.push(0);
58 }
59 if bit & 1 != 0 {
60 let shift = 7 - (self.bit_pos % 8) as u32;
61 self.bytes[byte_idx] |= 1u8 << shift;
62 }
63 self.bit_pos += 1;
64 }
65
66 /// Write the low `n` bits of `value` MSB-first. `n` must be ≤ 32;
67 /// bits above bit `n-1` of `value` are ignored.
68 pub fn write_bits(&mut self, value: u32, n: u32) {
69 debug_assert!(n <= 32, "BitWriter::write_bits n={n} > 32");
70 for i in (0..n).rev() {
71 self.write_bit((value >> i) & 1);
72 }
73 }
74
75 /// Write the low `n` bits of a `u64` MSB-first. `n` must be ≤ 64.
76 pub fn write_bits_u64(&mut self, value: u64, n: u32) {
77 debug_assert!(n <= 64, "BitWriter::write_bits_u64 n={n} > 64");
78 for i in (0..n).rev() {
79 self.write_bit(((value >> i) & 1) as u32);
80 }
81 }
82
83 /// Write an unsigned Exp-Golomb (`ue(v)`) code — the inverse of
84 /// [`BitReader::ue`](crate::bit_reader::BitReader::ue). Refuses
85 /// `u32::MAX` because `code_num = value + 1` would overflow.
86 pub fn write_ue(&mut self, value: u32) -> Result<(), BitstreamError> {
87 if value == u32::MAX {
88 return Err(BitstreamError::invalid(
89 "write_ue: value u32::MAX has no representable ue(v) code",
90 ));
91 }
92 let code_num = value + 1; // ≥ 1, so it has a defined MSB.
93 let bits = 32 - code_num.leading_zeros(); // number of significant bits
94 let leading_zeros = bits - 1;
95 for _ in 0..leading_zeros {
96 self.write_bit(0);
97 }
98 // `code_num` written in `bits` bits is `1` then the suffix;
99 // this matches the reader's `(1 << lz) - 1 + suffix` decode.
100 self.write_bits(code_num, bits);
101 Ok(())
102 }
103
104 /// Write a signed Exp-Golomb (`se(v)`) code — the inverse of
105 /// [`BitReader::se`](crate::bit_reader::BitReader::se).
106 pub fn write_se(&mut self, value: i32) -> Result<(), BitstreamError> {
107 // Mapping (H.264 9.1.1): 0→0, +k→2k-1, -k→2k for k>0.
108 let code_num: u32 = if value == 0 {
109 0
110 } else if value > 0 {
111 // 2*value - 1, computed without i32 overflow for i32::MAX.
112 (value as u32)
113 .checked_mul(2)
114 .and_then(|x| x.checked_sub(1))
115 .ok_or_else(|| BitstreamError::invalid("write_se: value too large for se(v)"))?
116 } else {
117 // value < 0: 2*|value|. `-(value as i64)` avoids i32::MIN
118 // negation UB; result fits u32 for all valid magnitudes.
119 let mag = -(value as i64) as u64;
120 mag.checked_mul(2)
121 .filter(|&x| x <= u32::MAX as u64)
122 .map(|x| x as u32)
123 .ok_or_else(|| BitstreamError::invalid("write_se: value too large for se(v)"))?
124 };
125 self.write_ue(code_num)
126 }
127
128 /// Pad with zero bits up to the next byte boundary.
129 pub fn align_to_byte(&mut self) {
130 while !self.byte_aligned() {
131 self.write_bit(0);
132 }
133 }
134
135 /// Consume the writer and return the accumulated bytes. The final
136 /// byte's unused low bits (if the bit count is not a multiple of 8)
137 /// are zero.
138 pub fn finish(self) -> Vec<u8> {
139 self.bytes
140 }
141
142 /// Borrow the accumulated bytes without consuming the writer.
143 pub fn as_bytes(&self) -> &[u8] {
144 &self.bytes
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::bit_reader::BitReader;
152
153 #[test]
154 fn write_bits_matches_known_pattern() {
155 let mut w = BitWriter::new();
156 w.write_bits(0b1010, 4);
157 w.write_bits(0b1100, 4);
158 w.write_bits(0b1111_0000, 8);
159 assert_eq!(w.finish(), vec![0b1010_1100, 0b1111_0000]);
160 }
161
162 #[test]
163 fn ue_roundtrips_small_values() {
164 let mut w = BitWriter::new();
165 for v in 0..=10u32 {
166 w.write_ue(v).unwrap();
167 }
168 let bytes = w.finish();
169 let mut r = BitReader::new(&bytes);
170 for v in 0..=10u32 {
171 assert_eq!(r.ue().unwrap(), v);
172 }
173 }
174
175 #[test]
176 fn se_roundtrips_signed_values() {
177 let mut w = BitWriter::new();
178 let vals = [0, 1, -1, 2, -2, 100, -100];
179 for &v in &vals {
180 w.write_se(v).unwrap();
181 }
182 let bytes = w.finish();
183 let mut r = BitReader::new(&bytes);
184 for &v in &vals {
185 assert_eq!(r.se().unwrap(), v);
186 }
187 }
188
189 #[test]
190 fn ue_rejects_u32_max() {
191 let mut w = BitWriter::new();
192 assert!(w.write_ue(u32::MAX).is_err());
193 }
194}