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