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