Skip to main content

digest_io/
writer.rs

1use digest::{Digest, FixedOutputReset, Output, Reset};
2use std::io;
3
4/// Abstraction over a writer which hashes the data being written.
5#[derive(Debug)]
6pub struct HashWriter<D: Digest, W: io::Write> {
7    writer: W,
8    hasher: D,
9}
10
11impl<D: Digest, W: io::Write> HashWriter<D, W> {
12    /// Construct a new `HashWriter` given an existing `writer` by value.
13    pub fn new(writer: W) -> Self {
14        Self::new_from_parts(D::new(), writer)
15    }
16
17    /// Construct a new `HashWriter` given an existing `hasher` and `writer` by value.
18    pub fn new_from_parts(hasher: D, writer: W) -> Self {
19        HashWriter { writer, hasher }
20    }
21
22    /// Replace the writer with another writer
23    pub fn replace_writer(&mut self, writer: W) {
24        self.writer = writer;
25    }
26
27    /// Gets a reference to the underlying hasher
28    pub fn get_hasher(&self) -> &D {
29        &self.hasher
30    }
31
32    /// Gets a reference to the underlying writer
33    pub fn get_writer(&self) -> &W {
34        &self.writer
35    }
36
37    /// Gets a mutable reference to the underlying hasher
38    /// Updates to the digest are not written to the underlying writer
39    pub fn get_hasher_mut(&mut self) -> &mut D {
40        &mut self.hasher
41    }
42
43    /// Gets a mutable reference to the underlying writer
44    /// Direct writes to the underlying writer are not hashed
45    pub fn get_writer_mut(&mut self) -> &mut W {
46        &mut self.writer
47    }
48
49    /// Consume the HashWriter and return its hasher
50    pub fn into_hasher(self) -> D {
51        self.hasher
52    }
53
54    /// Consume the HashWriter and return its internal writer
55    pub fn into_inner_writer(self) -> W {
56        self.writer
57    }
58
59    /// Consume the HashWriter and return its hasher and internal writer
60    pub fn into_parts(self) -> (D, W) {
61        (self.hasher, self.writer)
62    }
63
64    /// Retrieve result and consume HashWriter instance.
65    pub fn finalize(self) -> Output<D> {
66        self.hasher.finalize()
67    }
68
69    /// Write result into provided array and consume the HashWriter instance.
70    pub fn finalize_into(self, out: &mut Output<D>) {
71        self.hasher.finalize_into(out)
72    }
73
74    /// Get output size of the hasher
75    pub fn output_size() -> usize {
76        <D as Digest>::output_size()
77    }
78}
79
80impl<D: Digest + Clone, W: io::Write + Clone> Clone for HashWriter<D, W> {
81    fn clone(&self) -> HashWriter<D, W> {
82        HashWriter {
83            writer: self.writer.clone(),
84            hasher: self.hasher.clone(),
85        }
86    }
87}
88
89impl<D: Digest, W: io::Write> io::Write for HashWriter<D, W> {
90    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
91        let bytes = self.writer.write(buf)?;
92
93        if bytes > 0 {
94            self.hasher.update(&buf[0..bytes]);
95        }
96
97        Ok(bytes)
98    }
99
100    fn flush(&mut self) -> io::Result<()> {
101        self.writer.flush()
102    }
103}
104
105impl<D: Digest + FixedOutputReset, W: io::Write> HashWriter<D, W> {
106    /// Retrieve result and reset hasher instance.
107    pub fn finalize_reset(&mut self) -> Output<D> {
108        Digest::finalize_reset(&mut self.hasher)
109    }
110
111    /// Write result into provided array and reset the hasher instance.
112    pub fn finalize_into_reset(&mut self, out: &mut Output<D>) {
113        Digest::finalize_into_reset(&mut self.hasher, out)
114    }
115}
116
117impl<D: Digest + Reset, W: io::Write> Reset for HashWriter<D, W> {
118    fn reset(&mut self) {
119        Digest::reset(&mut self.hasher)
120    }
121}