gzip_header/crc_reader.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
//! Simple CRC wrappers backed by the crc32 crate.
use std::fmt;
use std::io;
use std::io::{BufRead, Read};
use crc32fast::Hasher;
/// A wrapper struct containing a CRC checksum in the format used by gzip and the amount of bytes
/// input to it mod 2^32.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Crc {
// We don't use the Digest struct from the Crc crate for now as it doesn't implement `Display`
// and other common traits.
checksum: u32,
amt: u32,
}
impl fmt::Display for Crc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:#x},{})", self.checksum, self.amt)
}
}
/// A reader that updates the checksum and counter of a `Crc` struct when reading from the wrapped
/// reader.
#[derive(Debug)]
pub struct CrcReader<R> {
inner: R,
crc: Crc,
}
impl Crc {
/// Create a new empty CRC struct.
pub const fn new() -> Crc {
Crc {
checksum: 0,
amt: 0,
}
}
pub const fn with_initial(checksum: u32, amt: u32) -> Crc {
Crc { checksum, amt }
}
/// Return the current checksum value.
pub const fn sum(&self) -> u32 {
self.checksum
}
/// Return the number of bytes input.
pub const fn amt_as_u32(&self) -> u32 {
self.amt
}
/// Update the checksum and byte counter with the provided data.
pub fn update(&mut self, data: &[u8]) {
self.amt = self.amt.wrapping_add(data.len() as u32);
let mut h = Hasher::new_with_initial(self.checksum);
h.update(data);
self.checksum = h.finalize();
}
/// Reset the checksum and byte counter.
pub fn reset(&mut self) {
self.checksum = 0;
self.amt = 0;
}
}
impl<R: Read> CrcReader<R> {
/// Create a new `CrcReader` with a blank checksum.
pub fn new(r: R) -> CrcReader<R> {
CrcReader {
inner: r,
crc: Crc::new(),
}
}
/// Return a reference to the underlying checksum struct.
pub fn crc(&self) -> &Crc {
&self.crc
}
/// Consume this `CrcReader` and return the wrapped `Read` instance.
pub fn into_inner(self) -> R {
self.inner
}
/// Return a mutable reference to the wrapped reader.
pub fn inner(&mut self) -> &mut R {
&mut self.inner
}
/// Reset the checksum and counter.
pub fn reset(&mut self) {
self.crc.reset();
}
}
impl<R: Read> Read for CrcReader<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
let amt = self.inner.read(into)?;
self.crc.update(&into[..amt]);
Ok(amt)
}
}
impl<R: BufRead> BufRead for CrcReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, amt: usize) {
if let Ok(data) = self.inner.fill_buf() {
self.crc.update(&data[..amt]);
}
self.inner.consume(amt);
}
}
#[cfg(test)]
mod test {
use super::Crc;
#[test]
fn checksum_correct() {
let mut c = Crc::new();
c.update(b"abcdefg12345689\n");
assert_eq!(c.sum(), 0x141ddb83);
assert_eq!(c.amt_as_u32(), 16);
}
}