Skip to main content

rw_builder/
digest.rs

1use crate::{Result, RwBuilder};
2use digest::Digest;
3use std::io::{Read, Write};
4
5/// A builder that computes a cryptographic hash or checksum on the stream.
6#[derive(Debug)]
7#[must_use]
8pub struct DigestBuilder<B, D>
9where
10    B: RwBuilder,
11    D: Digest,
12{
13    /// Inner builder
14    builder: B,
15    /// Phantom data
16    _marker: std::marker::PhantomData<D>,
17}
18
19impl<B, D> DigestBuilder<B, D>
20where
21    B: RwBuilder,
22    D: Digest,
23{
24    /// Factory function to wrap an inner builder for digesting
25    pub const fn new(builder: B) -> Self {
26        Self { builder, _marker: std::marker::PhantomData }
27    }
28}
29
30/// The type returned by the `sha256` function in the `RwBuilder` trait
31#[cfg(feature = "sha2")]
32pub type Sha256Builder<B> = DigestBuilder<B, ::sha2::Sha256>;
33/// The type returned by the `sha512` function in the `RwBuilder` trait
34#[cfg(feature = "sha2")]
35pub type Sha512Builder<B> = DigestBuilder<B, ::sha2::Sha512>;
36
37/// The type returned by the `sha3_256` function in the `RwBuilder` trait
38#[cfg(feature = "sha3")]
39pub type Sha3_256Builder<B> = DigestBuilder<B, ::sha3::Sha3_256>;
40/// The type returned by the `sha3_512` function in the `RwBuilder` trait
41#[cfg(feature = "sha3")]
42pub type Sha3_512Builder<B> = DigestBuilder<B, ::sha3::Sha3_512>;
43
44impl<B, D> RwBuilder for DigestBuilder<B, D>
45where
46    B: RwBuilder,
47    B::Reader: Read,
48    B::Writer: Write,
49    D: Digest,
50{
51    type Reader = DigestReader<B::Reader, D>;
52    type Writer = DigestWriter<B::Writer, D>;
53
54    fn reader(&self) -> Result<Self::Reader> {
55        Ok(DigestReader::new(self.builder.reader()?))
56    }
57
58    fn writer(&self) -> Result<Self::Writer> {
59        Ok(DigestWriter::new(self.builder.writer()?))
60    }
61}
62
63/// A reader wrapper that computes a digest while reading.
64#[derive(Debug)]
65pub struct DigestReader<R, D>
66where
67    R: Read,
68    D: Digest,
69{
70    /// Inner reader
71    inner: R,
72    /// Hasher instance
73    hasher: D,
74}
75
76impl<R, D> DigestReader<R, D>
77where
78    R: Read,
79    D: Digest,
80{
81    /// Creates a new `DigestReader`
82    pub fn new(inner: R) -> Self {
83        Self { inner, hasher: D::new() }
84    }
85
86    /// Consumes the reader and returns the computed hash.
87    pub fn finalize(self) -> digest::Output<D> {
88        self.hasher.finalize()
89    }
90
91    /// Unwraps the inner reader.
92    pub fn into_inner(self) -> R {
93        self.inner
94    }
95}
96
97impl<R, D> Read for DigestReader<R, D>
98where
99    R: Read,
100    D: Digest,
101{
102    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
103        let n = self.inner.read(buf)?;
104        self.hasher.update(&buf[..n]);
105        Ok(n)
106    }
107}
108
109/// A writer wrapper that computes a digest while writing.
110#[derive(Debug)]
111pub struct DigestWriter<W, D>
112where
113    W: Write,
114    D: Digest,
115{
116    /// Inner writer
117    inner: W,
118    /// Hasher instance
119    hasher: D,
120}
121
122impl<W, D> DigestWriter<W, D>
123where
124    W: Write,
125    D: Digest,
126{
127    /// Creates a new `DigestWriter`
128    pub fn new(inner: W) -> Self {
129        Self { inner, hasher: D::new() }
130    }
131
132    /// Consumes the writer and returns the computed hash.
133    pub fn finalize(self) -> digest::Output<D> {
134        self.hasher.finalize()
135    }
136
137    /// Unwraps the inner writer.
138    pub fn into_inner(self) -> W {
139        self.inner
140    }
141}
142
143impl<W, D> Write for DigestWriter<W, D>
144where
145    W: Write,
146    D: Digest,
147{
148    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
149        let n = self.inner.write(buf)?;
150        self.hasher.update(&buf[..n]);
151        Ok(n)
152    }
153
154    fn flush(&mut self) -> std::io::Result<()> {
155        self.inner.flush()
156    }
157}