1use super::{HAMT_VERSION, KeyValueChange, Node};
2use crate::{Hasher, serializable::HamtSerializable};
3use anyhow::Result;
4use semver::Version;
5use serde::{Serialize, de::DeserializeOwned};
6use std::hash::Hash;
7use wnfs_common::{
8 BlockStore, Cid, Link, Storable,
9 utils::{Arc, CondSync},
10};
11
12#[derive(Debug, Clone)]
30pub struct Hamt<K: CondSync, V: CondSync, H = blake3::Hasher>
31where
32 H: Hasher + CondSync,
33{
34 pub root: Arc<Node<K, V, H>>,
35 pub version: Version,
36}
37
38impl<K: CondSync, V: CondSync, H: Hasher + CondSync> Hamt<K, V, H> {
43 pub fn new() -> Self {
54 Self {
55 root: Arc::new(Node::default()),
56 version: HAMT_VERSION,
57 }
58 }
59
60 pub fn with_root(root: Arc<Node<K, V, H>>) -> Self {
73 Self {
74 root,
75 version: HAMT_VERSION,
76 }
77 }
78
79 pub async fn diff(
111 &self,
112 other: &Self,
113 store: &impl BlockStore,
114 ) -> Result<Vec<KeyValueChange<K, V>>>
115 where
116 K: Storable + Clone + Eq + Hash + AsRef<[u8]>,
117 V: Storable + Clone + Eq,
118 K::Serializable: Serialize + DeserializeOwned,
119 V::Serializable: Serialize + DeserializeOwned,
120 {
121 super::diff(
122 Link::from(Arc::clone(&self.root)),
123 Link::from(Arc::clone(&other.root)),
124 store,
125 )
126 .await
127 }
128}
129
130impl<K, V, H> Storable for Hamt<K, V, H>
131where
132 K: Storable + CondSync,
133 V: Storable + CondSync,
134 K::Serializable: Serialize + DeserializeOwned,
135 V::Serializable: Serialize + DeserializeOwned,
136 H: Hasher + CondSync,
137{
138 type Serializable = HamtSerializable<K::Serializable, V::Serializable>;
139
140 async fn to_serializable(&self, store: &impl BlockStore) -> Result<Self::Serializable> {
141 Ok(HamtSerializable {
142 root: self.root.to_serializable(store).await?,
143 version: self.version.clone(),
144 structure: "hamt".to_string(),
145 })
146 }
147
148 async fn from_serializable(
149 _cid: Option<&Cid>,
150 serializable: Self::Serializable,
151 ) -> Result<Self> {
152 Ok(Self {
153 root: Arc::new(Node::from_serializable(None, serializable.root).await?),
154 version: serializable.version,
155 })
156 }
157}
158
159impl<K: CondSync, V: CondSync, H: Hasher + CondSync> Default for Hamt<K, V, H> {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl<K: CondSync, V: CondSync, H> PartialEq for Hamt<K, V, H>
166where
167 K: Storable + PartialEq + CondSync,
168 V: Storable + PartialEq + CondSync,
169 K::Serializable: Serialize + DeserializeOwned,
170 V::Serializable: Serialize + DeserializeOwned,
171 H: Hasher + CondSync,
172{
173 fn eq(&self, other: &Self) -> bool {
174 self.root == other.root && self.version == other.version
175 }
176}
177
178#[cfg(test)]
183mod tests {
184 use super::*;
185 use wnfs_common::MemoryBlockStore;
186
187 #[async_std::test]
188 async fn hamt_can_encode_decode_as_cbor() {
189 let store = &MemoryBlockStore::default();
190 let root = Arc::new(Node::default());
191 let hamt: Hamt<String, i32> = Hamt::with_root(root);
192
193 let hamt_cid = hamt.store(store).await.unwrap();
194 let decoded_hamt = Hamt::load(&hamt_cid, store).await.unwrap();
195
196 assert_eq!(hamt, decoded_hamt);
197 }
198}
199
200#[cfg(test)]
201mod snapshot_tests {
202 use super::*;
203 use wnfs_common::utils::SnapshotBlockStore;
204
205 #[async_std::test]
206 async fn test_hamt() {
207 let store = &SnapshotBlockStore::default();
208 let node = &mut Arc::new(Node::<[u8; 4], String>::default());
209 for i in 0..99_u32 {
210 node.set(i.to_le_bytes(), i.to_string(), store)
211 .await
212 .unwrap();
213 }
214
215 let hamt = Hamt::with_root(Arc::clone(node));
216 let cid = hamt.store(store).await.unwrap();
217 let hamt = store.get_block_snapshot(&cid).await.unwrap();
218
219 insta::assert_json_snapshot!(hamt);
220 }
221}