Coverage Report

Created: 2026-08-31 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/fax-0.2.7/src/lib.rs
Line
Count
Source
1
#![deny(unsafe_code)]
2
use std::convert::Infallible;
3
use std::fmt;
4
use std::io::{self, Read};
5
use std::iter::Map;
6
use std::ops::Not;
7
8
#[cfg(feature = "debug")]
9
macro_rules! debug {
10
    ($($arg:expr),*) => (
11
        println!($($arg),*)
12
    )
13
}
14
#[cfg(not(feature = "debug"))]
15
macro_rules! debug {
16
    ($($arg:expr),*) => {
17
        ()
18
    };
19
}
20
21
pub mod maps;
22
23
/// Decoder module
24
pub mod decoder;
25
26
/// Encoder module
27
pub mod encoder;
28
29
/// TIFF helper functions
30
pub mod tiff;
31
32
/// Trait used to read data bitwise.
33
///
34
/// For lazy people `ByteReader` is provided which implements this trait.
35
pub trait BitReader {
36
    type Error;
37
38
    /// look at the next (up to 16) bits of data
39
    ///
40
    /// Data is returned in the lower bits of the `u16`.
41
    fn peek(&self, bits: u8) -> Option<u16>;
42
43
    /// Consume the given amount of bits from the input.
44
    fn consume(&mut self, bits: u8) -> Result<(), Self::Error>;
45
46
    /// Assert that the next bits matches the given pattern.
47
    ///
48
    /// If it does not match, the found pattern is returned if enough bits are aviable.
49
    /// Otherwise None is returned.
50
0
    fn expect(&mut self, bits: Bits) -> Result<(), Option<Bits>> {
51
0
        match self.peek(bits.len) {
52
0
            None => Err(None),
53
0
            Some(val) if val == bits.data => Ok(()),
54
0
            Some(val) => Err(Some(Bits {
55
0
                data: val,
56
0
                len: bits.len,
57
0
            })),
58
        }
59
0
    }
60
61
    fn bits_to_byte_boundary(&self) -> u8;
62
}
63
64
/// Trait to write data bitwise
65
///
66
/// The `VecWriter` struct is provided for convinience.
67
pub trait BitWriter {
68
    type Error;
69
    fn write(&mut self, bits: Bits) -> Result<(), Self::Error>;
70
}
71
pub struct VecWriter {
72
    data: Vec<u8>,
73
    partial: u32,
74
    len: u8,
75
}
76
impl BitWriter for VecWriter {
77
    type Error = Infallible;
78
0
    fn write(&mut self, bits: Bits) -> Result<(), Self::Error> {
79
0
        self.partial |= (bits.data as u32) << (32 - self.len - bits.len);
80
0
        self.len += bits.len;
81
0
        while self.len >= 8 {
82
0
            self.data.push((self.partial >> 24) as u8);
83
0
            self.partial <<= 8;
84
0
            self.len -= 8;
85
0
        }
86
0
        Ok(())
87
0
    }
88
}
89
impl VecWriter {
90
0
    pub fn new() -> Self {
91
0
        VecWriter {
92
0
            data: Vec::new(),
93
0
            partial: 0,
94
0
            len: 0,
95
0
        }
96
0
    }
97
    // with capacity of `n` bits.
98
0
    pub fn with_capacity(n: usize) -> Self {
99
0
        VecWriter {
100
0
            data: Vec::with_capacity((n + 7) / 8),
101
0
            partial: 0,
102
0
            len: 0,
103
0
        }
104
0
    }
105
106
    /// Pad the output with `0` bits until it is at a byte boundary.
107
0
    pub fn pad(&mut self) {
108
0
        if self.len > 0 {
109
0
            self.data.push((self.partial >> 24) as u8);
110
0
            self.partial = 0;
111
0
            self.len = 0;
112
0
        }
113
0
    }
114
115
    /// pad and return the accumulated bytes
116
0
    pub fn finish(mut self) -> Vec<u8> {
117
0
        self.pad();
118
0
        self.data
119
0
    }
120
}
121
122
pub struct ByteReader<R> {
123
    read: R,
124
    partial: u32,
125
    valid: u8,
126
}
127
impl<E, R: Iterator<Item = Result<u8, E>>> ByteReader<R> {
128
    /// Construct a new `ByteReader` from an iterator of `u8`
129
0
    pub fn new(read: R) -> Result<Self, E> {
130
0
        let mut bits = ByteReader {
131
0
            read,
132
0
            partial: 0,
133
0
            valid: 0,
134
0
        };
135
0
        bits.fill()?;
136
0
        Ok(bits)
137
0
    }
Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>>>::new
Unexecuted instantiation: <fax::ByteReader<core::iter::adapters::map::Map<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<u8>>, core::result::Result<u8, core::convert::Infallible>::Ok>>>::new
138
0
    fn fill(&mut self) -> Result<(), E> {
139
0
        while self.valid < 16 {
140
0
            match self.read.next() {
141
0
                Some(Ok(byte)) => {
142
0
                    self.partial = self.partial << 8 | byte as u32;
143
0
                    self.valid += 8;
144
0
                }
145
0
                Some(Err(e)) => return Err(e),
146
0
                None => break,
147
            }
148
        }
149
0
        Ok(())
150
0
    }
Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>>>::fill
Unexecuted instantiation: <fax::ByteReader<core::iter::adapters::map::Map<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<u8>>, core::result::Result<u8, core::convert::Infallible>::Ok>>>::fill
151
    /// Print the remaining data
152
    ///
153
    /// Note: For debug purposes only, not part of the API.
154
0
    pub fn print_remaining(&mut self) {
155
0
        println!(
156
0
            "partial: {:0w$b}, valid: {}",
157
0
            self.partial & ((1 << self.valid) - 1),
158
            self.valid,
159
0
            w = self.valid as usize
160
        );
161
0
        while let Some(Ok(b)) = self.read.next() {
162
0
            print!("{:08b} ", b);
163
0
        }
164
0
        println!();
165
0
    }
166
0
    pub fn print_peek(&self) {
167
0
        println!(
168
0
            "partial: {:0w$b}, valid: {}",
169
0
            self.partial & ((1 << self.valid) - 1),
170
            self.valid,
171
0
            w = self.valid as usize
172
        );
173
0
    }
174
}
175
176
0
pub fn slice_reader(slice: &[u8]) -> ByteReader<impl Iterator<Item = Result<u8, Infallible>> + '_> {
177
0
    ByteReader::new(slice.iter().cloned().map(Ok)).unwrap()
178
0
}
179
0
pub fn slice_bits(slice: &[u8]) -> impl Iterator<Item = bool> + '_ {
180
0
    slice
181
0
        .iter()
182
0
        .flat_map(|&b| [7, 6, 5, 4, 3, 2, 1, 0].map(|i| (b >> i) & 1 != 0))
183
0
}
184
185
impl<E, R: Iterator<Item = Result<u8, E>>> BitReader for ByteReader<R> {
186
    type Error = E;
187
188
0
    fn peek(&self, bits: u8) -> Option<u16> {
189
0
        if bits > 16 {
190
0
            return None;
191
0
        }
192
0
        if self.valid >= bits {
193
0
            let shift = self.valid - bits;
194
0
            let mask = if bits >= 16 {
195
0
                u16::MAX
196
            } else {
197
0
                (1u16 << bits) - 1
198
            };
199
0
            let out = (self.partial >> shift) as u16 & mask;
200
0
            Some(out)
201
        } else {
202
0
            None
203
        }
204
0
    }
Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>> as fax::BitReader>::peek
Unexecuted instantiation: <fax::ByteReader<_> as fax::BitReader>::peek
205
0
    fn consume(&mut self, bits: u8) -> Result<(), E> {
206
0
        self.valid = self.valid.saturating_sub(bits);
207
0
        self.fill()
208
0
    }
Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>> as fax::BitReader>::consume
Unexecuted instantiation: <fax::ByteReader<_> as fax::BitReader>::consume
209
0
    fn bits_to_byte_boundary(&self) -> u8 {
210
0
        self.valid & 7
211
0
    }
212
}
213
214
#[test]
215
fn test_bits() {
216
    let mut bits = slice_reader(&[0b0000_1101, 0b1010_0000]);
217
    assert_eq!(maps::black::decode(&mut bits), Some(42));
218
}
219
220
#[test]
221
fn test_peek_over_16_returns_none() {
222
    let bits = slice_reader(&[0xFF, 0xFF, 0xFF]);
223
    // peek(17) should return None, not panic
224
    assert_eq!(bits.peek(17), None);
225
    assert_eq!(bits.peek(255), None);
226
    // peek(16) should still work
227
    assert!(bits.peek(16).is_some());
228
}
229
230
#[test]
231
fn test_consume_more_than_valid_saturates() {
232
    let mut bits = slice_reader(&[0xAB]);
233
    // consume more bits than available — should not panic
234
    let _ = bits.consume(200);
235
    // after saturating to 0, peek should return None for any nonzero request
236
    assert_eq!(bits.peek(1), None);
237
}
238
239
#[cfg(test)]
240
mod tests {
241
    use super::*;
242
243
    /// Build a Group 3 bitstream from a sequence of bits.
244
    fn bits_to_bytes(bits: &[u8]) -> Vec<u8> {
245
        let mut bytes = Vec::new();
246
        let mut byte = 0u8;
247
        let mut count = 0;
248
        for &b in bits {
249
            byte = (byte << 1) | (b & 1);
250
            count += 1;
251
            if count == 8 {
252
                bytes.push(byte);
253
                byte = 0;
254
                count = 0;
255
            }
256
        }
257
        if count > 0 {
258
            byte <<= 8 - count;
259
            bytes.push(byte);
260
        }
261
        bytes
262
    }
263
264
    #[test]
265
    fn test_group3_all_white_line() {
266
        // Build a minimal Group 3 stream:
267
        // - Initial EOL (000000000001)
268
        // - Line 1: white(8) = 10011, EOL
269
        // - RTC: 5 more EOLs
270
        let mut stream_bits = Vec::new();
271
272
        // Initial EOL
273
        let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
274
        stream_bits.extend_from_slice(eol);
275
276
        // Line 1: white run of 8 pixels = 10011
277
        stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]);
278
        // EOL after line 1
279
        stream_bits.extend_from_slice(eol);
280
281
        // RTC: 5 more EOLs
282
        for _ in 0..5 {
283
            stream_bits.extend_from_slice(eol);
284
        }
285
286
        let data = bits_to_bytes(&stream_bits);
287
        let mut lines = Vec::new();
288
        decoder::decode_g3(data.into_iter(), |transitions| {
289
            lines.push(transitions.to_vec());
290
        });
291
292
        assert_eq!(lines.len(), 1, "expected 1 line, got {}", lines.len());
293
        // All-white line: single transition at position 8 (white→black at the end)
294
        // Actually, the run-length is 8 white pixels. The transitions list shows
295
        // color change positions. For an all-white line, there are no transitions
296
        // (white runs the full width). But the decoder adds a0 += p after each code,
297
        // and pushes a0. For white(8), a0 = 8, pushed once. That's one transition.
298
        assert_eq!(lines[0], vec![8]);
299
    }
300
301
    #[test]
302
    fn test_group3_mixed_line() {
303
        // Width 16: 4 white, 4 black, 8 white
304
        // white(4) = 1011, black(4) = 011, white(8) = 10011
305
        let mut stream_bits = Vec::new();
306
307
        let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
308
309
        // Initial EOL
310
        stream_bits.extend_from_slice(eol);
311
312
        // Line: white(4)=1011, black(4)=011, white(8)=10011
313
        stream_bits.extend_from_slice(&[1, 0, 1, 1]); // white 4
314
        stream_bits.extend_from_slice(&[0, 1, 1]); // black 4
315
        stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]); // white 8
316
        stream_bits.extend_from_slice(eol);
317
318
        // RTC
319
        for _ in 0..5 {
320
            stream_bits.extend_from_slice(eol);
321
        }
322
323
        let data = bits_to_bytes(&stream_bits);
324
        let mut lines = Vec::new();
325
        decoder::decode_g3(data.into_iter(), |transitions| {
326
            lines.push(transitions.to_vec());
327
        });
328
329
        assert_eq!(lines.len(), 1);
330
        // Transitions: white(4) -> position 4, black(4) -> position 8, white(8) -> position 16
331
        assert_eq!(lines[0], vec![4, 8, 16]);
332
    }
333
334
    #[test]
335
    fn test_group3_with_fill_bits() {
336
        // T.4 allows 0-7 fill bits (zeros) before each EOL for byte
337
        // alignment. Test all fill counts to verify is_eol_ahead detects
338
        // fill+EOL without the prefix tree consuming fill bits.
339
        let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
340
341
        for fill_count in 0u8..=7 {
342
            let mut stream_bits = Vec::new();
343
344
            // Initial EOL with fill
345
            for _ in 0..fill_count {
346
                stream_bits.push(0);
347
            }
348
            stream_bits.extend_from_slice(eol);
349
350
            // Line: white(4) = 1011
351
            stream_bits.extend_from_slice(&[1, 0, 1, 1]);
352
353
            // EOL with fill
354
            for _ in 0..fill_count {
355
                stream_bits.push(0);
356
            }
357
            stream_bits.extend_from_slice(eol);
358
359
            // RTC: 5 more EOLs with fill
360
            for _ in 0..5 {
361
                for _ in 0..fill_count {
362
                    stream_bits.push(0);
363
                }
364
                stream_bits.extend_from_slice(eol);
365
            }
366
367
            let data = bits_to_bytes(&stream_bits);
368
            let mut lines = Vec::new();
369
            decoder::decode_g3(data.into_iter(), |transitions| {
370
                lines.push(transitions.to_vec());
371
            });
372
373
            assert_eq!(
374
                lines.len(),
375
                1,
376
                "fill={fill_count}: expected 1 line, got {}",
377
                lines.len()
378
            );
379
            assert_eq!(
380
                lines[0],
381
                vec![4],
382
                "fill={fill_count}: expected [4], got {:?}",
383
                lines[0]
384
            );
385
        }
386
    }
387
388
    #[test]
389
    fn test_group3_multiple_lines() {
390
        let mut stream_bits = Vec::new();
391
        let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
392
393
        // Initial EOL
394
        stream_bits.extend_from_slice(eol);
395
396
        // Line 1: white(4)=1011
397
        stream_bits.extend_from_slice(&[1, 0, 1, 1]);
398
        stream_bits.extend_from_slice(eol);
399
400
        // Line 2: white(8)=10011
401
        stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]);
402
        stream_bits.extend_from_slice(eol);
403
404
        // Line 3: white(2)=0111, black(3)=10
405
        stream_bits.extend_from_slice(&[0, 1, 1, 1]); // white 2
406
        stream_bits.extend_from_slice(&[1, 0]); // black 3
407
        stream_bits.extend_from_slice(eol);
408
409
        // RTC
410
        for _ in 0..5 {
411
            stream_bits.extend_from_slice(eol);
412
        }
413
414
        let data = bits_to_bytes(&stream_bits);
415
        let mut lines = Vec::new();
416
        decoder::decode_g3(data.into_iter(), |transitions| {
417
            lines.push(transitions.to_vec());
418
        });
419
420
        assert_eq!(lines.len(), 3);
421
        assert_eq!(lines[0], vec![4]);
422
        assert_eq!(lines[1], vec![8]);
423
        assert_eq!(lines[2], vec![2, 5]); // white 2, then black 3 = positions 2, 5
424
    }
425
}
426
427
/// Enum used to signal black/white.
428
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
429
pub enum Color {
430
    Black,
431
    White,
432
}
433
impl Not for Color {
434
    type Output = Self;
435
0
    fn not(self) -> Self {
436
0
        match self {
437
0
            Color::Black => Color::White,
438
0
            Color::White => Color::Black,
439
        }
440
0
    }
441
}
442
443
struct Transitions<'a> {
444
    edges: &'a [u16],
445
    pos: usize,
446
}
447
impl<'a> Transitions<'a> {
448
0
    fn new(edges: &'a [u16]) -> Self {
449
0
        Transitions { edges, pos: 0 }
450
0
    }
451
0
    fn seek_back(&mut self, start: u16) {
452
0
        self.pos = self.pos.min(self.edges.len().saturating_sub(1));
453
0
        while self.pos > 0 {
454
0
            if start < self.edges[self.pos - 1] {
455
0
                self.pos -= 1;
456
0
            } else {
457
0
                break;
458
            }
459
        }
460
0
    }
461
0
    fn next_color(&mut self, start: u16, color: Color, start_of_row: bool) -> Option<u16> {
462
0
        if start_of_row {
463
0
            if color == Color::Black {
464
0
                self.pos = 1;
465
0
                return self.edges.get(0).cloned();
466
            } else {
467
0
                self.pos = 2;
468
0
                return self.edges.get(1).cloned();
469
            }
470
0
        }
471
0
        while self.pos < self.edges.len() {
472
0
            if self.edges[self.pos] <= start {
473
0
                self.pos += 1;
474
0
                continue;
475
0
            }
476
477
0
            if (self.pos % 2 == 0) != (color == Color::Black) {
478
0
                self.pos += 1;
479
0
            }
480
481
0
            break;
482
        }
483
0
        if self.pos < self.edges.len() {
484
0
            let val = self.edges[self.pos];
485
0
            self.pos += 1;
486
0
            Some(val)
487
        } else {
488
0
            None
489
        }
490
0
    }
491
0
    fn next(&mut self) -> Option<u16> {
492
0
        if self.pos < self.edges.len() {
493
0
            let val = self.edges[self.pos];
494
0
            self.pos += 1;
495
0
            Some(val)
496
        } else {
497
0
            None
498
        }
499
0
    }
500
0
    fn peek(&self) -> Option<u16> {
501
0
        self.edges.get(self.pos).cloned()
502
0
    }
503
0
    fn skip(&mut self, n: usize) {
504
0
        self.pos += n;
505
0
    }
506
}
507
508
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
509
pub struct Bits {
510
    pub data: u16,
511
    pub len: u8,
512
}
513
514
impl fmt::Debug for Bits {
515
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516
0
        write!(f, "d={:0b} w={}", self.data, self.len)
517
0
    }
518
}
519
impl fmt::Display for Bits {
520
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521
0
        write!(
522
0
            f,
523
0
            "{:0w$b}",
524
0
            self.data & ((1 << self.len) - 1),
525
0
            w = self.len as usize
526
        )
527
0
    }
528
}