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}