Skip to main content

dsi_bitstream/dispatch/
dynamic.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//! Dynamic dispatching for codes based on function pointers.
10//!
11//! This kind of dispatch is resolved at runtime, but just once, at construction
12//! time, against a specific [`CodesRead`]. The code is stored in a function
13//! pointer, so it cannot be inlined like in the [static
14//! case](crate::dispatch::static), but the approach is more flexible.
15
16use super::*;
17#[cfg(feature = "mem_dbg")]
18use mem_dbg::{MemDbg, MemSize};
19
20type ReadFn<E, CR> = fn(&mut CR) -> Result<u64, <CR as BitRead<E>>::Error>;
21
22/// A newtype containing a function pointer dispatching the read
23/// method for a code.
24///
25/// This is a more efficient way to pass a [`StaticCodeRead`] to a method, as a
26/// [`FuncCodeReader`] does not need to do a runtime test to dispatch the
27/// correct code.
28///
29/// Instances can be obtained by calling the [`new`](FuncCodeReader::new) method
30/// with a variant of the [`Codes`] enum, or by calling the
31/// [`new_with_func`](FuncCodeReader::new_with_func) method with a function
32/// pointer.
33///
34/// Note that since selection of the code happens in the
35/// [`new`](FuncCodeReader::new) method, it is more efficient to clone a
36/// [`FuncCodeReader`] than to create a new one.
37#[derive(Debug, Copy)]
38#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
39pub struct FuncCodeReader<E: Endianness, CR: CodesRead<E> + ?Sized>(ReadFn<E, CR>);
40
41/// Manually implement [`Clone`] to avoid the [`Clone`] bound on CR and E
42impl<E: Endianness, CR: CodesRead<E> + ?Sized> Clone for FuncCodeReader<E, CR> {
43    #[inline(always)]
44    fn clone(&self) -> Self {
45        Self(self.0)
46    }
47}
48
49impl<E: Endianness, CR: CodesRead<E> + ?Sized> FuncCodeReader<E, CR> {
50    const UNARY: ReadFn<E, CR> = |reader: &mut CR| reader.read_unary();
51    const GAMMA: ReadFn<E, CR> = |reader: &mut CR| reader.read_gamma();
52    const DELTA: ReadFn<E, CR> = |reader: &mut CR| reader.read_delta();
53    const OMEGA: ReadFn<E, CR> = |reader: &mut CR| reader.read_omega();
54    const VBYTE_BE: ReadFn<E, CR> = |reader: &mut CR| reader.read_vbyte_be();
55    const VBYTE_LE: ReadFn<E, CR> = |reader: &mut CR| reader.read_vbyte_le();
56    const ZETA2: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(2);
57    const ZETA3: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta3();
58    const ZETA4: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(4);
59    const ZETA5: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(5);
60    const ZETA6: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(6);
61    const ZETA7: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(7);
62    const ZETA8: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(8);
63    const ZETA9: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(9);
64    const ZETA10: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(10);
65    const RICE1: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(1);
66    const RICE2: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(2);
67    const RICE3: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(3);
68    const RICE4: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(4);
69    const RICE5: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(5);
70    const RICE6: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(6);
71    const RICE7: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(7);
72    const RICE8: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(8);
73    const RICE9: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(9);
74    const RICE10: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(10);
75    const PI1: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(1);
76    const PI2: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi2();
77    const PI3: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(3);
78    const PI4: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(4);
79    const PI5: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(5);
80    const PI6: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(6);
81    const PI7: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(7);
82    const PI8: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(8);
83    const PI9: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(9);
84    const PI10: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(10);
85    const GOLOMB3: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(3);
86    const GOLOMB5: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(5);
87    const GOLOMB6: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(6);
88    const GOLOMB7: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(7);
89    const GOLOMB9: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(9);
90    const GOLOMB10: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(10);
91    const EXP_GOLOMB1: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(1);
92    const EXP_GOLOMB2: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(2);
93    const EXP_GOLOMB3: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(3);
94    const EXP_GOLOMB4: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(4);
95    const EXP_GOLOMB5: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(5);
96    const EXP_GOLOMB6: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(6);
97    const EXP_GOLOMB7: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(7);
98    const EXP_GOLOMB8: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(8);
99    const EXP_GOLOMB9: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(9);
100    const EXP_GOLOMB10: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(10);
101
102    /// Returns a new [`FuncCodeReader`] for the given code.
103    ///
104    /// The code is [canonicalized](Codes::canonicalize) before
105    /// the lookup, so equivalent codes yield the same reader.
106    ///
107    /// # Errors
108    ///
109    /// The method will return an error if there is no constant
110    /// for the given code in [`FuncCodeReader`].
111    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
112        let code = code.canonicalize();
113        let read_func = match code {
114            Codes::Unary => Self::UNARY,
115            Codes::Gamma => Self::GAMMA,
116            Codes::Delta => Self::DELTA,
117            Codes::Omega => Self::OMEGA,
118            Codes::VByteBe => Self::VBYTE_BE,
119            Codes::VByteLe => Self::VBYTE_LE,
120            Codes::Zeta(2) => Self::ZETA2,
121            Codes::Zeta(3) => Self::ZETA3,
122            Codes::Zeta(4) => Self::ZETA4,
123            Codes::Zeta(5) => Self::ZETA5,
124            Codes::Zeta(6) => Self::ZETA6,
125            Codes::Zeta(7) => Self::ZETA7,
126            Codes::Zeta(8) => Self::ZETA8,
127            Codes::Zeta(9) => Self::ZETA9,
128            Codes::Zeta(10) => Self::ZETA10,
129            Codes::Rice(1) => Self::RICE1,
130            Codes::Rice(2) => Self::RICE2,
131            Codes::Rice(3) => Self::RICE3,
132            Codes::Rice(4) => Self::RICE4,
133            Codes::Rice(5) => Self::RICE5,
134            Codes::Rice(6) => Self::RICE6,
135            Codes::Rice(7) => Self::RICE7,
136            Codes::Rice(8) => Self::RICE8,
137            Codes::Rice(9) => Self::RICE9,
138            Codes::Rice(10) => Self::RICE10,
139            Codes::Pi(1) => Self::PI1,
140            Codes::Pi(2) => Self::PI2,
141            Codes::Pi(3) => Self::PI3,
142            Codes::Pi(4) => Self::PI4,
143            Codes::Pi(5) => Self::PI5,
144            Codes::Pi(6) => Self::PI6,
145            Codes::Pi(7) => Self::PI7,
146            Codes::Pi(8) => Self::PI8,
147            Codes::Pi(9) => Self::PI9,
148            Codes::Pi(10) => Self::PI10,
149            Codes::Golomb(3) => Self::GOLOMB3,
150            Codes::Golomb(5) => Self::GOLOMB5,
151            Codes::Golomb(6) => Self::GOLOMB6,
152            Codes::Golomb(7) => Self::GOLOMB7,
153            Codes::Golomb(9) => Self::GOLOMB9,
154            Codes::Golomb(10) => Self::GOLOMB10,
155            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
156            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
157            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
158            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
159            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
160            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
161            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
162            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
163            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
164            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
165            _ => return Err(DispatchError::UnsupportedCode(code)),
166        };
167        Ok(Self(read_func))
168    }
169
170    /// Returns a new [`FuncCodeReader`] for the given function.
171    #[must_use]
172    #[inline(always)]
173    pub const fn new_with_func(read_func: ReadFn<E, CR>) -> Self {
174        Self(read_func)
175    }
176
177    /// Returns the function pointer for the code.
178    #[must_use]
179    #[inline(always)]
180    pub const fn get_func(&self) -> ReadFn<E, CR> {
181        self.0
182    }
183}
184
185impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for FuncCodeReader<E, CR> {
186    #[inline(always)]
187    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
188        (self.0)(reader)
189    }
190}
191
192type WriteFn<E, CW> = fn(&mut CW, u64) -> Result<usize, <CW as BitWrite<E>>::Error>;
193
194/// A newtype containing a function pointer dispatching the write method for a
195/// code.
196///
197/// This is a more efficient way to pass a [`StaticCodeWrite`] to a method, as
198/// a [`FuncCodeWriter`] does not need to do a runtime test to dispatch the
199/// correct code.
200///
201/// Instances can be obtained by calling the [`new`](FuncCodeWriter::new) method
202/// with a variant of the [`Codes`] enum, or by calling the
203/// [`new_with_func`](FuncCodeWriter::new_with_func) method with a function
204/// pointer.
205///
206/// Note that since selection of the code happens in the
207/// [`new`](FuncCodeWriter::new) method, it is more efficient to clone a
208/// [`FuncCodeWriter`] than to create a new one.
209#[derive(Debug, Copy)]
210#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
211pub struct FuncCodeWriter<E: Endianness, CW: CodesWrite<E> + ?Sized>(WriteFn<E, CW>);
212
213/// Manually implement [`Clone`] to avoid the [`Clone`] bound on CW and E.
214impl<E: Endianness, CW: CodesWrite<E> + ?Sized> Clone for FuncCodeWriter<E, CW> {
215    #[inline(always)]
216    fn clone(&self) -> Self {
217        Self(self.0)
218    }
219}
220
221impl<E: Endianness, CW: CodesWrite<E> + ?Sized> FuncCodeWriter<E, CW> {
222    const UNARY: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_unary(n);
223    const GAMMA: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_gamma(n);
224    const DELTA: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_delta(n);
225    const OMEGA: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_omega(n);
226    const VBYTE_BE: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_vbyte_be(n);
227    const VBYTE_LE: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_vbyte_le(n);
228    const ZETA2: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 2);
229    const ZETA3: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta3(n);
230    const ZETA4: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 4);
231    const ZETA5: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 5);
232    const ZETA6: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 6);
233    const ZETA7: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 7);
234    const ZETA8: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 8);
235    const ZETA9: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 9);
236    const ZETA10: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_zeta(n, 10);
237    const RICE1: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 1);
238    const RICE2: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 2);
239    const RICE3: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 3);
240    const RICE4: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 4);
241    const RICE5: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 5);
242    const RICE6: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 6);
243    const RICE7: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 7);
244    const RICE8: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 8);
245    const RICE9: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 9);
246    const RICE10: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_rice(n, 10);
247    const PI1: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 1);
248    const PI2: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi2(n);
249    const PI3: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 3);
250    const PI4: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 4);
251    const PI5: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 5);
252    const PI6: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 6);
253    const PI7: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 7);
254    const PI8: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 8);
255    const PI9: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 9);
256    const PI10: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_pi(n, 10);
257    const GOLOMB3: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 3);
258    const GOLOMB5: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 5);
259    const GOLOMB6: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 6);
260    const GOLOMB7: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 7);
261    const GOLOMB9: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 9);
262    const GOLOMB10: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_golomb(n, 10);
263    const EXP_GOLOMB1: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 1);
264    const EXP_GOLOMB2: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 2);
265    const EXP_GOLOMB3: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 3);
266    const EXP_GOLOMB4: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 4);
267    const EXP_GOLOMB5: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 5);
268    const EXP_GOLOMB6: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 6);
269    const EXP_GOLOMB7: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 7);
270    const EXP_GOLOMB8: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 8);
271    const EXP_GOLOMB9: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 9);
272    const EXP_GOLOMB10: WriteFn<E, CW> = |writer: &mut CW, n: u64| writer.write_exp_golomb(n, 10);
273
274    /// Returns a new [`FuncCodeWriter`] for the given code.
275    ///
276    /// The code is [canonicalized](Codes::canonicalize) before
277    /// the lookup, so equivalent codes yield the same writer.
278    ///
279    /// # Errors
280    ///
281    /// The method will return an error if there is no constant
282    /// for the given code in [`FuncCodeWriter`].
283    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
284        let code = code.canonicalize();
285        let write_func = match code {
286            Codes::Unary => Self::UNARY,
287            Codes::Gamma => Self::GAMMA,
288            Codes::Delta => Self::DELTA,
289            Codes::Omega => Self::OMEGA,
290            Codes::VByteBe => Self::VBYTE_BE,
291            Codes::VByteLe => Self::VBYTE_LE,
292            Codes::Zeta(2) => Self::ZETA2,
293            Codes::Zeta(3) => Self::ZETA3,
294            Codes::Zeta(4) => Self::ZETA4,
295            Codes::Zeta(5) => Self::ZETA5,
296            Codes::Zeta(6) => Self::ZETA6,
297            Codes::Zeta(7) => Self::ZETA7,
298            Codes::Zeta(8) => Self::ZETA8,
299            Codes::Zeta(9) => Self::ZETA9,
300            Codes::Zeta(10) => Self::ZETA10,
301            Codes::Rice(1) => Self::RICE1,
302            Codes::Rice(2) => Self::RICE2,
303            Codes::Rice(3) => Self::RICE3,
304            Codes::Rice(4) => Self::RICE4,
305            Codes::Rice(5) => Self::RICE5,
306            Codes::Rice(6) => Self::RICE6,
307            Codes::Rice(7) => Self::RICE7,
308            Codes::Rice(8) => Self::RICE8,
309            Codes::Rice(9) => Self::RICE9,
310            Codes::Rice(10) => Self::RICE10,
311            Codes::Pi(1) => Self::PI1,
312            Codes::Pi(2) => Self::PI2,
313            Codes::Pi(3) => Self::PI3,
314            Codes::Pi(4) => Self::PI4,
315            Codes::Pi(5) => Self::PI5,
316            Codes::Pi(6) => Self::PI6,
317            Codes::Pi(7) => Self::PI7,
318            Codes::Pi(8) => Self::PI8,
319            Codes::Pi(9) => Self::PI9,
320            Codes::Pi(10) => Self::PI10,
321            Codes::Golomb(3) => Self::GOLOMB3,
322            Codes::Golomb(5) => Self::GOLOMB5,
323            Codes::Golomb(6) => Self::GOLOMB6,
324            Codes::Golomb(7) => Self::GOLOMB7,
325            Codes::Golomb(9) => Self::GOLOMB9,
326            Codes::Golomb(10) => Self::GOLOMB10,
327            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
328            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
329            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
330            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
331            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
332            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
333            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
334            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
335            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
336            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
337            _ => return Err(DispatchError::UnsupportedCode(code)),
338        };
339        Ok(Self(write_func))
340    }
341
342    /// Returns a new [`FuncCodeWriter`] for the given function.
343    #[must_use]
344    #[inline(always)]
345    pub const fn new_with_func(write_func: WriteFn<E, CW>) -> Self {
346        Self(write_func)
347    }
348
349    /// Returns the function pointer for the code.
350    #[must_use]
351    #[inline(always)]
352    pub const fn get_func(&self) -> WriteFn<E, CW> {
353        self.0
354    }
355}
356
357impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for FuncCodeWriter<E, CW> {
358    #[inline(always)]
359    fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
360        (self.0)(writer, n)
361    }
362}
363
364type LenFn = fn(u64) -> usize;
365
366/// A newtype containing a function pointer dispatching the length method for a
367/// code.
368///
369/// This is a more efficient way to pass a [`CodeLen`] to a method, as
370/// a [`FuncCodeLen`] does not need to do a runtime test to dispatch the correct
371/// method.
372///
373/// Instances can be obtained by calling the [`new`](FuncCodeLen::new) method
374/// with a variant of the [`Codes`] enum, or by calling the
375/// [`new_with_func`](FuncCodeLen::new_with_func) method with a function pointer.
376///
377/// Note that since selection of the code happens in the [`new`](FuncCodeLen::new)
378/// method, it is more efficient to clone a [`FuncCodeLen`] than to create a new one.
379#[derive(Debug, Clone, Copy)]
380#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
381#[cfg_attr(feature = "mem_dbg", mem_size_flat)]
382pub struct FuncCodeLen(LenFn);
383
384impl FuncCodeLen {
385    const UNARY: LenFn = |n| n as usize + 1;
386    const GAMMA: LenFn = |n| len_gamma(n);
387    const DELTA: LenFn = |n| len_delta(n);
388    const OMEGA: LenFn = |n| len_omega(n);
389    const VBYTE_BE: LenFn = |n| bit_len_vbyte(n);
390    const VBYTE_LE: LenFn = |n| bit_len_vbyte(n);
391    const ZETA2: LenFn = |n| len_zeta(n, 2);
392    const ZETA3: LenFn = |n| len_zeta(n, 3);
393    const ZETA4: LenFn = |n| len_zeta(n, 4);
394    const ZETA5: LenFn = |n| len_zeta(n, 5);
395    const ZETA6: LenFn = |n| len_zeta(n, 6);
396    const ZETA7: LenFn = |n| len_zeta(n, 7);
397    const ZETA8: LenFn = |n| len_zeta(n, 8);
398    const ZETA9: LenFn = |n| len_zeta(n, 9);
399    const ZETA10: LenFn = |n| len_zeta(n, 10);
400    const RICE1: LenFn = |n| len_rice(n, 1);
401    const RICE2: LenFn = |n| len_rice(n, 2);
402    const RICE3: LenFn = |n| len_rice(n, 3);
403    const RICE4: LenFn = |n| len_rice(n, 4);
404    const RICE5: LenFn = |n| len_rice(n, 5);
405    const RICE6: LenFn = |n| len_rice(n, 6);
406    const RICE7: LenFn = |n| len_rice(n, 7);
407    const RICE8: LenFn = |n| len_rice(n, 8);
408    const RICE9: LenFn = |n| len_rice(n, 9);
409    const RICE10: LenFn = |n| len_rice(n, 10);
410    const PI1: LenFn = |n| len_pi(n, 1);
411    const PI2: LenFn = |n| len_pi(n, 2);
412    const PI3: LenFn = |n| len_pi(n, 3);
413    const PI4: LenFn = |n| len_pi(n, 4);
414    const PI5: LenFn = |n| len_pi(n, 5);
415    const PI6: LenFn = |n| len_pi(n, 6);
416    const PI7: LenFn = |n| len_pi(n, 7);
417    const PI8: LenFn = |n| len_pi(n, 8);
418    const PI9: LenFn = |n| len_pi(n, 9);
419    const PI10: LenFn = |n| len_pi(n, 10);
420    const GOLOMB3: LenFn = |n| len_golomb(n, 3);
421    const GOLOMB5: LenFn = |n| len_golomb(n, 5);
422    const GOLOMB6: LenFn = |n| len_golomb(n, 6);
423    const GOLOMB7: LenFn = |n| len_golomb(n, 7);
424    const GOLOMB9: LenFn = |n| len_golomb(n, 9);
425    const GOLOMB10: LenFn = |n| len_golomb(n, 10);
426    const EXP_GOLOMB1: LenFn = |n| len_exp_golomb(n, 1);
427    const EXP_GOLOMB2: LenFn = |n| len_exp_golomb(n, 2);
428    const EXP_GOLOMB3: LenFn = |n| len_exp_golomb(n, 3);
429    const EXP_GOLOMB4: LenFn = |n| len_exp_golomb(n, 4);
430    const EXP_GOLOMB5: LenFn = |n| len_exp_golomb(n, 5);
431    const EXP_GOLOMB6: LenFn = |n| len_exp_golomb(n, 6);
432    const EXP_GOLOMB7: LenFn = |n| len_exp_golomb(n, 7);
433    const EXP_GOLOMB8: LenFn = |n| len_exp_golomb(n, 8);
434    const EXP_GOLOMB9: LenFn = |n| len_exp_golomb(n, 9);
435    const EXP_GOLOMB10: LenFn = |n| len_exp_golomb(n, 10);
436
437    /// Returns a new [`FuncCodeLen`] for the given code.
438    ///
439    /// The code is [canonicalized](Codes::canonicalize) before
440    /// the lookup, so equivalent codes yield the same length
441    /// function.
442    ///
443    /// # Errors
444    ///
445    /// The method will return an error if there is no constant
446    /// for the given code in [`FuncCodeLen`].
447    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
448        let code = code.canonicalize();
449        let len_func = match code {
450            Codes::Unary => Self::UNARY,
451            Codes::Gamma => Self::GAMMA,
452            Codes::Delta => Self::DELTA,
453            Codes::Omega => Self::OMEGA,
454            Codes::VByteBe => Self::VBYTE_BE,
455            Codes::VByteLe => Self::VBYTE_LE,
456            Codes::Zeta(2) => Self::ZETA2,
457            Codes::Zeta(3) => Self::ZETA3,
458            Codes::Zeta(4) => Self::ZETA4,
459            Codes::Zeta(5) => Self::ZETA5,
460            Codes::Zeta(6) => Self::ZETA6,
461            Codes::Zeta(7) => Self::ZETA7,
462            Codes::Zeta(8) => Self::ZETA8,
463            Codes::Zeta(9) => Self::ZETA9,
464            Codes::Zeta(10) => Self::ZETA10,
465            Codes::Rice(1) => Self::RICE1,
466            Codes::Rice(2) => Self::RICE2,
467            Codes::Rice(3) => Self::RICE3,
468            Codes::Rice(4) => Self::RICE4,
469            Codes::Rice(5) => Self::RICE5,
470            Codes::Rice(6) => Self::RICE6,
471            Codes::Rice(7) => Self::RICE7,
472            Codes::Rice(8) => Self::RICE8,
473            Codes::Rice(9) => Self::RICE9,
474            Codes::Rice(10) => Self::RICE10,
475            Codes::Pi(1) => Self::PI1,
476            Codes::Pi(2) => Self::PI2,
477            Codes::Pi(3) => Self::PI3,
478            Codes::Pi(4) => Self::PI4,
479            Codes::Pi(5) => Self::PI5,
480            Codes::Pi(6) => Self::PI6,
481            Codes::Pi(7) => Self::PI7,
482            Codes::Pi(8) => Self::PI8,
483            Codes::Pi(9) => Self::PI9,
484            Codes::Pi(10) => Self::PI10,
485            Codes::Golomb(3) => Self::GOLOMB3,
486            Codes::Golomb(5) => Self::GOLOMB5,
487            Codes::Golomb(6) => Self::GOLOMB6,
488            Codes::Golomb(7) => Self::GOLOMB7,
489            Codes::Golomb(9) => Self::GOLOMB9,
490            Codes::Golomb(10) => Self::GOLOMB10,
491            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
492            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
493            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
494            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
495            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
496            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
497            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
498            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
499            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
500            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
501            _ => return Err(DispatchError::UnsupportedCode(code)),
502        };
503        Ok(Self(len_func))
504    }
505
506    /// Returns a new [`FuncCodeLen`] for the given function.
507    #[must_use]
508    #[inline(always)]
509    pub const fn new_with_func(len_func: LenFn) -> Self {
510        Self(len_func)
511    }
512    /// Returns the function pointer for the code.
513    #[must_use]
514    #[inline(always)]
515    pub const fn get_func(&self) -> LenFn {
516        self.0
517    }
518}
519
520/// Here we do not depend on the bitstream, so there is no need for a "static"
521/// version of the trait.
522impl CodeLen for FuncCodeLen {
523    #[inline(always)]
524    fn len(&self, n: u64) -> usize {
525        (self.0)(n)
526    }
527}