• 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

26.84
/src/dispatch/codes.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
//! Enumeration of all available codes, with associated read and write methods.
10
//!
11
//! This is the slower and more generic form of dispatching, mostly used for
12
//! testing and writing examples. For faster dispatching, consider using
13
//! [dynamic] or [static] dispatch.
14

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

19
/// An enum whose variants represent all the available codes.
20
///
21
/// This enum is kept in sync with implementations in the
22
/// [`codes`](crate::codes) module.
23
///
24
/// Both [`Display`](std::fmt::Display) and [`FromStr`](std::str::FromStr) are
25
/// implemented for this enum in a dual way, which makes it possible to store a
26
/// code as a string in a configuration file, and then parse it back.
27
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
29
#[cfg_attr(feature = "mem_dbg", mem_size_flat)]
30
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
31
#[non_exhaustive]
32
pub enum Codes {
33
    Unary,
34
    Gamma,
35
    Delta,
36
    Omega,
37
    VByteLe,
38
    VByteBe,
39
    Zeta(usize),
40
    Pi(usize),
41
    Golomb(u64),
42
    ExpGolomb(usize),
43
    Rice(usize),
44
}
45

46
impl Codes {
47
    /// Returns the canonical form of this code.
48
    ///
49
    /// Some codes are equivalent, in the sense that they are defined
50
    /// differently, but they give rise to the same codewords. Among equivalent
51
    /// codes, there is usually one that is faster to encode and decode, which
52
    /// we call the _canonical representative_ of the equivalence class.
53
    ///
54
    /// The mapping is:
55
    ///
56
    /// - [`Rice(0)`](Codes::Rice),
57
    ///   [`Golomb(1)`](Codes::Golomb) →
58
    ///   [`Unary`](Codes::Unary)
59
    ///
60
    /// - [`Zeta(1)`](Codes::Zeta),
61
    ///   [`ExpGolomb(0)`](Codes::ExpGolomb),
62
    ///   [`Pi(0)`](Codes::Pi) →
63
    ///   [`Gamma`](Codes::Gamma)
64
    ///
65
    /// - [`Golomb(2ⁿ)`](Codes::Golomb) → [`Rice(n)`](Codes::Rice)
66
    pub const fn canonicalize(self) -> Self {
690,192✔
67
        match self {
98,340✔
68
            Self::Zeta(1) | Self::ExpGolomb(0) | Self::Pi(0) => Self::Gamma,
39,204✔
69
            Self::Rice(0) | Self::Golomb(1) => Self::Unary,
24,576✔
70
            Self::Golomb(b) if b.is_power_of_two() => Self::Rice(b.trailing_zeros() as usize),
307,272✔
71
            other => other,
1,179,096✔
72
        }
73
    }
74

75
    /// Delegates to the [`DynamicCodeRead`] implementation.
76
    ///
77
    /// This inherent method is provided to reduce ambiguity in method
78
    /// resolution.
79
    #[inline(always)]
80
    pub fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
×
81
        &self,
82
        reader: &mut CR,
83
    ) -> Result<u64, CR::Error> {
84
        DynamicCodeRead::read(self, reader)
×
85
    }
86

87
    /// Delegates to the [`DynamicCodeWrite`] implementation.
88
    ///
89
    /// This inherent method is provided to reduce ambiguity in method
90
    /// resolution.
91
    #[inline(always)]
92
    pub fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
×
93
        &self,
94
        writer: &mut CW,
95
        value: u64,
96
    ) -> Result<usize, CW::Error> {
97
        DynamicCodeWrite::write(self, writer, value)
×
98
    }
99

100
    /// Converts a code to the constant enum [`code_consts`]
101
    /// used for [`ConstCode`]. This is mostly used to verify
102
    /// that the code is supported by [`ConstCode`].
103
    ///
104
    /// The code is [canonicalized](Codes::canonicalize) before
105
    /// the conversion, so equivalent codes map to the same
106
    /// constant.
NEW
107
    pub const fn to_code_const(&self) -> Result<usize, DispatchError> {
×
NEW
108
        Ok(match self.canonicalize() {
×
109
            Self::Unary => code_consts::UNARY,
×
110
            Self::Gamma => code_consts::GAMMA,
×
111
            Self::Delta => code_consts::DELTA,
×
112
            Self::Omega => code_consts::OMEGA,
×
113
            Self::VByteLe => code_consts::VBYTE_LE,
×
114
            Self::VByteBe => code_consts::VBYTE_BE,
×
115
            Self::Zeta(2) => code_consts::ZETA2,
×
116
            Self::Zeta(3) => code_consts::ZETA3,
×
117
            Self::Zeta(4) => code_consts::ZETA4,
×
118
            Self::Zeta(5) => code_consts::ZETA5,
×
119
            Self::Zeta(6) => code_consts::ZETA6,
×
120
            Self::Zeta(7) => code_consts::ZETA7,
×
121
            Self::Zeta(8) => code_consts::ZETA8,
×
122
            Self::Zeta(9) => code_consts::ZETA9,
×
123
            Self::Zeta(10) => code_consts::ZETA10,
×
124
            Self::Rice(1) => code_consts::RICE1,
×
125
            Self::Rice(2) => code_consts::RICE2,
×
126
            Self::Rice(3) => code_consts::RICE3,
×
127
            Self::Rice(4) => code_consts::RICE4,
×
128
            Self::Rice(5) => code_consts::RICE5,
×
129
            Self::Rice(6) => code_consts::RICE6,
×
130
            Self::Rice(7) => code_consts::RICE7,
×
131
            Self::Rice(8) => code_consts::RICE8,
×
132
            Self::Rice(9) => code_consts::RICE9,
×
133
            Self::Rice(10) => code_consts::RICE10,
×
134
            Self::Pi(1) => code_consts::PI1,
×
135
            Self::Pi(2) => code_consts::PI2,
×
136
            Self::Pi(3) => code_consts::PI3,
×
137
            Self::Pi(4) => code_consts::PI4,
×
138
            Self::Pi(5) => code_consts::PI5,
×
139
            Self::Pi(6) => code_consts::PI6,
×
140
            Self::Pi(7) => code_consts::PI7,
×
141
            Self::Pi(8) => code_consts::PI8,
×
142
            Self::Pi(9) => code_consts::PI9,
×
143
            Self::Pi(10) => code_consts::PI10,
×
144
            Self::Golomb(3) => code_consts::GOLOMB3,
×
145
            Self::Golomb(5) => code_consts::GOLOMB5,
×
146
            Self::Golomb(6) => code_consts::GOLOMB6,
×
147
            Self::Golomb(7) => code_consts::GOLOMB7,
×
148
            Self::Golomb(9) => code_consts::GOLOMB9,
×
149
            Self::Golomb(10) => code_consts::GOLOMB10,
×
150
            Self::ExpGolomb(1) => code_consts::EXP_GOLOMB1,
×
151
            Self::ExpGolomb(2) => code_consts::EXP_GOLOMB2,
×
152
            Self::ExpGolomb(3) => code_consts::EXP_GOLOMB3,
×
153
            Self::ExpGolomb(4) => code_consts::EXP_GOLOMB4,
×
154
            Self::ExpGolomb(5) => code_consts::EXP_GOLOMB5,
×
155
            Self::ExpGolomb(6) => code_consts::EXP_GOLOMB6,
×
156
            Self::ExpGolomb(7) => code_consts::EXP_GOLOMB7,
×
157
            Self::ExpGolomb(8) => code_consts::EXP_GOLOMB8,
×
158
            Self::ExpGolomb(9) => code_consts::EXP_GOLOMB9,
×
159
            Self::ExpGolomb(10) => code_consts::EXP_GOLOMB10,
×
160
            _ => {
161
                return Err(DispatchError::UnsupportedCode(*self));
×
162
            }
163
        })
164
    }
165

166
    /// Converts a value from [`code_consts`] to a code.
NEW
167
    pub const fn from_code_const(const_code: usize) -> Result<Self, DispatchError> {
×
168
        Ok(match const_code {
×
169
            code_consts::UNARY => Self::Unary,
×
170
            code_consts::GAMMA => Self::Gamma,
×
171
            code_consts::DELTA => Self::Delta,
×
172
            code_consts::OMEGA => Self::Omega,
×
173
            code_consts::VBYTE_LE => Self::VByteLe,
×
174
            code_consts::VBYTE_BE => Self::VByteBe,
×
175
            code_consts::ZETA2 => Self::Zeta(2),
×
176
            code_consts::ZETA3 => Self::Zeta(3),
×
177
            code_consts::ZETA4 => Self::Zeta(4),
×
178
            code_consts::ZETA5 => Self::Zeta(5),
×
179
            code_consts::ZETA6 => Self::Zeta(6),
×
180
            code_consts::ZETA7 => Self::Zeta(7),
×
181
            code_consts::ZETA8 => Self::Zeta(8),
×
182
            code_consts::ZETA9 => Self::Zeta(9),
×
183
            code_consts::ZETA10 => Self::Zeta(10),
×
184
            code_consts::RICE1 => Self::Rice(1),
×
185
            code_consts::RICE2 => Self::Rice(2),
×
186
            code_consts::RICE3 => Self::Rice(3),
×
187
            code_consts::RICE4 => Self::Rice(4),
×
188
            code_consts::RICE5 => Self::Rice(5),
×
189
            code_consts::RICE6 => Self::Rice(6),
×
190
            code_consts::RICE7 => Self::Rice(7),
×
191
            code_consts::RICE8 => Self::Rice(8),
×
192
            code_consts::RICE9 => Self::Rice(9),
×
193
            code_consts::RICE10 => Self::Rice(10),
×
194
            code_consts::PI1 => Self::Pi(1),
×
195
            code_consts::PI2 => Self::Pi(2),
×
196
            code_consts::PI3 => Self::Pi(3),
×
197
            code_consts::PI4 => Self::Pi(4),
×
198
            code_consts::PI5 => Self::Pi(5),
×
199
            code_consts::PI6 => Self::Pi(6),
×
200
            code_consts::PI7 => Self::Pi(7),
×
201
            code_consts::PI8 => Self::Pi(8),
×
202
            code_consts::PI9 => Self::Pi(9),
×
203
            code_consts::PI10 => Self::Pi(10),
×
204
            code_consts::GOLOMB3 => Self::Golomb(3),
×
205
            code_consts::GOLOMB5 => Self::Golomb(5),
×
206
            code_consts::GOLOMB6 => Self::Golomb(6),
×
207
            code_consts::GOLOMB7 => Self::Golomb(7),
×
208
            code_consts::GOLOMB9 => Self::Golomb(9),
×
209
            code_consts::GOLOMB10 => Self::Golomb(10),
×
210
            code_consts::EXP_GOLOMB1 => Self::ExpGolomb(1),
×
211
            code_consts::EXP_GOLOMB2 => Self::ExpGolomb(2),
×
212
            code_consts::EXP_GOLOMB3 => Self::ExpGolomb(3),
×
213
            code_consts::EXP_GOLOMB4 => Self::ExpGolomb(4),
×
214
            code_consts::EXP_GOLOMB5 => Self::ExpGolomb(5),
×
215
            code_consts::EXP_GOLOMB6 => Self::ExpGolomb(6),
×
216
            code_consts::EXP_GOLOMB7 => Self::ExpGolomb(7),
×
217
            code_consts::EXP_GOLOMB8 => Self::ExpGolomb(8),
×
218
            code_consts::EXP_GOLOMB9 => Self::ExpGolomb(9),
×
219
            code_consts::EXP_GOLOMB10 => Self::ExpGolomb(10),
×
220
            _ => return Err(DispatchError::UnsupportedCodeConst(const_code)),
×
221
        })
222
    }
223
}
224

225
impl DynamicCodeRead for Codes {
226
    #[inline]
227
    fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
230,064✔
228
        &self,
229
        reader: &mut CR,
230
    ) -> Result<u64, CR::Error> {
231
        Ok(match self.canonicalize() {
230,064✔
232
            Codes::Unary => reader.read_unary()?,
24,576✔
233
            Codes::Gamma => reader.read_gamma()?,
34,848✔
234
            Codes::Delta => reader.read_delta()?,
8,712✔
235
            Codes::Omega => reader.read_omega()?,
8,712✔
236
            Codes::VByteBe => reader.read_vbyte_be()?,
8,720✔
237
            Codes::VByteLe => reader.read_vbyte_le()?,
8,720✔
238
            Codes::Zeta(3) => reader.read_zeta3()?,
8,712✔
239
            Codes::Zeta(k) => reader.read_zeta(k)?,
121,968✔
240
            Codes::Pi(2) => reader.read_pi2()?,
8,712✔
241
            Codes::Pi(k) => reader.read_pi(k)?,
139,392✔
242
            Codes::Golomb(b) => reader.read_golomb(b)?,
81,968✔
243
            Codes::ExpGolomb(k) => reader.read_exp_golomb(k)?,
156,848✔
244
            Codes::Rice(log2_b) => reader.read_rice(log2_b)?,
196,656✔
245
        })
246
    }
247
}
248

249
impl DynamicCodeWrite for Codes {
250
    #[inline]
251
    fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
230,064✔
252
        &self,
253
        writer: &mut CW,
254
        value: u64,
255
    ) -> Result<usize, CW::Error> {
256
        Ok(match self.canonicalize() {
230,064✔
257
            Codes::Unary => writer.write_unary(value)?,
36,864✔
258
            Codes::Gamma => writer.write_gamma(value)?,
52,272✔
259
            Codes::Delta => writer.write_delta(value)?,
13,068✔
260
            Codes::Omega => writer.write_omega(value)?,
13,068✔
261
            Codes::VByteBe => writer.write_vbyte_be(value)?,
13,080✔
262
            Codes::VByteLe => writer.write_vbyte_le(value)?,
13,080✔
263
            Codes::Zeta(3) => writer.write_zeta3(value)?,
13,068✔
264
            Codes::Zeta(k) => writer.write_zeta(value, k)?,
152,460✔
265
            Codes::Pi(2) => writer.write_pi2(value)?,
13,068✔
266
            Codes::Pi(k) => writer.write_pi(value, k)?,
174,240✔
267
            Codes::Golomb(b) => writer.write_golomb(value, b)?,
102,460✔
268
            Codes::ExpGolomb(k) => writer.write_exp_golomb(value, k)?,
196,060✔
269
            Codes::Rice(log2_b) => writer.write_rice(value, log2_b)?,
245,820✔
270
        })
271
    }
272
}
273

274
impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for Codes {
275
    #[inline(always)]
276
    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
115,032✔
277
        <Self as DynamicCodeRead>::read(self, reader)
345,096✔
278
    }
279
}
280

281
impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for Codes {
282
    #[inline(always)]
283
    fn write(&self, writer: &mut CW, value: u64) -> Result<usize, CW::Error> {
115,032✔
284
        <Self as DynamicCodeWrite>::write(self, writer, value)
460,128✔
285
    }
286
}
287

288
impl CodeLen for Codes {
289
    #[inline]
290
    fn len(&self, value: u64) -> usize {
230,064✔
291
        match self.canonicalize() {
230,064✔
292
            Codes::Unary => value as usize + 1,
12,288✔
293
            Codes::Gamma => len_gamma(value),
34,848✔
294
            Codes::Delta => len_delta(value),
8,712✔
295
            Codes::Omega => len_omega(value),
8,712✔
296
            Codes::VByteLe | Codes::VByteBe => bit_len_vbyte(value),
17,440✔
297
            Codes::Zeta(k) => len_zeta(value, k),
139,392✔
298
            Codes::Pi(k) => len_pi(value, k),
156,816✔
299
            Codes::Golomb(b) => len_golomb(value, b),
81,968✔
300
            Codes::ExpGolomb(k) => len_exp_golomb(value, k),
156,848✔
301
            Codes::Rice(log2_b) => len_rice(value, log2_b),
196,656✔
302
        }
303
    }
304
}
305

306
/// Error type for parsing a code from a string.
307
#[derive(Debug, Clone)]
308
pub enum CodeError {
309
    /// Error parsing an integer parameter.
310
    ParseError(core::num::ParseIntError),
311
    /// Unknown code name. Uses a fixed-size array instead of `String` for `no_std` compatibility.
312
    UnknownCode([u8; 32]),
313
}
314
impl core::error::Error for CodeError {}
315
impl core::fmt::Display for CodeError {
316
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
×
317
        match self {
×
318
            CodeError::ParseError(e) => write!(f, "parse error: {}", e),
×
319
            CodeError::UnknownCode(s) => {
×
320
                write!(f, "unknown code: ")?;
×
321
                for c in s {
×
322
                    if *c == 0 {
×
323
                        break;
×
324
                    }
325
                    write!(f, "{}", *c as char)?;
×
326
                }
327
                Ok(())
×
328
            }
329
        }
330
    }
331
}
332

333
impl From<core::num::ParseIntError> for CodeError {
334
    fn from(e: core::num::ParseIntError) -> Self {
×
335
        CodeError::ParseError(e)
×
336
    }
337
}
338

339
impl core::fmt::Display for Codes {
340
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
×
341
        match self {
×
342
            Codes::Unary => write!(f, "Unary"),
×
343
            Codes::Gamma => write!(f, "Gamma"),
×
344
            Codes::Delta => write!(f, "Delta"),
×
345
            Codes::Omega => write!(f, "Omega"),
×
346
            Codes::VByteBe => write!(f, "VByteBe"),
×
347
            Codes::VByteLe => write!(f, "VByteLe"),
×
348
            Codes::Zeta(k) => write!(f, "Zeta({})", k),
×
349
            Codes::Pi(k) => write!(f, "Pi({})", k),
×
350
            Codes::Golomb(b) => write!(f, "Golomb({})", b),
×
351
            Codes::ExpGolomb(k) => write!(f, "ExpGolomb({})", k),
×
352
            Codes::Rice(log2_b) => write!(f, "Rice({})", log2_b),
×
353
        }
354
    }
355
}
356

357
fn array_format_error(s: &str) -> [u8; 32] {
×
358
    let mut error_buffer = [0u8; 32];
×
359
    const ERROR_PREFIX: &[u8] = b"could not parse ";
360
    error_buffer[..ERROR_PREFIX.len()].copy_from_slice(ERROR_PREFIX);
×
361
    error_buffer[ERROR_PREFIX.len()..ERROR_PREFIX.len() + s.len().min(32 - ERROR_PREFIX.len())]
×
362
        .copy_from_slice(&s.as_bytes()[..s.len().min(32 - ERROR_PREFIX.len())]);
×
363
    error_buffer
×
364
}
365

366
impl core::str::FromStr for Codes {
367
    type Err = CodeError;
368

369
    fn from_str(s: &str) -> Result<Self, Self::Err> {
×
370
        match s {
×
371
            "Unary" => Ok(Codes::Unary),
×
372
            "Gamma" => Ok(Codes::Gamma),
×
373
            "Delta" => Ok(Codes::Delta),
×
374
            "Omega" => Ok(Codes::Omega),
×
375
            "VByteBe" => Ok(Codes::VByteBe),
×
376
            "VByteLe" => Ok(Codes::VByteLe),
×
377

378
            _ => {
379
                let mut parts = s.split('(');
×
380
                let name = parts
×
381
                    .next()
382
                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
×
383
                let k = parts
×
384
                    .next()
385
                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?
×
386
                    .split(')')
387
                    .next()
388
                    .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
×
389
                match name {
×
390
                    "Zeta" => Ok(Codes::Zeta(k.parse()?)),
×
391
                    "Pi" => Ok(Codes::Pi(k.parse()?)),
×
392
                    "Golomb" => Ok(Codes::Golomb(k.parse()?)),
×
393
                    "ExpGolomb" => Ok(Codes::ExpGolomb(k.parse()?)),
×
394
                    "Rice" => Ok(Codes::Rice(k.parse()?)),
×
395
                    _ => Err(CodeError::UnknownCode(array_format_error(name))),
×
396
                }
397
            }
398
        }
399
    }
400
}
401

402
#[cfg(feature = "serde")]
403
impl serde::Serialize for Codes {
404
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
×
405
    where
406
        S: serde::Serializer,
407
    {
408
        serializer.serialize_str(&self.to_string())
×
409
    }
410
}
411

412
#[cfg(feature = "serde")]
413
impl<'de> serde::Deserialize<'de> for Codes {
414
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
×
415
    where
416
        D: serde::Deserializer<'de>,
417
    {
418
        let s = String::deserialize(deserializer)?;
×
419
        s.parse().map_err(serde::de::Error::custom)
×
420
    }
421
}
422

423
/// Structure representing minimal binary coding with a fixed length.
424
///
425
/// [Minimal binary coding](crate::codes::minimal_binary) does not
426
/// fit the [`Codes`] enum because it is not defined for all integers.
427
///
428
/// Instances of this structure can be used in contexts in which a
429
/// [`DynamicCodeRead`], [`DynamicCodeWrite`], [`StaticCodeRead`],
430
/// [`StaticCodeWrite`] or [`CodeLen`] implementing minimal binary coding
431
/// is necessary.
432
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
433
pub struct MinimalBinary(pub u64);
434

435
impl DynamicCodeRead for MinimalBinary {
436
    fn read<E: Endianness, R: CodesRead<E> + ?Sized>(
48✔
437
        &self,
438
        reader: &mut R,
439
    ) -> Result<u64, R::Error> {
440
        reader.read_minimal_binary(self.0)
144✔
441
    }
442
}
443

444
impl DynamicCodeWrite for MinimalBinary {
445
    fn write<E: Endianness, W: CodesWrite<E> + ?Sized>(
48✔
446
        &self,
447
        writer: &mut W,
448
        n: u64,
449
    ) -> Result<usize, W::Error> {
450
        writer.write_minimal_binary(n, self.0)
192✔
451
    }
452
}
453

454
impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for MinimalBinary {
455
    fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
24✔
456
        <Self as DynamicCodeRead>::read(self, reader)
72✔
457
    }
458
}
459

460
impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for MinimalBinary {
461
    fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
24✔
462
        <Self as DynamicCodeWrite>::write(self, writer, n)
96✔
463
    }
464
}
465

466
impl CodeLen for MinimalBinary {
467
    fn len(&self, n: u64) -> usize {
48✔
468
        len_minimal_binary(n, self.0)
144✔
469
    }
470
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc