use digest::{Digest, FixedOutputReset, Output, Reset};
use std::io;
#[derive(Debug)]
pub struct HashReader<D: Digest, R: io::Read> {
reader: R,
hasher: D,
}
impl<D: Digest, R: io::Read> HashReader<D, R> {
pub fn new(reader: R) -> Self {
Self::new_from_parts(D::new(), reader)
}
pub fn new_from_parts(hasher: D, reader: R) -> Self {
HashReader { reader, hasher }
}
pub fn replace_reader(&mut self, reader: R) {
self.reader = reader;
}
pub fn get_hasher(&self) -> &D {
&self.hasher
}
pub fn get_reader(&self) -> &R {
&self.reader
}
pub fn get_hasher_mut(&mut self) -> &mut D {
&mut self.hasher
}
pub fn get_reader_mut(&mut self) -> &mut R {
&mut self.reader
}
pub fn into_hasher(self) -> D {
self.hasher
}
pub fn into_inner_reader(self) -> R {
self.reader
}
pub fn into_parts(self) -> (D, R) {
(self.hasher, self.reader)
}
pub fn finalize(self) -> Output<D> {
self.hasher.finalize()
}
pub fn finalize_into(self, out: &mut Output<D>) {
self.hasher.finalize_into(out)
}
pub fn output_size() -> usize {
<D as Digest>::output_size()
}
}
impl<D: Digest + Clone, R: io::Read + Clone> Clone for HashReader<D, R> {
fn clone(&self) -> HashReader<D, R> {
HashReader {
reader: self.reader.clone(),
hasher: self.hasher.clone(),
}
}
}
impl<D: Digest, R: io::Read> io::Read for HashReader<D, R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.reader.read(buf)?;
if bytes > 0 {
self.hasher.update(&buf[0..bytes]);
}
Ok(bytes)
}
}
impl<D: Digest + FixedOutputReset, R: io::Read> HashReader<D, R> {
pub fn finalize_reset(&mut self) -> Output<D> {
Digest::finalize_reset(&mut self.hasher)
}
pub fn finalize_into_reset(&mut self, out: &mut Output<D>) {
Digest::finalize_into_reset(&mut self.hasher, out)
}
}
impl<D: Digest + Reset, R: io::Read> Reset for HashReader<D, R> {
fn reset(&mut self) {
Digest::reset(&mut self.hasher)
}
}
impl<D: Digest, R: io::BufRead> HashReader<D, R> {
pub fn hash_to_end(&mut self) {
loop {
let count = {
let data = self.reader.fill_buf().unwrap();
if data.is_empty() {
break;
}
self.hasher.update(data);
data.len()
};
self.reader.consume(count);
}
}
}