Skip to main content

oximedia_io/bits/
reader.rs

1//! Bit-level reader for parsing binary formats.
2
3use oximedia_core::{OxiError, OxiResult};
4
5/// Bit-level reader for parsing binary formats.
6///
7/// `BitReader` allows reading individual bits and multi-bit values from
8/// a byte slice. It tracks both byte position and bit position within
9/// the current byte.
10///
11/// # Bit Ordering
12///
13/// Bits are read from MSB (most significant bit) to LSB (least significant bit)
14/// within each byte. This is the standard ordering used by most video codecs
15/// including H.264, HEVC, AV1, and VP9.
16///
17/// # Example
18///
19/// ```
20/// use oximedia_io::bits::BitReader;
21///
22/// let data = [0b10110100, 0b11001010];
23/// let mut reader = BitReader::new(&data);
24///
25/// // Read individual bits (from MSB to LSB)
26/// assert_eq!(reader.read_bit()?, 1);
27/// assert_eq!(reader.read_bit()?, 0);
28/// assert_eq!(reader.read_bit()?, 1);
29/// assert_eq!(reader.read_bit()?, 1);
30///
31/// // Read multiple bits as a value
32/// assert_eq!(reader.read_bits(4)?, 0b0100);
33/// # Ok::<(), oximedia_core::OxiError>(())
34/// ```
35#[derive(Debug, Clone)]
36pub struct BitReader<'a> {
37    /// The underlying byte slice
38    data: &'a [u8],
39    /// Current byte position
40    byte_pos: usize,
41    /// Current bit position within the byte (0-7, where 0 is MSB)
42    bit_pos: u8,
43}
44
45#[allow(clippy::elidable_lifetime_names)]
46impl<'a> BitReader<'a> {
47    /// Creates a new `BitReader` from a byte slice.
48    ///
49    /// # Example
50    ///
51    /// ```
52    /// use oximedia_io::bits::BitReader;
53    ///
54    /// let data = [0xFF, 0x00];
55    /// let reader = BitReader::new(&data);
56    /// assert!(reader.has_more_data());
57    /// ```
58    #[must_use]
59    pub const fn new(data: &'a [u8]) -> Self {
60        Self {
61            data,
62            byte_pos: 0,
63            bit_pos: 0,
64        }
65    }
66
67    /// Reads a single bit from the stream.
68    ///
69    /// Returns `0` or `1`.
70    ///
71    /// # Errors
72    ///
73    /// Returns [`OxiError::UnexpectedEof`] if there are no more bits to read.
74    ///
75    /// # Example
76    ///
77    /// ```
78    /// use oximedia_io::bits::BitReader;
79    ///
80    /// let data = [0b10000000];
81    /// let mut reader = BitReader::new(&data);
82    ///
83    /// assert_eq!(reader.read_bit()?, 1);
84    /// assert_eq!(reader.read_bit()?, 0);
85    /// # Ok::<(), oximedia_core::OxiError>(())
86    /// ```
87    pub fn read_bit(&mut self) -> OxiResult<u8> {
88        if self.byte_pos >= self.data.len() {
89            return Err(OxiError::UnexpectedEof);
90        }
91
92        // Read bit from MSB to LSB (bit_pos 0 = MSB)
93        let bit = (self.data[self.byte_pos] >> (7 - self.bit_pos)) & 1;
94        self.bit_pos += 1;
95
96        if self.bit_pos == 8 {
97            self.bit_pos = 0;
98            self.byte_pos += 1;
99        }
100
101        Ok(bit)
102    }
103
104    /// Reads up to 64 bits from the stream.
105    ///
106    /// # Arguments
107    ///
108    /// * `n` - Number of bits to read (0-64)
109    ///
110    /// # Errors
111    ///
112    /// Returns [`OxiError::InvalidData`] if `n > 64`.
113    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
114    ///
115    /// # Example
116    ///
117    /// ```
118    /// use oximedia_io::bits::BitReader;
119    ///
120    /// let data = [0b10110100, 0b11001010];
121    /// let mut reader = BitReader::new(&data);
122    ///
123    /// assert_eq!(reader.read_bits(4)?, 0b1011);
124    /// assert_eq!(reader.read_bits(4)?, 0b0100);
125    /// assert_eq!(reader.read_bits(8)?, 0b11001010);
126    /// # Ok::<(), oximedia_core::OxiError>(())
127    /// ```
128    pub fn read_bits(&mut self, n: u8) -> OxiResult<u64> {
129        if n > 64 {
130            return Err(OxiError::InvalidData(
131                "Cannot read more than 64 bits at once".to_string(),
132            ));
133        }
134
135        if n == 0 {
136            return Ok(0);
137        }
138
139        // Fast path: byte-aligned read for multiples of 8 bits.
140        // When bit_pos == 0 the reader is on a byte boundary; if n is a
141        // multiple of 8 and enough bytes remain we can use from_be_bytes
142        // instead of iterating bit-by-bit (up to 8× fewer iterations).
143        if self.bit_pos == 0 && n % 8 == 0 {
144            let num_bytes = usize::from(n / 8);
145            if self.byte_pos + num_bytes <= self.data.len() {
146                let slice = &self.data[self.byte_pos..self.byte_pos + num_bytes];
147                let value = match num_bytes {
148                    1 => u64::from(slice[0]),
149                    2 => {
150                        let arr: [u8; 2] = [slice[0], slice[1]];
151                        u64::from(u16::from_be_bytes(arr))
152                    }
153                    4 => {
154                        let arr: [u8; 4] = [slice[0], slice[1], slice[2], slice[3]];
155                        u64::from(u32::from_be_bytes(arr))
156                    }
157                    8 => {
158                        let arr: [u8; 8] = [
159                            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6],
160                            slice[7],
161                        ];
162                        u64::from_be_bytes(arr)
163                    }
164                    // For other multiples-of-8 (3, 5, 6, 7 bytes) use a
165                    // loop over whole bytes — still avoids per-bit branching.
166                    _ => {
167                        let mut v = 0u64;
168                        for &byte in slice {
169                            v = (v << 8) | u64::from(byte);
170                        }
171                        v
172                    }
173                };
174                self.byte_pos += num_bytes;
175                return Ok(value);
176            }
177        }
178
179        // Slow path: unaligned or non-multiple-of-8 — bit-by-bit loop.
180        let mut value = 0u64;
181        for _ in 0..n {
182            value = (value << 1) | u64::from(self.read_bit()?);
183        }
184
185        Ok(value)
186    }
187
188    /// Reads an 8-bit unsigned integer.
189    ///
190    /// # Errors
191    ///
192    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
193    ///
194    /// # Example
195    ///
196    /// ```
197    /// use oximedia_io::bits::BitReader;
198    ///
199    /// let data = [0x12, 0x34];
200    /// let mut reader = BitReader::new(&data);
201    ///
202    /// assert_eq!(reader.read_u8()?, 0x12);
203    /// assert_eq!(reader.read_u8()?, 0x34);
204    /// # Ok::<(), oximedia_core::OxiError>(())
205    /// ```
206    #[allow(clippy::cast_possible_truncation)]
207    pub fn read_u8(&mut self) -> OxiResult<u8> {
208        Ok(self.read_bits(8)? as u8)
209    }
210
211    /// Reads a 16-bit unsigned integer in big-endian order.
212    ///
213    /// # Errors
214    ///
215    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
216    ///
217    /// # Example
218    ///
219    /// ```
220    /// use oximedia_io::bits::BitReader;
221    ///
222    /// let data = [0x12, 0x34];
223    /// let mut reader = BitReader::new(&data);
224    ///
225    /// assert_eq!(reader.read_u16()?, 0x1234);
226    /// # Ok::<(), oximedia_core::OxiError>(())
227    /// ```
228    #[allow(clippy::cast_possible_truncation)]
229    pub fn read_u16(&mut self) -> OxiResult<u16> {
230        Ok(self.read_bits(16)? as u16)
231    }
232
233    /// Reads a 32-bit unsigned integer in big-endian order.
234    ///
235    /// # Errors
236    ///
237    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
238    ///
239    /// # Example
240    ///
241    /// ```
242    /// use oximedia_io::bits::BitReader;
243    ///
244    /// let data = [0x12, 0x34, 0x56, 0x78];
245    /// let mut reader = BitReader::new(&data);
246    ///
247    /// assert_eq!(reader.read_u32()?, 0x12345678);
248    /// # Ok::<(), oximedia_core::OxiError>(())
249    /// ```
250    #[allow(clippy::cast_possible_truncation)]
251    pub fn read_u32(&mut self) -> OxiResult<u32> {
252        Ok(self.read_bits(32)? as u32)
253    }
254
255    /// Reads a 64-bit unsigned integer in big-endian order.
256    ///
257    /// # Errors
258    ///
259    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
260    ///
261    /// # Example
262    ///
263    /// ```
264    /// use oximedia_io::bits::BitReader;
265    ///
266    /// let data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
267    /// let mut reader = BitReader::new(&data);
268    ///
269    /// assert_eq!(reader.read_u64()?, 0x123456789ABCDEF0);
270    /// # Ok::<(), oximedia_core::OxiError>(())
271    /// ```
272    pub fn read_u64(&mut self) -> OxiResult<u64> {
273        self.read_bits(64)
274    }
275
276    /// Reads a boolean flag (single bit).
277    ///
278    /// Returns `true` if the bit is 1, `false` if 0.
279    ///
280    /// # Errors
281    ///
282    /// Returns [`OxiError::UnexpectedEof`] if there are no more bits.
283    ///
284    /// # Example
285    ///
286    /// ```
287    /// use oximedia_io::bits::BitReader;
288    ///
289    /// let data = [0b10000000];
290    /// let mut reader = BitReader::new(&data);
291    ///
292    /// assert!(reader.read_flag()?);
293    /// assert!(!reader.read_flag()?);
294    /// # Ok::<(), oximedia_core::OxiError>(())
295    /// ```
296    pub fn read_flag(&mut self) -> OxiResult<bool> {
297        Ok(self.read_bit()? != 0)
298    }
299
300    /// Skips the specified number of bits.
301    ///
302    /// This method silently ignores attempts to skip past the end of data.
303    ///
304    /// # Example
305    ///
306    /// ```
307    /// use oximedia_io::bits::BitReader;
308    ///
309    /// let data = [0xFF, 0x00];
310    /// let mut reader = BitReader::new(&data);
311    ///
312    /// reader.skip_bits(4);
313    /// assert_eq!(reader.bits_read(), 4);
314    /// ```
315    pub fn skip_bits(&mut self, n: usize) {
316        for _ in 0..n {
317            if self.read_bit().is_err() {
318                break;
319            }
320        }
321    }
322
323    /// Aligns the reader to the next byte boundary.
324    ///
325    /// If the reader is already at a byte boundary, this is a no-op.
326    /// Otherwise, the remaining bits in the current byte are skipped.
327    ///
328    /// # Example
329    ///
330    /// ```
331    /// use oximedia_io::bits::BitReader;
332    ///
333    /// let data = [0xFF, 0x00];
334    /// let mut reader = BitReader::new(&data);
335    ///
336    /// reader.read_bits(3)?;  // Read 3 bits
337    /// reader.byte_align();           // Skip remaining 5 bits
338    /// assert_eq!(reader.bits_read(), 8);
339    /// # Ok::<(), oximedia_core::OxiError>(())
340    /// ```
341    pub fn byte_align(&mut self) {
342        if self.bit_pos != 0 {
343            self.bit_pos = 0;
344            self.byte_pos += 1;
345        }
346    }
347
348    /// Returns `true` if there is more data available to read.
349    ///
350    /// # Example
351    ///
352    /// ```
353    /// use oximedia_io::bits::BitReader;
354    ///
355    /// let data = [0xFF];
356    /// let mut reader = BitReader::new(&data);
357    ///
358    /// assert!(reader.has_more_data());
359    /// reader.read_bits(8)?;
360    /// assert!(!reader.has_more_data());
361    /// # Ok::<(), oximedia_core::OxiError>(())
362    /// ```
363    #[must_use]
364    pub fn has_more_data(&self) -> bool {
365        self.byte_pos < self.data.len()
366    }
367
368    /// Returns the number of complete bytes remaining.
369    ///
370    /// This does not count partial bytes at the current position.
371    ///
372    /// # Example
373    ///
374    /// ```
375    /// use oximedia_io::bits::BitReader;
376    ///
377    /// let data = [0xFF, 0x00, 0xFF];
378    /// let mut reader = BitReader::new(&data);
379    ///
380    /// assert_eq!(reader.remaining_bytes(), 3);
381    /// reader.read_bits(4)?;
382    /// assert_eq!(reader.remaining_bytes(), 2);  // Partial byte not counted
383    /// # Ok::<(), oximedia_core::OxiError>(())
384    /// ```
385    #[must_use]
386    pub fn remaining_bytes(&self) -> usize {
387        if self.byte_pos >= self.data.len() {
388            0
389        } else {
390            self.data.len() - self.byte_pos - usize::from(self.bit_pos > 0)
391        }
392    }
393
394    /// Returns the total number of bits read so far.
395    ///
396    /// # Example
397    ///
398    /// ```
399    /// use oximedia_io::bits::BitReader;
400    ///
401    /// let data = [0xFF, 0x00];
402    /// let mut reader = BitReader::new(&data);
403    ///
404    /// assert_eq!(reader.bits_read(), 0);
405    /// reader.read_bits(5)?;
406    /// assert_eq!(reader.bits_read(), 5);
407    /// reader.read_bits(3)?;
408    /// assert_eq!(reader.bits_read(), 8);
409    /// # Ok::<(), oximedia_core::OxiError>(())
410    /// ```
411    #[must_use]
412    pub fn bits_read(&self) -> usize {
413        self.byte_pos * 8 + self.bit_pos as usize
414    }
415
416    /// Returns the total number of remaining bits.
417    ///
418    /// # Example
419    ///
420    /// ```
421    /// use oximedia_io::bits::BitReader;
422    ///
423    /// let data = [0xFF, 0x00];
424    /// let mut reader = BitReader::new(&data);
425    ///
426    /// assert_eq!(reader.remaining_bits(), 16);
427    /// reader.read_bits(5)?;
428    /// assert_eq!(reader.remaining_bits(), 11);
429    /// # Ok::<(), oximedia_core::OxiError>(())
430    /// ```
431    #[must_use]
432    pub fn remaining_bits(&self) -> usize {
433        if self.byte_pos >= self.data.len() {
434            0
435        } else {
436            (self.data.len() - self.byte_pos) * 8 - self.bit_pos as usize
437        }
438    }
439
440    /// Peeks at the next bit without consuming it.
441    ///
442    /// # Errors
443    ///
444    /// Returns [`OxiError::UnexpectedEof`] if there are no more bits.
445    ///
446    /// # Example
447    ///
448    /// ```
449    /// use oximedia_io::bits::BitReader;
450    ///
451    /// let data = [0b10000000];
452    /// let mut reader = BitReader::new(&data);
453    ///
454    /// assert_eq!(reader.peek_bit()?, 1);
455    /// assert_eq!(reader.peek_bit()?, 1);  // Still 1, not consumed
456    /// assert_eq!(reader.read_bit()?, 1);  // Now consumed
457    /// assert_eq!(reader.peek_bit()?, 0);  // Next bit
458    /// # Ok::<(), oximedia_core::OxiError>(())
459    /// ```
460    pub fn peek_bit(&self) -> OxiResult<u8> {
461        if self.byte_pos >= self.data.len() {
462            return Err(OxiError::UnexpectedEof);
463        }
464
465        Ok((self.data[self.byte_pos] >> (7 - self.bit_pos)) & 1)
466    }
467
468    /// Returns the underlying byte slice.
469    #[must_use]
470    pub const fn data(&self) -> &'a [u8] {
471        self.data
472    }
473
474    /// Returns the current byte position.
475    #[must_use]
476    pub const fn byte_position(&self) -> usize {
477        self.byte_pos
478    }
479
480    /// Returns the current bit position within the current byte (0-7).
481    #[must_use]
482    pub const fn bit_position(&self) -> u8 {
483        self.bit_pos
484    }
485}
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490
491    #[test]
492    fn test_new() {
493        let data = [0xFF, 0x00];
494        let reader = BitReader::new(&data);
495        assert_eq!(reader.byte_position(), 0);
496        assert_eq!(reader.bit_position(), 0);
497        assert!(reader.has_more_data());
498    }
499
500    #[test]
501    fn test_read_bit() {
502        let data = [0b10110100];
503        let mut reader = BitReader::new(&data);
504
505        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 1);
506        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 0);
507        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 1);
508        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 1);
509        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 0);
510        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 1);
511        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 0);
512        assert_eq!(reader.read_bit().expect("read_bit should succeed"), 0);
513    }
514
515    #[test]
516    fn test_read_bits() {
517        let data = [0b10110100, 0b11001010];
518        let mut reader = BitReader::new(&data);
519
520        assert_eq!(
521            reader.read_bits(4).expect("read_bits should succeed"),
522            0b1011
523        );
524        assert_eq!(
525            reader.read_bits(4).expect("read_bits should succeed"),
526            0b0100
527        );
528        assert_eq!(
529            reader.read_bits(8).expect("read_bits should succeed"),
530            0b11001010
531        );
532    }
533
534    #[test]
535    fn test_read_bits_across_bytes() {
536        let data = [0b10110100, 0b11001010];
537        let mut reader = BitReader::new(&data);
538
539        assert_eq!(
540            reader.read_bits(12).expect("read_bits should succeed"),
541            0b101101001100
542        );
543        assert_eq!(
544            reader.read_bits(4).expect("read_bits should succeed"),
545            0b1010
546        );
547    }
548
549    #[test]
550    fn test_read_bits_zero() {
551        let data = [0xFF];
552        let mut reader = BitReader::new(&data);
553        assert_eq!(reader.read_bits(0).expect("read_bits should succeed"), 0);
554        assert_eq!(reader.bits_read(), 0);
555    }
556
557    #[test]
558    fn test_read_bits_too_many() {
559        let data = [0xFF];
560        let mut reader = BitReader::new(&data);
561        let result = reader.read_bits(65);
562        assert!(result.is_err());
563    }
564
565    #[test]
566    fn test_read_u8() {
567        let data = [0x12, 0x34];
568        let mut reader = BitReader::new(&data);
569        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x12);
570        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x34);
571    }
572
573    #[test]
574    fn test_read_u16() {
575        let data = [0x12, 0x34];
576        let mut reader = BitReader::new(&data);
577        assert_eq!(reader.read_u16().expect("read_u16 should succeed"), 0x1234);
578    }
579
580    #[test]
581    fn test_read_u32() {
582        let data = [0x12, 0x34, 0x56, 0x78];
583        let mut reader = BitReader::new(&data);
584        assert_eq!(
585            reader.read_u32().expect("read_u32 should succeed"),
586            0x1234_5678
587        );
588    }
589
590    #[test]
591    fn test_read_u64() {
592        let data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
593        let mut reader = BitReader::new(&data);
594        assert_eq!(
595            reader.read_u64().expect("read_u64 should succeed"),
596            0x1234_5678_9ABC_DEF0
597        );
598    }
599
600    #[test]
601    fn test_read_flag() {
602        let data = [0b10100000];
603        let mut reader = BitReader::new(&data);
604        assert!(reader.read_flag().expect("read_flag should succeed"));
605        assert!(!reader.read_flag().expect("read_flag should succeed"));
606        assert!(reader.read_flag().expect("read_flag should succeed"));
607    }
608
609    #[test]
610    fn test_skip_bits() {
611        let data = [0xFF, 0x12];
612        let mut reader = BitReader::new(&data);
613        reader.skip_bits(8);
614        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x12);
615    }
616
617    #[test]
618    fn test_byte_align() {
619        let data = [0xFF, 0x12];
620        let mut reader = BitReader::new(&data);
621        reader.read_bits(3).expect("read_bits should succeed");
622        reader.byte_align();
623        assert_eq!(reader.bits_read(), 8);
624        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x12);
625    }
626
627    #[test]
628    fn test_byte_align_already_aligned() {
629        let data = [0xFF, 0x12];
630        let mut reader = BitReader::new(&data);
631        reader.byte_align();
632        assert_eq!(reader.bits_read(), 0);
633    }
634
635    #[test]
636    fn test_has_more_data() {
637        let data = [0xFF];
638        let mut reader = BitReader::new(&data);
639        assert!(reader.has_more_data());
640        reader.read_bits(8).expect("read_bits should succeed");
641        assert!(!reader.has_more_data());
642    }
643
644    #[test]
645    fn test_remaining_bytes() {
646        let data = [0xFF, 0x00, 0xFF];
647        let mut reader = BitReader::new(&data);
648        assert_eq!(reader.remaining_bytes(), 3);
649        reader.read_bits(4).expect("read_bits should succeed");
650        assert_eq!(reader.remaining_bytes(), 2);
651        reader.read_bits(4).expect("read_bits should succeed");
652        assert_eq!(reader.remaining_bytes(), 2);
653    }
654
655    #[test]
656    fn test_bits_read() {
657        let data = [0xFF, 0x00];
658        let mut reader = BitReader::new(&data);
659        assert_eq!(reader.bits_read(), 0);
660        reader.read_bits(5).expect("read_bits should succeed");
661        assert_eq!(reader.bits_read(), 5);
662        reader.read_bits(3).expect("read_bits should succeed");
663        assert_eq!(reader.bits_read(), 8);
664    }
665
666    #[test]
667    fn test_remaining_bits() {
668        let data = [0xFF, 0x00];
669        let mut reader = BitReader::new(&data);
670        assert_eq!(reader.remaining_bits(), 16);
671        reader.read_bits(5).expect("read_bits should succeed");
672        assert_eq!(reader.remaining_bits(), 11);
673    }
674
675    #[test]
676    fn test_peek_bit() {
677        let data = [0b10000000];
678        let mut reader = BitReader::new(&data);
679        assert_eq!(reader.peek_bit().expect("peek_bit should succeed"), 1);
680        assert_eq!(reader.peek_bit().expect("peek_bit should succeed"), 1);
681        assert_eq!(reader.bits_read(), 0);
682        reader.read_bit().expect("read_bit should succeed");
683        assert_eq!(reader.peek_bit().expect("peek_bit should succeed"), 0);
684    }
685
686    #[test]
687    fn test_eof() {
688        let data = [0xFF];
689        let mut reader = BitReader::new(&data);
690        reader.read_bits(8).expect("read_bits should succeed");
691        assert!(reader.read_bit().is_err());
692        assert!(reader.read_bits(1).is_err());
693        assert!(reader.peek_bit().is_err());
694    }
695
696    #[test]
697    fn test_empty_data() {
698        let data: [u8; 0] = [];
699        let reader = BitReader::new(&data);
700        assert!(!reader.has_more_data());
701        assert_eq!(reader.remaining_bytes(), 0);
702        assert_eq!(reader.remaining_bits(), 0);
703    }
704
705    // Additional comprehensive tests
706
707    #[test]
708    fn test_read_64_bits_max() {
709        let data = [0xFF; 8];
710        let mut reader = BitReader::new(&data);
711        let value = reader.read_bits(64).expect("read_bits should succeed");
712        assert_eq!(value, u64::MAX);
713    }
714
715    #[test]
716    fn test_read_across_multiple_bytes() {
717        // Test reading across 3 byte boundaries
718        let data = [0b10101010, 0b11001100, 0b11110000];
719        let mut reader = BitReader::new(&data);
720
721        assert_eq!(
722            reader.read_bits(4).expect("read_bits should succeed"),
723            0b1010
724        );
725        assert_eq!(
726            reader.read_bits(8).expect("read_bits should succeed"),
727            0b1010_1100
728        );
729        assert_eq!(
730            reader.read_bits(12).expect("read_bits should succeed"),
731            0b1100_1111_0000
732        );
733    }
734
735    #[test]
736    fn test_mixed_read_operations() {
737        let data = [0b11010010, 0b10110100];
738        let mut reader = BitReader::new(&data);
739
740        assert!(reader.read_flag().expect("read_flag should succeed")); // 1
741        assert!(reader.read_flag().expect("read_flag should succeed")); // 1
742        assert!(!reader.read_flag().expect("read_flag should succeed")); // 0
743        assert_eq!(
744            reader.read_bits(5).expect("read_bits should succeed"),
745            0b10010
746        ); // 10010
747        assert_eq!(
748            reader.read_u8().expect("read_u8 should succeed"),
749            0b10110100
750        );
751    }
752
753    #[test]
754    fn test_byte_align_at_boundary() {
755        let data = [0xFF, 0x12, 0x34];
756        let mut reader = BitReader::new(&data);
757
758        reader.byte_align(); // Should do nothing
759        assert_eq!(reader.bits_read(), 0);
760
761        reader.read_bits(8).expect("read_bits should succeed");
762        reader.byte_align(); // Should still do nothing
763        assert_eq!(reader.bits_read(), 8);
764    }
765
766    #[test]
767    fn test_skip_bits_partial_byte() {
768        let data = [0xFF, 0x12];
769        let mut reader = BitReader::new(&data);
770
771        reader.skip_bits(3);
772        assert_eq!(
773            reader.read_bits(5).expect("read_bits should succeed"),
774            0b11111
775        );
776        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x12);
777    }
778
779    #[test]
780    fn test_skip_bits_beyond_end() {
781        let data = [0xFF];
782        let mut reader = BitReader::new(&data);
783
784        reader.skip_bits(100); // Should stop at end
785        assert!(!reader.has_more_data());
786    }
787
788    #[test]
789    fn test_remaining_methods_consistency() {
790        let data = [0xFF, 0x00, 0xFF, 0x00];
791        let mut reader = BitReader::new(&data);
792
793        assert_eq!(reader.remaining_bits(), 32);
794        assert_eq!(reader.remaining_bytes(), 4);
795
796        reader.read_bits(5).expect("read_bits should succeed");
797        assert_eq!(reader.remaining_bits(), 27);
798        assert_eq!(reader.remaining_bytes(), 3);
799
800        reader.read_bits(11).expect("read_bits should succeed"); // Total 16 bits = 2 bytes
801        assert_eq!(reader.remaining_bits(), 16);
802        assert_eq!(reader.remaining_bytes(), 2);
803    }
804
805    #[test]
806    fn test_peek_doesnt_consume() {
807        let data = [0b10110100];
808        let mut reader = BitReader::new(&data);
809
810        for _ in 0..10 {
811            assert_eq!(reader.peek_bit().expect("peek_bit should succeed"), 1);
812        }
813        assert_eq!(reader.bits_read(), 0);
814
815        reader.read_bit().expect("read_bit should succeed");
816        for _ in 0..10 {
817            assert_eq!(reader.peek_bit().expect("peek_bit should succeed"), 0);
818        }
819        assert_eq!(reader.bits_read(), 1);
820    }
821
822    #[test]
823    fn test_read_all_integer_types() {
824        // Test reading all integer types in sequence
825        let data = [
826            0x12, // u8
827            0x34, 0x56, // u16
828            0x78, 0x9A, 0xBC, 0xDE, // u32
829            0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // u64
830        ];
831        let mut reader = BitReader::new(&data);
832
833        assert_eq!(reader.read_u8().expect("read_u8 should succeed"), 0x12);
834        assert_eq!(reader.read_u16().expect("read_u16 should succeed"), 0x3456);
835        assert_eq!(
836            reader.read_u32().expect("read_u32 should succeed"),
837            0x789A_BCDE
838        );
839        assert_eq!(
840            reader.read_u64().expect("read_u64 should succeed"),
841            0xF011_2233_4455_6677
842        );
843        assert!(!reader.has_more_data());
844    }
845
846    #[test]
847    fn test_unaligned_integer_reads() {
848        let data = [0xFF, 0x12, 0x34, 0x56, 0x78];
849        let mut reader = BitReader::new(&data);
850
851        reader.read_bits(4).expect("read_bits should succeed"); // Unalign by 4 bits
852
853        // Now all integer reads should work across byte boundaries
854        assert_eq!(reader.read_bits(8).expect("read_bits should succeed"), 0xF1);
855        assert_eq!(
856            reader.read_bits(16).expect("read_bits should succeed"),
857            0x2345
858        );
859        assert_eq!(reader.read_bits(8).expect("read_bits should succeed"), 0x67);
860    }
861
862    #[test]
863    fn test_position_tracking() {
864        let data = [0xFF, 0x00, 0xFF];
865        let mut reader = BitReader::new(&data);
866
867        assert_eq!(reader.byte_position(), 0);
868        assert_eq!(reader.bit_position(), 0);
869
870        reader.read_bits(10).expect("read_bits should succeed");
871        assert_eq!(reader.byte_position(), 1);
872        assert_eq!(reader.bit_position(), 2);
873
874        reader.byte_align();
875        assert_eq!(reader.byte_position(), 2);
876        assert_eq!(reader.bit_position(), 0);
877    }
878
879    #[test]
880    fn test_data_accessor() {
881        let data = [0xFF, 0x00, 0xFF];
882        let reader = BitReader::new(&data);
883
884        assert_eq!(reader.data(), &data);
885        assert_eq!(reader.data().len(), 3);
886    }
887
888    #[test]
889    fn test_single_bit_pattern() {
890        // Test reading alternating bit pattern
891        let data = [0b10101010];
892        let mut reader = BitReader::new(&data);
893
894        for i in 0..8 {
895            let expected = if i % 2 == 0 { 1 } else { 0 };
896            assert_eq!(
897                reader.read_bit().expect("read_bit should succeed"),
898                expected
899            );
900        }
901    }
902
903    #[test]
904    fn test_eof_on_exact_boundary() {
905        let data = [0xFF];
906        let mut reader = BitReader::new(&data);
907
908        reader.read_bits(8).expect("read_bits should succeed");
909        assert!(!reader.has_more_data());
910        assert_eq!(reader.remaining_bits(), 0);
911
912        let result = reader.read_bit();
913        assert!(result.is_err());
914    }
915
916    // -----------------------------------------------------------------------
917    // Batch extraction tests (fast-path for aligned byte-multiple reads)
918    // -----------------------------------------------------------------------
919
920    #[test]
921    fn test_batch_read_u16_aligned() {
922        let data = [0xAB_u8, 0xCD];
923        // Fast path: read_u16 (16 bits, aligned)
924        let mut r_fast = BitReader::new(&data);
925        let fast = r_fast.read_u16().expect("read_u16 should succeed");
926
927        // Slow path reference: new reader, then bit-by-bit via read_bits
928        let mut r_slow = BitReader::new(&data);
929        let slow = r_slow.read_bits(16).expect("read_bits(16) should succeed") as u16;
930
931        assert_eq!(fast, slow);
932        assert_eq!(fast, 0xABCD);
933    }
934
935    #[test]
936    fn test_batch_read_u32_aligned() {
937        let data = [0x12_u8, 0x34, 0x56, 0x78];
938        let mut r_fast = BitReader::new(&data);
939        let fast = r_fast.read_u32().expect("read_u32 should succeed");
940
941        let mut r_slow = BitReader::new(&data);
942        let slow = r_slow.read_bits(32).expect("read_bits(32) should succeed") as u32;
943
944        assert_eq!(fast, slow);
945        assert_eq!(fast, 0x1234_5678);
946    }
947
948    #[test]
949    fn test_batch_read_u64_aligned() {
950        let data = [0x01_u8, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
951        let mut r_fast = BitReader::new(&data);
952        let fast = r_fast.read_u64().expect("read_u64 should succeed");
953
954        let mut r_slow = BitReader::new(&data);
955        let slow = r_slow.read_bits(64).expect("read_bits(64) should succeed");
956
957        assert_eq!(fast, slow);
958        assert_eq!(fast, 0x0102_0304_0506_0708);
959    }
960
961    #[test]
962    fn test_batch_read_unaligned_fallback() {
963        // After reading 1 bit (bit_pos=1), reading 8 bits must fall back to
964        // the slow path and produce the same result as reading two raw bits
965        // across a byte boundary.
966        let data = [0b1010_1010_u8, 0b1100_1100];
967
968        // Reference: bit-by-bit reader from scratch
969        let mut r_ref = BitReader::new(&data);
970        r_ref.read_bit().expect("skip first bit");
971        let expected = r_ref.read_bits(8).expect("read_bits(8) reference");
972
973        // Fast-path candidate (should fall through to slow path since bit_pos!=0)
974        let mut r_test = BitReader::new(&data);
975        r_test.read_bit().expect("skip first bit");
976        let actual = r_test.read_bits(8).expect("read_bits(8) fast-path");
977
978        assert_eq!(actual, expected);
979    }
980
981    /// Regression test for GitHub issue #15.
982    ///
983    /// The module-level doctest used to read the AVC SPS constraint field as
984    /// 6 bits, which mis-aligned the subsequent `level_idc` byte and yielded
985    /// 7 instead of the expected 31.  Per ITU-T H.264 §7.3.2.1.1 the
986    /// constraint field is a full 8-bit byte: `constraint_set0_flag` through
987    /// `constraint_set5_flag` followed by `reserved_zero_2bits`.  This test
988    /// pins the correct alignment so the doctest cannot drift again.
989    #[test]
990    fn test_issue_15_avc_sps_constraint_byte_alignment() {
991        // profile_idc (8) | constraint byte (6 flags + 2 reserved) | level_idc (8)
992        let sps_bytes = [0x64u8, 0x00, 0x1f];
993        let mut reader = BitReader::new(&sps_bytes);
994
995        let profile_idc = reader.read_bits(8).expect("profile_idc read failed");
996        assert_eq!(profile_idc, 100, "High Profile profile_idc should be 100");
997
998        let constraint = reader.read_bits(8).expect("constraint byte read failed");
999        assert_eq!(constraint, 0x00, "all constraint flags clear in fixture");
1000
1001        let level_idc = reader.read_bits(8).expect("level_idc read failed");
1002        assert_eq!(level_idc, 31, "Level 3.1 level_idc should be 31");
1003    }
1004}