Skip to main content

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