Skip to main content

dsi_bitstream/traits/
bits.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::error::Error;
10use core::fmt::{Display, Formatter};
11
12use crate::traits::*;
13use num_primitive::PrimitiveUnsigned;
14
15/// The error returned by the bit copy methods [`BitRead::copy_to`]
16/// and [`BitWrite::copy_from`].
17///
18/// It can be a read or a write error, depending on which stream (source or
19/// destination) generated the error.
20#[derive(Debug, Clone)]
21pub enum CopyError<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> {
22    ReadError(RE),
23    WriteError(WE),
24}
25
26impl<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> Display
27    for CopyError<RE, WE>
28{
29    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
30        match self {
31            CopyError::ReadError(e) => write!(f, "read error while copying: {}", e),
32            CopyError::WriteError(e) => write!(f, "write error while copying: {}", e),
33        }
34    }
35}
36
37impl<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> Error
38    for CopyError<RE, WE>
39{
40    fn source(&self) -> Option<&(dyn Error + 'static)> {
41        match self {
42            CopyError::ReadError(e) => Some(e),
43            CopyError::WriteError(e) => Some(e),
44        }
45    }
46}
47
48/// Sequential, streaming bit-by-bit reads.
49///
50/// This trait specifies basic operations over which codes can be implemented by
51/// traits such as [`GammaReadParam`].
52///
53/// To quickly read complex codes, such traits may use the [`peek_bits`] method
54/// to read a few bits in advance and then use a table to decode them. For this
55/// to happen correctly, [`peek_bits`] must return a sufficient number of bits.
56/// Each table module provides a `check_read_table` const fn that can be used in
57/// a `const { }` block to verify at compile time that the peek word is large
58/// enough.
59///
60/// Please see the documentation of the [`impls`] module for more details.
61///
62/// [`GammaReadParam`]: crate::codes::gamma::GammaReadParam
63/// [`peek_bits`]: BitRead::peek_bits
64/// [`impls`]: crate::impls
65pub trait BitRead<E: Endianness> {
66    type Error: Error + Send + Sync + 'static;
67
68    /// The type we can read from the stream without advancing.
69    type PeekWord: PrimitiveUnsigned;
70
71    /// The number of bits that [`peek_bits`] is guaranteed to return
72    /// successfully (with zero-extended EOF).
73    ///
74    /// [`peek_bits`]: BitRead::peek_bits
75    const PEEK_BITS: usize;
76
77    /// Reads `num_bits` bits and returns them in the lowest bits.
78    ///
79    /// Implementors should check the value of `num_bits` when in test mode
80    /// and panic if it is greater than 64.
81    fn read_bits(&mut self, num_bits: usize) -> Result<u64, Self::Error>;
82
83    /// Peeks at `n` bits without advancing the stream position.
84    /// `n` must be nonzero, and at most `Self::PEEK_BITS`.
85    fn peek_bits(&mut self, n: usize) -> Result<Self::PeekWord, Self::Error>;
86
87    /// Skip `n` bits from the stream.
88    ///
89    /// When moving forward by a small amount of bits, this method might be
90    /// more efficient than [`BitSeek::set_bit_pos`].
91    fn skip_bits(&mut self, n: usize) -> Result<(), Self::Error>;
92
93    /// Skip bits from the stream after a call to [`BitRead::peek_bits`].
94    ///
95    /// This is an internal optimization used to skip bits we know are already
96    /// in some internal buffer as we [peeked] at them. Please don't use.
97    ///
98    /// [peeked]: BitRead::peek_bits
99    #[doc(hidden)]
100    fn skip_bits_after_peek(&mut self, n: usize);
101
102    /// Reads a unary code.
103    ///
104    /// Implementations are required to support the range [0 . . 2⁶⁴ – 1).
105    fn read_unary(&mut self) -> Result<u64, Self::Error>;
106
107    /// Copy bits from `self` to a [`BitWrite`] stream.
108    ///
109    /// Note that when the endianness `F` of the destination is different from
110    /// the endianness `E` of the source, the resulting bit order is
111    /// implementation-dependent, as bits are copied in chunks, and each chunk
112    /// is written in the bit order of the destination.
113    ///
114    /// # Errors
115    ///
116    /// This method can return a [`CopyError`] if the source stream returns an
117    /// error while reading, or if the destination stream returns an error while
118    /// writing.
119    fn copy_to<F: Endianness, W: BitWrite<F>>(
120        &mut self,
121        bit_write: &mut W,
122        mut n: u64,
123    ) -> Result<(), CopyError<Self::Error, W::Error>> {
124        while n > 0 {
125            let to_read = core::cmp::min(n, 64) as usize;
126            let read = self.read_bits(to_read).map_err(CopyError::ReadError)?;
127            bit_write
128                .write_bits(read, to_read)
129                .map_err(CopyError::WriteError)?;
130            n -= to_read as u64;
131        }
132        Ok(())
133    }
134}
135
136/// Sequential, streaming bit-by-bit writes.
137///
138/// This trait specifies basic operations over which codes can be implemented
139/// by traits such as [`crate::codes::gamma::GammaWriteParam`].
140pub trait BitWrite<E: Endianness> {
141    type Error: Error + Send + Sync + 'static;
142
143    /// Writes the lowest `num_bits` bits of `value` to the stream and
144    /// returns the number of bits written, that is, `num_bits`.
145    ///
146    /// Implementors should check the value of `num_bits` in test mode and panic
147    /// if it is greater than 64. Moreover, if the feature `checks` is enabled
148    /// they should check that the remaining bits of `value` are zero.
149    fn write_bits(&mut self, value: u64, num_bits: usize) -> Result<usize, Self::Error>;
150
151    /// Writes `n` as a unary code to the stream and returns the number of
152    /// bits written, that is, `n` plus one.
153    ///
154    /// Implementations are required to support the range [0 . . 2⁶⁴ – 1).
155    fn write_unary(&mut self, n: u64) -> Result<usize, Self::Error>;
156
157    /// Flushes the buffer, consuming the bit stream.
158    ///
159    /// Returns the number of bits written from the bit buffer (not
160    /// including padding).
161    fn flush(&mut self) -> Result<usize, Self::Error>;
162
163    /// Copy bits from a [`BitRead`] stream to `self`.
164    ///
165    /// Note that when the endianness `F` of the source is different from the
166    /// endianness `E` of the destination, the resulting bit order is
167    /// implementation-dependent, as bits are copied in chunks, and each chunk
168    /// is written in the bit order of the destination.
169    ///
170    /// # Errors
171    ///
172    /// This method can return a [`CopyError`] if the source stream returns an
173    /// error while reading, or if the destination stream returns an error while
174    /// writing.
175    fn copy_from<F: Endianness, R: BitRead<F>>(
176        &mut self,
177        bit_read: &mut R,
178        mut n: u64,
179    ) -> Result<(), CopyError<R::Error, Self::Error>> {
180        while n > 0 {
181            let to_read = core::cmp::min(n, 64) as usize;
182            let read = bit_read.read_bits(to_read).map_err(CopyError::ReadError)?;
183            self.write_bits(read, to_read)
184                .map_err(CopyError::WriteError)?;
185            n -= to_read as u64;
186        }
187        Ok(())
188    }
189}
190
191/// Seekability for [`BitRead`] and [`BitWrite`] streams.
192pub trait BitSeek {
193    type Error: Error + Send + Sync + 'static;
194    /// Gets the current position in bits from the start of the stream.
195    ///
196    /// Note that, consistently with [`Seek::stream_position`], this method
197    /// takes a mutable reference to `self`.
198    ///
199    /// [`Seek::stream_position`]: https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position
200    fn bit_pos(&mut self) -> Result<u64, Self::Error>;
201
202    /// Sets the current position in bits from the start of the
203    /// stream to `bit_pos`.
204    ///
205    /// Note that moving forward by a small amount of bits may be accomplished
206    /// more efficiently by calling [`BitRead::skip_bits`].
207    fn set_bit_pos(&mut self, bit_pos: u64) -> Result<(), Self::Error>;
208}