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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use super::Digest;

/// The root hash of a [`MerkleSearchTree`], representative of the state of the
/// tree.
///
/// Two instances of a [`MerkleSearchTree`] are guaranteed to contain the same
/// state iff both [`RootHash`] read from the trees are identical (assuming
/// identical, deterministic [`Hasher`] implementations).
///
/// [`MerkleSearchTree`]: crate::MerkleSearchTree
/// [`Hasher`]: super::Hasher
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RootHash(Digest<16>);

impl std::ops::Deref for RootHash {
    type Target = Digest<16>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl RootHash {
    pub(crate) const fn new(value: PageDigest) -> Self {
        Self(value.0)
    }
}

#[cfg(feature = "digest_base64")]
impl std::fmt::Display for RootHash {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

/// Type wrapper over a [`Digest`] of a [`Page`], representing the hash of the
/// nodes & subtree rooted at the [`Page`].
///
/// [`Page`]: crate::page::Page
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PageDigest(Digest<16>);

impl std::ops::Deref for PageDigest {
    type Target = Digest<16>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl PageDigest {
    /// Construct a new [`PageDigest`] from a raw 16-byte array.
    pub const fn new(value: [u8; 16]) -> Self {
        Self(Digest::new(value))
    }
}

impl From<Digest<16>> for PageDigest {
    fn from(value: Digest<16>) -> Self {
        Self(value)
    }
}

#[cfg(feature = "digest_base64")]
impl std::fmt::Display for PageDigest {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

/// Type wrapper over a [`Digest`] of a tree value, for readability / clarity /
/// compile-time safety.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ValueDigest<const N: usize>(Digest<N>);

impl<const N: usize> std::ops::Deref for ValueDigest<N> {
    type Target = Digest<N>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<const N: usize> ValueDigest<N> {
    pub(crate) const fn new(value: Digest<N>) -> Self {
        Self(value)
    }
}

#[cfg(feature = "digest_base64")]
impl<const N: usize> std::fmt::Display for ValueDigest<N> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

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

    #[test]
    #[cfg(feature = "digest_base64")]
    fn test_base64_format() {
        let d = Digest::new([0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a]);
        assert_eq!(d.to_string(), "YmFuYW5hcwo=");

        let value = ValueDigest::new(Digest::new([
            0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a,
        ]));
        assert_eq!(value.to_string(), "YmFuYW5hcwo=");

        let page = PageDigest::from(Digest::new([
            0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x73, 0x0a, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61,
            0x73, 0x0a,
        ]));
        assert_eq!(page.to_string(), "YmFuYW5hcwpiYW5hbmFzCg==");
    }

    #[test]
    fn test_as_bytes() {
        let b = [
            42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
        ];
        let d = PageDigest::from(Digest::new(b));
        assert_eq!(b, *d.as_bytes());
    }
}