Skip to main content

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}