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
12#[cfg(feature = "std")]
13use crate::prelude::{delta_tables, gamma_tables, zeta_tables};
14use crate::traits::*;
15use common_traits::CastableInto;
16
17pub trait Peek<const N: usize> {}
18macro_rules! impl_peekable {
19 ($($n:literal),*) => {$(
20 impl<T: Peek<{$n + 1}>> Peek<$n> for T {}
21 )*};
22}
23
24impl_peekable!(
25 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26 26, 27, 28, 29, 30, 31, 32
27);
28
29/// The error returned by the bit copy methods [`BitRead::copy_to`] and [`BitWrite::copy_from`].
30///
31/// It can be a read or a write error, depending on which stream (source or
32/// destination) generated the error.
33#[derive(Debug, Clone)]
34pub enum CopyError<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> {
35 ReadError(RE),
36 WriteError(WE),
37}
38
39impl<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> Display
40 for CopyError<RE, WE>
41{
42 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
43 match self {
44 CopyError::ReadError(e) => write!(f, "Read error while copying: {}", e),
45 CopyError::WriteError(e) => write!(f, "Write error while copying: {}", e),
46 }
47 }
48}
49
50impl<RE: Error + Send + Sync + 'static, WE: Error + Send + Sync + 'static> Error
51 for CopyError<RE, WE>
52{
53 fn source(&self) -> Option<&(dyn Error + 'static)> {
54 match self {
55 CopyError::ReadError(e) => Some(e),
56 CopyError::WriteError(e) => Some(e),
57 }
58 }
59}
60
61/// Sequential, streaming bit-by-bit reads.
62///
63/// This trait specify basic operation over which codes can be implemented by
64/// traits such as [`GammaReadParam`](crate::codes::GammaReadParam).
65///
66/// To read quickly complex codes, such traits may use the
67/// [`peek_bits`](BitRead::peek_bits) method to read a few bits in advance and
68/// then use a table to decode them. For this to happen correctly,
69/// [`peek_bits`](BitRead::peek_bits) must return a sufficient number of bits.
70/// It is unfortunately difficult at the time being to check statically that
71/// this is the case, but in test mode an assertion will be triggered if the
72/// number of bits returned by [`peek_bits`](BitRead::peek_bits) is not
73/// sufficient.
74///
75/// Implementors are invited to call [`check_tables`] at construction time to
76/// provide a warning to the user if the peek word is not large enough.
77///
78/// Please see the documentation of the [`impls`](crate::impls) module for more
79/// details.
80pub trait BitRead<E: Endianness> {
81 type Error: Error + Send + Sync + 'static;
82
83 /// The type we can read from the stream without advancing.
84 type PeekWord: CastableInto<u64>;
85
86 /// Read `n` bits and return them in the lowest bits.
87 ///
88 /// Implementors should check the value of `n` when in test mode
89 /// and panic if it is greater than 64.
90 fn read_bits(&mut self, n: usize) -> Result<u64, Self::Error>;
91
92 /// Peeks at `n` bits without advancing the stream position.
93 /// `n` must be nonzero, and at most `PeekWord::BITS`.
94 fn peek_bits(&mut self, n: usize) -> Result<Self::PeekWord, Self::Error>;
95
96 /// Skip `n` bits from the stream.
97 ///
98 /// When moving forward by a small amount of bits, this method might be
99 /// more efficient than [`BitSeek::set_bit_pos`].
100 fn skip_bits(&mut self, n: usize) -> Result<(), Self::Error>;
101
102 #[doc(hidden)]
103 /// Skip bits form the stream after a call to [`BitRead::peek_bits`].
104 ///
105 /// This is an internal optimization used to skip bits we know
106 /// are already in some internal buffer as we [peeked](BitRead::peek_bits)
107 /// at them. Please don't use.
108 fn skip_bits_after_peek(&mut self, n: usize);
109
110 /// Read a unary code.
111 ///
112 /// Implementations are required to support the range [0 . . 2⁶⁴ – 1).
113 fn read_unary(&mut self) -> Result<u64, Self::Error>;
114
115 fn copy_to<F: Endianness, W: BitWrite<F>>(
116 &mut self,
117 bit_write: &mut W,
118 mut n: u64,
119 ) -> Result<(), CopyError<Self::Error, W::Error>> {
120 while n > 0 {
121 let to_read = core::cmp::min(n, 64) as usize;
122 let read = self.read_bits(to_read).map_err(CopyError::ReadError)?;
123 bit_write
124 .write_bits(read, to_read)
125 .map_err(CopyError::WriteError)?;
126 n -= to_read as u64;
127 }
128 Ok(())
129 }
130}
131
132/// Sequential, streaming bit-by-bit writes.
133///
134/// This trait specify basic operation over which codes can be implemented
135/// by traits such as [`crate::codes::GammaWriteParam`].
136pub trait BitWrite<E: Endianness> {
137 type Error: Error + Send + Sync + 'static;
138
139 /// Write the lowest `n` bits of `value` to the stream and return the number
140 /// of bits written, that is, `n`.
141 ///
142 ///
143 /// Implementors should check the value of `n` in test mode and panic if it
144 /// is greater than 64. Moreover, if the feature `checks` is enabled they
145 /// should check that the remaining bits of `value` are zero.
146 fn write_bits(&mut self, value: u64, n: usize) -> Result<usize, Self::Error>;
147
148 /// Write `value` as a unary code to the stream and return the number of
149 /// bits written, that is, `value` plus one.
150 ///
151 /// Implementations are required to support the range [0 . . 2⁶⁴ – 1).
152 fn write_unary(&mut self, value: u64) -> Result<usize, Self::Error>;
153
154 /// Flush the buffer, consuming the bit stream.
155 ///
156 /// Returns the number of bits written from the bit buffer (not including padding).
157 fn flush(&mut self) -> Result<usize, Self::Error>;
158
159 fn copy_from<F: Endianness, R: BitRead<F>>(
160 &mut self,
161 bit_read: &mut R,
162 mut n: u64,
163 ) -> Result<(), CopyError<R::Error, Self::Error>> {
164 while n > 0 {
165 let to_read = core::cmp::min(n, 64) as usize;
166 let read = bit_read.read_bits(to_read).map_err(CopyError::ReadError)?;
167 self.write_bits(read, to_read)
168 .map_err(CopyError::WriteError)?;
169 n -= to_read as u64;
170 }
171 Ok(())
172 }
173}
174
175/// Seekability for [`BitRead`] and [`BitWrite`] streams.
176pub trait BitSeek {
177 type Error: Error + Send + Sync + 'static;
178 /// Get the current position in bits from the start of the stream.
179 fn bit_pos(&mut self) -> Result<u64, Self::Error>;
180
181 /// Set the current position in bits from the start of the stream to `bit_pos`.
182 ///
183 /// Note that moving forward by a small amount of bits may be accomplished
184 /// more efficiently by calling [`BitRead::skip_bits`].
185 fn set_bit_pos(&mut self, bit_pos: u64) -> Result<(), Self::Error>;
186}
187
188/// Utility function to check that the peek word is large enough.
189///
190/// It **strongly suggested** that this function is called by the
191/// creation methods of types implementing [`BitRead`].
192#[cfg(feature = "std")]
193pub fn check_tables(peek_bits: usize) {
194 if peek_bits < gamma_tables::READ_BITS {
195 eprintln!(
196 "DANGER: your BitRead can peek at {} bits, but the tables for γ codes use {} bits",
197 peek_bits,
198 gamma_tables::READ_BITS
199 );
200 }
201 if peek_bits < delta_tables::READ_BITS {
202 eprintln!(
203 "DANGER: your BitRead can peek at {} bits, but the tables for δ codes use {} bits",
204 peek_bits,
205 delta_tables::READ_BITS
206 );
207 }
208 if peek_bits < zeta_tables::READ_BITS {
209 eprintln!(
210 "DANGER: your BitRead can peek at {} bits, but the tables for ζ₃ codes use {} bits",
211 peek_bits,
212 zeta_tables::READ_BITS
213 );
214 }
215}