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