dsi_bitstream/impls/
buf_bit_writer.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 LGPL-2.1-or-later
7 */
8
9use core::any::TypeId;
10use core::{mem, ptr};
11
12use crate::codes::params::{DefaultWriteParams, WriteParams};
13use crate::traits::*;
14use common_traits::{AsBytes, CastableInto, FiniteRangeNumber, Integer, Number};
15#[cfg(feature = "mem_dbg")]
16use mem_dbg::{MemDbg, MemSize};
17
18/// An implementation of [`BitWrite`] for a [`WordWrite`].
19///
20/// This implementation uses a bit buffer to store bits that are not yet
21/// written. The size of the bit buffer is the size of the word used by the
22/// [`WordWrite`], which on most platform should be `usize`.
23///
24/// The additional type parameter `WP` is used to select the parameters for the
25/// instantanous codes, but the casual user should be happy with the default
26/// value. See [`WriteParams`] for more details.
27///
28/// For additional flexibility, this structures implements [`std::io::Write`].
29/// Note that because of coherence rules it is not possible to implement
30/// [`std::io::Write`] for a generic [`BitWrite`].
31
32#[derive(Debug)]
33#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
34pub struct BufBitWriter<E: Endianness, WW: WordWrite, WP: WriteParams = DefaultWriteParams> {
35    /// The [`WordWrite`] to which we will write words.
36    backend: WW,
37    /// The buffer where we store bits until we have a word worth of them.
38    /// It might be empty, but it is never full.
39    /// Only the lower (BE) or upper (LE) `WW::Word::BITS - space_left_in_buffer`
40    /// bits are valid: the rest have undefined value.
41    buffer: WW::Word,
42    /// Number of upper (BE) or lower (LE) free bits in the buffer. It is always greater than zero.
43    space_left_in_buffer: usize,
44    _marker_endianness: core::marker::PhantomData<(E, WP)>,
45}
46
47impl<E: Endianness, WW: WordWrite, WP: WriteParams> BufBitWriter<E, WW, WP>
48where
49    BufBitWriter<E, WW, WP>: BitWrite<E>,
50{
51    /// Create a new [`BufBitWriter`] around a [`WordWrite`].
52    ///
53    /// ### Example
54    /// ```
55    /// use dsi_bitstream::prelude::*;
56    /// let buffer = Vec::<usize>::new();
57    /// let word_writer = MemWordWriterVec::new(buffer);
58    /// let mut buf_bit_writer = <BufBitWriter<BE, _>>::new(word_writer);
59    pub fn new(backend: WW) -> Self {
60        Self {
61            backend,
62            buffer: WW::Word::ZERO,
63            space_left_in_buffer: WW::Word::BITS,
64            _marker_endianness: core::marker::PhantomData,
65        }
66    }
67
68    ///  Return the backend, consuming this writer after
69    /// [flushing it](BufBitWriter::flush).
70    pub fn into_inner(mut self) -> Result<WW, <Self as BitWrite<E>>::Error> {
71        self.flush()?;
72        // SAFETY: forget(self) prevents double dropping backend
73        let backend = unsafe { ptr::read(&self.backend) };
74        mem::forget(self);
75        Ok(backend)
76    }
77}
78
79impl<E: Endianness, WW: WordWrite, WP: WriteParams> core::ops::Drop for BufBitWriter<E, WW, WP> {
80    fn drop(&mut self) {
81        if TypeId::of::<E>() == TypeId::of::<LE>() {
82            flush_le(self).unwrap();
83        } else {
84            // TypeId::of::<E>() = TypeId::of::<BE>()
85            flush_be(self).unwrap();
86        }
87    }
88}
89
90/// Helper function flushing a [`BufBitWriter`] in big-endian fashion.
91///
92/// The endianness is hardwired because the function is called
93/// from [`BufBitWriter::drop`] using a check on the
94/// [`TypeId`] of the endianness.
95fn flush_be<E: Endianness, WW: WordWrite, WP: WriteParams>(
96    buf_bit_writer: &mut BufBitWriter<E, WW, WP>,
97) -> Result<usize, WW::Error> {
98    let to_flush = WW::Word::BITS - buf_bit_writer.space_left_in_buffer;
99    if to_flush != 0 {
100        buf_bit_writer.buffer <<= buf_bit_writer.space_left_in_buffer;
101        buf_bit_writer
102            .backend
103            .write_word(buf_bit_writer.buffer.to_be())?;
104        buf_bit_writer.space_left_in_buffer = WW::Word::BITS;
105    }
106    buf_bit_writer.backend.flush()?;
107    Ok(to_flush)
108}
109
110impl<WW: WordWrite, WP: WriteParams> BitWrite<BE> for BufBitWriter<BE, WW, WP>
111where
112    u64: CastableInto<WW::Word>,
113{
114    type Error = <WW as WordWrite>::Error;
115
116    fn flush(&mut self) -> Result<usize, Self::Error> {
117        flush_be(self)
118    }
119
120    #[allow(unused_mut)]
121    #[inline(always)]
122    fn write_bits(&mut self, mut value: u64, n_bits: usize) -> Result<usize, Self::Error> {
123        debug_assert!(n_bits <= 64);
124        #[cfg(feature = "checks")]
125        assert!(
126            value & (1_u128 << n_bits).wrapping_sub(1) as u64 == value,
127            "Error: value {} does not fit in {} bits",
128            value,
129            n_bits
130        );
131        debug_assert!(self.space_left_in_buffer > 0);
132
133        #[cfg(test)]
134        if n_bits < 64 {
135            // We put garbage in the higher bits for testing
136            value |= u64::MAX << n_bits;
137        }
138
139        // Easy way out: we fit the buffer
140        if n_bits < self.space_left_in_buffer {
141            self.buffer <<= n_bits;
142            // Clean up bits higher than n_bits
143            self.buffer |= value.cast() & !(WW::Word::MAX << n_bits as u32);
144            self.space_left_in_buffer -= n_bits;
145            return Ok(n_bits);
146        }
147
148        // Load the bottom of the buffer, if necessary, and dump the whole buffer
149        self.buffer = self.buffer << (self.space_left_in_buffer - 1) << 1;
150        // The first shift discards bits higher than n_bits
151        self.buffer |= (value << (64 - n_bits) >> (64 - self.space_left_in_buffer)).cast();
152        self.backend.write_word(self.buffer.to_be())?;
153
154        let mut to_write = n_bits - self.space_left_in_buffer;
155
156        for _ in 0..to_write / WW::Word::BITS {
157            to_write -= WW::Word::BITS;
158            self.backend
159                .write_word((value >> to_write).cast().to_be())?;
160        }
161
162        self.space_left_in_buffer = WW::Word::BITS - to_write;
163        self.buffer = value.cast();
164        Ok(n_bits)
165    }
166
167    #[inline(always)]
168    #[allow(clippy::collapsible_if)]
169    fn write_unary(&mut self, mut value: u64) -> Result<usize, Self::Error> {
170        debug_assert_ne!(value, u64::MAX);
171        debug_assert!(self.space_left_in_buffer > 0);
172
173        let code_length = value + 1;
174
175        // Easy way out: we fit the buffer
176        if code_length <= self.space_left_in_buffer as u64 {
177            self.space_left_in_buffer -= code_length as usize;
178            self.buffer = self.buffer << value << 1;
179            self.buffer |= WW::Word::ONE;
180            if self.space_left_in_buffer == 0 {
181                self.backend.write_word(self.buffer.to_be())?;
182                self.space_left_in_buffer = WW::Word::BITS;
183            }
184            return Ok(code_length as usize);
185        }
186
187        self.buffer = self.buffer << (self.space_left_in_buffer - 1) << 1;
188        self.backend.write_word(self.buffer.to_be())?;
189
190        value -= self.space_left_in_buffer as u64;
191
192        for _ in 0..value / WW::Word::BITS as u64 {
193            self.backend.write_word(WW::Word::ZERO)?;
194        }
195
196        value %= WW::Word::BITS as u64;
197
198        if value == WW::Word::BITS as u64 - 1 {
199            self.backend.write_word(WW::Word::ONE.to_be())?;
200            self.space_left_in_buffer = WW::Word::BITS;
201        } else {
202            self.buffer = WW::Word::ONE;
203            self.space_left_in_buffer = WW::Word::BITS - (value as usize + 1);
204        }
205
206        Ok(code_length as usize)
207    }
208
209    #[cfg(not(feature = "no_copy_impls"))]
210    fn copy_from<F: Endianness, R: BitRead<F>>(
211        &mut self,
212        bit_read: &mut R,
213        mut n: u64,
214    ) -> Result<(), CopyError<R::Error, Self::Error>> {
215        if n < self.space_left_in_buffer as u64 {
216            self.buffer = (self.buffer << n)
217                | bit_read
218                    .read_bits(n as usize)
219                    .map_err(CopyError::ReadError)?
220                    .cast();
221            self.space_left_in_buffer -= n as usize;
222            return Ok(());
223        }
224
225        self.buffer = (self.buffer << (self.space_left_in_buffer - 1) << 1)
226            | bit_read
227                .read_bits(self.space_left_in_buffer)
228                .map_err(CopyError::ReadError)?
229                .cast();
230        n -= self.space_left_in_buffer as u64;
231
232        self.backend
233            .write_word(self.buffer.to_be())
234            .map_err(CopyError::WriteError)?;
235
236        for _ in 0..n / WW::Word::BITS as u64 {
237            self.backend
238                .write_word(
239                    bit_read
240                        .read_bits(WW::Word::BITS)
241                        .map_err(CopyError::ReadError)?
242                        .cast()
243                        .to_be(),
244                )
245                .map_err(CopyError::WriteError)?;
246        }
247
248        n %= WW::Word::BITS as u64;
249        self.buffer = bit_read
250            .read_bits(n as usize)
251            .map_err(CopyError::ReadError)?
252            .cast();
253        self.space_left_in_buffer = WW::Word::BITS - n as usize;
254
255        Ok(())
256    }
257}
258
259/// Helper function flushing a [`BufBitWriter`] in big-endian fashion.
260///
261/// The endianness is hardwired because the function is called
262/// from [`BufBitWriter::drop`] using a check on the
263/// [`TypeId`] of the endianness.
264fn flush_le<E: Endianness, WW: WordWrite, WP: WriteParams>(
265    buf_bit_writer: &mut BufBitWriter<E, WW, WP>,
266) -> Result<usize, WW::Error> {
267    let to_flush = WW::Word::BITS - buf_bit_writer.space_left_in_buffer;
268    if to_flush != 0 {
269        buf_bit_writer.buffer >>= buf_bit_writer.space_left_in_buffer;
270        buf_bit_writer
271            .backend
272            .write_word(buf_bit_writer.buffer.to_le())?;
273        buf_bit_writer.space_left_in_buffer = WW::Word::BITS;
274    }
275    buf_bit_writer.backend.flush()?;
276    Ok(to_flush)
277}
278
279impl<WW: WordWrite, WP: WriteParams> BitWrite<LE> for BufBitWriter<LE, WW, WP>
280where
281    u64: CastableInto<WW::Word>,
282{
283    type Error = <WW as WordWrite>::Error;
284
285    fn flush(&mut self) -> Result<usize, Self::Error> {
286        flush_le(self)
287    }
288
289    #[inline(always)]
290    fn write_bits(&mut self, mut value: u64, n_bits: usize) -> Result<usize, Self::Error> {
291        debug_assert!(n_bits <= 64);
292        #[cfg(feature = "checks")]
293        assert!(
294            value & (1_u128 << n_bits).wrapping_sub(1) as u64 == value,
295            "Error: value {} does not fit in {} bits",
296            value,
297            n_bits
298        );
299        debug_assert!(self.space_left_in_buffer > 0);
300
301        #[cfg(test)]
302        if n_bits < 64 {
303            // We put garbage in the higher bits for testing
304            value |= u64::MAX << n_bits;
305        }
306
307        // Easy way out: we fit the buffer
308        if n_bits < self.space_left_in_buffer {
309            self.buffer >>= n_bits;
310            // Clean up bits higher than n_bits
311            self.buffer |=
312                (value.cast() & !(WW::Word::MAX << n_bits as u32)).rotate_right(n_bits as u32);
313            self.space_left_in_buffer -= n_bits;
314            return Ok(n_bits);
315        }
316
317        // Load the top of the buffer, if necessary, and dump the whole buffer
318        self.buffer = self.buffer >> (self.space_left_in_buffer - 1) >> 1;
319        self.buffer |= value.cast() << (WW::Word::BITS - self.space_left_in_buffer);
320        self.backend.write_word(self.buffer.to_le())?;
321
322        let to_write = n_bits - self.space_left_in_buffer;
323        value = value >> (self.space_left_in_buffer - 1) >> 1;
324
325        for _ in 0..to_write / WW::Word::BITS {
326            self.backend.write_word(value.cast().to_le())?;
327            // This cannot be executed with WW::Word::BITS >= 64
328            value >>= WW::Word::BITS;
329        }
330
331        self.space_left_in_buffer = WW::Word::BITS - to_write % WW::Word::BITS;
332        self.buffer = value.cast().rotate_right(to_write as u32);
333        Ok(n_bits)
334    }
335
336    #[inline(always)]
337    #[allow(clippy::collapsible_if)]
338    fn write_unary(&mut self, mut value: u64) -> Result<usize, Self::Error> {
339        debug_assert_ne!(value, u64::MAX);
340        debug_assert!(self.space_left_in_buffer > 0);
341
342        let code_length = value + 1;
343
344        // Easy way out: we fit the buffer
345        if code_length <= self.space_left_in_buffer as u64 {
346            self.space_left_in_buffer -= code_length as usize;
347            self.buffer = self.buffer >> value >> 1;
348            self.buffer |= WW::Word::ONE << (WW::Word::BITS - 1);
349            if self.space_left_in_buffer == 0 {
350                self.backend.write_word(self.buffer.to_le())?;
351                self.space_left_in_buffer = WW::Word::BITS;
352            }
353            return Ok(code_length as usize);
354        }
355
356        self.buffer = self.buffer >> (self.space_left_in_buffer - 1) >> 1;
357        self.backend.write_word(self.buffer.to_le())?;
358
359        value -= self.space_left_in_buffer as u64;
360
361        for _ in 0..value / WW::Word::BITS as u64 {
362            self.backend.write_word(WW::Word::ZERO)?;
363        }
364
365        value %= WW::Word::BITS as u64;
366
367        if value == WW::Word::BITS as u64 - 1 {
368            self.backend
369                .write_word((WW::Word::ONE << (WW::Word::BITS - 1)).to_le())?;
370            self.space_left_in_buffer = WW::Word::BITS;
371        } else {
372            self.buffer = WW::Word::ONE << (WW::Word::BITS - 1);
373            self.space_left_in_buffer = WW::Word::BITS - (value as usize + 1);
374        }
375
376        Ok(code_length as usize)
377    }
378
379    #[cfg(not(feature = "no_copy_impls"))]
380    fn copy_from<F: Endianness, R: BitRead<F>>(
381        &mut self,
382        bit_read: &mut R,
383        mut n: u64,
384    ) -> Result<(), CopyError<R::Error, Self::Error>> {
385        if n < self.space_left_in_buffer as u64 {
386            self.buffer = (self.buffer >> n)
387                | (bit_read
388                    .read_bits(n as usize)
389                    .map_err(CopyError::ReadError)?)
390                .cast()
391                .rotate_right(n as u32);
392            self.space_left_in_buffer -= n as usize;
393            return Ok(());
394        }
395
396        self.buffer = (self.buffer >> (self.space_left_in_buffer - 1) >> 1)
397            | (bit_read
398                .read_bits(self.space_left_in_buffer)
399                .map_err(CopyError::ReadError)?
400                .cast())
401            .rotate_right(self.space_left_in_buffer as u32);
402        n -= self.space_left_in_buffer as u64;
403
404        self.backend
405            .write_word(self.buffer.to_le())
406            .map_err(CopyError::WriteError)?;
407
408        for _ in 0..n / WW::Word::BITS as u64 {
409            self.backend
410                .write_word(
411                    bit_read
412                        .read_bits(WW::Word::BITS)
413                        .map_err(CopyError::ReadError)?
414                        .cast()
415                        .to_le(),
416                )
417                .map_err(CopyError::WriteError)?;
418        }
419
420        n %= WW::Word::BITS as u64;
421        self.buffer = bit_read
422            .read_bits(n as usize)
423            .map_err(CopyError::ReadError)?
424            .cast()
425            .rotate_right(n as u32);
426        self.space_left_in_buffer = WW::Word::BITS - n as usize;
427
428        Ok(())
429    }
430}
431
432impl<WW: WordWrite, WP: WriteParams> std::io::Write for BufBitWriter<BE, WW, WP>
433where
434    u64: CastableInto<WW::Word>,
435{
436    #[inline(always)]
437    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
438        let mut iter = buf.chunks_exact(WW::Word::BYTES);
439
440        for word in &mut iter {
441            self.write_bits(u64::from_be_bytes(word.try_into().unwrap()), 64)
442                .map_err(|_| {
443                    std::io::Error::new(std::io::ErrorKind::Other, "Could not write bits to stream")
444                })?;
445        }
446
447        let rem = iter.remainder();
448        if !rem.is_empty() {
449            let mut word = 0;
450            let bits = rem.len() * 8;
451            for byte in rem.iter() {
452                word <<= 8;
453                word |= *byte as u64;
454            }
455            self.write_bits(word, bits).map_err(|_| {
456                std::io::Error::new(std::io::ErrorKind::Other, "Could not write bits to stream")
457            })?;
458        }
459
460        Ok(buf.len())
461    }
462
463    fn flush(&mut self) -> std::io::Result<()> {
464        flush_be(self).map_err(|_| {
465            std::io::Error::new(std::io::ErrorKind::Other, "Could not flush bits to stream")
466        })?;
467        Ok(())
468    }
469}
470
471impl<WW: WordWrite, WP: WriteParams> std::io::Write for BufBitWriter<LE, WW, WP>
472where
473    u64: CastableInto<WW::Word>,
474{
475    #[inline(always)]
476    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
477        let mut iter = buf.chunks_exact(WW::Word::BYTES);
478
479        for word in &mut iter {
480            self.write_bits(u64::from_le_bytes(word.try_into().unwrap()), 64)
481                .map_err(|_| {
482                    std::io::Error::new(std::io::ErrorKind::Other, "Could not write bits to stream")
483                })?;
484        }
485
486        let rem = iter.remainder();
487        if !rem.is_empty() {
488            let mut word = 0;
489            let bits = rem.len() * 8;
490            for byte in rem.iter().rev() {
491                word <<= 8;
492                word |= *byte as u64;
493            }
494            self.write_bits(word, bits).map_err(|_| {
495                std::io::Error::new(std::io::ErrorKind::Other, "Could not write bits to stream")
496            })?;
497        }
498
499        Ok(buf.len())
500    }
501
502    fn flush(&mut self) -> std::io::Result<()> {
503        flush_le(self).map_err(|_| {
504            std::io::Error::new(std::io::ErrorKind::Other, "Could not flush bits to stream")
505        })?;
506        Ok(())
507    }
508}
509
510#[cfg(test)]
511mod test {
512    use super::*;
513    use crate::prelude::MemWordWriterVec;
514    use std::io::Write;
515
516    #[test]
517    fn test_write() {
518        let data = [
519            0x90, 0x2d, 0xd0, 0x26, 0xdf, 0x89, 0xbb, 0x7e, 0x3a, 0xd6, 0xc6, 0x96, 0x73, 0xe9,
520            0x9d, 0xc9, 0x2a, 0x77, 0x82, 0xa9, 0xe6, 0x4b, 0x53, 0xcc, 0x83, 0x80, 0x4a, 0xf3,
521            0xcd, 0xe3, 0x50, 0x4e, 0x45, 0x4a, 0x3a, 0x42, 0x00, 0x4b, 0x4d, 0xbe, 0x4c, 0x88,
522            0x24, 0xf2, 0x4b, 0x6b, 0xbd, 0x79, 0xeb, 0x74, 0xbc, 0xe8, 0x7d, 0xff, 0x4b, 0x3d,
523            0xa7, 0xd6, 0x0d, 0xef, 0x9c, 0x5b, 0xb3, 0xec, 0x94, 0x97, 0xcc, 0x8b, 0x41, 0xe1,
524            0x9c, 0xcc, 0x1a, 0x03, 0x58, 0xc4, 0xfb, 0xd0, 0xc0, 0x10, 0xe2, 0xa0, 0xc9, 0xac,
525            0xa7, 0xbb, 0x50, 0xf6, 0x5c, 0x87, 0x68, 0x0f, 0x42, 0x93, 0x3f, 0x2e, 0x28, 0x28,
526            0x76, 0x83, 0x9b, 0xeb, 0x12, 0xe0, 0x4f, 0xc5, 0xb0, 0x8d, 0x14, 0xda, 0x3b, 0xdf,
527            0xd3, 0x4b, 0x80, 0xd1, 0xfc, 0x87, 0x85, 0xae, 0x54, 0xc7, 0x45, 0xc9, 0x38, 0x43,
528            0xa7, 0x9f, 0xdd, 0xa9, 0x71, 0xa7, 0x52, 0x36, 0x82, 0xff, 0x49, 0x55, 0xdb, 0x84,
529            0xc2, 0x95, 0xad, 0x45, 0x80, 0xc6, 0x02, 0x80, 0xf8, 0xfc, 0x86, 0x79, 0xae, 0xb9,
530            0x57, 0xe7, 0x3b, 0x33, 0x64, 0xa8,
531        ];
532
533        for i in 0..data.len() {
534            let mut buffer = Vec::<u64>::new();
535            let mut writer = BufBitWriter::<BE, _>::new(MemWordWriterVec::new(&mut buffer));
536
537            writer.write_all(&data[..i]).unwrap();
538            std::io::Write::flush(&mut writer).unwrap();
539
540            let buffer = writer.into_inner().unwrap().into_inner();
541            assert_eq!(unsafe { &buffer.align_to::<u8>().1[..i] }, &data[..i]);
542
543            let mut buffer = Vec::<u64>::new();
544            let mut writer = BufBitWriter::<LE, _>::new(MemWordWriterVec::new(&mut buffer));
545
546            writer.write_all(&data[..i]).unwrap();
547            std::io::Write::flush(&mut writer).unwrap();
548
549            let buffer = writer.into_inner().unwrap().into_inner();
550            assert_eq!(unsafe { &buffer.align_to::<u8>().1[..i] }, &data[..i]);
551        }
552    }
553
554    macro_rules! test_buf_bit_writer {
555        ($f: ident, $word:ty) => {
556            #[test]
557            fn $f() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
558                #[allow(unused_imports)]
559                use crate::{
560                    codes::{GammaRead, GammaWrite},
561                    prelude::{
562                        len_delta, len_gamma, BufBitReader, DeltaRead, DeltaWrite, MemWordReader,
563                    },
564                };
565                use rand::Rng;
566                use rand::{rngs::SmallRng, SeedableRng};
567
568                let mut buffer_be: Vec<$word> = vec![];
569                let mut buffer_le: Vec<$word> = vec![];
570                let mut big = BufBitWriter::<BE, _>::new(MemWordWriterVec::new(&mut buffer_be));
571                let mut little = BufBitWriter::<LE, _>::new(MemWordWriterVec::new(&mut buffer_le));
572
573                let mut r = SmallRng::seed_from_u64(0);
574                const ITER: usize = 1_000_000;
575
576                for _ in 0..ITER {
577                    let value = r.random_range(0..128);
578                    assert_eq!(big.write_gamma(value)?, len_gamma(value));
579                    let value = r.random_range(0..128);
580                    assert_eq!(little.write_gamma(value)?, len_gamma(value));
581                    let value = r.random_range(0..128);
582                    assert_eq!(big.write_gamma(value)?, len_gamma(value));
583                    let value = r.random_range(0..128);
584                    assert_eq!(little.write_gamma(value)?, len_gamma(value));
585                    let value = r.random_range(0..128);
586                    assert_eq!(big.write_delta(value)?, len_delta(value));
587                    let value = r.random_range(0..128);
588                    assert_eq!(little.write_delta(value)?, len_delta(value));
589                    let value = r.random_range(0..128);
590                    assert_eq!(big.write_delta(value)?, len_delta(value));
591                    let value = r.random_range(0..128);
592                    assert_eq!(little.write_delta(value)?, len_delta(value));
593                    let n_bits = r.random_range(0..=64);
594                    if n_bits == 0 {
595                        big.write_bits(0, 0)?;
596                    } else {
597                        big.write_bits(r.random::<u64>() & u64::MAX >> 64 - n_bits, n_bits)?;
598                    }
599                    let n_bits = r.random_range(0..=64);
600                    if n_bits == 0 {
601                        little.write_bits(0, 0)?;
602                    } else {
603                        little.write_bits(r.random::<u64>() & u64::MAX >> 64 - n_bits, n_bits)?;
604                    }
605                    let value = r.random_range(0..128);
606                    assert_eq!(big.write_unary(value)?, value as usize + 1);
607                    let value = r.random_range(0..128);
608                    assert_eq!(little.write_unary(value)?, value as usize + 1);
609                }
610
611                drop(big);
612                drop(little);
613
614                type ReadWord = u16;
615                #[allow(clippy::size_of_in_element_count)] // false positive
616                let be_trans: &[ReadWord] = unsafe {
617                    core::slice::from_raw_parts(
618                        buffer_be.as_ptr() as *const ReadWord,
619                        buffer_be.len()
620                            * (core::mem::size_of::<$word>() / core::mem::size_of::<ReadWord>()),
621                    )
622                };
623                #[allow(clippy::size_of_in_element_count)] // false positive
624                let le_trans: &[ReadWord] = unsafe {
625                    core::slice::from_raw_parts(
626                        buffer_le.as_ptr() as *const ReadWord,
627                        buffer_le.len()
628                            * (core::mem::size_of::<$word>() / core::mem::size_of::<ReadWord>()),
629                    )
630                };
631
632                let mut big_buff = BufBitReader::<BE, _>::new(MemWordReader::new(be_trans));
633                let mut little_buff = BufBitReader::<LE, _>::new(MemWordReader::new(le_trans));
634
635                let mut r = SmallRng::seed_from_u64(0);
636
637                for _ in 0..ITER {
638                    assert_eq!(big_buff.read_gamma()?, r.random_range(0..128));
639                    assert_eq!(little_buff.read_gamma()?, r.random_range(0..128));
640                    assert_eq!(big_buff.read_gamma()?, r.random_range(0..128));
641                    assert_eq!(little_buff.read_gamma()?, r.random_range(0..128));
642                    assert_eq!(big_buff.read_delta()?, r.random_range(0..128));
643                    assert_eq!(little_buff.read_delta()?, r.random_range(0..128));
644                    assert_eq!(big_buff.read_delta()?, r.random_range(0..128));
645                    assert_eq!(little_buff.read_delta()?, r.random_range(0..128));
646                    let n_bits = r.random_range(0..=64);
647                    if n_bits == 0 {
648                        assert_eq!(big_buff.read_bits(0)?, 0);
649                    } else {
650                        assert_eq!(
651                            big_buff.read_bits(n_bits)?,
652                            r.random::<u64>() & u64::MAX >> 64 - n_bits
653                        );
654                    }
655                    let n_bits = r.random_range(0..=64);
656                    if n_bits == 0 {
657                        assert_eq!(little_buff.read_bits(0)?, 0);
658                    } else {
659                        assert_eq!(
660                            little_buff.read_bits(n_bits)?,
661                            r.random::<u64>() & u64::MAX >> 64 - n_bits
662                        );
663                    }
664
665                    assert_eq!(big_buff.read_unary()?, r.random_range(0..128));
666                    assert_eq!(little_buff.read_unary()?, r.random_range(0..128));
667                }
668
669                Ok(())
670            }
671        };
672    }
673
674    test_buf_bit_writer!(test_u128, u128);
675    test_buf_bit_writer!(test_u64, u64);
676    test_buf_bit_writer!(test_u32, u32);
677
678    test_buf_bit_writer!(test_u16, u16);
679    test_buf_bit_writer!(test_usize, usize);
680}