//! Simple CRC bindings backed by miniz.c use std::io; use std::io::prelude::*; use crc32fast::Hasher; /// The CRC calculated by a [`CrcReader`]. /// /// [`CrcReader`]: struct.CrcReader.html #[derive(Debug)] pub struct Crc { amt: u32, hasher: Hasher, } /// A wrapper around a [`Read`] that calculates the CRC. /// /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html #[derive(Debug)] pub struct CrcReader { inner: R, crc: Crc, } impl Crc { /// Create a new CRC. pub fn new() -> Crc { Crc { amt: 0, hasher: Hasher::new(), } } /// Returns the current crc32 checksum. pub fn sum(&self) -> u32 { self.hasher.clone().finalize() } /// The number of bytes that have been used to calculate the CRC. /// This value is only accurate if the amount is lower than 232. pub fn amount(&self) -> u32 { self.amt } /// Update the CRC with the bytes in `data`. pub fn update(&mut self, data: &[u8]) { self.amt = self.amt.wrapping_add(data.len() as u32); self.hasher.update(data); } /// Reset the CRC. pub fn reset(&mut self) { self.amt = 0; self.hasher.reset(); } /// Combine the CRC with the CRC for the subsequent block of bytes. pub fn combine(&mut self, additional_crc: &Crc) { self.amt += additional_crc.amt; self.hasher.combine(&additional_crc.hasher); } } impl CrcReader { /// Create a new CrcReader. pub fn new(r: R) -> CrcReader { CrcReader { inner: r, crc: Crc::new(), } } } impl CrcReader { /// Get the Crc for this CrcReader. pub fn crc(&self) -> &Crc { &self.crc } /// Get the reader that is wrapped by this CrcReader. pub fn into_inner(self) -> R { self.inner } /// Get the reader that is wrapped by this CrcReader by reference. pub fn get_ref(&self) -> &R { &self.inner } /// Get a mutable reference to the reader that is wrapped by this CrcReader. pub fn get_mut(&mut self) -> &mut R { &mut self.inner } /// Reset the Crc in this CrcReader. pub fn reset(&mut self) { self.crc.reset(); } } impl Read for CrcReader { fn read(&mut self, into: &mut [u8]) -> io::Result { let amt = self.inner.read(into)?; self.crc.update(&into[..amt]); Ok(amt) } } impl BufRead for CrcReader { 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); } } /// A wrapper around a [`Write`] that calculates the CRC. /// /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html #[derive(Debug)] pub struct CrcWriter { inner: W, crc: Crc, } impl CrcWriter { /// Get the Crc for this CrcWriter. pub fn crc(&self) -> &Crc { &self.crc } /// Get the writer that is wrapped by this CrcWriter. pub fn into_inner(self) -> W { self.inner } /// Get the writer that is wrapped by this CrcWriter by reference. pub fn get_ref(&self) -> &W { &self.inner } /// Get a mutable reference to the writer that is wrapped by this CrcWriter. pub fn get_mut(&mut self) -> &mut W { &mut self.inner } /// Reset the Crc in this CrcWriter. pub fn reset(&mut self) { self.crc.reset(); } } impl CrcWriter { /// Create a new CrcWriter. pub fn new(w: W) -> CrcWriter { CrcWriter { inner: w, crc: Crc::new(), } } } impl Write for CrcWriter { fn write(&mut self, buf: &[u8]) -> io::Result { let amt = self.inner.write(buf)?; self.crc.update(&buf[..amt]); Ok(amt) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } }