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