fuchsia_merkle/
writer.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::io;
6use std::io::Write;
7
8use crate::builder::MerkleTreeBuilder;
9use crate::tree::MerkleTree;
10
11/// A `MerkleTreeWriter` wraps a [`MerkleTreeBuilder`] and another type that implements
12/// [`std::io::Write`].
13///
14/// `MerkleTreeWriter`s can be used to compute a [`MerkleTree`] while streaming data from one
15/// location to another. To simply compute a [`MerkleTree`] without chaining writes to a separate
16/// Writer, see [`MerkleTreeBuilder`].
17///
18/// # Examples
19/// ```
20/// # use fuchsia_merkle::*;
21/// # use std::io::{Result,Write};
22/// # fn main() -> Result<()> {
23/// let data = vec![0xff; 8192];
24/// let mut written = Vec::new();
25/// {
26///     let mut writer = MerkleTreeWriter::new(&mut written);
27///     writer.write_all(&data)?;
28///     assert_eq!(
29///         writer.finish().root(),
30///         "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737"
31///             .parse()
32///             .unwrap()
33///     );
34/// }
35/// assert_eq!(written, data);
36/// #     Ok(())
37/// # }
38/// ```
39pub struct MerkleTreeWriter<W> {
40    inner: W,
41    builder: MerkleTreeBuilder,
42}
43
44impl<W: Write> MerkleTreeWriter<W> {
45    /// Creates a new `MerkleTreeWriter`
46    pub fn new(inner: W) -> Self {
47        MerkleTreeWriter { inner, builder: MerkleTreeBuilder::new() }
48    }
49
50    /// Finalizes all levels of the merkle tree, converting this `MerkleTreeWriter` instance into a
51    /// [`MerkleTree`].
52    pub fn finish(self) -> MerkleTree {
53        self.builder.finish()
54    }
55}
56
57impl<W: Write> Write for MerkleTreeWriter<W> {
58    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
59        self.inner.write_all(buf)?;
60        self.builder.write(buf);
61        Ok(buf.len())
62    }
63
64    fn flush(&mut self) -> io::Result<()> {
65        self.inner.flush()
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::Hash;
73    use test_case::test_case;
74
75    #[allow(clippy::unused_unit)]
76    #[test_case(vec![], "15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b" ; "test_empty")]
77    #[test_case(vec![0xFF; 8192], "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737"; "test_oneblock")]
78    #[test_case(vec![0xFF; 65536], "f75f59a944d2433bc6830ec243bfefa457704d2aed12f30539cd4f18bf1d62cf"; "test_small")]
79    #[test_case(vec![0xFF; 2105344], "7d75dfb18bfd48e03b5be4e8e9aeea2f89880cb81c1551df855e0d0a0cc59a67"; "test_large")]
80    #[test_case(vec![0xFF; 2109440], "7577266aa98ce587922fdc668c186e27f3c742fb1b732737153b70ae46973e43"; "test_unaligned")]
81    fn tests(input: Vec<u8>, output: &str) {
82        let mut written = Vec::with_capacity(input.len());
83        let actual = {
84            let mut tree = MerkleTreeWriter::new(&mut written);
85            tree.write_all(input.as_slice()).unwrap();
86            tree.finish().root()
87        };
88        let expected: Hash = output.parse().unwrap();
89        assert_eq!(expected, actual);
90        assert_eq!(input, written);
91    }
92}