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