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

vigna / dsi-bitstream-rs / 22518245728

28 Feb 2026 09:40AM UTC coverage: 57.751% (+3.1%) from 54.618%
22518245728

push

github

vigna
delta_gamma in filenames

2213 of 3832 relevant lines covered (57.75%)

2595204.38 hits per line

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

0.0
/src/dispatch/factory.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 factories for readers with a lifetime.
10
//!
11
//! # Motivation
12
//!
13
//! [`FuncCodeReader`] already provides dynamic dispatching of read functions,
14
//! but in some use cases the reader has to reference some data (e.g., readers
15
//! based on the same memory buffer). In this case, one would need to create a
16
//! dispatching function pointer for each code and each reader because the
17
//! lifetime of different readers make the function pointers incompatible.
18
//!
19
//! The trait [`CodesReaderFactory`] solves this problem by providing a way to
20
//! create a [`CodesRead`] with a lifetime that can reference data owned by the
21
//! factory. This trait must be implemented by client applications.
22
//!
23
//! At that point, one can create a [`FactoryFuncCodeReader`] depending on a
24
//! specific [`CodesReaderFactory`]. The [`FactoryFuncCodeReader`] will store a
25
//! function pointer with a generic lifetime that can be downcast to a specific
26
//! lifetime. Thus, the function pointer is created just once at the creation of
27
//! the [`FactoryFuncCodeReader`], and can be reused to create
28
//! [`FuncCodeReader`]s with any lifetime using [`FactoryFuncCodeReader::get`].
29
//!
30
//! # Implementation Notes
31
//!
32
//! In principle, we would like to have inside a [`FactoryFuncCodeReader`] a
33
//! field with type
34
//!
35
//! ```ignore
36
//! for<'a> FuncCodeReader<E, CRF::CodesReader<'a>>
37
//! ```
38
//!
39
//! However, this is not possible in the Rust type system. We can however write
40
//! the type
41
//!
42
//! ```ignore
43
//! for<'a> fn(&mut CRF::CodesReader<'a>) -> Result<u64>
44
//! ```
45
//!
46
//! This workaround is not perfect as we cannot properly specify the error type:
47
//! ```ignore
48
//! Result<u64, <CRF::CodesReader<'a> as BitRead<E>>::Error>
49
//! ```
50
//! The compiler here complains that the return type has a lifetime not
51
//! constrained by the input arguments.
52
//!
53
//! To work around this problem, we could add an otherwise useless associated
54
//! type `CodesReaderFactory::Error` to the [`CodesReaderFactory`] trait,
55
//! imposing that the error type of [`CodesReaderFactory::CodesReader`] is the
56
//! same. Unfortunately, this requires that all users of the factory add a `where`
57
//! constraint in which the error type is written explicitly.
58
//!
59
//! To mitigate this problem, we provide instead a helper trait
60
//! [`CodesReaderFactoryHelper`] that extends [`CodesReaderFactory`]; the helper
61
//! trait contains an `Error` associated type and [uses higher-rank trait
62
//! bounds](https://users.rust-lang.org/t/extracting-static-associated-type-from-type-with-lifetime/126880)
63
//! to bind the associated type to the error type of the
64
//! [`CodesReaderFactory::CodesReader`]. The user can implement
65
//! [`CodesReaderFactory`] on its own types and write trait bounds using
66
//! [`CodesReaderFactoryHelper`]:
67
//! ```ignore
68
//! fn test<E: Endianness, CRF: CodesReaderFactoryHelper<E>>(factory: CRF)
69
//! {
70
//!     let reader = factory.new_reader();
71
//!     // do something with the reader
72
//!     // CRF::Error is the error type of CRF::CodesReader<'a>
73
//! }
74
//! ```
75

76
use super::*;
77
/// A trait that models a type that can return a [`CodesRead`] that can reference
78
/// data owned by the factory. The typical case is a factory that owns the
79
/// bit stream, and returns a [`CodesRead`] that can read from it.
80
pub trait CodesReaderFactory<E: Endianness> {
81
    type CodesReader<'a>
82
    where
83
        Self: 'a;
84

85
    /// Creates a new code reader that can reference data owned by the factory.
86
    fn new_reader(&self) -> Self::CodesReader<'_>;
87
}
88

89
/// Extension helper trait for [`CodesReaderFactory`].
90
///
91
/// By writing trait bounds using this helper instead of [`CodesReaderFactory`],
92
/// you can access the error type of the [`CodesReaderFactory::CodesReader`] through
93
/// [`CodesReaderFactoryHelper::Error`].
94
pub trait CodesReaderFactoryHelper<E: Endianness>:
95
    for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = Self::Error>>
96
{
97
    type Error;
98
}
99

100
impl<E: Endianness, F, ERR> CodesReaderFactoryHelper<E> for F
101
where
102
    F: ?Sized + for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = ERR>>,
103
{
104
    type Error = ERR;
105
}
106

107
/// The function type stored in a [`FactoryFuncCodeReader`].
108
///
109
/// The role of this type is analogous to that of `ReadFn` in [`FuncCodeReader`],
110
/// but we have an extra lifetime parameter to handle the lifetime
111
/// of the [`CodesReaderFactory::CodesReader`].
112
type FactoryReadFn<E, CRF> = for<'a> fn(
113
    &mut <CRF as CodesReaderFactory<E>>::CodesReader<'a>,
114
)
115
    -> Result<u64, <CRF as CodesReaderFactoryHelper<E>>::Error>;
116

117
/// A newtype depending on a [`CodesReaderFactory`] and containing a function
118
/// pointer dispatching the read method for a code.
119
///
120
/// It is essentially a version of [`FuncCodeReader`] that depends on a
121
/// [`CodesReaderFactory`] and its associated
122
/// [`CodesReaderFactory::CodesReader`] instead of a generic [`CodesRead`].
123
#[derive(Debug, Copy)]
124
pub struct FactoryFuncCodeReader<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized>(
125
    FactoryReadFn<E, CRF>,
126
);
127

128
/// Manually implement [`Clone`] to avoid the [`Clone`] bound on `CRF` and `E`.
129
impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> Clone
130
    for FactoryFuncCodeReader<E, CRF>
131
{
132
    #[inline(always)]
133
    fn clone(&self) -> Self {
×
134
        Self(self.0)
×
135
    }
136
}
137

138
impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> FactoryFuncCodeReader<E, CRF> {
139
    // due to the added lifetime generic we cannot just re-use the FuncCodeReader definitions
140
    const UNARY: FactoryReadFn<E, CRF> = |reader| reader.read_unary();
×
141
    const GAMMA: FactoryReadFn<E, CRF> = |reader| reader.read_gamma();
×
142
    const DELTA: FactoryReadFn<E, CRF> = |reader| reader.read_delta();
×
143
    const OMEGA: FactoryReadFn<E, CRF> = |reader| reader.read_omega();
×
144
    const VBYTE_BE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_be();
×
145
    const VBYTE_LE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_le();
×
146
    const ZETA2: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(2);
×
147
    const ZETA3: FactoryReadFn<E, CRF> = |reader| reader.read_zeta3();
×
148
    const ZETA4: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(4);
×
149
    const ZETA5: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(5);
×
150
    const ZETA6: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(6);
×
151
    const ZETA7: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(7);
×
152
    const ZETA8: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(8);
×
153
    const ZETA9: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(9);
×
154
    const ZETA10: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(10);
×
155
    const RICE1: FactoryReadFn<E, CRF> = |reader| reader.read_rice(1);
×
156
    const RICE2: FactoryReadFn<E, CRF> = |reader| reader.read_rice(2);
×
157
    const RICE3: FactoryReadFn<E, CRF> = |reader| reader.read_rice(3);
×
158
    const RICE4: FactoryReadFn<E, CRF> = |reader| reader.read_rice(4);
×
159
    const RICE5: FactoryReadFn<E, CRF> = |reader| reader.read_rice(5);
×
160
    const RICE6: FactoryReadFn<E, CRF> = |reader| reader.read_rice(6);
×
161
    const RICE7: FactoryReadFn<E, CRF> = |reader| reader.read_rice(7);
×
162
    const RICE8: FactoryReadFn<E, CRF> = |reader| reader.read_rice(8);
×
163
    const RICE9: FactoryReadFn<E, CRF> = |reader| reader.read_rice(9);
×
164
    const RICE10: FactoryReadFn<E, CRF> = |reader| reader.read_rice(10);
×
165
    const PI1: FactoryReadFn<E, CRF> = |reader| reader.read_pi(1);
×
166
    const PI2: FactoryReadFn<E, CRF> = |reader| reader.read_pi2();
×
167
    const PI3: FactoryReadFn<E, CRF> = |reader| reader.read_pi(3);
×
168
    const PI4: FactoryReadFn<E, CRF> = |reader| reader.read_pi(4);
×
169
    const PI5: FactoryReadFn<E, CRF> = |reader| reader.read_pi(5);
×
170
    const PI6: FactoryReadFn<E, CRF> = |reader| reader.read_pi(6);
×
171
    const PI7: FactoryReadFn<E, CRF> = |reader| reader.read_pi(7);
×
172
    const PI8: FactoryReadFn<E, CRF> = |reader| reader.read_pi(8);
×
173
    const PI9: FactoryReadFn<E, CRF> = |reader| reader.read_pi(9);
×
174
    const PI10: FactoryReadFn<E, CRF> = |reader| reader.read_pi(10);
×
175
    const GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(3);
×
176
    const GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(5);
×
177
    const GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(6);
×
178
    const GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(7);
×
179
    const GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(9);
×
180
    const GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(10);
×
181
    const EXP_GOLOMB1: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(1);
×
182
    const EXP_GOLOMB2: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(2);
×
183
    const EXP_GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(3);
×
184
    const EXP_GOLOMB4: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(4);
×
185
    const EXP_GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(5);
×
186
    const EXP_GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(6);
×
187
    const EXP_GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(7);
×
188
    const EXP_GOLOMB8: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(8);
×
189
    const EXP_GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(9);
×
190
    const EXP_GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(10);
×
191

192
    /// Returns a new [`FactoryFuncCodeReader`] for the given code.
193
    ///
194
    /// The code is [canonicalized](Codes::canonicalize) before
195
    /// the lookup, so equivalent codes yield the same reader.
196
    ///
197
    /// # Errors
198
    ///
199
    /// The method will return an error if there is no constant
200
    /// for the given code in [`FactoryFuncCodeReader`].
201
    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
×
202
        let code = code.canonicalize();
×
203
        let read_func = match code {
×
204
            Codes::Unary => Self::UNARY,
×
205
            Codes::Gamma => Self::GAMMA,
×
206
            Codes::Delta => Self::DELTA,
×
207
            Codes::Omega => Self::OMEGA,
×
208
            Codes::VByteBe => Self::VBYTE_BE,
×
209
            Codes::VByteLe => Self::VBYTE_LE,
×
210
            Codes::Zeta(2) => Self::ZETA2,
×
211
            Codes::Zeta(3) => Self::ZETA3,
×
212
            Codes::Zeta(4) => Self::ZETA4,
×
213
            Codes::Zeta(5) => Self::ZETA5,
×
214
            Codes::Zeta(6) => Self::ZETA6,
×
215
            Codes::Zeta(7) => Self::ZETA7,
×
216
            Codes::Zeta(8) => Self::ZETA8,
×
217
            Codes::Zeta(9) => Self::ZETA9,
×
218
            Codes::Zeta(10) => Self::ZETA10,
×
219
            Codes::Rice(1) => Self::RICE1,
×
220
            Codes::Rice(2) => Self::RICE2,
×
221
            Codes::Rice(3) => Self::RICE3,
×
222
            Codes::Rice(4) => Self::RICE4,
×
223
            Codes::Rice(5) => Self::RICE5,
×
224
            Codes::Rice(6) => Self::RICE6,
×
225
            Codes::Rice(7) => Self::RICE7,
×
226
            Codes::Rice(8) => Self::RICE8,
×
227
            Codes::Rice(9) => Self::RICE9,
×
228
            Codes::Rice(10) => Self::RICE10,
×
229
            Codes::Pi(1) => Self::PI1,
×
230
            Codes::Pi(2) => Self::PI2,
×
231
            Codes::Pi(3) => Self::PI3,
×
232
            Codes::Pi(4) => Self::PI4,
×
233
            Codes::Pi(5) => Self::PI5,
×
234
            Codes::Pi(6) => Self::PI6,
×
235
            Codes::Pi(7) => Self::PI7,
×
236
            Codes::Pi(8) => Self::PI8,
×
237
            Codes::Pi(9) => Self::PI9,
×
238
            Codes::Pi(10) => Self::PI10,
×
239
            Codes::Golomb(3) => Self::GOLOMB3,
×
240
            Codes::Golomb(5) => Self::GOLOMB5,
×
241
            Codes::Golomb(6) => Self::GOLOMB6,
×
242
            Codes::Golomb(7) => Self::GOLOMB7,
×
243
            Codes::Golomb(9) => Self::GOLOMB9,
×
244
            Codes::Golomb(10) => Self::GOLOMB10,
×
245
            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
×
246
            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
×
247
            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
×
248
            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
×
249
            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
×
250
            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
×
251
            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
×
252
            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
×
253
            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
×
254
            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
×
255
            _ => return Err(DispatchError::UnsupportedCode(code)),
×
256
        };
257
        Ok(Self(read_func))
×
258
    }
259

260
    /// Returns a new [`FactoryFuncCodeReader`] for the given function.
261
    #[must_use]
262
    #[inline(always)]
263
    pub fn new_with_func(read_func: FactoryReadFn<E, CRF>) -> Self {
×
264
        Self(read_func)
×
265
    }
266

267
    /// Returns the function pointer for the code.
268
    #[must_use]
269
    #[inline(always)]
270
    pub fn get_func(&self) -> FactoryReadFn<E, CRF> {
×
271
        self.0
×
272
    }
273

274
    /// Returns a [`FuncCodeReader`] compatible with `CRF`'s
275
    /// [`CodesReaderFactory::CodesReader`] for a given lifetime `'a`.
276
    #[must_use]
277
    #[inline(always)]
278
    pub fn get<'a>(
×
279
        &self,
280
    ) -> super::FuncCodeReader<E, <CRF as CodesReaderFactory<E>>::CodesReader<'a>> {
281
        super::FuncCodeReader::new_with_func(self.0)
×
282
    }
283
}
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