• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vigna / dsi-bitstream-rs / 22257013902

21 Feb 2026 12:42PM UTC coverage: 54.618% (+0.7%) from 53.899%
22257013902

push

github

vigna
Explicit Codes::canonicalize method; many const to code-conversion functions

32 of 48 new or added lines in 5 files covered. (66.67%)

2111 of 3865 relevant lines covered (54.62%)

2728423.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/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

16
use super::*;
17
#[cfg(feature = "mem_dbg")]
18
use mem_dbg::{MemDbg, MemSize};
19

20
type 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))]
39
pub 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
42
impl<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

49
impl<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
    /// Returns a new [`FuncCodeReader`] for the given code.
102
    ///
103
    /// The code is [canonicalized](Codes::canonicalize) before
104
    /// the lookup, so equivalent codes yield the same reader.
105
    ///
106
    /// # Errors
107
    ///
108
    /// The method will return an error if there is no constant
109
    /// for the given code in [`FuncCodeReader`].
NEW
110
    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
×
NEW
111
        let code = code.canonicalize();
×
112
        let read_func = match code {
×
113
            Codes::Unary => Self::UNARY,
×
114
            Codes::Gamma => Self::GAMMA,
×
115
            Codes::Delta => Self::DELTA,
×
116
            Codes::Omega => Self::OMEGA,
×
117
            Codes::VByteBe => Self::VBYTE_BE,
×
118
            Codes::VByteLe => Self::VBYTE_LE,
×
119
            Codes::Zeta(2) => Self::ZETA2,
×
120
            Codes::Zeta(3) => Self::ZETA3,
×
121
            Codes::Zeta(4) => Self::ZETA4,
×
122
            Codes::Zeta(5) => Self::ZETA5,
×
123
            Codes::Zeta(6) => Self::ZETA6,
×
124
            Codes::Zeta(7) => Self::ZETA7,
×
125
            Codes::Zeta(8) => Self::ZETA8,
×
126
            Codes::Zeta(9) => Self::ZETA9,
×
127
            Codes::Zeta(10) => Self::ZETA10,
×
128
            Codes::Rice(1) => Self::RICE1,
×
129
            Codes::Rice(2) => Self::RICE2,
×
130
            Codes::Rice(3) => Self::RICE3,
×
131
            Codes::Rice(4) => Self::RICE4,
×
132
            Codes::Rice(5) => Self::RICE5,
×
133
            Codes::Rice(6) => Self::RICE6,
×
134
            Codes::Rice(7) => Self::RICE7,
×
135
            Codes::Rice(8) => Self::RICE8,
×
136
            Codes::Rice(9) => Self::RICE9,
×
137
            Codes::Rice(10) => Self::RICE10,
×
138
            Codes::Pi(1) => Self::PI1,
×
139
            Codes::Pi(2) => Self::PI2,
×
140
            Codes::Pi(3) => Self::PI3,
×
141
            Codes::Pi(4) => Self::PI4,
×
142
            Codes::Pi(5) => Self::PI5,
×
143
            Codes::Pi(6) => Self::PI6,
×
144
            Codes::Pi(7) => Self::PI7,
×
145
            Codes::Pi(8) => Self::PI8,
×
146
            Codes::Pi(9) => Self::PI9,
×
147
            Codes::Pi(10) => Self::PI10,
×
148
            Codes::Golomb(3) => Self::GOLOMB3,
×
149
            Codes::Golomb(5) => Self::GOLOMB5,
×
150
            Codes::Golomb(6) => Self::GOLOMB6,
×
151
            Codes::Golomb(7) => Self::GOLOMB7,
×
152
            Codes::Golomb(9) => Self::GOLOMB9,
×
153
            Codes::Golomb(10) => Self::GOLOMB10,
×
154
            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
×
155
            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
×
156
            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
×
157
            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
×
158
            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
×
159
            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
×
160
            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
×
161
            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
×
162
            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
×
163
            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
×
164
            _ => return Err(DispatchError::UnsupportedCode(code)),
×
165
        };
166
        Ok(Self(read_func))
×
167
    }
168

169
    /// Returns a new [`FuncCodeReader`] for the given function.
170
    #[inline(always)]
171
    pub fn new_with_func(read_func: ReadFn<E, CR>) -> Self {
×
172
        Self(read_func)
×
173
    }
174

175
    /// Gets the function pointer for the code.
176
    #[inline(always)]
177
    pub fn get_func(&self) -> ReadFn<E, CR> {
×
178
        self.0
×
179
    }
180
}
181

182
impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for FuncCodeReader<E, CR> {
183
    #[inline(always)]
184
    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
×
185
        (self.0)(reader)
×
186
    }
187
}
188

189
type WriteFn<E, CW> = fn(&mut CW, u64) -> Result<usize, <CW as BitWrite<E>>::Error>;
190

191
/// A newtype containing a function pointer dispatching the write method for a
192
/// code.
193
///
194
/// This is a more efficient way to pass a [`StaticCodeWrite`] to a method, as
195
/// a [`FuncCodeWriter`] does not need to do a runtime test to dispatch the
196
/// correct code.
197
///
198
/// Instances can be obtained by calling the [`new`](FuncCodeWriter::new) method
199
/// with a variant of the [`Codes`] enum, or by calling the
200
/// [`new_with_func`](FuncCodeWriter::new_with_func) method with a function
201
/// pointer.
202
///
203
/// Note that since selection of the code happens in the
204
/// [`new`](FuncCodeReader::new) method, it is more efficient to clone a
205
/// [`FuncCodeWriter`] than to create a new one.
206
#[derive(Debug, Copy)]
207
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
208
pub struct FuncCodeWriter<E: Endianness, CW: CodesWrite<E> + ?Sized>(WriteFn<E, CW>);
209

210
/// manually implement Clone to avoid the Clone bound on CR and E
211
impl<E: Endianness, CR: CodesWrite<E> + ?Sized> Clone for FuncCodeWriter<E, CR> {
212
    #[inline(always)]
213
    fn clone(&self) -> Self {
×
214
        Self(self.0)
×
215
    }
216
}
217

218
impl<E: Endianness, CW: CodesWrite<E> + ?Sized> FuncCodeWriter<E, CW> {
219
    const UNARY: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_unary(value);
×
220
    const GAMMA: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_gamma(value);
×
221
    const DELTA: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_delta(value);
×
222
    const OMEGA: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_omega(value);
×
223
    const VBYTE_BE: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_vbyte_be(value);
×
224
    const VBYTE_LE: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_vbyte_le(value);
×
225
    const ZETA2: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 2);
×
226
    const ZETA3: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta3(value);
×
227
    const ZETA4: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 4);
×
228
    const ZETA5: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 5);
×
229
    const ZETA6: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 6);
×
230
    const ZETA7: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 7);
×
231
    const ZETA8: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 8);
×
232
    const ZETA9: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 9);
×
233
    const ZETA10: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_zeta(value, 10);
×
234
    const RICE1: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 1);
×
235
    const RICE2: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 2);
×
236
    const RICE3: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 3);
×
237
    const RICE4: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 4);
×
238
    const RICE5: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 5);
×
239
    const RICE6: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 6);
×
240
    const RICE7: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 7);
×
241
    const RICE8: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 8);
×
242
    const RICE9: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 9);
×
243
    const RICE10: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_rice(value, 10);
×
244
    const PI1: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 1);
×
245
    const PI2: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi2(value);
×
246
    const PI3: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 3);
×
247
    const PI4: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 4);
×
248
    const PI5: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 5);
×
249
    const PI6: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 6);
×
250
    const PI7: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 7);
×
251
    const PI8: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 8);
×
252
    const PI9: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 9);
×
253
    const PI10: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_pi(value, 10);
×
254
    const GOLOMB3: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 3);
×
255
    const GOLOMB5: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 5);
×
256
    const GOLOMB6: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 6);
×
257
    const GOLOMB7: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 7);
×
258
    const GOLOMB9: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 9);
×
259
    const GOLOMB10: WriteFn<E, CW> = |writer: &mut CW, value: u64| writer.write_golomb(value, 10);
×
260
    const EXP_GOLOMB1: WriteFn<E, CW> =
261
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 1);
×
262
    const EXP_GOLOMB2: WriteFn<E, CW> =
263
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 2);
×
264
    const EXP_GOLOMB3: WriteFn<E, CW> =
265
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 3);
×
266
    const EXP_GOLOMB4: WriteFn<E, CW> =
267
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 4);
×
268
    const EXP_GOLOMB5: WriteFn<E, CW> =
269
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 5);
×
270
    const EXP_GOLOMB6: WriteFn<E, CW> =
271
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 6);
×
272
    const EXP_GOLOMB7: WriteFn<E, CW> =
273
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 7);
×
274
    const EXP_GOLOMB8: WriteFn<E, CW> =
275
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 8);
×
276
    const EXP_GOLOMB9: WriteFn<E, CW> =
277
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 9);
×
278
    const EXP_GOLOMB10: WriteFn<E, CW> =
279
        |writer: &mut CW, value: u64| writer.write_exp_golomb(value, 10);
×
280

281
    /// Returns a new [`FuncCodeWriter`] for the given code.
282
    ///
283
    /// The code is [canonicalized](Codes::canonicalize) before
284
    /// the lookup, so equivalent codes yield the same writer.
285
    ///
286
    /// # Errors
287
    ///
288
    /// The method will return an error if there is no constant
289
    /// for the given code in [`FuncCodeWriter`].
NEW
290
    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
×
NEW
291
        let code = code.canonicalize();
×
292
        let write_func = match code {
×
293
            Codes::Unary => Self::UNARY,
×
294
            Codes::Gamma => Self::GAMMA,
×
295
            Codes::Delta => Self::DELTA,
×
296
            Codes::Omega => Self::OMEGA,
×
297
            Codes::VByteBe => Self::VBYTE_BE,
×
298
            Codes::VByteLe => Self::VBYTE_LE,
×
299
            Codes::Zeta(2) => Self::ZETA2,
×
300
            Codes::Zeta(3) => Self::ZETA3,
×
301
            Codes::Zeta(4) => Self::ZETA4,
×
302
            Codes::Zeta(5) => Self::ZETA5,
×
303
            Codes::Zeta(6) => Self::ZETA6,
×
304
            Codes::Zeta(7) => Self::ZETA7,
×
305
            Codes::Zeta(8) => Self::ZETA8,
×
306
            Codes::Zeta(9) => Self::ZETA9,
×
307
            Codes::Zeta(10) => Self::ZETA10,
×
308
            Codes::Rice(1) => Self::RICE1,
×
309
            Codes::Rice(2) => Self::RICE2,
×
310
            Codes::Rice(3) => Self::RICE3,
×
311
            Codes::Rice(4) => Self::RICE4,
×
312
            Codes::Rice(5) => Self::RICE5,
×
313
            Codes::Rice(6) => Self::RICE6,
×
314
            Codes::Rice(7) => Self::RICE7,
×
315
            Codes::Rice(8) => Self::RICE8,
×
316
            Codes::Rice(9) => Self::RICE9,
×
317
            Codes::Rice(10) => Self::RICE10,
×
318
            Codes::Pi(1) => Self::PI1,
×
319
            Codes::Pi(2) => Self::PI2,
×
320
            Codes::Pi(3) => Self::PI3,
×
321
            Codes::Pi(4) => Self::PI4,
×
322
            Codes::Pi(5) => Self::PI5,
×
323
            Codes::Pi(6) => Self::PI6,
×
324
            Codes::Pi(7) => Self::PI7,
×
325
            Codes::Pi(8) => Self::PI8,
×
326
            Codes::Pi(9) => Self::PI9,
×
327
            Codes::Pi(10) => Self::PI10,
×
328
            Codes::Golomb(3) => Self::GOLOMB3,
×
329
            Codes::Golomb(5) => Self::GOLOMB5,
×
330
            Codes::Golomb(6) => Self::GOLOMB6,
×
331
            Codes::Golomb(7) => Self::GOLOMB7,
×
332
            Codes::Golomb(9) => Self::GOLOMB9,
×
333
            Codes::Golomb(10) => Self::GOLOMB10,
×
334
            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
×
335
            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
×
336
            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
×
337
            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
×
338
            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
×
339
            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
×
340
            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
×
341
            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
×
342
            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
×
343
            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
×
344
            _ => return Err(DispatchError::UnsupportedCode(code)),
×
345
        };
346
        Ok(Self(write_func))
×
347
    }
348

349
    /// Returns a new [`FuncCodeWriter`] for the given function.
350
    #[inline(always)]
351
    pub fn new_with_func(write_func: WriteFn<E, CW>) -> Self {
×
352
        Self(write_func)
×
353
    }
354

355
    /// Gets the function pointer for the code.
356
    #[inline(always)]
357
    pub fn get_func(&self) -> WriteFn<E, CW> {
×
358
        self.0
×
359
    }
360
}
361

362
impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for FuncCodeWriter<E, CW> {
363
    #[inline(always)]
364
    fn write(&self, writer: &mut CW, value: u64) -> Result<usize, CW::Error> {
×
365
        (self.0)(writer, value)
×
366
    }
367
}
368

369
type LenFn = fn(u64) -> usize;
370

371
/// A newtype containing a function pointer dispatching the length method for a
372
/// code.
373
///
374
/// This is a more efficient way to pass a [`StaticCodeRead`] to a method, as
375
/// a [`FuncCodeReader`] does not need to do a runtime test to dispatch the correct
376
/// method.
377
///
378
/// Instances can be obtained by calling the [`new`](FuncCodeLen::new) method
379
/// with a variant of the [`Codes`] enum, or by calling the
380
/// [`new_with_func`](FuncCodeLen::new_with_func) method with a function pointer.
381
///
382
/// Note that since selection of the code happens in the [`new`](FuncCodeLen::new)
383
/// method, it is more efficient to clone a [`FuncCodeLen`] than to create a new one.
384
#[derive(Debug, Clone, Copy)]
385
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
386
#[cfg_attr(feature = "mem_dbg", mem_size_flat)]
387
pub struct FuncCodeLen(LenFn);
388

389
impl FuncCodeLen {
390
    const UNARY: LenFn = |value| value as usize + 1;
×
391
    const GAMMA: LenFn = |value| len_gamma(value);
×
392
    const DELTA: LenFn = |value| len_delta(value);
×
393
    const OMEGA: LenFn = |value| len_omega(value);
×
394
    const VBYTE_BE: LenFn = |value| bit_len_vbyte(value);
×
395
    const VBYTE_LE: LenFn = |value| bit_len_vbyte(value);
×
396
    const ZETA2: LenFn = |value| len_zeta(value, 2);
×
397
    const ZETA3: LenFn = |value| len_zeta(value, 3);
×
398
    const ZETA4: LenFn = |value| len_zeta(value, 4);
×
399
    const ZETA5: LenFn = |value| len_zeta(value, 5);
×
400
    const ZETA6: LenFn = |value| len_zeta(value, 6);
×
401
    const ZETA7: LenFn = |value| len_zeta(value, 7);
×
402
    const ZETA8: LenFn = |value| len_zeta(value, 8);
×
403
    const ZETA9: LenFn = |value| len_zeta(value, 9);
×
404
    const ZETA10: LenFn = |value| len_zeta(value, 10);
×
405
    const RICE1: LenFn = |value| len_rice(value, 1);
×
406
    const RICE2: LenFn = |value| len_rice(value, 2);
×
407
    const RICE3: LenFn = |value| len_rice(value, 3);
×
408
    const RICE4: LenFn = |value| len_rice(value, 4);
×
409
    const RICE5: LenFn = |value| len_rice(value, 5);
×
410
    const RICE6: LenFn = |value| len_rice(value, 6);
×
411
    const RICE7: LenFn = |value| len_rice(value, 7);
×
412
    const RICE8: LenFn = |value| len_rice(value, 8);
×
413
    const RICE9: LenFn = |value| len_rice(value, 9);
×
414
    const RICE10: LenFn = |value| len_rice(value, 10);
×
415
    const PI1: LenFn = |value| len_pi(value, 1);
×
416
    const PI2: LenFn = |value| len_pi(value, 2);
×
417
    const PI3: LenFn = |value| len_pi(value, 3);
×
418
    const PI4: LenFn = |value| len_pi(value, 4);
×
419
    const PI5: LenFn = |value| len_pi(value, 5);
×
420
    const PI6: LenFn = |value| len_pi(value, 6);
×
421
    const PI7: LenFn = |value| len_pi(value, 7);
×
422
    const PI8: LenFn = |value| len_pi(value, 8);
×
423
    const PI9: LenFn = |value| len_pi(value, 9);
×
424
    const PI10: LenFn = |value| len_pi(value, 10);
×
425
    const GOLOMB3: LenFn = |value| len_golomb(value, 3);
×
426
    const GOLOMB5: LenFn = |value| len_golomb(value, 5);
×
427
    const GOLOMB6: LenFn = |value| len_golomb(value, 6);
×
428
    const GOLOMB7: LenFn = |value| len_golomb(value, 7);
×
429
    const GOLOMB9: LenFn = |value| len_golomb(value, 9);
×
430
    const GOLOMB10: LenFn = |value| len_golomb(value, 10);
×
431
    const EXP_GOLOMB1: LenFn = |value| len_exp_golomb(value, 1);
×
432
    const EXP_GOLOMB2: LenFn = |value| len_exp_golomb(value, 2);
×
433
    const EXP_GOLOMB3: LenFn = |value| len_exp_golomb(value, 3);
×
434
    const EXP_GOLOMB4: LenFn = |value| len_exp_golomb(value, 4);
×
435
    const EXP_GOLOMB5: LenFn = |value| len_exp_golomb(value, 5);
×
436
    const EXP_GOLOMB6: LenFn = |value| len_exp_golomb(value, 6);
×
437
    const EXP_GOLOMB7: LenFn = |value| len_exp_golomb(value, 7);
×
438
    const EXP_GOLOMB8: LenFn = |value| len_exp_golomb(value, 8);
×
439
    const EXP_GOLOMB9: LenFn = |value| len_exp_golomb(value, 9);
×
440
    const EXP_GOLOMB10: LenFn = |value| len_exp_golomb(value, 10);
×
441
    /// Returns a new [`FuncCodeLen`] for the given code.
442
    ///
443
    /// The code is [canonicalized](Codes::canonicalize) before
444
    /// the lookup, so equivalent codes yield the same length
445
    /// function.
446
    ///
447
    /// # Errors
448
    ///
449
    /// The method will return an error if there is no constant
450
    /// for the given code in [`FuncCodeLen`].
NEW
451
    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
×
NEW
452
        let code = code.canonicalize();
×
453
        let len_func = match code {
×
454
            Codes::Unary => Self::UNARY,
×
455
            Codes::Gamma => Self::GAMMA,
×
456
            Codes::Delta => Self::DELTA,
×
457
            Codes::Omega => Self::OMEGA,
×
458
            Codes::VByteBe => Self::VBYTE_BE,
×
459
            Codes::VByteLe => Self::VBYTE_LE,
×
460
            Codes::Zeta(2) => Self::ZETA2,
×
461
            Codes::Zeta(3) => Self::ZETA3,
×
462
            Codes::Zeta(4) => Self::ZETA4,
×
463
            Codes::Zeta(5) => Self::ZETA5,
×
464
            Codes::Zeta(6) => Self::ZETA6,
×
465
            Codes::Zeta(7) => Self::ZETA7,
×
466
            Codes::Zeta(8) => Self::ZETA8,
×
467
            Codes::Zeta(9) => Self::ZETA9,
×
468
            Codes::Zeta(10) => Self::ZETA10,
×
469
            Codes::Rice(1) => Self::RICE1,
×
470
            Codes::Rice(2) => Self::RICE2,
×
471
            Codes::Rice(3) => Self::RICE3,
×
472
            Codes::Rice(4) => Self::RICE4,
×
473
            Codes::Rice(5) => Self::RICE5,
×
474
            Codes::Rice(6) => Self::RICE6,
×
475
            Codes::Rice(7) => Self::RICE7,
×
476
            Codes::Rice(8) => Self::RICE8,
×
477
            Codes::Rice(9) => Self::RICE9,
×
478
            Codes::Rice(10) => Self::RICE10,
×
479
            Codes::Pi(1) => Self::PI1,
×
480
            Codes::Pi(2) => Self::PI2,
×
481
            Codes::Pi(3) => Self::PI3,
×
482
            Codes::Pi(4) => Self::PI4,
×
483
            Codes::Pi(5) => Self::PI5,
×
484
            Codes::Pi(6) => Self::PI6,
×
485
            Codes::Pi(7) => Self::PI7,
×
486
            Codes::Pi(8) => Self::PI8,
×
487
            Codes::Pi(9) => Self::PI9,
×
488
            Codes::Pi(10) => Self::PI10,
×
489
            Codes::Golomb(3) => Self::GOLOMB3,
×
490
            Codes::Golomb(5) => Self::GOLOMB5,
×
491
            Codes::Golomb(6) => Self::GOLOMB6,
×
492
            Codes::Golomb(7) => Self::GOLOMB7,
×
493
            Codes::Golomb(9) => Self::GOLOMB9,
×
494
            Codes::Golomb(10) => Self::GOLOMB10,
×
495
            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
×
496
            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
×
497
            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
×
498
            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
×
499
            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
×
500
            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
×
501
            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
×
502
            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
×
503
            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
×
504
            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
×
505
            _ => return Err(DispatchError::UnsupportedCode(code)),
×
506
        };
507
        Ok(Self(len_func))
×
508
    }
509

510
    /// Returns a new [`FuncCodeLen`] for the given function.
511
    #[inline(always)]
512
    pub fn new_with_func(len_func: LenFn) -> Self {
×
513
        Self(len_func)
×
514
    }
515
    /// Gets the function pointer for the code.
516
    #[inline(always)]
517
    pub fn get_func(&self) -> LenFn {
×
518
        self.0
×
519
    }
520
}
521

522
/// Here we do not depend on the bitstream, so there is no need for a "static"
523
/// version of the trait.
524
impl CodeLen for FuncCodeLen {
525
    #[inline(always)]
526
    fn len(&self, value: u64) -> usize {
×
527
        (self.0)(value)
×
528
    }
529
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc