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

vigna / dsi-bitstream-rs / 18145139209

30 Sep 2025 10:26PM UTC coverage: 43.572% (-5.2%) from 48.731%
18145139209

push

github

vigna
Unified test

7 of 11 new or added lines in 2 files covered. (63.64%)

323 existing lines in 12 files now uncovered.

1559 of 3578 relevant lines covered (43.57%)

2347492.34 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 method 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> {
UNCOV
50
    const UNARY: ReadFn<E, CR> = |reader: &mut CR| reader.read_unary();
×
UNCOV
51
    const GAMMA: ReadFn<E, CR> = |reader: &mut CR| reader.read_gamma();
×
UNCOV
52
    const DELTA: ReadFn<E, CR> = |reader: &mut CR| reader.read_delta();
×
UNCOV
53
    const OMEGA: ReadFn<E, CR> = |reader: &mut CR| reader.read_omega();
×
UNCOV
54
    const VBYTE_BE: ReadFn<E, CR> = |reader: &mut CR| reader.read_vbyte_be();
×
UNCOV
55
    const VBYTE_LE: ReadFn<E, CR> = |reader: &mut CR| reader.read_vbyte_le();
×
UNCOV
56
    const ZETA2: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(2);
×
UNCOV
57
    const ZETA3: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta3();
×
UNCOV
58
    const ZETA4: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(4);
×
UNCOV
59
    const ZETA5: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(5);
×
UNCOV
60
    const ZETA6: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(6);
×
UNCOV
61
    const ZETA7: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(7);
×
UNCOV
62
    const ZETA8: ReadFn<E, CR> = |reader: &mut CR| reader.read_zeta(8);
×
UNCOV
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);
×
UNCOV
65
    const RICE1: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(1);
×
UNCOV
66
    const RICE2: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(2);
×
UNCOV
67
    const RICE3: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(3);
×
UNCOV
68
    const RICE4: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(4);
×
UNCOV
69
    const RICE5: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(5);
×
UNCOV
70
    const RICE6: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(6);
×
UNCOV
71
    const RICE7: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(7);
×
UNCOV
72
    const RICE8: ReadFn<E, CR> = |reader: &mut CR| reader.read_rice(8);
×
UNCOV
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);
×
UNCOV
75
    const PI1: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(1);
×
UNCOV
76
    const PI2: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(2);
×
UNCOV
77
    const PI3: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(3);
×
UNCOV
78
    const PI4: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(4);
×
UNCOV
79
    const PI5: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(5);
×
UNCOV
80
    const PI6: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(6);
×
UNCOV
81
    const PI7: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(7);
×
UNCOV
82
    const PI8: ReadFn<E, CR> = |reader: &mut CR| reader.read_pi(8);
×
UNCOV
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);
×
UNCOV
85
    const GOLOMB3: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(3);
×
UNCOV
86
    const GOLOMB5: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(5);
×
UNCOV
87
    const GOLOMB6: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(6);
×
UNCOV
88
    const GOLOMB7: ReadFn<E, CR> = |reader: &mut CR| reader.read_golomb(7);
×
UNCOV
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);
×
UNCOV
91
    const EXP_GOLOMB1: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(1);
×
UNCOV
92
    const EXP_GOLOMB2: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(2);
×
UNCOV
93
    const EXP_GOLOMB3: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(3);
×
UNCOV
94
    const EXP_GOLOMB4: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(4);
×
UNCOV
95
    const EXP_GOLOMB5: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(5);
×
UNCOV
96
    const EXP_GOLOMB6: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(6);
×
UNCOV
97
    const EXP_GOLOMB7: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(7);
×
UNCOV
98
    const EXP_GOLOMB8: ReadFn<E, CR> = |reader: &mut CR| reader.read_exp_golomb(8);
×
UNCOV
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
    /// Return a new [`FuncCodeReader`] for the given code.
102
    ///
103
    /// # Errors
104
    ///
105
    /// The method will return an error if there is no constant
106
    /// for the given code in [`FuncCodeReader`].
UNCOV
107
    pub fn new(code: Codes) -> anyhow::Result<Self> {
×
UNCOV
108
        let read_func = match code {
×
UNCOV
109
            Codes::Unary => Self::UNARY,
×
UNCOV
110
            Codes::Gamma => Self::GAMMA,
×
UNCOV
111
            Codes::Delta => Self::DELTA,
×
UNCOV
112
            Codes::Omega => Self::OMEGA,
×
UNCOV
113
            Codes::VByteBe => Self::VBYTE_BE,
×
UNCOV
114
            Codes::VByteLe => Self::VBYTE_LE,
×
UNCOV
115
            Codes::Zeta { k: 1 } => Self::GAMMA,
×
UNCOV
116
            Codes::Zeta { k: 2 } => Self::ZETA2,
×
UNCOV
117
            Codes::Zeta { k: 3 } => Self::ZETA3,
×
UNCOV
118
            Codes::Zeta { k: 4 } => Self::ZETA4,
×
UNCOV
119
            Codes::Zeta { k: 5 } => Self::ZETA5,
×
UNCOV
120
            Codes::Zeta { k: 6 } => Self::ZETA6,
×
UNCOV
121
            Codes::Zeta { k: 7 } => Self::ZETA7,
×
UNCOV
122
            Codes::Zeta { k: 8 } => Self::ZETA8,
×
UNCOV
123
            Codes::Zeta { k: 9 } => Self::ZETA9,
×
124
            Codes::Zeta { k: 10 } => Self::ZETA10,
×
UNCOV
125
            Codes::Rice { log2_b: 0 } => Self::UNARY,
×
UNCOV
126
            Codes::Rice { log2_b: 1 } => Self::RICE1,
×
UNCOV
127
            Codes::Rice { log2_b: 2 } => Self::RICE2,
×
UNCOV
128
            Codes::Rice { log2_b: 3 } => Self::RICE3,
×
UNCOV
129
            Codes::Rice { log2_b: 4 } => Self::RICE4,
×
UNCOV
130
            Codes::Rice { log2_b: 5 } => Self::RICE5,
×
UNCOV
131
            Codes::Rice { log2_b: 6 } => Self::RICE6,
×
UNCOV
132
            Codes::Rice { log2_b: 7 } => Self::RICE7,
×
UNCOV
133
            Codes::Rice { log2_b: 8 } => Self::RICE8,
×
UNCOV
134
            Codes::Rice { log2_b: 9 } => Self::RICE9,
×
135
            Codes::Rice { log2_b: 10 } => Self::RICE10,
×
UNCOV
136
            Codes::Pi { k: 0 } => Self::GAMMA,
×
UNCOV
137
            Codes::Pi { k: 1 } => Self::PI1,
×
UNCOV
138
            Codes::Pi { k: 2 } => Self::PI2,
×
UNCOV
139
            Codes::Pi { k: 3 } => Self::PI3,
×
UNCOV
140
            Codes::Pi { k: 4 } => Self::PI4,
×
UNCOV
141
            Codes::Pi { k: 5 } => Self::PI5,
×
UNCOV
142
            Codes::Pi { k: 6 } => Self::PI6,
×
UNCOV
143
            Codes::Pi { k: 7 } => Self::PI7,
×
UNCOV
144
            Codes::Pi { k: 8 } => Self::PI8,
×
UNCOV
145
            Codes::Pi { k: 9 } => Self::PI9,
×
146
            Codes::Pi { k: 10 } => Self::PI10,
×
UNCOV
147
            Codes::Golomb { b: 1 } => Self::UNARY,
×
UNCOV
148
            Codes::Golomb { b: 2 } => Self::RICE1,
×
UNCOV
149
            Codes::Golomb { b: 3 } => Self::GOLOMB3,
×
UNCOV
150
            Codes::Golomb { b: 4 } => Self::RICE2,
×
UNCOV
151
            Codes::Golomb { b: 5 } => Self::GOLOMB5,
×
UNCOV
152
            Codes::Golomb { b: 6 } => Self::GOLOMB6,
×
UNCOV
153
            Codes::Golomb { b: 7 } => Self::GOLOMB7,
×
UNCOV
154
            Codes::Golomb { b: 8 } => Self::RICE3,
×
UNCOV
155
            Codes::Golomb { b: 9 } => Self::GOLOMB9,
×
156
            Codes::Golomb { b: 10 } => Self::GOLOMB10,
×
UNCOV
157
            Codes::ExpGolomb { k: 0 } => Self::GAMMA,
×
UNCOV
158
            Codes::ExpGolomb { k: 1 } => Self::EXP_GOLOMB1,
×
UNCOV
159
            Codes::ExpGolomb { k: 2 } => Self::EXP_GOLOMB2,
×
UNCOV
160
            Codes::ExpGolomb { k: 3 } => Self::EXP_GOLOMB3,
×
UNCOV
161
            Codes::ExpGolomb { k: 4 } => Self::EXP_GOLOMB4,
×
UNCOV
162
            Codes::ExpGolomb { k: 5 } => Self::EXP_GOLOMB5,
×
UNCOV
163
            Codes::ExpGolomb { k: 6 } => Self::EXP_GOLOMB6,
×
UNCOV
164
            Codes::ExpGolomb { k: 7 } => Self::EXP_GOLOMB7,
×
UNCOV
165
            Codes::ExpGolomb { k: 8 } => Self::EXP_GOLOMB8,
×
UNCOV
166
            Codes::ExpGolomb { k: 9 } => Self::EXP_GOLOMB9,
×
167
            Codes::ExpGolomb { k: 10 } => Self::EXP_GOLOMB10,
×
168
            _ => anyhow::bail!("Unsupported read dispatch for code {:?}", code),
×
169
        };
170
        Ok(Self(read_func))
×
171
    }
172

173
    /// Return a new [`FuncCodeReader`] for the given function.
174
    #[inline(always)]
175
    pub fn new_with_func(read_func: ReadFn<E, CR>) -> Self {
×
176
        Self(read_func)
×
177
    }
178

179
    /// Get the function pointer for the code.
180
    #[inline(always)]
181
    pub fn get_func(&self) -> ReadFn<E, CR> {
×
182
        self.0
×
183
    }
184
}
185

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

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

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

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

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

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

357
    /// Return a new [`FuncCodeWriter`] for the given function.
358
    #[inline(always)]
359
    pub fn new_with_func(write_func: WriteFn<E, CW>) -> Self {
×
360
        Self(write_func)
×
361
    }
362

363
    /// Get the function pointer for the code.
364
    #[inline(always)]
365
    pub fn get_func(&self) -> WriteFn<E, CW> {
×
366
        self.0
×
367
    }
368
}
369

370
impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for FuncCodeWriter<E, CW> {
371
    #[inline(always)]
UNCOV
372
    fn write(&self, writer: &mut CW, value: u64) -> Result<usize, CW::Error> {
×
UNCOV
373
        (self.0)(writer, value)
×
374
    }
375
}
376

377
type LenFn = fn(u64) -> usize;
378

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

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

520
    /// Return a new [`FuncCodeReader`] for the given function.
521
    #[inline(always)]
522
    pub fn new_with_func(len_func: LenFn) -> Self {
×
523
        Self(len_func)
×
524
    }
525
    /// Get the function pointer for the code.
526
    #[inline(always)]
527
    pub fn get_func(&self) -> LenFn {
×
528
        self.0
×
529
    }
530
}
531

532
/// Here we do not depend on the bitstream, so there is no need for a "static"
533
/// version of the trait.
534
impl CodeLen for FuncCodeLen {
535
    #[inline(always)]
536
    fn len(&self, value: u64) -> usize {
×
537
        (self.0)(value)
×
538
    }
539
}
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