Skip to main content

dsi_bitstream/dispatch/
codes.rs

1/*
2 * SPDX-FileCopyrightText: 2025 Tommaso Fontana
3 * SPDX-FileCopyrightText: 2025 Inria
4 * SPDX-FileCopyrightText: 2025 Sebastiano Vigna
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
7 */
8
9//! Enumeration of all available codes, with associated read and write methods.
10//!
11//! This is the slower and more generic form of dispatching, mostly used for
12//! testing and writing examples. For faster dispatching, consider using
13//! [dynamic] or [static] dispatch.
14
15use super::*;
16#[cfg(feature = "mem_dbg")]
17use mem_dbg::{MemDbg, MemSize};
18
19#[derive(Debug, Clone, Copy, Eq)]
20#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
21#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
22#[non_exhaustive]
23/// An enum whose variants represent all the available codes.
24///
25/// This enum is kept in sync with implementations in the
26/// [`codes`](crate::codes) module.
27///
28/// Both [`Display`](std::fmt::Display) and [`FromStr`](std::str::FromStr) are
29/// implemented for this enum in a dual way, which makes it possible to store a
30/// code as a string in a configuration file, and then parse it back.
31pub enum Codes {
32    Unary,
33    Gamma,
34    Delta,
35    Omega,
36    VByteLe,
37    VByteBe,
38    Zeta(usize),
39    Pi(usize),
40    Golomb(u64),
41    ExpGolomb(usize),
42    Rice(usize),
43}
44
45/// Some codes are equivalent, so we implement [`PartialEq`] to make them
46/// interchangeable so `Codes::Unary == Codes::Rice(0)`.
47impl PartialEq for Codes {
48    fn eq(&self, other: &Self) -> bool {
49        match (self, other) {
50            // First we check the equivalence classes
51            (
52                Self::Unary | Self::Rice(0) | Self::Golomb(1),
53                Self::Unary | Self::Rice(0) | Self::Golomb(1),
54            ) => true,
55            (
56                Self::Gamma | Self::Zeta(1) | Self::ExpGolomb(0),
57                Self::Gamma | Self::Zeta(1) | Self::ExpGolomb(0),
58            ) => true,
59            (Self::Golomb(2) | Self::Rice(1), Self::Golomb(2) | Self::Rice(1)) => true,
60            (Self::Golomb(4) | Self::Rice(2), Self::Golomb(4) | Self::Rice(2)) => true,
61            (Self::Golomb(8) | Self::Rice(3), Self::Golomb(8) | Self::Rice(3)) => true,
62            // we know that we are not in a special case, so we can directly
63            // compare them naively
64            (Self::Delta, Self::Delta) => true,
65            (Self::Omega, Self::Omega) => true,
66            (Self::VByteLe, Self::VByteLe) => true,
67            (Self::VByteBe, Self::VByteBe) => true,
68            (Self::Zeta(k), Self::Zeta(k2)) => k == k2,
69            (Self::Pi(k), Self::Pi(k2)) => k == k2,
70            (Self::Golomb(b), Self::Golomb(b2)) => b == b2,
71            (Self::ExpGolomb(k), Self::ExpGolomb(k2)) => k == k2,
72            (Self::Rice(log2_b), Self::Rice(log2_b2)) => log2_b == log2_b2,
73            _ => false,
74        }
75    }
76}
77
78impl Codes {
79    /// Delegates to the [`DynamicCodeRead`] implementation.
80    ///
81    /// This inherent method is provided to reduce ambiguity in method
82    /// resolution.
83    #[inline(always)]
84    pub fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
85        &self,
86        reader: &mut CR,
87    ) -> Result<u64, CR::Error> {
88        DynamicCodeRead::read(self, reader)
89    }
90
91    /// Delegates to the [`DynamicCodeWrite`] implementation.
92    ///
93    /// This inherent method is provided to reduce ambiguity in method
94    /// resolution.
95    #[inline(always)]
96    pub fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
97        &self,
98        writer: &mut CW,
99        value: u64,
100    ) -> Result<usize, CW::Error> {
101        DynamicCodeWrite::write(self, writer, value)
102    }
103
104    /// Converts a code to the constant enum [`code_consts`] used for [`ConstCode`].
105    /// This is mostly used to verify that the code is supported by
106    /// [`ConstCode`].
107    pub fn to_code_const(&self) -> Result<usize> {
108        Ok(match self {
109            Self::Unary => code_consts::UNARY,
110            Self::Gamma => code_consts::GAMMA,
111            Self::Delta => code_consts::DELTA,
112            Self::Omega => code_consts::OMEGA,
113            Self::VByteLe => code_consts::VBYTE_LE,
114            Self::VByteBe => code_consts::VBYTE_BE,
115            Self::Zeta(1) => code_consts::ZETA1,
116            Self::Zeta(2) => code_consts::ZETA2,
117            Self::Zeta(3) => code_consts::ZETA3,
118            Self::Zeta(4) => code_consts::ZETA4,
119            Self::Zeta(5) => code_consts::ZETA5,
120            Self::Zeta(6) => code_consts::ZETA6,
121            Self::Zeta(7) => code_consts::ZETA7,
122            Self::Zeta(8) => code_consts::ZETA8,
123            Self::Zeta(9) => code_consts::ZETA9,
124            Self::Zeta(10) => code_consts::ZETA10,
125            Self::Rice(0) => code_consts::RICE0,
126            Self::Rice(1) => code_consts::RICE1,
127            Self::Rice(2) => code_consts::RICE2,
128            Self::Rice(3) => code_consts::RICE3,
129            Self::Rice(4) => code_consts::RICE4,
130            Self::Rice(5) => code_consts::RICE5,
131            Self::Rice(6) => code_consts::RICE6,
132            Self::Rice(7) => code_consts::RICE7,
133            Self::Rice(8) => code_consts::RICE8,
134            Self::Rice(9) => code_consts::RICE9,
135            Self::Rice(10) => code_consts::RICE10,
136            Self::Pi(0) => code_consts::PI0,
137            Self::Pi(1) => code_consts::PI1,
138            Self::Pi(2) => code_consts::PI2,
139            Self::Pi(3) => code_consts::PI3,
140            Self::Pi(4) => code_consts::PI4,
141            Self::Pi(5) => code_consts::PI5,
142            Self::Pi(6) => code_consts::PI6,
143            Self::Pi(7) => code_consts::PI7,
144            Self::Pi(8) => code_consts::PI8,
145            Self::Pi(9) => code_consts::PI9,
146            Self::Pi(10) => code_consts::PI10,
147            Self::Golomb(1) => code_consts::GOLOMB1,
148            Self::Golomb(2) => code_consts::GOLOMB2,
149            Self::Golomb(3) => code_consts::GOLOMB3,
150            Self::Golomb(4) => code_consts::GOLOMB4,
151            Self::Golomb(5) => code_consts::GOLOMB5,
152            Self::Golomb(6) => code_consts::GOLOMB6,
153            Self::Golomb(7) => code_consts::GOLOMB7,
154            Self::Golomb(8) => code_consts::GOLOMB8,
155            Self::Golomb(9) => code_consts::GOLOMB9,
156            Self::Golomb(10) => code_consts::GOLOMB10,
157            Self::ExpGolomb(0) => code_consts::EXP_GOLOMB0,
158            Self::ExpGolomb(1) => code_consts::EXP_GOLOMB1,
159            Self::ExpGolomb(2) => code_consts::EXP_GOLOMB2,
160            Self::ExpGolomb(3) => code_consts::EXP_GOLOMB3,
161            Self::ExpGolomb(4) => code_consts::EXP_GOLOMB4,
162            Self::ExpGolomb(5) => code_consts::EXP_GOLOMB5,
163            Self::ExpGolomb(6) => code_consts::EXP_GOLOMB6,
164            Self::ExpGolomb(7) => code_consts::EXP_GOLOMB7,
165            Self::ExpGolomb(8) => code_consts::EXP_GOLOMB8,
166            Self::ExpGolomb(9) => code_consts::EXP_GOLOMB9,
167            Self::ExpGolomb(10) => code_consts::EXP_GOLOMB10,
168            _ => {
169                return Err(anyhow::anyhow!(
170                    "Code {:?} not supported as const code",
171                    self
172                ));
173            }
174        })
175    }
176
177    /// Converts a value from [`code_consts`] to a code.
178    pub fn from_code_const(const_code: usize) -> Result<Self> {
179        Ok(match const_code {
180            code_consts::UNARY => Self::Unary,
181            code_consts::GAMMA => Self::Gamma,
182            code_consts::DELTA => Self::Delta,
183            code_consts::OMEGA => Self::Omega,
184            code_consts::VBYTE_LE => Self::VByteLe,
185            code_consts::VBYTE_BE => Self::VByteBe,
186            code_consts::ZETA2 => Self::Zeta(2),
187            code_consts::ZETA3 => Self::Zeta(3),
188            code_consts::ZETA4 => Self::Zeta(4),
189            code_consts::ZETA5 => Self::Zeta(5),
190            code_consts::ZETA6 => Self::Zeta(6),
191            code_consts::ZETA7 => Self::Zeta(7),
192            code_consts::ZETA8 => Self::Zeta(8),
193            code_consts::ZETA9 => Self::Zeta(9),
194            code_consts::ZETA10 => Self::Zeta(10),
195            code_consts::RICE1 => Self::Rice(1),
196            code_consts::RICE2 => Self::Rice(2),
197            code_consts::RICE3 => Self::Rice(3),
198            code_consts::RICE4 => Self::Rice(4),
199            code_consts::RICE5 => Self::Rice(5),
200            code_consts::RICE6 => Self::Rice(6),
201            code_consts::RICE7 => Self::Rice(7),
202            code_consts::RICE8 => Self::Rice(8),
203            code_consts::RICE9 => Self::Rice(9),
204            code_consts::RICE10 => Self::Rice(10),
205            code_consts::PI1 => Self::Pi(1),
206            code_consts::PI2 => Self::Pi(2),
207            code_consts::PI3 => Self::Pi(3),
208            code_consts::PI4 => Self::Pi(4),
209            code_consts::PI5 => Self::Pi(5),
210            code_consts::PI6 => Self::Pi(6),
211            code_consts::PI7 => Self::Pi(7),
212            code_consts::PI8 => Self::Pi(8),
213            code_consts::PI9 => Self::Pi(9),
214            code_consts::PI10 => Self::Pi(10),
215            code_consts::GOLOMB3 => Self::Golomb(3),
216            code_consts::GOLOMB5 => Self::Golomb(5),
217            code_consts::GOLOMB6 => Self::Golomb(6),
218            code_consts::GOLOMB7 => Self::Golomb(7),
219            code_consts::GOLOMB9 => Self::Golomb(9),
220            code_consts::GOLOMB10 => Self::Golomb(10),
221            code_consts::EXP_GOLOMB1 => Self::ExpGolomb(1),
222            code_consts::EXP_GOLOMB2 => Self::ExpGolomb(2),
223            code_consts::EXP_GOLOMB3 => Self::ExpGolomb(3),
224            code_consts::EXP_GOLOMB4 => Self::ExpGolomb(4),
225            code_consts::EXP_GOLOMB5 => Self::ExpGolomb(5),
226            code_consts::EXP_GOLOMB6 => Self::ExpGolomb(6),
227            code_consts::EXP_GOLOMB7 => Self::ExpGolomb(7),
228            code_consts::EXP_GOLOMB8 => Self::ExpGolomb(8),
229            code_consts::EXP_GOLOMB9 => Self::ExpGolomb(9),
230            code_consts::EXP_GOLOMB10 => Self::ExpGolomb(10),
231            _ => return Err(anyhow::anyhow!("Code {} not supported", const_code)),
232        })
233    }
234}
235
236impl DynamicCodeRead for Codes {
237    #[inline]
238    fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
239        &self,
240        reader: &mut CR,
241    ) -> Result<u64, CR::Error> {
242        Ok(match self {
243            Codes::Unary => reader.read_unary()?,
244            Codes::Gamma => reader.read_gamma()?,
245            Codes::Delta => reader.read_delta()?,
246            Codes::Omega => reader.read_omega()?,
247            Codes::VByteBe => reader.read_vbyte_be()?,
248            Codes::VByteLe => reader.read_vbyte_le()?,
249            Codes::Zeta(3) => reader.read_zeta3()?,
250            Codes::Zeta(k) => reader.read_zeta(*k)?,
251            Codes::Pi(2) => reader.read_pi2()?,
252            Codes::Pi(k) => reader.read_pi(*k)?,
253            Codes::Golomb(b) => reader.read_golomb(*b)?,
254            Codes::ExpGolomb(k) => reader.read_exp_golomb(*k)?,
255            Codes::Rice(log2_b) => reader.read_rice(*log2_b)?,
256        })
257    }
258}
259
260impl DynamicCodeWrite for Codes {
261    #[inline]
262    fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
263        &self,
264        writer: &mut CW,
265        value: u64,
266    ) -> Result<usize, CW::Error> {
267        Ok(match self {
268            Codes::Unary => writer.write_unary(value)?,
269            Codes::Gamma => writer.write_gamma(value)?,
270            Codes::Delta => writer.write_delta(value)?,
271            Codes::Omega => writer.write_omega(value)?,
272            Codes::VByteBe => writer.write_vbyte_be(value)?,
273            Codes::VByteLe => writer.write_vbyte_le(value)?,
274            Codes::Zeta(1) => writer.write_gamma(value)?,
275            Codes::Zeta(3) => writer.write_zeta3(value)?,
276            Codes::Zeta(k) => writer.write_zeta(value, *k)?,
277            Codes::Pi(2) => writer.write_pi2(value)?,
278            Codes::Pi(k) => writer.write_pi(value, *k)?,
279            Codes::Golomb(b) => writer.write_golomb(value, *b)?,
280            Codes::ExpGolomb(k) => writer.write_exp_golomb(value, *k)?,
281            Codes::Rice(log2_b) => writer.write_rice(value, *log2_b)?,
282        })
283    }
284}
285
286impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for Codes {
287    #[inline(always)]
288    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
289        <Self as DynamicCodeRead>::read(self, reader)
290    }
291}
292
293impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for Codes {
294    #[inline(always)]
295    fn write(&self, writer: &mut CW, value: u64) -> Result<usize, CW::Error> {
296        <Self as DynamicCodeWrite>::write(self, writer, value)
297    }
298}
299
300impl CodeLen for Codes {
301    #[inline]
302    fn len(&self, value: u64) -> usize {
303        match self {
304            Codes::Unary => value as usize + 1,
305            Codes::Gamma => len_gamma(value),
306            Codes::Delta => len_delta(value),
307            Codes::Omega => len_omega(value),
308            Codes::VByteLe | Codes::VByteBe => bit_len_vbyte(value),
309            Codes::Zeta(1) => len_gamma(value),
310            Codes::Zeta(k) => len_zeta(value, *k),
311            Codes::Pi(k) => len_pi(value, *k),
312            Codes::Golomb(b) => len_golomb(value, *b),
313            Codes::ExpGolomb(k) => len_exp_golomb(value, *k),
314            Codes::Rice(log2_b) => len_rice(value, *log2_b),
315        }
316    }
317}
318
319#[derive(Debug, Clone)]
320/// Error type for parsing a code from a string.
321pub enum CodeError {
322    /// Error parsing an integer parameter.
323    ParseError(core::num::ParseIntError),
324    /// Unknown code name. Uses a fixed-size array instead of `String` for `no_std` compatibility.
325    UnknownCode([u8; 32]),
326}
327#[cfg(feature = "std")]
328impl std::error::Error for CodeError {}
329impl core::fmt::Display for CodeError {
330    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
331        match self {
332            CodeError::ParseError(e) => write!(f, "Parse error: {}", e),
333            CodeError::UnknownCode(s) => {
334                write!(f, "Unknown code: ")?;
335                for c in s {
336                    if *c == 0 {
337                        break;
338                    }
339                    write!(f, "{}", *c as char)?;
340                }
341                Ok(())
342            }
343        }
344    }
345}
346
347impl From<core::num::ParseIntError> for CodeError {
348    fn from(e: core::num::ParseIntError) -> Self {
349        CodeError::ParseError(e)
350    }
351}
352
353impl core::fmt::Display for Codes {
354    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
355        match self {
356            Codes::Unary => write!(f, "Unary"),
357            Codes::Gamma => write!(f, "Gamma"),
358            Codes::Delta => write!(f, "Delta"),
359            Codes::Omega => write!(f, "Omega"),
360            Codes::VByteBe => write!(f, "VByteBe"),
361            Codes::VByteLe => write!(f, "VByteLe"),
362            Codes::Zeta(k) => write!(f, "Zeta({})", k),
363            Codes::Pi(k) => write!(f, "Pi({})", k),
364            Codes::Golomb(b) => write!(f, "Golomb({})", b),
365            Codes::ExpGolomb(k) => write!(f, "ExpGolomb({})", k),
366            Codes::Rice(log2_b) => write!(f, "Rice({})", log2_b),
367        }
368    }
369}
370
371fn array_format_error(s: &str) -> [u8; 32] {
372    let mut error_buffer = [0u8; 32];
373    const ERROR_PREFIX: &[u8] = b"Could not parse ";
374    error_buffer[..ERROR_PREFIX.len()].copy_from_slice(ERROR_PREFIX);
375    error_buffer[ERROR_PREFIX.len()..ERROR_PREFIX.len() + s.len().min(32 - ERROR_PREFIX.len())]
376        .copy_from_slice(&s.as_bytes()[..s.len().min(32 - ERROR_PREFIX.len())]);
377    error_buffer
378}
379
380impl core::str::FromStr for Codes {
381    type Err = CodeError;
382
383    fn from_str(s: &str) -> Result<Self, Self::Err> {
384        match s {
385            "Unary" => Ok(Codes::Unary),
386            "Gamma" => Ok(Codes::Gamma),
387            "Delta" => Ok(Codes::Delta),
388            "Omega" => Ok(Codes::Omega),
389            "VByteBe" => Ok(Codes::VByteBe),
390            "VByteLe" => Ok(Codes::VByteLe),
391
392            _ => {
393                let mut parts = s.split('(');
394                let name = parts
395                    .next()
396                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
397                let k = parts
398                    .next()
399                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?
400                    .split(')')
401                    .next()
402                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
403                match name {
404                    "Zeta" => Ok(Codes::Zeta(k.parse()?)),
405                    "Pi" => Ok(Codes::Pi(k.parse()?)),
406                    "Golomb" => Ok(Codes::Golomb(k.parse()?)),
407                    "ExpGolomb" => Ok(Codes::ExpGolomb(k.parse()?)),
408                    "Rice" => Ok(Codes::Rice(k.parse()?)),
409                    _ => Err(CodeError::UnknownCode(array_format_error(name))),
410                }
411            }
412        }
413    }
414}
415
416#[cfg(feature = "serde")]
417impl serde::Serialize for Codes {
418    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
419    where
420        S: serde::Serializer,
421    {
422        serializer.serialize_str(&self.to_string())
423    }
424}
425
426#[cfg(feature = "serde")]
427impl<'de> serde::Deserialize<'de> for Codes {
428    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
429    where
430        D: serde::Deserializer<'de>,
431    {
432        let s = String::deserialize(deserializer)?;
433        s.parse().map_err(serde::de::Error::custom)
434    }
435}
436
437/// Structure representing minimal binary coding with a fixed length.
438///
439/// [Minimal binary coding](crate::codes::minimal_binary) does not
440/// fit the [`Codes`] enum because it is not defined for all integers.
441///
442/// Instances of this structure can be used in context in which a
443/// [`DynamicCodeRead`], [`DynamicCodeWrite`], [`StaticCodeRead`],
444/// [`StaticCodeWrite`] or [`CodeLen`] implementing minimal binary coding
445/// is necessary.
446#[derive(Clone, Copy, Debug, PartialEq, Eq)]
447pub struct MinimalBinary(pub u64);
448
449impl DynamicCodeRead for MinimalBinary {
450    fn read<E: Endianness, R: CodesRead<E> + ?Sized>(
451        &self,
452        reader: &mut R,
453    ) -> Result<u64, R::Error> {
454        reader.read_minimal_binary(self.0)
455    }
456}
457
458impl DynamicCodeWrite for MinimalBinary {
459    fn write<E: Endianness, W: CodesWrite<E> + ?Sized>(
460        &self,
461        writer: &mut W,
462        n: u64,
463    ) -> Result<usize, W::Error> {
464        writer.write_minimal_binary(n, self.0)
465    }
466}
467
468impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for MinimalBinary {
469    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
470        <Self as DynamicCodeRead>::read(self, reader)
471    }
472}
473
474impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for MinimalBinary {
475    fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
476        <Self as DynamicCodeWrite>::write(self, writer, n)
477    }
478}
479
480impl CodeLen for MinimalBinary {
481    fn len(&self, n: u64) -> usize {
482        len_minimal_binary(n, self.0)
483    }
484}