Skip to main content

dsi_bitstream/impls/
buf_bit_reader.rs

1/*
2 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
3 * SPDX-FileCopyrightText: 2023 Inria
4 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR MIT
7 */
8
9use num_primitive::{PrimitiveInteger, PrimitiveNumber};
10
11use crate::codes::params::{DefaultReadParams, ReadParams};
12use crate::traits::*;
13#[cfg(feature = "mem_dbg")]
14use mem_dbg::{MemDbg, MemSize};
15
16/// An internal shortcut to the double type of the word of a
17/// [`WordRead`].
18type BB<WR> = <<WR as WordRead>::Word as DoubleType>::DoubleType;
19
20/// An implementation of [`BitRead`] and [`BitSeek`] for a [`WordRead`] and a
21/// [`WordSeek`].
22///
23/// This implementation uses a bit buffer to store bits that are not yet read.
24/// The buffer is sized as twice the word size of the underlying [`WordRead`].
25/// Typically, the best choice is to have a buffer that is sized as `usize`,
26/// which means that the word of the underlying [`WordRead`] should be half of
27/// that (i.e., `u32` for a 64-bit architecture). However, results will vary
28/// depending on the CPU.
29///
30/// The peek word is equal to the bit buffer. The value returned by
31/// [`peek_bits`] contains at least as many bits as the word size (extended with
32/// zeros beyond end of stream): a peek is served by at most one refill, so only
33/// one word of peekable bits can be guaranteed.
34///
35/// The convenience functions [`from_path`] and [`from_file`] (requiring the
36/// `std` feature) create a [`BufBitReader`] around a buffered file reader.
37///
38/// This implementation is usually faster than [`BitReader`].
39///
40/// The additional type parameter `RP` is used to select the parameters for the
41/// instantaneous codes, but the casual user should be happy with the default
42/// value. See [`ReadParams`] for more details.
43///
44/// For additional flexibility, when the `std` feature is enabled, this
45/// structure implements [`std::io::Read`]. Note that because of coherence
46/// rules it is not possible to implement [`std::io::Read`] for a generic
47/// [`BitRead`].
48///
49/// [`peek_bits`]: crate::traits::BitRead::peek_bits
50/// [`BitReader`]: crate::impls::BitReader
51
52#[derive(Debug)]
53#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
54pub struct BufBitReader<E: Endianness, WR: WordRead, RP: ReadParams = DefaultReadParams>
55where
56    WR::Word: DoubleType,
57{
58    /// The [`WordRead`] used to fill the buffer.
59    backend: WR,
60    /// The 2-word bit buffer that is used to read the codes. It is never full,
61    /// but it may be empty. Only the upper (BE) or lower (LE)
62    /// `bits_in_buffer` bits are valid; the other bits are always zeroes.
63    buffer: BB<WR>,
64    /// Number of valid upper (BE) or lower (LE) bits in the buffer.
65    /// It is always smaller than `BB::<WR>::BITS`.
66    bits_in_buffer: usize,
67    _marker: core::marker::PhantomData<(E, RP)>,
68}
69
70/// Creates a new [`BufBitReader`] with [default read parameters] from a file
71/// path using the provided endianness and read word.
72///
73/// # Examples
74///
75/// ```no_run
76/// use dsi_bitstream::prelude::*;
77/// let mut reader = buf_bit_reader::from_path::<LE, u32>("data.bin")?;
78/// # Ok::<(), Box<dyn core::error::Error>>(())
79/// ```
80///
81/// [default read parameters]: `DefaultReadParams`
82#[cfg(feature = "std")]
83pub fn from_path<E: Endianness, W: Word + DoubleType>(
84    path: impl AsRef<std::path::Path>,
85) -> std::io::Result<
86    BufBitReader<E, super::WordAdapter<W, std::io::BufReader<std::fs::File>>, DefaultReadParams>,
87>
88where
89    W::Bytes: Default + AsMut<[u8]>,
90{
91    Ok(from_file::<E, W>(std::fs::File::open(path)?))
92}
93
94/// Creates a new [`BufBitReader`] with [default read parameters] from a file
95/// using the provided endianness and read word.
96///
97/// See also [`from_path`] for a version that takes a path.
98///
99/// [default read parameters]: `DefaultReadParams`
100#[must_use]
101#[cfg(feature = "std")]
102pub fn from_file<E: Endianness, W: Word + DoubleType>(
103    file: std::fs::File,
104) -> BufBitReader<E, super::WordAdapter<W, std::io::BufReader<std::fs::File>>, DefaultReadParams>
105where
106    W::Bytes: Default + AsMut<[u8]>,
107{
108    BufBitReader::new(super::WordAdapter::new(std::io::BufReader::new(file)))
109}
110
111impl<E: Endianness, WR: WordRead + Clone, RP: ReadParams> core::clone::Clone
112    for BufBitReader<E, WR, RP>
113where
114    WR::Word: DoubleType,
115{
116    fn clone(&self) -> Self {
117        Self {
118            backend: self.backend.clone(),
119            buffer: self.buffer,
120            bits_in_buffer: self.bits_in_buffer,
121            _marker: core::marker::PhantomData,
122        }
123    }
124}
125
126impl<E: Endianness, WR: WordRead, RP: ReadParams> BufBitReader<E, WR, RP>
127where
128    WR::Word: DoubleType,
129{
130    const WORD_BITS: usize = WR::Word::BITS as usize;
131    const BUFFER_BITS: usize = BB::<WR>::BITS as usize;
132
133    /// Creates a new [`BufBitReader`] around a [`WordRead`].
134    ///
135    /// # Examples
136    /// ```
137    /// use dsi_bitstream::prelude::*;
138    /// let words: [u32; 2] = [0x0043b59f, 0xccf16077];
139    /// let word_reader = MemWordReader::new_inf(&words);
140    /// let mut buf_bit_reader = <BufBitReader<BE, _>>::new(word_reader);
141    /// ```
142    #[must_use]
143    pub const fn new(backend: WR) -> Self {
144        Self {
145            backend,
146            buffer: BB::<WR>::ZERO,
147            bits_in_buffer: 0,
148            _marker: core::marker::PhantomData,
149        }
150    }
151
152    /// Consumes this reader and returns the underlying [`WordRead`].
153    #[must_use]
154    pub fn into_inner(self) -> WR {
155        self.backend
156    }
157}
158
159//
160// Big-endian implementation
161//
162
163impl<WR: WordRead, RP: ReadParams> BufBitReader<BE, WR, RP>
164where
165    WR::Word: DoubleType,
166{
167    /// Ensures that in the buffer there are at least `Self::WORD_BITS` bits to read.
168    /// This method can be called only if there are at least
169    /// `Self::WORD_BITS` free bits in the buffer.
170    #[inline(always)]
171    fn refill(&mut self) -> Result<(), <WR as WordRead>::Error> {
172        debug_assert!(Self::BUFFER_BITS - self.bits_in_buffer >= Self::WORD_BITS);
173
174        let new_word: BB<WR> = self.backend.read_word()?.to_be().as_double();
175        self.bits_in_buffer += Self::WORD_BITS;
176        self.buffer |= new_word << (Self::BUFFER_BITS - self.bits_in_buffer);
177        Ok(())
178    }
179    /// Single-word refill for 64-bit words (128-bit buffer), specialized so
180    /// that the result and the pre-top-up buffer, which both live entirely
181    /// in the high 64 bits of the buffer, are computed in u64 arithmetic
182    /// (no cross-half 128-bit shifts).
183    ///
184    /// Must be called only when `WORD_BITS == 64`, with `w` the word read
185    /// for this request and `bits_in_buffer < num_bits <= WORD_BITS`.
186    #[inline(always)]
187    fn read_bits_refill_word64(
188        &mut self,
189        num_bits: usize,
190        w: WR::Word,
191    ) -> Result<u64, <WR as WordRead>::Error> {
192        debug_assert!(Self::WORD_BITS == 64);
193        let bits = self.bits_in_buffer;
194        // High half of buffer | word placed right below the buffered bits.
195        // Shifts valid: bits < num_bits <= WORD_BITS = 64, and num_bits >= 1
196        // because the in-buffer fast path handled num_bits <= bits.
197        let virt_hi: u64 = (self.buffer >> Self::WORD_BITS).as_to::<u64>() | (w.as_u64() >> bits);
198        let result = virt_hi >> (Self::WORD_BITS - num_bits);
199        // The remaining low WORD_BITS - (num_bits - bits) bits of the word,
200        // placed at the top of the high half; double shift as
201        // num_bits - bits may equal WORD_BITS.
202        let hi = (w << (num_bits - bits - 1)) << 1_u32;
203        let mut buffer = hi.as_double() << Self::WORD_BITS;
204        let mut new_bits = bits + Self::WORD_BITS - num_bits;
205        // Top up with a second word if available: new_bits < WORD_BITS here,
206        // so there is always room and the buffer stays short of full. The
207        // atomic optional read never consumes past the end of the stream.
208        if let Some(w2) = self.backend.read_word_opt() {
209            // Shifts valid: WORD_BITS and new_bits are < BUFFER_BITS.
210            buffer |= (w2.to_be().as_double() << Self::WORD_BITS) >> new_bits;
211            new_bits += Self::WORD_BITS;
212        }
213        self.buffer = buffer;
214        self.bits_in_buffer = new_bits;
215        Ok(result)
216    }
217}
218
219impl<WR: WordRead, RP: ReadParams> BitRead<BE> for BufBitReader<BE, WR, RP>
220where
221    WR::Word: DoubleType,
222{
223    type Error = <WR as WordRead>::Error;
224    type PeekWord = BB<WR>;
225    // We guarantee only half a buffer (one word) of peekable bits, so that a
226    // peek needs at most one refill and the buffer is never completely full;
227    // this keeps the read/skip/unary hot paths free of full-buffer handling.
228    const PEEK_BITS: usize = <WR as WordRead>::Word::BITS as usize;
229
230    #[inline(always)]
231    fn peek_bits(&mut self, n_bits: usize) -> Result<Self::PeekWord, Self::Error> {
232        debug_assert!(n_bits > 0);
233        debug_assert!(n_bits <= Self::PEEK_BITS);
234
235        // A peek can do at most one refill, otherwise we might lose data
236        if n_bits > self.bits_in_buffer {
237            self.refill()?;
238        }
239
240        debug_assert!(n_bits <= self.bits_in_buffer);
241
242        // Move the n_bits highest bits of the buffer to the lowest
243        Ok(self.buffer >> (Self::BUFFER_BITS - n_bits))
244    }
245
246    #[inline(always)]
247    fn skip_bits_after_peek(&mut self, n_bits: usize) {
248        self.bits_in_buffer -= n_bits;
249        self.buffer <<= n_bits;
250    }
251
252    #[inline]
253    fn read_bits(&mut self, mut num_bits: usize) -> Result<u64, Self::Error> {
254        debug_assert!(num_bits <= 64);
255        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
256
257        // most common path, we just read the buffer
258        if num_bits <= self.bits_in_buffer {
259            // Valid right shift of BB::<WR>::BITS - num_bits, even when num_bits is zero
260            let result: u64 = (self.buffer >> (Self::BUFFER_BITS - num_bits - 1) >> 1_u32).as_to();
261            self.bits_in_buffer -= num_bits;
262            self.buffer <<= num_bits;
263            return Ok(result);
264        }
265        // Single-word refill path: past the test above, a request of at most
266        // WORD_BITS bits always consumes exactly one word, which we can
267        // compose with the buffer without the loop and the branches of the
268        // general path below.
269        if num_bits <= Self::WORD_BITS {
270            let bits = self.bits_in_buffer;
271            // The word is required in any case, so no peek is needed.
272            let w = self.backend.read_word()?.to_be();
273            // For 64-bit words (128-bit buffer), the result and the
274            // pre-top-up buffer both live entirely in the high 64 bits of
275            // the buffer, so the specialized helper uses u64 arithmetic,
276            // avoiding cross-half 128-bit shifts. The branch is resolved at
277            // compile time; the helper keeps the dead branch's MIR footprint
278            // to one statement so that inlining decisions for narrow-word
279            // readers are unaffected.
280            if Self::WORD_BITS == 64 {
281                return self.read_bits_refill_word64(num_bits, w);
282            }
283            // Place the word right below the buffered bits; the word fits
284            // entirely because bits < num_bits <= WORD_BITS, and both
285            // shifts are valid as WORD_BITS and bits are < BUFFER_BITS.
286            let placed = (w.as_double() << Self::WORD_BITS) >> bits;
287            let virt = self.buffer | placed;
288            // Valid right shift, even when num_bits is zero
289            let result: u64 = (virt >> (Self::BUFFER_BITS - num_bits - 1) >> 1_u32).as_to();
290            // The new buffer comes from the placed word alone: bits <
291            // num_bits, so all buffered bits are consumed and
292            // `self.buffer << num_bits` would be zero; dropping the `|` from
293            // this computation shortens the loop-carried dependency chain.
294            let mut buffer = placed << num_bits;
295            let mut new_bits = bits + Self::WORD_BITS - num_bits;
296            // Top up with a second word if available: new_bits < WORD_BITS
297            // here, so there is always room and the buffer stays short of
298            // full. This halves the number of refills, making the in-buffer
299            // test above more predictable. The atomic optional read never
300            // consumes past the end of the stream.
301            if let Some(w2) = self.backend.read_word_opt() {
302                // Shifts valid: WORD_BITS and new_bits are < BUFFER_BITS.
303                buffer |= (w2.to_be().as_double() << Self::WORD_BITS) >> new_bits;
304                new_bits += Self::WORD_BITS;
305            }
306            self.buffer = buffer;
307            self.bits_in_buffer = new_bits;
308            return Ok(result);
309        }
310
311        let mut result: u64 =
312            (self.buffer >> (Self::BUFFER_BITS - 1 - self.bits_in_buffer) >> 1_u8).as_to();
313        num_bits -= self.bits_in_buffer;
314
315        // Directly read to the result without updating the buffer
316        while num_bits > Self::WORD_BITS {
317            let new_word: u64 = self.backend.read_word()?.to_be().as_u64();
318            result = (result << Self::WORD_BITS) | new_word;
319            num_bits -= Self::WORD_BITS;
320        }
321
322        debug_assert!(num_bits > 0);
323        debug_assert!(num_bits <= Self::WORD_BITS);
324
325        // get the final word
326        let new_word = self.backend.read_word()?.to_be();
327        self.bits_in_buffer = Self::WORD_BITS - num_bits;
328        // compose the remaining bits
329        let upcast: u64 = new_word.as_u64();
330        let final_bits: u64 = upcast >> self.bits_in_buffer;
331        result = (result << (num_bits - 1) << 1) | final_bits;
332        // and put the rest in the buffer
333        self.buffer = (new_word.as_double() << (Self::BUFFER_BITS - self.bits_in_buffer - 1)) << 1;
334
335        Ok(result)
336    }
337
338    #[inline]
339    fn read_unary(&mut self) -> Result<u64, Self::Error> {
340        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
341
342        // count the zeros from the left
343        let zeros: usize = self.buffer.leading_zeros() as _;
344
345        // if we encountered a 1 in the bits_in_buffer we can return
346        if zeros < self.bits_in_buffer {
347            // zeros + 1 <= bits_in_buffer < BUFFER_BITS, so both forms are
348            // always valid. On 128-bit buffers a single merged shift avoids a
349            // second synthesized wide shift (measured -13% on u64-word
350            // read_unary); on 64-bit buffers the two-step shift measured
351            // slightly faster, so each width keeps its best form (const-folded).
352            if Self::BUFFER_BITS > 64 {
353                self.buffer <<= zeros + 1;
354            } else {
355                self.buffer = self.buffer << zeros << 1;
356            }
357            self.bits_in_buffer -= zeros + 1;
358            return Ok(zeros as u64);
359        }
360
361        let mut result: u64 = self.bits_in_buffer as _;
362
363        loop {
364            let new_word = self.backend.read_word()?.to_be();
365
366            if new_word != WR::Word::ZERO {
367                let zeros: usize = new_word.leading_zeros() as _;
368                let mut buffer = new_word.as_double() << (Self::WORD_BITS + zeros) << 1;
369                let mut new_bits = Self::WORD_BITS - zeros - 1;
370                // Top up with a second word if available: new_bits <
371                // WORD_BITS here, so there is always room and the buffer
372                // stays short of full. The atomic optional read never
373                // consumes past the end of the stream (see read_bits).
374                if let Some(w2) = self.backend.read_word_opt() {
375                    // Shifts valid: WORD_BITS and new_bits are < BUFFER_BITS.
376                    buffer |= (w2.to_be().as_double() << Self::WORD_BITS) >> new_bits;
377                    new_bits += Self::WORD_BITS;
378                }
379                self.buffer = buffer;
380                self.bits_in_buffer = new_bits;
381                return Ok(result + zeros as u64);
382            }
383            result += Self::WORD_BITS as u64;
384        }
385    }
386
387    #[inline]
388    fn skip_bits(&mut self, mut n_bits: usize) -> Result<(), Self::Error> {
389        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
390        // happy case, just shift the buffer
391        if n_bits <= self.bits_in_buffer {
392            self.bits_in_buffer -= n_bits;
393            self.buffer <<= n_bits;
394            return Ok(());
395        }
396
397        n_bits -= self.bits_in_buffer;
398
399        // skip words as needed
400        while n_bits > Self::WORD_BITS {
401            let _ = self.backend.read_word()?;
402            n_bits -= Self::WORD_BITS;
403        }
404
405        // get the final word
406        let new_word = self.backend.read_word()?.to_be();
407        self.bits_in_buffer = Self::WORD_BITS - n_bits;
408
409        self.buffer = new_word.as_double() << (Self::BUFFER_BITS - 1 - self.bits_in_buffer) << 1;
410
411        Ok(())
412    }
413
414    #[cfg(not(feature = "no_copy_impls"))]
415    fn copy_to<F: Endianness, W: BitWrite<F>>(
416        &mut self,
417        bit_write: &mut W,
418        mut n: u64,
419    ) -> Result<(), CopyError<Self::Error, W::Error>> {
420        // Copy from the buffer at most 64 bits at a time, as the buffer
421        // can hold more than 64 bits, but write_bits accepts at most 64
422        while n > 0 && self.bits_in_buffer > 0 {
423            let m = Ord::min(Ord::min(n, 64), self.bits_in_buffer as u64) as usize;
424            // The m highest bits of the buffer; m >= 1, so the shift is valid
425            let value: u64 = (self.buffer >> (Self::BUFFER_BITS - m)).as_to();
426            bit_write
427                .write_bits(value, m)
428                .map_err(CopyError::WriteError)?;
429            // m >= 1, so the two-step shift is valid even when m == BUFFER_BITS
430            self.buffer = self.buffer << (m - 1) << 1;
431            self.bits_in_buffer -= m;
432            n -= m as u64;
433        }
434
435        if n == 0 {
436            return Ok(());
437        }
438
439        // The buffer is empty: copy whole words
440        while n > Self::WORD_BITS as u64 {
441            bit_write
442                .write_bits(
443                    self.backend
444                        .read_word()
445                        .map_err(CopyError::ReadError)?
446                        .to_be()
447                        .as_u64(),
448                    Self::WORD_BITS,
449                )
450                .map_err(CopyError::WriteError)?;
451            n -= Self::WORD_BITS as u64;
452        }
453
454        debug_assert!(n > 0);
455        // Copy the n highest bits of a final word, and store the remaining
456        // bits at the top of the buffer, with zeros below
457        let new_word = self
458            .backend
459            .read_word()
460            .map_err(CopyError::ReadError)?
461            .to_be();
462        self.bits_in_buffer = Self::WORD_BITS - n as usize;
463        bit_write
464            .write_bits((new_word >> self.bits_in_buffer).as_u64(), n as usize)
465            .map_err(CopyError::WriteError)?;
466        // n >= 1, so the two-step shift is valid
467        self.buffer = (new_word.as_double() << (Self::WORD_BITS + n as usize - 1)) << 1;
468
469        Ok(())
470    }
471}
472
473impl<WR: WordRead + WordSeek<Error = <WR as WordRead>::Error>, RP: ReadParams> BitSeek
474    for BufBitReader<BE, WR, RP>
475where
476    WR::Word: DoubleType,
477{
478    type Error = <WR as WordSeek>::Error;
479
480    #[inline]
481    fn bit_pos(&mut self) -> Result<u64, Self::Error> {
482        Ok(self.backend.word_pos()? * Self::WORD_BITS as u64 - self.bits_in_buffer as u64)
483    }
484
485    #[inline]
486    fn set_bit_pos(&mut self, bit_index: u64) -> Result<(), Self::Error> {
487        self.backend
488            .set_word_pos(bit_index / Self::WORD_BITS as u64)?;
489        let bit_offset = (bit_index % Self::WORD_BITS as u64) as usize;
490        self.buffer = BB::<WR>::ZERO;
491        self.bits_in_buffer = 0;
492        if bit_offset != 0 {
493            let new_word: BB<WR> = self.backend.read_word()?.to_be().as_double();
494            self.bits_in_buffer = Self::WORD_BITS - bit_offset;
495            self.buffer = new_word << (Self::BUFFER_BITS - self.bits_in_buffer);
496        }
497        Ok(())
498    }
499}
500
501//
502// Little-endian implementation
503//
504
505impl<WR: WordRead, RP: ReadParams> BufBitReader<LE, WR, RP>
506where
507    WR::Word: DoubleType,
508{
509    /// Ensures that in the buffer there are at least `Self::WORD_BITS` bits to read.
510    /// This method can be called only if there are at least
511    /// `Self::WORD_BITS` free bits in the buffer.
512    #[inline(always)]
513    fn refill(&mut self) -> Result<(), <WR as WordRead>::Error> {
514        debug_assert!(Self::BUFFER_BITS - self.bits_in_buffer >= Self::WORD_BITS);
515
516        let new_word: BB<WR> = self.backend.read_word()?.to_le().as_double();
517        self.buffer |= new_word << self.bits_in_buffer;
518        self.bits_in_buffer += Self::WORD_BITS;
519        Ok(())
520    }
521}
522
523impl<WR: WordRead, RP: ReadParams> BitRead<LE> for BufBitReader<LE, WR, RP>
524where
525    WR::Word: DoubleType,
526{
527    type Error = <WR as WordRead>::Error;
528    type PeekWord = BB<WR>;
529    // We guarantee only half a buffer (one word) of peekable bits, so that a
530    // peek needs at most one refill and the buffer is never completely full;
531    // this keeps the read/skip/unary hot paths free of full-buffer handling.
532    const PEEK_BITS: usize = <WR as WordRead>::Word::BITS as usize;
533
534    #[inline(always)]
535    fn peek_bits(&mut self, n_bits: usize) -> Result<Self::PeekWord, Self::Error> {
536        debug_assert!(n_bits > 0);
537        debug_assert!(n_bits <= Self::PEEK_BITS);
538
539        // A peek can do at most one refill, otherwise we might lose data
540        if n_bits > self.bits_in_buffer {
541            self.refill()?;
542        }
543
544        debug_assert!(n_bits <= self.bits_in_buffer);
545
546        // Keep the n_bits lowest bits of the buffer
547        let shamt = Self::BUFFER_BITS - n_bits;
548        Ok((self.buffer << shamt) >> shamt)
549    }
550
551    #[inline(always)]
552    fn skip_bits_after_peek(&mut self, n_bits: usize) {
553        self.bits_in_buffer -= n_bits;
554        self.buffer >>= n_bits;
555    }
556
557    #[inline]
558    fn read_bits(&mut self, mut num_bits: usize) -> Result<u64, Self::Error> {
559        debug_assert!(num_bits <= 64);
560        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
561
562        // most common path, we just read the buffer
563        if num_bits <= self.bits_in_buffer {
564            let result: u64 = (self.buffer & ((BB::<WR>::ONE << num_bits) - BB::<WR>::ONE)).as_to();
565            self.bits_in_buffer -= num_bits;
566            self.buffer >>= num_bits;
567            return Ok(result);
568        }
569
570        // Single-word refill path: see the big-endian implementation for the
571        // invariants.
572        if num_bits <= Self::WORD_BITS {
573            let bits = self.bits_in_buffer;
574            // The word is required in any case, so no peek is needed.
575            let w = self.backend.read_word()?.to_le();
576            // Shift valid: bits < num_bits <= WORD_BITS < BUFFER_BITS,
577            // and the word fits entirely above the buffered bits.
578            let virt = self.buffer | (w.as_double() << bits);
579            // Extract the low num_bits (num_bits <= WORD_BITS < BUFFER_BITS)
580            let result: u64 = (virt & ((BB::<WR>::ONE << num_bits) - BB::<WR>::ONE)).as_to();
581            // The new buffer comes from the word alone: bits < num_bits, so
582            // all buffered bits are consumed and `buffer >> num_bits` would
583            // be zero. Keeping `virt` off this computation shortens the
584            // loop-carried dependency chain. Shift valid: 1 <= num_bits -
585            // bits <= WORD_BITS < BUFFER_BITS.
586            let mut buffer = w.as_double() >> (num_bits - bits);
587            let mut new_bits = bits + Self::WORD_BITS - num_bits;
588            // Top up with a second word if available: new_bits < WORD_BITS
589            // here, so there is always room and the buffer stays short of
590            // full. This halves the number of refills, making the in-buffer
591            // test above more predictable. The atomic optional read never
592            // consumes past the end of the stream.
593            if let Some(w2) = self.backend.read_word_opt() {
594                // Shift valid: new_bits < WORD_BITS <= BUFFER_BITS - WORD_BITS.
595                buffer |= w2.to_le().as_double() << new_bits;
596                new_bits += Self::WORD_BITS;
597            }
598            self.buffer = buffer;
599            self.bits_in_buffer = new_bits;
600            return Ok(result);
601        }
602
603        let mut result: u64 = self.buffer.as_to();
604        let mut bits_in_res = self.bits_in_buffer;
605
606        // Directly read to the result without updating the buffer
607        while num_bits > Self::WORD_BITS + bits_in_res {
608            let new_word: u64 = self.backend.read_word()?.to_le().as_u64();
609            result |= new_word << bits_in_res;
610            bits_in_res += Self::WORD_BITS;
611        }
612
613        num_bits -= bits_in_res;
614
615        debug_assert!(num_bits > 0);
616        debug_assert!(num_bits <= Self::WORD_BITS);
617
618        // get the final word
619        let new_word = self.backend.read_word()?.to_le();
620        self.bits_in_buffer = Self::WORD_BITS - num_bits;
621        // compose the remaining bits
622        let shamt = 64 - num_bits;
623        let upcast: u64 = new_word.as_u64();
624        let final_bits: u64 = (upcast << shamt) >> shamt;
625        result |= final_bits << bits_in_res;
626        // and put the rest in the buffer
627        self.buffer = new_word.as_double() >> num_bits;
628
629        Ok(result)
630    }
631
632    #[inline]
633    fn read_unary(&mut self) -> Result<u64, Self::Error> {
634        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
635
636        // count the zeros from the right
637        let zeros: usize = self.buffer.trailing_zeros() as usize;
638
639        // if we encountered a 1 in the bits_in_buffer we can return
640        if zeros < self.bits_in_buffer {
641            // See the big-endian implementation for the shift-form choice.
642            if Self::BUFFER_BITS > 64 {
643                self.buffer >>= zeros + 1;
644            } else {
645                self.buffer = self.buffer >> zeros >> 1;
646            }
647            self.bits_in_buffer -= zeros + 1;
648            return Ok(zeros as u64);
649        }
650
651        let mut result: u64 = self.bits_in_buffer as _;
652
653        loop {
654            let new_word = self.backend.read_word()?.to_le();
655
656            if new_word != WR::Word::ZERO {
657                let zeros: usize = new_word.trailing_zeros() as _;
658                let mut buffer = new_word.as_double() >> zeros >> 1;
659                let mut new_bits = Self::WORD_BITS - zeros - 1;
660                // Top up with a second word if available: new_bits <
661                // WORD_BITS here, so there is always room and the buffer
662                // stays short of full. The atomic optional read never
663                // consumes past the end of the stream (see read_bits).
664                if let Some(w2) = self.backend.read_word_opt() {
665                    // Shift valid: new_bits < WORD_BITS <= BUFFER_BITS - WORD_BITS.
666                    buffer |= w2.to_le().as_double() << new_bits;
667                    new_bits += Self::WORD_BITS;
668                }
669                self.buffer = buffer;
670                self.bits_in_buffer = new_bits;
671                return Ok(result + zeros as u64);
672            }
673            result += Self::WORD_BITS as u64;
674        }
675    }
676
677    #[inline]
678    fn skip_bits(&mut self, mut n_bits: usize) -> Result<(), Self::Error> {
679        debug_assert!(self.bits_in_buffer < Self::BUFFER_BITS);
680        // happy case, just shift the buffer
681        if n_bits <= self.bits_in_buffer {
682            self.bits_in_buffer -= n_bits;
683            self.buffer >>= n_bits;
684            return Ok(());
685        }
686
687        n_bits -= self.bits_in_buffer;
688
689        // skip words as needed
690        while n_bits > Self::WORD_BITS {
691            let _ = self.backend.read_word()?;
692            n_bits -= Self::WORD_BITS;
693        }
694
695        // get the final word
696        let new_word = self.backend.read_word()?.to_le();
697        self.bits_in_buffer = Self::WORD_BITS - n_bits;
698        self.buffer = new_word.as_double() >> n_bits;
699
700        Ok(())
701    }
702
703    #[cfg(not(feature = "no_copy_impls"))]
704    fn copy_to<F: Endianness, W: BitWrite<F>>(
705        &mut self,
706        bit_write: &mut W,
707        mut n: u64,
708    ) -> Result<(), CopyError<Self::Error, W::Error>> {
709        // Copy from the buffer at most 64 bits at a time, as the buffer
710        // can hold more than 64 bits, but write_bits accepts at most 64
711        while n > 0 && self.bits_in_buffer > 0 {
712            let m = Ord::min(Ord::min(n, 64), self.bits_in_buffer as u64) as usize;
713            // The m lowest bits of the buffer; m >= 1, so the mask shift is valid
714            let value = self.buffer.as_to::<u64>() & (u64::MAX >> (64 - m));
715            bit_write
716                .write_bits(value, m)
717                .map_err(CopyError::WriteError)?;
718            // m >= 1, so the two-step shift is valid even when m == BUFFER_BITS
719            self.buffer = self.buffer >> (m - 1) >> 1;
720            self.bits_in_buffer -= m;
721            n -= m as u64;
722        }
723
724        if n == 0 {
725            return Ok(());
726        }
727
728        // The buffer is empty: copy whole words
729        while n > Self::WORD_BITS as u64 {
730            bit_write
731                .write_bits(
732                    self.backend
733                        .read_word()
734                        .map_err(CopyError::ReadError)?
735                        .to_le()
736                        .as_u64(),
737                    Self::WORD_BITS,
738                )
739                .map_err(CopyError::WriteError)?;
740            n -= Self::WORD_BITS as u64;
741        }
742
743        debug_assert!(n > 0);
744        // Copy the n lowest bits of a final word, and store the remaining
745        // bits at the bottom of the buffer, with zeros above
746        let new_word = self
747            .backend
748            .read_word()
749            .map_err(CopyError::ReadError)?
750            .to_le();
751        self.bits_in_buffer = Self::WORD_BITS - n as usize;
752        // n >= 1, so the mask shift is valid
753        let value = new_word.as_u64() & (u64::MAX >> (64 - n as usize));
754        bit_write
755            .write_bits(value, n as usize)
756            .map_err(CopyError::WriteError)?;
757        self.buffer = new_word.as_double() >> n;
758        Ok(())
759    }
760}
761
762impl<WR: WordRead + WordSeek<Error = <WR as WordRead>::Error>, RP: ReadParams> BitSeek
763    for BufBitReader<LE, WR, RP>
764where
765    WR::Word: DoubleType,
766{
767    type Error = <WR as WordSeek>::Error;
768
769    #[inline]
770    fn bit_pos(&mut self) -> Result<u64, Self::Error> {
771        Ok(self.backend.word_pos()? * Self::WORD_BITS as u64 - self.bits_in_buffer as u64)
772    }
773
774    #[inline]
775    fn set_bit_pos(&mut self, bit_index: u64) -> Result<(), Self::Error> {
776        self.backend
777            .set_word_pos(bit_index / Self::WORD_BITS as u64)?;
778
779        let bit_offset = (bit_index % Self::WORD_BITS as u64) as usize;
780        self.buffer = BB::<WR>::ZERO;
781        self.bits_in_buffer = 0;
782        if bit_offset != 0 {
783            let new_word: BB<WR> = self.backend.read_word()?.to_le().as_double();
784            self.bits_in_buffer = Self::WORD_BITS - bit_offset;
785            self.buffer = new_word >> bit_offset;
786        }
787        Ok(())
788    }
789}
790
791#[cfg(feature = "std")]
792impl<WR: WordRead, RP: ReadParams> std::io::Read for BufBitReader<LE, WR, RP>
793where
794    WR::Word: DoubleType,
795{
796    /// Note that this implementation transfers data in 8-byte chunks, and a
797    /// [`WordRead`] backend error is not atomic with respect to the chunk:
798    /// near the end of the stream a partial chunk may be consumed and then
799    /// discarded, so up to 7 trailing bytes can be unreachable through this
800    /// interface when the destination buffer length is a multiple of 8.
801    /// Moreover, the backend error type cannot distinguish end of stream
802    /// from a backend failure, so reading past the last available byte fails
803    /// with [`std::io::ErrorKind::UnexpectedEof`] instead of returning
804    /// `Ok(0)`.
805    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
806        let mut read = 0;
807        let mut iter = buf.chunks_exact_mut(8);
808
809        for chunk in &mut iter {
810            match self.read_bits(64) {
811                Ok(word) => {
812                    chunk.copy_from_slice(&word.to_le_bytes());
813                    read += 8;
814                }
815                // If we read some bytes, return them; the error will
816                // resurface at the next call
817                Err(_) if read > 0 => return Ok(read),
818                Err(e) => {
819                    return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e));
820                }
821            }
822        }
823
824        let rem = iter.into_remainder();
825        if !rem.is_empty() {
826            match self.read_bits(rem.len() * 8) {
827                Ok(word) => {
828                    rem.copy_from_slice(&word.to_le_bytes()[..rem.len()]);
829                    read += rem.len();
830                }
831                Err(_) if read > 0 => return Ok(read),
832                Err(e) => {
833                    return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e));
834                }
835            }
836        }
837
838        Ok(read)
839    }
840}
841
842#[cfg(feature = "std")]
843impl<WR: WordRead, RP: ReadParams> std::io::Read for BufBitReader<BE, WR, RP>
844where
845    WR::Word: DoubleType,
846{
847    /// Note that this implementation transfers data in 8-byte chunks, and a
848    /// [`WordRead`] backend error is not atomic with respect to the chunk:
849    /// near the end of the stream a partial chunk may be consumed and then
850    /// discarded, so up to 7 trailing bytes can be unreachable through this
851    /// interface when the destination buffer length is a multiple of 8.
852    /// Moreover, the backend error type cannot distinguish end of stream
853    /// from a backend failure, so reading past the last available byte fails
854    /// with [`std::io::ErrorKind::UnexpectedEof`] instead of returning
855    /// `Ok(0)`.
856    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
857        let mut read = 0;
858        let mut iter = buf.chunks_exact_mut(8);
859
860        for chunk in &mut iter {
861            match self.read_bits(64) {
862                Ok(word) => {
863                    chunk.copy_from_slice(&word.to_be_bytes());
864                    read += 8;
865                }
866                // If we read some bytes, return them; the error will
867                // resurface at the next call
868                Err(_) if read > 0 => return Ok(read),
869                Err(e) => {
870                    return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e));
871                }
872            }
873        }
874
875        let rem = iter.into_remainder();
876        if !rem.is_empty() {
877            match self.read_bits(rem.len() * 8) {
878                Ok(word) => {
879                    rem.copy_from_slice(&word.to_be_bytes()[8 - rem.len()..]);
880                    read += rem.len();
881                }
882                Err(_) if read > 0 => return Ok(read),
883                Err(e) => {
884                    return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e));
885                }
886            }
887        }
888
889        Ok(read)
890    }
891}
892
893#[cfg(test)]
894#[cfg(feature = "std")]
895mod tests {
896    use super::*;
897    use crate::prelude::{MemWordReader, MemWordWriterVec};
898    use core::error::Error;
899    use std::io::Read;
900    /// On a strict (finite) backend, the two-word top-up must consume a word
901    /// only when one is available, and the read-and-consume must be atomic:
902    /// every bit of the stream is read back exactly once, the reader works
903    /// through the exact end of the data, and only then errors.
904    #[test]
905    fn test_topup_at_end_of_stream() {
906        macro_rules! check {
907            ($E:ty, $to:ident) => {{
908                let words: [u32; 3] = [0xA1B2_C3D4_u32.$to(), 0x1596_37D8_u32.$to(), !0];
909                let mut r = BufBitReader::<$E, _>::new(MemWordReader::new(&words));
910                let mut all: Vec<u64> = Vec::new();
911                // 20 + 40 + 20 + 16 = 96 bits = exactly three words; the
912                // first and third reads cross a word boundary and top up.
913                for n in [20, 40, 20, 16] {
914                    all.push(r.read_bits(n).unwrap());
915                }
916                // The stream is exhausted: no word was consumed early, none
917                // was lost, and the next read fails.
918                assert!(r.read_bits(1).is_err());
919                // The same bits read in one 64-bit and one 32-bit piece must
920                // reassemble identically.
921                let mut r2 = BufBitReader::<$E, _>::new(MemWordReader::new(&words));
922                let a = r2.read_bits(64).unwrap();
923                let b = r2.read_bits(32).unwrap();
924                assert!(r2.read_bits(1).is_err());
925                if TypeId::of::<$E>() == TypeId::of::<BE>() {
926                    assert_eq!(all[0], a >> 44);
927                    assert_eq!(all[1], (a >> 4) & ((1 << 40) - 1));
928                    assert_eq!(all[2], ((a & 0xF) << 16) | (b >> 16));
929                    assert_eq!(all[3], b & 0xFFFF);
930                } else {
931                    assert_eq!(all[0], a & ((1 << 20) - 1));
932                    assert_eq!(all[1], (a >> 20) & ((1 << 40) - 1));
933                    assert_eq!(all[2], (a >> 60) | ((b & 0xFFFF) << 4));
934                    assert_eq!(all[3], b >> 16);
935                }
936            }};
937        }
938        use core::any::TypeId;
939        check!(BE, to_be);
940        check!(LE, to_le);
941    }
942
943    /// The maximum documented peek (`PEEK_BITS` = one word) must be served
944    /// by a single refill from a completely empty buffer.
945    #[test]
946    fn test_peek_max_from_empty_buffer() {
947        macro_rules! check {
948            ($W:ty) => {{
949                const BITS: usize = <$W>::BITS as usize;
950                let words: [$W; 4] = [!0, 0, 0, 0];
951                let mut r = BufBitReader::<BE, _>::new(MemWordReader::new(&words));
952                assert_eq!(
953                    <BufBitReader<BE, MemWordReader<$W, &[$W; 4]>> as BitRead<BE>>::PEEK_BITS,
954                    BITS
955                );
956                assert_eq!(
957                    r.peek_bits(BITS).unwrap().as_to::<u64>(),
958                    (!0 as $W).as_to::<u64>()
959                );
960                let mut r = BufBitReader::<LE, _>::new(MemWordReader::new(&words));
961                assert_eq!(
962                    r.peek_bits(BITS).unwrap().as_to::<u64>(),
963                    (!0 as $W).as_to::<u64>()
964                );
965            }};
966        }
967        check!(u16);
968        check!(u32);
969        check!(u64);
970    }
971
972    /// Peeking more than `PEEK_BITS` bits violates the documented contract;
973    /// in debug builds the tightened assertion catches it.
974    #[test]
975    #[cfg(debug_assertions)]
976    #[should_panic]
977    fn test_peek_beyond_peek_bits_panics_be() {
978        let words: [u32; 4] = [0; 4];
979        let mut r = BufBitReader::<BE, _>::new(MemWordReader::new(&words));
980        let _ = r.peek_bits(33);
981    }
982
983    /// See [`test_peek_beyond_peek_bits_panics_be`].
984    #[test]
985    #[cfg(debug_assertions)]
986    #[should_panic]
987    fn test_peek_beyond_peek_bits_panics_le() {
988        let words: [u32; 4] = [0; 4];
989        let mut r = BufBitReader::<LE, _>::new(MemWordReader::new(&words));
990        let _ = r.peek_bits(33);
991    }
992
993    #[test]
994    fn test_read() -> std::io::Result<()> {
995        let data = [
996            0x90, 0x2d, 0xd0, 0x26, 0xdf, 0x89, 0xbb, 0x7e, 0x3a, 0xd6, 0xc6, 0x96, 0x73, 0xe9,
997            0x9d, 0xc9, 0x2a, 0x77, 0x82, 0xa9, 0xe6, 0x4b, 0x53, 0xcc, 0x83, 0x80, 0x4a, 0xf3,
998            0xcd, 0xe3, 0x50, 0x4e, 0x45, 0x4a, 0x3a, 0x42, 0x00, 0x4b, 0x4d, 0xbe, 0x4c, 0x88,
999            0x24, 0xf2, 0x4b, 0x6b, 0xbd, 0x79, 0xeb, 0x74, 0xbc, 0xe8, 0x7d, 0xff, 0x4b, 0x3d,
1000            0xa7, 0xd6, 0x0d, 0xef, 0x9c, 0x5b, 0xb3, 0xec, 0x94, 0x97, 0xcc, 0x8b, 0x41, 0xe1,
1001            0x9c, 0xcc, 0x1a, 0x03, 0x58, 0xc4, 0xfb, 0xd0, 0xc0, 0x10, 0xe2, 0xa0, 0xc9, 0xac,
1002            0xa7, 0xbb, 0x50, 0xf6, 0x5c, 0x87, 0x68, 0x0f, 0x42, 0x93, 0x3f, 0x2e, 0x28, 0x28,
1003            0x76, 0x83, 0x9b, 0xeb, 0x12, 0xe0, 0x4f, 0xc5, 0xb0, 0x8d, 0x14, 0xda, 0x3b, 0xdf,
1004            0xd3, 0x4b, 0x80, 0xd1, 0xfc, 0x87, 0x85, 0xae, 0x54, 0xc7, 0x45, 0xc9, 0x38, 0x43,
1005            0xa7, 0x9f, 0xdd, 0xa9, 0x71, 0xa7, 0x52, 0x36, 0x82, 0xff, 0x49, 0x55, 0xdb, 0x84,
1006            0xc2, 0x95, 0xad, 0x45, 0x80, 0xc6, 0x02, 0x80, 0xf8, 0xfc, 0x86, 0x79, 0xae, 0xb9,
1007            0x57, 0xe7, 0x3b, 0x33, 0x64, 0xa8,
1008        ];
1009        let data_u32 = unsafe { data.align_to::<u32>().1 };
1010
1011        for i in 0..data.len() {
1012            let mut reader = BufBitReader::<LE, _>::new(MemWordReader::new_inf(&data_u32));
1013            let mut buffer = vec![0; i];
1014            assert_eq!(reader.read(&mut buffer)?, i);
1015            assert_eq!(&buffer, &data[..i]);
1016
1017            let mut reader = BufBitReader::<BE, _>::new(MemWordReader::new_inf(&data_u32));
1018            let mut buffer = vec![0; i];
1019            assert_eq!(reader.read(&mut buffer)?, i);
1020            assert_eq!(&buffer, &data[..i]);
1021        }
1022        Ok(())
1023    }
1024
1025    #[test]
1026    fn test_copy_to_then_decode() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
1027        use crate::prelude::BufBitWriter;
1028        // Regression test: the big-endian copy_to used to leave garbage in
1029        // the low bits of the buffer, corrupting reads after a refill
1030        // caused by a peek
1031        let data: Vec<u32> = vec![u32::from_be(0x0000_FFFF), 0, 0, 0, 0, 0, 0, 0];
1032        let mut r = BufBitReader::<BE, _>::new(MemWordReader::new(&data));
1033        assert_eq!(r.read_bits(16)?, 0);
1034        let mut sink: Vec<u64> = vec![];
1035        let mut w = BufBitWriter::<BE, _>::new(MemWordWriterVec::new(&mut sink));
1036        r.copy_to(&mut w, 10)?;
1037        assert_eq!(r.read_bits(2)?, 0b11);
1038        let _ = r.peek_bits(32)?;
1039        assert_eq!(r.read_bits(30)?, 0b1111 << 26);
1040        let _ = r.peek_bits(32)?;
1041        assert_eq!(r.read_bits(33)?, 0);
1042        Ok(())
1043    }
1044
1045    #[test]
1046    fn test_copy_to_large_buffer() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
1047        use crate::prelude::BufBitWriter;
1048        // Regression test: copy_to used to pass more than 64 bits to a
1049        // single write_bits call when the buffer held more than 64 bits
1050        let data: Vec<u64> = vec![
1051            u64::from_be(0x0123_4567_89AB_CDEF),
1052            u64::from_be(0xFEDC_BA98_7654_3210),
1053            u64::from_be(0xAAAA_5555_AAAA_5555),
1054            0,
1055            0,
1056        ];
1057        let mut r = BufBitReader::<BE, _>::new(MemWordReader::new(&data));
1058        let _ = r.read_bits(10)?;
1059        // A peek of a full word grows the buffer past 64 bits (54 + 64 = 118)
1060        let _ = r.peek_bits(64)?; // now the buffer holds more than 64 bits
1061        let mut sink: Vec<u64> = vec![];
1062        {
1063            let mut w = BufBitWriter::<BE, _>::new(MemWordWriterVec::new(&mut sink));
1064            r.copy_to(&mut w, 100)?;
1065            w.flush()?;
1066        }
1067        let mut r2 = BufBitReader::<BE, _>::new(MemWordReader::new(&data));
1068        let _ = r2.read_bits(10)?;
1069        let hi = r2.read_bits(50)?;
1070        let lo = r2.read_bits(50)?;
1071        let mut check = BufBitReader::<BE, _>::new(MemWordReader::new(&sink));
1072        assert_eq!(check.read_bits(50)?, hi);
1073        assert_eq!(check.read_bits(50)?, lo);
1074        Ok(())
1075    }
1076
1077    macro_rules! test_buf_bit_reader {
1078        ($f: ident, $word:ty) => {
1079            #[test]
1080            fn $f() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
1081                #[allow(unused_imports)]
1082                use crate::{
1083                    codes::{GammaRead, GammaWrite},
1084                    prelude::{
1085                        BufBitWriter, DeltaRead, DeltaWrite, MemWordReader, len_delta, len_gamma,
1086                    },
1087                };
1088                use rand::{RngExt, SeedableRng, rngs::SmallRng};
1089
1090                let mut buffer_be: Vec<$word> = vec![];
1091                let mut buffer_le: Vec<$word> = vec![];
1092                let mut big = BufBitWriter::<BE, _>::new(MemWordWriterVec::new(&mut buffer_be));
1093                let mut little = BufBitWriter::<LE, _>::new(MemWordWriterVec::new(&mut buffer_le));
1094
1095                let mut r = SmallRng::seed_from_u64(0);
1096                const ITER: usize = 1_000_000;
1097
1098                for _ in 0..ITER {
1099                    let value = r.random_range(0..128);
1100                    assert_eq!(big.write_gamma(value)?, len_gamma(value));
1101                    let value = r.random_range(0..128);
1102                    assert_eq!(little.write_gamma(value)?, len_gamma(value));
1103                    let value = r.random_range(0..128);
1104                    assert_eq!(big.write_gamma(value)?, len_gamma(value));
1105                    let value = r.random_range(0..128);
1106                    assert_eq!(little.write_gamma(value)?, len_gamma(value));
1107                    let value = r.random_range(0..128);
1108                    assert_eq!(big.write_delta(value)?, len_delta(value));
1109                    let value = r.random_range(0..128);
1110                    assert_eq!(little.write_delta(value)?, len_delta(value));
1111                    let value = r.random_range(0..128);
1112                    assert_eq!(big.write_delta(value)?, len_delta(value));
1113                    let value = r.random_range(0..128);
1114                    assert_eq!(little.write_delta(value)?, len_delta(value));
1115                    let n_bits = r.random_range(0..=64);
1116                    if n_bits == 0 {
1117                        big.write_bits(0, 0)?;
1118                    } else {
1119                        big.write_bits(1, n_bits)?;
1120                    }
1121                    let n_bits = r.random_range(0..=64);
1122                    if n_bits == 0 {
1123                        little.write_bits(0, 0)?;
1124                    } else {
1125                        little.write_bits(1, n_bits)?;
1126                    }
1127                    let value = r.random_range(0..128);
1128                    assert_eq!(big.write_unary(value)?, value as usize + 1);
1129                    let value = r.random_range(0..128);
1130                    assert_eq!(little.write_unary(value)?, value as usize + 1);
1131                }
1132
1133                drop(big);
1134                drop(little);
1135
1136                type ReadWord = $word;
1137
1138                #[allow(clippy::size_of_in_element_count)] // false positive
1139                let be_trans: &[ReadWord] = unsafe {
1140                    core::slice::from_raw_parts(
1141                        buffer_be.as_ptr() as *const ReadWord,
1142                        buffer_be.len()
1143                            * (core::mem::size_of::<$word>() / core::mem::size_of::<ReadWord>()),
1144                    )
1145                };
1146
1147                #[allow(clippy::size_of_in_element_count)] // false positive
1148                let le_trans: &[ReadWord] = unsafe {
1149                    core::slice::from_raw_parts(
1150                        buffer_le.as_ptr() as *const ReadWord,
1151                        buffer_le.len()
1152                            * (core::mem::size_of::<$word>() / core::mem::size_of::<ReadWord>()),
1153                    )
1154                };
1155
1156                let mut big_buff = BufBitReader::<BE, _>::new(MemWordReader::new_inf(be_trans));
1157                let mut little_buff = BufBitReader::<LE, _>::new(MemWordReader::new_inf(le_trans));
1158
1159                let mut r = SmallRng::seed_from_u64(0);
1160
1161                for _ in 0..ITER {
1162                    assert_eq!(big_buff.read_gamma()?, r.random_range(0..128));
1163                    assert_eq!(little_buff.read_gamma()?, r.random_range(0..128));
1164                    assert_eq!(big_buff.read_gamma()?, r.random_range(0..128));
1165                    assert_eq!(little_buff.read_gamma()?, r.random_range(0..128));
1166                    assert_eq!(big_buff.read_delta()?, r.random_range(0..128));
1167                    assert_eq!(little_buff.read_delta()?, r.random_range(0..128));
1168                    assert_eq!(big_buff.read_delta()?, r.random_range(0..128));
1169                    assert_eq!(little_buff.read_delta()?, r.random_range(0..128));
1170                    let n_bits = r.random_range(0..=64);
1171                    if n_bits == 0 {
1172                        assert_eq!(big_buff.read_bits(0)?, 0);
1173                    } else {
1174                        assert_eq!(big_buff.read_bits(n_bits)?, 1);
1175                    }
1176                    let n_bits = r.random_range(0..=64);
1177                    if n_bits == 0 {
1178                        assert_eq!(little_buff.read_bits(0)?, 0);
1179                    } else {
1180                        assert_eq!(little_buff.read_bits(n_bits)?, 1);
1181                    }
1182
1183                    assert_eq!(big_buff.read_unary()?, r.random_range(0..128));
1184                    assert_eq!(little_buff.read_unary()?, r.random_range(0..128));
1185                }
1186
1187                Ok(())
1188            }
1189        };
1190    }
1191
1192    test_buf_bit_reader!(test_u64, u64);
1193    test_buf_bit_reader!(test_u32, u32);
1194
1195    test_buf_bit_reader!(test_u16, u16);
1196}