fvm_std/collections/
hyper_map.rs

1use crate::{runtime};
2use crate::spread::SpreadLayout;
3use core::hash::Hash;
4use core::borrow::Borrow;
5use crate::prelude::{Vec};
6use crate::collections::entry_state::{ValueWrapper, EntryState};
7use scale::{Decode, Encode};
8use alloc::collections::BTreeMap;
9use alloc::borrow::ToOwned;
10use alloc::collections::btree_map::Entry;
11
12/// An non-iterable implementation of a map that stores its content directly on the trie.
13pub struct HyperMap<K, V> {
14    // the size of the map values
15    origin_size: u64,
16    size: u64,
17    // when deploy: storage_prefix is `_`, it will always empty of read result
18    // when invoke: storage_prefix is `field_name` from the framework
19    storage_prefix: Vec<u8>,
20    // 为每一个元素记录是否有被修改过
21    cache_values: BTreeMap<K, ValueWrapper<V>>,
22}
23
24impl<K, V> HyperMap<K, V> {
25    /// Make a new, empty `HyperMap`,
26    ///
27    /// It should be called when contract init.
28    ///
29    /// # Examples
30    ///
31    /// Basic usage:
32    /// ``` ignore
33    /// use fvm_std::collections::hyper_map::HyperMap;
34    /// use fvm_macros::contract;
35    /// use fvm_macros::storage;
36    ///
37    /// #[storage]
38    /// pub struct HyperMapDemo {
39    ///     map: HyperMap<String, String>,
40    /// }
41    ///
42    /// #[contract]
43    /// impl HyperMapDemo {
44    ///     /// used in construct method
45    ///     fn new() -> Self {
46    ///         Self { map: HyperMap::new() }
47    ///     }
48    /// }
49    /// ```
50    pub fn new() -> Self {
51        Self {
52            origin_size: 0,
53            size: 0,
54            storage_prefix: "_".as_bytes().to_vec(),
55            cache_values: BTreeMap::<K, ValueWrapper<V>>::new(),
56        }
57    }
58}
59
60impl<K, V> HyperMap<K, V>
61    where
62        K: Ord + Hash + Encode + Decode,
63        V: Encode + Decode
64{
65    /// Returns a reference to the value corresponding to the key.
66    ///
67    /// The key may be any borrowed form of the map's key type, but the ordering
68    /// on the borrowed form *must* match the ordering on the key type.
69    pub fn get<Q: ?Sized>(&mut self, k: &Q) -> Option<&V>
70        where
71            K: Borrow<Q> + Ord,
72            Q: Hash + Ord + Encode + ToOwned<Owned=K>,
73    {
74        match self.cache_values.entry(k.to_owned()) {
75            Entry::Vacant(entry) => {
76                // get from ledger
77                let storage_key = k.encode();
78                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
79                match value {
80                    Some(v) => {
81                        let input = &mut &v[..];
82                        let res: V = V::decode(input).unwrap();
83                        let wrapper = ValueWrapper::new(res, EntryState::NoChanged);
84                        // push it to cache
85                        let va = entry.insert(wrapper);
86                        va.value.as_ref()
87                    }
88                    None => {
89                        None
90                    }
91                }
92            }
93            Entry::Occupied(entry) => {
94                let ent = entry.into_mut();
95                if ent.state == EntryState::Deleted {
96                    return None;
97                }
98                // return from cache
99                ent.value.as_ref()
100            }
101        }
102    }
103
104    /// Returns a mutable reference to the value corresponding to the key.
105    ///
106    /// The key may be any borrowed form of the map's key type, but the ordering
107    /// on the borrowed form *must* match the ordering on the key type.
108    ///
109    /// All `get_mut` result we wil think it to be changed.
110    pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
111        where
112            K: Borrow<Q> + Ord,
113            Q: Hash + Ord + Encode + ToOwned<Owned=K>,
114    {
115        match self.cache_values.entry(k.to_owned()) {
116            Entry::Vacant(entry) => {
117                // get from ledger
118                let storage_key = k.encode();
119                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
120                match value {
121                    Some(v) => {
122                        let input = &mut &v[..];
123                        let res: V = V::decode(input).unwrap();
124                        let wrapper = ValueWrapper::new(res, EntryState::Changed);
125                        // push it to cache
126                        let va = entry.insert(wrapper);
127                        va.value.as_mut()
128                    }
129                    None => {
130                        None
131                    }
132                }
133            }
134            Entry::Occupied(entry) => {
135                // return from cache
136                let ent = entry.into_mut();
137                if ent.state == EntryState::Deleted {
138                    return None;
139                }
140                ent.state = EntryState::Changed;
141                return ent.value.as_mut();
142            }
143        }
144    }
145
146
147    /// Inserts a key-value pair into the map.
148    ///
149    /// If the map did not have this key present, [`None`] is returned.
150    ///
151    /// If the map did have this key present, the value is updated, and the old
152    /// value is returned. The key is not updated, though; this matters for
153    /// types that can be `==` without being identical. See the [module-level
154    /// documentation] for more.
155    pub fn insert(&mut self, key: K, value: V) -> Option<V> where K: Clone {
156        // insert before get
157        match self.get_mut(&key) {
158            Some(v) => {
159                // change the value and return old value
160                let old_value = core::mem::replace(v, value);
161                Some(old_value)
162            }
163            None => {
164                // insert to cache first and make it `Changed`
165                let wrapper = ValueWrapper::new(value, EntryState::Changed);
166                self.cache_values.insert(key, wrapper);
167                self.size += 1;
168                None
169            }
170        }
171    }
172
173    /// Removes a key from the map, returning the stored key and value if the
174    /// key was previously in the map.
175    ///
176    /// The key may be any borrowed form of the map's key type, but the ordering
177    /// on the borrowed form *must* match the ordering on the key type.
178    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
179        where
180            K: Borrow<Q>,
181            Q: Hash + Eq + Ord + Encode + ToOwned<Owned=K>,
182    {
183        // remove before get
184        match self.cache_values.entry(k.to_owned()) {
185            Entry::Vacant(entry) => {
186                // get from ledger
187                let storage_key = k.encode();
188                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
189                match value {
190                    Some(v) => {
191                        let input = &mut &v[..];
192                        let res: V = V::decode(input).unwrap();
193                        let wrapper = ValueWrapper::new_empty_value(EntryState::Deleted);
194                        // push it to cache
195                        entry.insert(wrapper);
196                        self.size -= 1;  // change the size of the map
197                        Some(res)
198                    }
199                    None => {
200                        None
201                    }
202                }
203            }
204            Entry::Occupied(mut entry) => {
205                // return from cache
206                let old = entry.insert(ValueWrapper::new_empty_value(EntryState::Deleted));
207                if old.state == EntryState::Deleted {
208                    return None;
209                }
210                self.size -= 1;  // change the size of the map
211                return old.value;
212            }
213        }
214    }
215
216    /// Returns the number of elements in the map.
217    ///
218    pub fn len(&self) -> u64 {
219        self.size
220    }
221
222    /// Returns `true` if the map contains no elements.
223    ///
224    pub fn is_empty(&self) -> bool {
225        self.size == 0
226    }
227
228    /// Returns the key-value pair corresponding to the supplied key.
229    ///
230    /// The key may be any borrowed form of the map's key type, but the ordering
231    /// on the borrowed form *must* match the ordering on the key type.
232    pub fn get_key_value<Q: ?Sized>(&mut self, k: &Q) -> Option<(&K, &V)>
233        where
234            K: Borrow<Q> + Ord,
235            Q: Hash + Ord + Encode + ToOwned<Owned=K>,
236    {
237        // use the
238        match self.get(k) {
239            None => { None }
240            Some(_) => {
241                let (key, value) = self.cache_values.get_key_value(k).unwrap();
242                Some((key, &value.value.as_ref().unwrap()))
243            }
244        }
245    }
246
247    /// Returns `true` if the map contains a value for the specified key.
248    ///
249    /// The key may be any borrowed form of the map's key type, but the ordering
250    /// on the borrowed form *must* match the ordering on the key type.
251    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
252        where
253            K: Borrow<Q> + Ord,
254            Q: Hash + Ord + Encode + ToOwned<Owned=K>,
255    {
256        // form cache first
257        if let Some(v) = self.cache_values.get(k) {
258            return v.state != EntryState::Deleted;
259        }
260
261        // from ledger
262        let storage_key = k.encode();
263        let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
264
265        value.is_some()
266    }
267}
268
269impl<K, V> Default for HyperMap<K, V> {
270    fn default() -> Self {
271        HyperMap::new()
272    }
273}
274
275impl<K, V> SpreadLayout for HyperMap<K, V>
276    where
277        K: Ord + Hash + Encode + Decode,
278        V: Encode + Decode
279{
280    fn read_ledger(key_prefix: &[u8], _: &[u8]) -> Self {
281        // 这里只是创建一个包含缓存的对象
282        let mut map = HyperMap::<K, V>::new();
283        map.storage_prefix = Vec::from(key_prefix);
284        let size = runtime::storage_read(key_prefix, "@HyperMap".as_bytes()).unwrap();
285        map.size = <u64 as scale::Decode>::decode(&mut &size[..]).unwrap();
286        map.origin_size = map.size;
287        map
288    }
289
290    fn write_ledger(&self, key_prefix: &[u8], deploy_flag: &[u8]) {
291        if deploy_flag == "deploy".as_bytes() {
292            // if deploy, write a basic size 0 of the map, real key is: @HyperMap@{fieldName}
293            runtime::storage_write(key_prefix, "@HyperMap".as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 0])
294        }
295        // write all cached k->v
296        self.cache_values.iter().for_each(|(key, value)| {
297            match value.state {
298                EntryState::Changed => {
299                    let sto_key = key.encode();
300                    let sto_value = value.value.as_ref().unwrap().encode();
301                    runtime::storage_write(sto_key.as_slice(), key_prefix, sto_value.as_slice());
302                }
303                EntryState::Deleted => {
304                    let sto_key = key.encode();
305                    runtime::storage_delete(sto_key.as_slice(), key_prefix);
306                }
307                _ => {}
308            }
309        });
310        // update size
311        if self.size != self.origin_size {
312            runtime::storage_write(key_prefix, "@HyperMap".as_bytes(), self.size.encode().as_slice())
313        }
314    }
315}
316
317#[cfg(test)]
318mod test {
319    use crate::collections::hyper_map::HyperMap;
320    use std::string::String;
321    use crate::spread::SpreadLayout;
322    use crate::runtime;
323    use scale::Encode;
324    use scale::Decode;
325
326    #[test]
327    fn use_map_normal() {
328        let _mock = fvm_mock::build_runtime();
329        let mut map: HyperMap<String, String> = HyperMap::new();
330        map.insert(String::from("123"), String::from("456"));
331        let res = map.get(&String::from("123")).unwrap();
332        assert_eq!(*res, String::from("456"))
333    }
334
335    #[test]
336    fn map_get() {
337        let mock = fvm_mock::build_runtime();
338        let mut map: HyperMap<i32, i64> = Default::default();
339        assert_eq!(map.get(&1), None);
340
341        mock.storage_write(1.encode().as_slice(), "_".as_bytes(), 100i64.encode());
342        assert_eq!(map.get(&1), Some(&100i64));
343    }
344
345
346    #[test]
347    fn map_get_insert() {
348        let _mock = fvm_mock::build_runtime();
349        let mut map: HyperMap<i32, i32> = Default::default();
350        map.insert(1, 100);
351        map.insert(2, 200);
352        assert_eq!(map.len(), 2);
353        assert_eq!(map.get(&1), Some(&100));
354        map.write_ledger("map".as_bytes(), "invoke".as_bytes());
355        // check result
356        assert_eq!(runtime::storage_read(1.encode().as_slice(), "map".as_bytes()), Some(100.encode()));
357        assert_eq!(runtime::storage_read(2.encode().as_slice(), "map".as_bytes()), Some(200.encode()));
358        assert_eq!(runtime::storage_read(3.encode().as_slice(), "map".as_bytes()), None);
359        assert_eq!(runtime::storage_read("map".as_bytes(), "@HyperMap".as_bytes()), Some(2u64.encode()));
360    }
361
362    #[test]
363    fn map_delete_normal() {
364        let mock = fvm_mock::build_runtime();
365        let mut map: HyperMap<i32, i64> = Default::default();
366        map.origin_size = 1;
367        map.size = 1;
368        assert_eq!(map.remove(&1), None);
369
370        mock.storage_write(1.encode().as_slice(), "_".as_bytes(), 100i64.encode());
371        assert_eq!(map.remove(&1), Some(100i64));
372    }
373
374    #[test]
375    fn map_delete_complex() {
376        #[derive(Encode, Decode, Eq, PartialEq, Debug)]
377        struct Student {
378            id: u32,
379            name: String,
380        }
381
382        let _mock = fvm_mock::build_runtime();
383        let mut map: HyperMap<i32, Student> = Default::default();
384        map.insert(1, Student { id: 0, name: String::from("Xiao Ming") });
385        map.insert(2, Student { id: 1, name: String::from("Xiao Fang") });
386        assert_eq!(map.len(), 2);
387        assert_eq!(map.get(&1), Some(&Student { id: 0, name: String::from("Xiao Ming") }));
388
389        // begin delete
390        let old_value = map.remove(&1);
391        assert_eq!(old_value, Some(Student { id: 0, name: String::from("Xiao Ming") }));
392        assert_eq!(map.get(&1), None);
393
394        map.write_ledger("map".as_bytes(), "invoke".as_bytes());
395        // check result
396        assert_eq!(runtime::storage_read(1.encode().as_slice(), "map".as_bytes()), None);
397        assert_eq!(runtime::storage_read(2.encode().as_slice(), "map".as_bytes()), Some(vec![1, 0, 0, 0, 36, 88, 105, 97, 111, 32, 70, 97, 110, 103]));
398        assert_eq!(runtime::storage_read(3.encode().as_slice(), "map".as_bytes()), None);
399        assert_eq!(runtime::storage_read("map".as_bytes(), "@HyperMap".as_bytes()), Some(1u64.encode()));
400    }
401
402    #[test]
403    fn map_operate_many_times() {
404        let _mock = fvm_mock::build_runtime();
405        let mut map = HyperMap::new();
406        // insert twice
407        map.insert(String::from("abc"), String::from("def"));
408        map.insert(String::from("abc"), String::from("ggg"));
409        assert_eq!(map.get(&String::from("abc")), Some(&String::from("ggg")));
410
411        // get twice
412        assert_eq!(map.get(&String::from("abc")), Some(&String::from("ggg")));
413        assert_eq!(map.get_mut(&String::from("abc")), Some(&mut String::from("ggg")));
414
415        // delete twice
416        let old = map.remove(&String::from("abc"));
417        assert_eq!(old, Some(String::from("ggg")));
418        let old = map.remove(&String::from("abc"));
419        assert_eq!(old, None);
420
421        // check result
422        map.write_ledger("map".as_bytes(), "deploy".as_bytes());
423        assert_eq!(runtime::storage_read("abc".encode().as_slice(), "map".as_bytes()), None);
424        assert_eq!(runtime::storage_read("map".as_bytes(), "@HyperMap".as_bytes()), Some(0u64.encode()));
425    }
426
427    #[test]
428    fn map_others_methods() {
429        let _mock = fvm_mock::build_runtime();
430        let mut map = HyperMap::new();
431        assert_eq!(map.is_empty(), true);
432        map.insert(b'A', 100);
433        map.insert(9, 200);
434        assert_eq!(map.is_empty(), false);
435        assert_eq!(map.len(), 2);
436
437        let key_value = map.get_key_value(&b'A');
438        assert!(key_value.is_some());
439        assert_eq!(key_value.unwrap().0, &b'A');
440        assert_eq!(key_value.unwrap().1, &100);
441    }
442}
443