fuchsia_merkle/
writer.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::io;
use std::io::Write;

use crate::builder::MerkleTreeBuilder;
use crate::tree::MerkleTree;

/// A `MerkleTreeWriter` wraps a [`MerkleTreeBuilder`] and another type that implements
/// [`std::io::Write`].
///
/// `MerkleTreeWriter`s can be used to compute a [`MerkleTree`] while streaming data from one
/// location to another. To simply compute a [`MerkleTree`] without chaining writes to a separate
/// Writer, see [`MerkleTreeBuilder`].
///
/// # Examples
/// ```
/// # use fuchsia_merkle::*;
/// # use std::io::{Result,Write};
/// # fn main() -> Result<()> {
/// let data = vec![0xff; 8192];
/// let mut written = Vec::new();
/// {
///     let mut writer = MerkleTreeWriter::new(&mut written);
///     writer.write_all(&data)?;
///     assert_eq!(
///         writer.finish().root(),
///         "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737"
///             .parse()
///             .unwrap()
///     );
/// }
/// assert_eq!(written, data);
/// #     Ok(())
/// # }
/// ```
pub struct MerkleTreeWriter<W> {
    inner: W,
    builder: MerkleTreeBuilder,
}

impl<W: Write> MerkleTreeWriter<W> {
    /// Creates a new `MerkleTreeWriter`
    pub fn new(inner: W) -> Self {
        MerkleTreeWriter { inner, builder: MerkleTreeBuilder::new() }
    }

    /// Finalizes all levels of the merkle tree, converting this `MerkleTreeWriter` instance into a
    /// [`MerkleTree`].
    pub fn finish(self) -> MerkleTree {
        self.builder.finish()
    }
}

impl<W: Write> Write for MerkleTreeWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.write_all(buf)?;
        self.builder.write(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Hash;
    use test_case::test_case;

    #[allow(clippy::unused_unit)]
    #[test_case(vec![], "15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b" ; "test_empty")]
    #[test_case(vec![0xFF; 8192], "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737"; "test_oneblock")]
    #[test_case(vec![0xFF; 65536], "f75f59a944d2433bc6830ec243bfefa457704d2aed12f30539cd4f18bf1d62cf"; "test_small")]
    #[test_case(vec![0xFF; 2105344], "7d75dfb18bfd48e03b5be4e8e9aeea2f89880cb81c1551df855e0d0a0cc59a67"; "test_large")]
    #[test_case(vec![0xFF; 2109440], "7577266aa98ce587922fdc668c186e27f3c742fb1b732737153b70ae46973e43"; "test_unaligned")]
    fn tests(input: Vec<u8>, output: &str) {
        let mut written = Vec::with_capacity(input.len());
        let actual = {
            let mut tree = MerkleTreeWriter::new(&mut written);
            tree.write_all(input.as_slice()).unwrap();
            tree.finish().root()
        };
        let expected: Hash = output.parse().unwrap();
        assert_eq!(expected, actual);
        assert_eq!(input, written);
    }
}