Skip to main content

bitstream/
reader.rs

1//! Bit-level reader with bounded operations.
2
3use crate::error::{BitError, BitResult};
4
5/// A bit-level reader for decoding packed binary data.
6///
7/// All read operations are bounds-checked and return errors on failure.
8/// The reader never panics on malformed input.
9#[derive(Debug)]
10pub struct BitReader<'a> {
11    data: &'a [u8],
12    bit_pos: usize,
13}
14
15impl<'a> BitReader<'a> {
16    /// Creates a new `BitReader` from a byte slice.
17    #[must_use]
18    pub const fn new(data: &'a [u8]) -> Self {
19        Self { data, bit_pos: 0 }
20    }
21
22    /// Returns the number of bits remaining to read.
23    #[must_use]
24    pub const fn bits_remaining(&self) -> usize {
25        self.data
26            .len()
27            .saturating_mul(8)
28            .saturating_sub(self.bit_pos)
29    }
30
31    /// Returns `true` if there are no more bits to read.
32    #[must_use]
33    pub const fn is_empty(&self) -> bool {
34        self.bits_remaining() == 0
35    }
36
37    /// Returns the current bit position.
38    #[must_use]
39    pub const fn bit_position(&self) -> usize {
40        self.bit_pos
41    }
42
43    /// Reads a single bit as a boolean.
44    pub fn read_bit(&mut self) -> BitResult<bool> {
45        if self.bits_remaining() == 0 {
46            return Err(BitError::UnexpectedEof {
47                requested: 1,
48                available: 0,
49            });
50        }
51        let byte_idx = self.bit_pos / 8;
52        let bit_idx = self.bit_pos % 8;
53        let bit = (self.data[byte_idx] >> (7 - bit_idx)) & 1;
54        self.bit_pos += 1;
55        Ok(bit == 1)
56    }
57
58    /// Reads up to 64 bits as an unsigned integer.
59    pub fn read_bits(&mut self, bits: u8) -> BitResult<u64> {
60        if bits > 64 {
61            return Err(BitError::InvalidBitCount { bits, max_bits: 64 });
62        }
63        if bits == 0 {
64            return Ok(0);
65        }
66        if bits as usize > self.bits_remaining() {
67            return Err(BitError::UnexpectedEof {
68                requested: bits as usize,
69                available: self.bits_remaining(),
70            });
71        }
72
73        let mut value = 0u64;
74        for _ in 0..bits {
75            value = (value << 1) | u64::from(self.read_bit()?);
76        }
77        Ok(value)
78    }
79
80    /// Aligns to the next byte boundary.
81    pub fn align_to_byte(&mut self) -> BitResult<()> {
82        let rem = self.bit_pos % 8;
83        if rem == 0 {
84            return Ok(());
85        }
86        let skip = 8 - rem;
87        if skip > self.bits_remaining() {
88            return Err(BitError::UnexpectedEof {
89                requested: skip,
90                available: self.bits_remaining(),
91            });
92        }
93        self.bit_pos += skip;
94        Ok(())
95    }
96
97    /// Reads a byte-aligned `u8`.
98    pub fn read_u8_aligned(&mut self) -> BitResult<u8> {
99        self.ensure_aligned()?;
100        self.ensure_bits(8)?;
101        let idx = self.bit_pos / 8;
102        let value = self.data[idx];
103        self.bit_pos += 8;
104        Ok(value)
105    }
106
107    /// Reads a byte-aligned `u16` (little-endian).
108    pub fn read_u16_aligned(&mut self) -> BitResult<u16> {
109        let bytes = self.read_aligned_bytes::<2>()?;
110        Ok(u16::from_le_bytes(bytes))
111    }
112
113    /// Reads a byte-aligned `u32` (little-endian).
114    pub fn read_u32_aligned(&mut self) -> BitResult<u32> {
115        let bytes = self.read_aligned_bytes::<4>()?;
116        Ok(u32::from_le_bytes(bytes))
117    }
118
119    /// Reads a byte-aligned `u64` (little-endian).
120    pub fn read_u64_aligned(&mut self) -> BitResult<u64> {
121        let bytes = self.read_aligned_bytes::<8>()?;
122        Ok(u64::from_le_bytes(bytes))
123    }
124
125    /// Reads a byte-aligned varint `u32`.
126    pub fn read_varu32(&mut self) -> BitResult<u32> {
127        self.ensure_aligned()?;
128        let mut result = 0u32;
129        for shift in (0..35).step_by(7) {
130            let byte = self.read_u8_aligned()?;
131            result |= u32::from(byte & 0x7F) << shift;
132            if byte & 0x80 == 0 {
133                return Ok(result);
134            }
135        }
136        Err(BitError::InvalidVarint)
137    }
138
139    /// Reads a byte-aligned zigzag varint `i32`.
140    pub fn read_vars32(&mut self) -> BitResult<i32> {
141        let value = self.read_varu32()?;
142        let decoded = ((value >> 1) as i32) ^ (-((value & 1) as i32));
143        Ok(decoded)
144    }
145
146    fn ensure_aligned(&self) -> BitResult<()> {
147        if self.bit_pos % 8 != 0 {
148            return Err(BitError::MisalignedAccess {
149                bit_position: self.bit_pos,
150            });
151        }
152        Ok(())
153    }
154
155    fn ensure_bits(&self, bits: usize) -> BitResult<()> {
156        let available = self.bits_remaining();
157        if bits > available {
158            return Err(BitError::UnexpectedEof {
159                requested: bits,
160                available,
161            });
162        }
163        Ok(())
164    }
165
166    fn read_aligned_bytes<const N: usize>(&mut self) -> BitResult<[u8; N]> {
167        self.ensure_aligned()?;
168        self.ensure_bits(N * 8)?;
169        let idx = self.bit_pos / 8;
170        let mut out = [0u8; N];
171        out.copy_from_slice(&self.data[idx..idx + N]);
172        self.bit_pos += N * 8;
173        Ok(out)
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn empty_reader() {
183        let reader = BitReader::new(&[]);
184        assert!(reader.is_empty());
185        assert_eq!(reader.bits_remaining(), 0);
186        assert_eq!(reader.bit_position(), 0);
187    }
188
189    #[test]
190    fn read_from_empty_fails() {
191        let mut reader = BitReader::new(&[]);
192        let result = reader.read_bit();
193        assert!(matches!(result, Err(BitError::UnexpectedEof { .. })));
194    }
195
196    #[test]
197    fn read_bits_across_bytes() {
198        let mut reader = BitReader::new(&[0b1111_0000, 0b0000_1111]);
199        assert_eq!(reader.read_bits(12).unwrap(), 0b1111_0000_0000);
200        assert_eq!(reader.bits_remaining(), 4);
201    }
202
203    #[test]
204    fn read_aligned_u32() {
205        let mut reader = BitReader::new(&[0x78, 0x56, 0x34, 0x12]);
206        assert_eq!(reader.read_u32_aligned().unwrap(), 0x1234_5678);
207    }
208
209    #[test]
210    fn read_misaligned_fails() {
211        let mut reader = BitReader::new(&[0xFF, 0xFF]);
212        reader.read_bits(1).unwrap();
213        let err = reader.read_u8_aligned().unwrap_err();
214        assert!(matches!(err, BitError::MisalignedAccess { .. }));
215    }
216
217    #[test]
218    fn read_varu32() {
219        let mut reader = BitReader::new(&[0xAC, 0x02]);
220        assert_eq!(reader.read_varu32().unwrap(), 300);
221    }
222
223    #[test]
224    fn read_vars32() {
225        let mut reader = BitReader::new(&[0x01]);
226        assert_eq!(reader.read_vars32().unwrap(), -1);
227    }
228
229    #[test]
230    fn read_varu32_invalid() {
231        let mut reader = BitReader::new(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]);
232        let err = reader.read_varu32().unwrap_err();
233        assert!(matches!(err, BitError::InvalidVarint));
234    }
235}