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

vigna / dsi-bitstream-rs / 22229074271

20 Feb 2026 03:01PM UTC coverage: 55.302% (-0.3%) from 55.614%
22229074271

push

github

vigna
Table checking is now at compile time

0 of 15 new or added lines in 5 files covered. (0.0%)

3 existing lines in 1 file now uncovered.

2112 of 3819 relevant lines covered (55.3%)

3169518.64 hits per line

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

76.19
/src/codes/params.rs
1
/*
2
 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
3
 * SPDX-FileCopyrightText: 2023 Inria
4
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
5
 *
6
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
7
 */
8

9
/*!
10

11
Mechanisms for selecting parameters.
12

13
Traits and structures in this file are of no interest for the standard
14
user. Their purpose is to provide a systematic way, and in particular
15
a default way, to select parameters for parameterized traits
16
such as [`GammaReadParam`] and [`GammaWriteParam`].
17

18
The traits and structure in this module work closely with the
19
bitstream readers and writers in [`impls`](crate::impls), which have an
20
additional type parameter `RP`/`WP` that must
21
implement marker traits [`ReadParams`] or [`WriteParams`], respectively.
22
The type is then used as a selector type to provide blanket implementations
23
of parameterless traits in [`codes`](crate::codes) such as [`GammaRead`],
24
[`GammaWrite`], [`DeltaRead`], [`DeltaWrite`], and so on.
25

26
This module provides default selector types [`DefaultReadParams`] and [`DefaultWriteParams`]
27
which are also the default value for the parameter `RP`/`WP` in the bitstream
28
readers and writers in [`crate::impls`]. Type-selected blanket implementations
29
of all parameterless traits in [`crate::codes`] are provided for the bitstream
30
readers and writers in [`impls`](crate::impls). Thus, if you not specify a value for the
31
parameter `RP`/`WP`, you will obtain automatically
32
the blanket implementations for parameterless traits contained in this module.
33

34
However, you can also create new selector types implementing [`ReadParams`]/[`WriteParams`] and
35
write blanket implementations for the bitstream readers and writers in [`crate::impls`]
36
where `RP`/`WP` is set to your selector types. Then, by specifying your type as value of the
37
parameter `RP`/`WP` when creating such readers and writers you will use
38
automatically your blanket implementations instead of the ones provided by this module.
39

40
Note that the default implementations provided by this module are targeted at
41
`u32` read words and `u64` write words. If you use different word sizes,
42
you may want to write your own selector types.
43

44
# Table peek-word checks
45

46
When a default read implementation enables table-based decoding (i.e., it calls
47
a `read_*_param` method with a `USE_TABLE` or `USE_*_TABLE` const parameter set
48
to `true`), it must verify at compile time that the reader's peek word is large
49
enough for the table. Each table module (e.g.,
50
[`gamma_tables`](super::gamma_tables),
51
[`delta_tables`](super::delta_tables), etc.) provides a
52
`check_read_table` const fn for this purpose.
53

54
The [`DefaultReadParams`] implementations in this module already include such
55
checks via `const { }` blocks. If you create your own selector type and write
56
custom blanket implementations that enable tables, you should add analogous
57
checks. For example:
58

59
```ignore
60
const { gamma_tables::check_read_table(WR::Word::BITS + 1) }
61
```
62

63
for a [`BufBitReader`](crate::impls::BufBitReader) (whose peek word
64
provides `WR::Word::BITS + 1` bits), or:
65

66
```ignore
67
const { gamma_tables::check_read_table(32) }
68
```
69

70
for a [`BitReader`](crate::impls::BitReader) (whose peek word is always 32
71
bits).
72

73
*/
74

75
use crate::codes::*;
76
use crate::impls::*;
77
use crate::traits::*;
78
use common_traits::*;
79
use core::error::Error;
80
#[cfg(feature = "mem_dbg")]
81
use mem_dbg::{MemDbg, MemSize};
82

83
/// Marker trait for read-parameters selector types.
84
///
85
/// Note that in principle marker traits are not necessary to use
86
/// selector types, but they are useful to avoid that the user specifies
87
/// a nonsensical type, and to document the meaning of type parameters.
88
pub trait ReadParams {}
89

90
/// A selector type for read parameters providing reasonable defaults.
91
///
92
/// If you want to optimize these choices for your architecture, we suggest to
93
/// run the benchmarks in the `benchmarks` directory and write your
94
/// own implementation.
95
#[derive(Debug, Clone)]
96
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
97
pub struct DefaultReadParams;
98
impl ReadParams for DefaultReadParams {}
99

100
macro_rules! impl_default_read_codes {
101
    ($($endianess:ident),*) => {$(
102
        impl<WR: WordRead> GammaRead<$endianess>
103
            for BufBitReader<$endianess, WR, DefaultReadParams>
104
        where
105
            WR:: Word: DoubleType + UpcastableInto<u64>,
106
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
107
        {
108
            #[inline(always)]
109
            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
28,049,409✔
110
                // From our tests on all architectures ɣ codes are faster
111
                // without tables
112
                self.read_gamma_param::<false>()
56,098,818✔
113
            }
114
        }
115

116
        impl<WR: WordRead> DeltaRead<$endianess>
117
            for BufBitReader<$endianess, WR, DefaultReadParams>
118
        where
119
            WR:: Word: DoubleType + UpcastableInto<u64>,
120
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
121
        {
122
            #[inline(always)]
123
            fn read_delta(&mut self) -> Result<u64, Self::Error> {
28,004,457✔
124
                // USE_GAMMA_TABLE is true, so check gamma tables
125
                const { gamma_tables::check_read_table(WR::Word::BITS + 1) }
126
                self.read_delta_param::<false, true>()
56,008,914✔
127
            }
128
        }
129

130
        impl<WR: WordRead> OmegaRead<$endianess>
131
            for BufBitReader<$endianess, WR, DefaultReadParams>
132
        where
133
            WR:: Word: DoubleType + UpcastableInto<u64>,
134
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
135
        {
136
            #[inline(always)]
137
            fn read_omega(&mut self) -> Result<u64, Self::Error> {
6,274✔
138
                const { omega_tables::check_read_table(WR::Word::BITS + 1) }
139
                self.read_omega_param::<true>()
12,548✔
140
            }
141
        }
142

143
        impl<WR: WordRead> ZetaRead<$endianess>
144
            for BufBitReader<$endianess, WR, DefaultReadParams>
145
        where
146
            WR:: Word: DoubleType + UpcastableInto<u64>,
147
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
148
        {
149
            #[inline(always)]
150
            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
34,849✔
151
                self.read_zeta_param(k)
104,547✔
152
            }
153

154
            #[inline(always)]
155
            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
4,357✔
156
                const { zeta_tables::check_read_table(WR::Word::BITS + 1) }
157
                self.read_zeta3_param::<true>()
8,714✔
158
            }
159
        }
160

161
        impl<WR: WordRead> PiRead<$endianess>
162
            for BufBitReader<$endianess, WR, DefaultReadParams>
163
        where
164
            WR:: Word: DoubleType + UpcastableInto<u64>,
165
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
166
        {
167
            #[inline(always)]
168
            fn read_pi(&mut self, k: usize) -> Result<u64, Self::Error> {
40,293✔
169
                self.read_pi_param(k)
120,879✔
170
            }
171

172
            #[inline(always)]
173
            fn read_pi2(&mut self) -> Result<u64, Self::Error> {
6,534✔
174
                const { pi_tables::check_read_table(WR::Word::BITS + 1) }
175
                self.read_pi2_param::<true>()
13,068✔
176
            }
177
        }
178

179
        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> GammaRead<$endianess>
180
            for BitReader<$endianess, WR, DefaultReadParams>
181
        where
182
            WR:: Word: DoubleType + UpcastableInto<u64>,
183
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
184
        {
185
            #[inline(always)]
186
            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
1,256✔
187
                // From our tests, the ARM architecture is faster
188
                // without tables for ɣ codes.
189
                self.read_gamma_param::<false>()
2,512✔
190
            }
191
        }
192

193
        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> DeltaRead<$endianess>
194
            for BitReader<$endianess, WR, DefaultReadParams>
195
        where
196
            WR:: Word: DoubleType + UpcastableInto<u64>,
197
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
198
        {
199
            #[inline(always)]
200
            fn read_delta(&mut self) -> Result<u64, Self::Error> {
×
201
                // USE_GAMMA_TABLE is true, so check gamma tables
202
                const { gamma_tables::check_read_table(32) }
UNCOV
203
                self.read_delta_param::<false, true>()
×
204
            }
205
        }
206

207
        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> OmegaRead<$endianess>
208
            for BitReader<$endianess, WR, DefaultReadParams>
209
        where
210
            WR:: Word: DoubleType + UpcastableInto<u64>,
211
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
212
        {
213
            #[inline(always)]
214
            fn read_omega(&mut self) -> Result<u64, Self::Error> {
1,918✔
215
                const { omega_tables::check_read_table(32) }
216
                self.read_omega_param::<true>()
3,836✔
217
            }
218
        }
219

220
        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> ZetaRead<$endianess>
221
            for BitReader<$endianess, WR, DefaultReadParams>
222
        where
223
            WR:: Word: DoubleType + UpcastableInto<u64>,
224
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
225
        {
226
            #[inline(always)]
227
            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
×
228
                self.read_zeta_param(k)
×
229
            }
230

231
            #[inline(always)]
232
            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
×
233
                const { zeta_tables::check_read_table(32) }
UNCOV
234
                self.read_zeta3_param::<true>()
×
235
            }
236
        }
237

238
        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> PiRead<$endianess>
239
            for BitReader<$endianess, WR, DefaultReadParams>
240
        where
241
            WR:: Word: DoubleType + UpcastableInto<u64>,
242
            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
243
        {
244
            #[inline(always)]
245
            fn read_pi(&mut self, k: usize) -> Result<u64, Self::Error> {
×
246
                self.read_pi_param(k)
×
247
            }
248

249
            #[inline(always)]
250
            fn read_pi2(&mut self) -> Result<u64, Self::Error> {
×
251
                const { pi_tables::check_read_table(32) }
UNCOV
252
                self.read_pi2_param::<true>()
×
253
            }
254
        }
255
    )*};
256
}
257

258
impl_default_read_codes! {LittleEndian, BigEndian}
259

260
/// Marker trait for write-parameters selector types.
261
///
262
/// Note that in principle marker traits are not necessary to use
263
/// selector types, but they are useful to avoid that the user specifies
264
/// a nonsensical type, and to document the meaning of type parameters.
265
pub trait WriteParams {}
266

267
/// A selector type for write parameters providing reasonable defaults.
268
///
269
/// If you want to optimize these choices for your architecture, we suggest to
270
/// run the benchmarks in the `benchmarks` directory and write your
271
/// own implementation.
272
#[derive(Debug, Clone)]
273
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
274
pub struct DefaultWriteParams;
275
impl WriteParams for DefaultWriteParams {}
276

277
macro_rules! impl_default_write_codes {
278
    ($($endianess:ident),*) => {$(
279
        impl<WR: WordWrite> GammaWrite<$endianess>
280
            for BufBitWriter<$endianess, WR, DefaultWriteParams>
281
            where u64: CastableInto<WR::Word>,
282
        {
283
            #[inline(always)]
284
            fn write_gamma(&mut self, value: u64) -> Result<usize, Self::Error> {
20,053,786✔
285
                self.write_gamma_param::<true>(value)
60,161,358✔
286
            }
287
        }
288

289
        impl<WR: WordWrite, DC: WriteParams> DeltaWrite<$endianess>
290
            for BufBitWriter<$endianess, WR, DC>
291
            where u64: CastableInto<WR::Word>,
292
        {
293
            #[inline(always)]
294
            fn write_delta(&mut self, value: u64) -> Result<usize, Self::Error> {
20,004,494✔
295
                self.write_delta_param::<true, true>(value)
60,013,482✔
296
            }
297
        }
298

299
        impl<WR: WordWrite, WP: WriteParams> OmegaWrite<$endianess>
300
            for BufBitWriter<$endianess, WR, WP>
301
            where u64: CastableInto<WR::Word>,
302
        {
303
            #[inline(always)]
304
            fn write_omega(&mut self, value: u64) -> Result<usize, Self::Error> {
6,298✔
305
                self.write_omega_param::<true>(value)
18,894✔
306
            }
307
        }
308

309
        impl<WR: WordWrite, DC: WriteParams> ZetaWrite<$endianess>
310
            for BufBitWriter<$endianess, WR, DC>
311
            where u64: CastableInto<WR::Word>,
312
        {
313
            #[inline(always)]
314
            fn write_zeta(&mut self, value: u64, k: usize) -> Result<usize, Self::Error> {
30,815✔
315
                self.write_zeta_param::<true>(value, k)
123,260✔
316
            }
317

318
            #[inline(always)]
319
            fn write_zeta3(&mut self, value: u64) -> Result<usize, Self::Error> {
4,379✔
320
                self.write_zeta3_param::<true>(value)
13,137✔
321
            }
322
        }
323

324
        impl<WR: WordWrite, DC: WriteParams> PiWrite<$endianess>
325
            for BufBitWriter<$endianess, WR, DC>
326
            where u64: CastableInto<WR::Word>,
327
        {
328
            #[inline(always)]
329
            fn write_pi(&mut self, value: u64, k: usize) -> Result<usize, Self::Error> {
40,610✔
330
                self.write_pi_param::<true>(value, k)
162,440✔
331
            }
332

333
            #[inline(always)]
334
            fn write_pi2(&mut self, value: u64) -> Result<usize, Self::Error> {
6,534✔
335
                self.write_pi2_param::<true>(value)
19,602✔
336
            }
337
        }
338

339
    )*};
340
}
341

342
impl_default_write_codes! {LittleEndian, BigEndian}
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