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}