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