merkle_search_tree/digest/
wrappers.rs

1use super::Digest;
2
3/// The root hash of a [`MerkleSearchTree`], representative of the state of the
4/// tree.
5///
6/// Two instances of a [`MerkleSearchTree`] are guaranteed to contain the same
7/// state iff both [`RootHash`] read from the trees are identical (assuming
8/// identical, deterministic [`Hasher`] implementations).
9///
10/// [`MerkleSearchTree`]: crate::MerkleSearchTree
11/// [`Hasher`]: super::Hasher
12#[derive(Debug, PartialEq, Eq, Clone)]
13pub struct RootHash(Digest<16>);
14
15impl std::ops::Deref for RootHash {
16    type Target = Digest<16>;
17
18    fn deref(&self) -> &Self::Target {
19        &self.0
20    }
21}
22
23impl RootHash {
24    pub(crate) const fn new(value: PageDigest) -> Self {
25        Self(value.0)
26    }
27}
28
29#[cfg(feature = "digest_base64")]
30impl std::fmt::Display for RootHash {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        self.0.fmt(f)
33    }
34}
35
36/// Type wrapper over a [`Digest`] of a [`Page`], representing the hash of the
37/// nodes & subtree rooted at the [`Page`].
38///
39/// [`Page`]: crate::page::Page
40#[derive(Debug, PartialEq, Eq, Clone)]
41pub struct PageDigest(Digest<16>);
42
43impl std::ops::Deref for PageDigest {
44    type Target = Digest<16>;
45
46    fn deref(&self) -> &Self::Target {
47        &self.0
48    }
49}
50
51impl PageDigest {
52    /// Construct a new [`PageDigest`] from a raw 16-byte array.
53    pub const fn new(value: [u8; 16]) -> Self {
54        Self(Digest::new(value))
55    }
56}
57
58impl From<Digest<16>> for PageDigest {
59    fn from(value: Digest<16>) -> Self {
60        Self(value)
61    }
62}
63
64#[cfg(feature = "digest_base64")]
65impl std::fmt::Display for PageDigest {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        self.0.fmt(f)
68    }
69}
70
71/// Type wrapper over a [`Digest`] of a tree value, for readability / clarity /
72/// compile-time safety.
73#[derive(Debug, PartialEq, Eq, Clone)]
74pub struct ValueDigest<const N: usize>(Digest<N>);
75
76impl<const N: usize> std::ops::Deref for ValueDigest<N> {
77    type Target = Digest<N>;
78
79    fn deref(&self) -> &Self::Target {
80        &self.0
81    }
82}
83
84impl<const N: usize> ValueDigest<N> {
85    pub(crate) const fn new(value: Digest<N>) -> Self {
86        Self(value)
87    }
88}
89
90#[cfg(feature = "digest_base64")]
91impl<const N: usize> std::fmt::Display for ValueDigest<N> {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        self.0.fmt(f)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    #[cfg(feature = "digest_base64")]
103    fn test_base64_format() {
104        let d = Digest::new([0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a]);
105        assert_eq!(d.to_string(), "YmFuYW5hcwo=");
106
107        let value = ValueDigest::new(Digest::new([
108            0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a,
109        ]));
110        assert_eq!(value.to_string(), "YmFuYW5hcwo=");
111
112        let page = PageDigest::from(Digest::new([
113            0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61,
114            0x73, 0x0a,
115        ]));
116        assert_eq!(page.to_string(), "YmFuYW5hcwpiYW5hbmFzCg==");
117    }
118
119    #[test]
120    fn test_as_bytes() {
121        let b = [
122            42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
123        ];
124        let d = PageDigest::from(Digest::new(b));
125        assert_eq!(b, *d.as_bytes());
126    }
127}