use digest::{Digest, FixedOutputReset, Output, Reset};
use std::io;
#[derive(Debug)]
pub struct HashWriter<D: Digest, W: io::Write> {
writer: W,
hasher: D,
}
impl<D: Digest, W: io::Write> HashWriter<D, W> {
pub fn new(writer: W) -> Self {
Self::new_from_parts(D::new(), writer)
}
pub fn new_from_parts(hasher: D, writer: W) -> Self {
HashWriter { writer, hasher }
}
pub fn replace_writer(&mut self, writer: W) {
self.writer = writer;
}
pub fn get_hasher(&self) -> &D {
&self.hasher
}
pub fn get_writer(&self) -> &W {
&self.writer
}
pub fn get_hasher_mut(&mut self) -> &mut D {
&mut self.hasher
}
pub fn get_writer_mut(&mut self) -> &mut W {
&mut self.writer
}
pub fn into_hasher(self) -> D {
self.hasher
}
pub fn into_inner_writer(self) -> W {
self.writer
}
pub fn into_parts(self) -> (D, W) {
(self.hasher, self.writer)
}
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, W: io::Write + Clone> Clone for HashWriter<D, W> {
fn clone(&self) -> HashWriter<D, W> {
HashWriter {
writer: self.writer.clone(),
hasher: self.hasher.clone(),
}
}
}
impl<D: Digest, W: io::Write> io::Write for HashWriter<D, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let bytes = self.writer.write(buf)?;
if bytes > 0 {
self.hasher.update(&buf[0..bytes]);
}
Ok(bytes)
}
fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
}
impl<D: Digest + FixedOutputReset, W: io::Write> HashWriter<D, W> {
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, W: io::Write> Reset for HashWriter<D, W> {
fn reset(&mut self) {
Digest::reset(&mut self.hasher)
}
}