fvm_std/collections/
hyper_list.rs

1use crate::{runtime};
2use crate::spread::SpreadLayout;
3use crate::prelude::{Vec};
4use crate::collections::entry_state::{ValueWrapper, EntryState};
5use scale::{Decode, Encode};
6use alloc::collections::BTreeMap;
7use alloc::collections::btree_map::Entry;
8
9pub struct HyperList<T> {
10    size: u32, // index is u32, so size can be u32
11    list_name: Vec<u8>,
12    //prefix is "list_name@K"
13    storage_prefix: Vec<u8>,
14    //HyperList raw key is i64, index is u32
15    cache_values: BTreeMap<i64, ValueWrapper<T>>,
16}
17
18static mut DEPLOY_LIST_ID :i32 = 0;
19
20fn get_id() -> i32 {
21    unsafe {
22        DEPLOY_LIST_ID = DEPLOY_LIST_ID + 1;
23        DEPLOY_LIST_ID.clone()
24    }
25}
26
27impl<T> HyperList<T> {
28    pub fn new() -> Self {
29        let new_id = get_id();
30        Self {
31            size: 0,
32            list_name: new_id.encode(),
33            storage_prefix: "_".as_bytes().to_vec(),
34            cache_values: BTreeMap::<i64, ValueWrapper<T>>::new(),
35        }
36    }
37}
38
39impl<T> HyperList<T>
40    where
41        T: Encode + Decode,
42{
43
44    // returns the value, the return can not be change
45    fn get_by_key(&mut self, key: i64) -> Option<&T> {
46        match self.cache_values.entry(key) {
47            // not in cache
48            Entry::Vacant(entry) => {
49                // key to vec<u8>
50                let storage_key = key.encode();// impl encode for i64
51                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
52                match value {
53                    // get in DB
54                    Some(v) => {
55                        let input = &mut &v[..];
56                        let res: T = T::decode(input).unwrap();
57                        let wrapper = ValueWrapper::new(res, EntryState::NoChanged);
58                        // save in cache
59                        let va = entry.insert(wrapper);
60                        va.value.as_ref()
61                    }
62                    // not in DB
63                    None => {
64                        None
65                    }
66                }
67            }
68            // in cache
69            Entry::Occupied(entry) => {
70                let ent = entry.into_mut();
71                // has been deleted
72                if ent.state == EntryState::Deleted {
73                    return None;
74                }
75                ent.value.as_ref()
76            }
77        }
78    }
79
80    // the state should be changed, get None means be deleted or not exist 
81    fn get_mut_by_key(&mut self, key: i64) -> Option<&mut T> {
82        match self.cache_values.entry(key) {
83            // not in cache
84            Entry::Vacant(entry) => {
85                let storage_key = key.encode();
86                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
87                match value {
88                    // in DB
89                    Some(v) => {
90                        let input = &mut &v[..];
91                        let res: T = T::decode(input).unwrap();
92                        let wrapper = ValueWrapper::new(res, EntryState::Changed);
93                        // save in cache
94                        let va = entry.insert(wrapper);
95                        va.value.as_mut()
96                    }
97                    // not in DB
98                    None => {
99                        None
100                    }
101                }
102            }
103            // in cache
104            Entry::Occupied(entry) => {
105                let ent = entry.into_mut();
106                if ent.state == EntryState::Deleted {
107                    return None;
108                }
109                ent.state = EntryState::Changed;
110                ent.value.as_mut()
111            }
112        }
113    }
114    // replace: if old value exist, means replace, return old value
115    // insert:  if old value not exist, means insert, return none
116    fn insert_by_key(&mut self, key: i64, val: T) -> Option<T>{
117        match self.get_mut_by_key(key) {
118            // in cache or DB, replace
119            Some(v)=>{
120                let old_value = core::mem::replace(v, val);
121                Some(old_value)
122            }
123            // insert new
124            None=>{
125                let wrapper = ValueWrapper::new(val, EntryState::Changed);
126                // save in cache, if the old state is deleted, it will be updated
127                self.cache_values.insert(key, wrapper);
128                // update size
129                self.size += 1;
130                // no old value
131                None
132            }
133        }
134    }
135    // remove, return old value if exist, else return none
136    fn remove_by_key(&mut self, key: i64) -> Option<T> {
137        // match self.get_mut_by_key(key) 
138        match self.cache_values.entry(key) {
139            // not in cache
140            Entry::Vacant(entry) => {
141                let storage_key = key.encode();
142                let value = runtime::storage_read(storage_key.as_slice(), self.storage_prefix.as_slice());
143                match value {
144                    Some(v) => {
145                        let input = &mut &v[..];
146                        let res: T = T::decode(input).unwrap();
147                        let wrapper = ValueWrapper::new_empty_value(EntryState::Deleted);
148                        // push it to cache
149                        entry.insert(wrapper);
150                        self.size -= 1;  // change the size 
151                        Some(res)
152                    }
153                    None => {
154                        None
155                    }
156                }
157            }
158            // in cache
159            Entry::Occupied(mut entry) => {
160                // return from cache
161                let old = entry.insert(ValueWrapper::new_empty_value(EntryState::Deleted));
162                if old.state == EntryState::Deleted {
163                    return None;
164                }
165                self.size -= 1;  // change the size
166                return old.value;
167            }
168        }
169    }
170
171    // just call add
172	pub fn push(&mut self, ele:  T) -> bool {
173        self.insert(self.size, ele)
174    }
175
176    // insert ele
177    // index<=size, index==size means append new value
178    pub fn insert(&mut self, index: u32, ele: T) -> bool {
179        // check index
180        if index > self.size {
181            return false;
182        }
183        // get key from mapping table
184        match runtime::add_list_key(self.list_name.as_slice(), index) {
185            Some(key) => {
186                self.insert_by_key(key, ele);
187                true
188            }
189            None => {
190                false
191            }
192        }
193    }
194
195    // get immutable value
196    pub fn get(&mut self, index: u32) -> Option<&T> {
197        // check index
198        if index >= self.size {
199            return None;
200        }
201        match runtime::get_list_key(self.list_name.as_slice(), index) {
202            Some(key) => {
203                self.get_by_key(key)
204            }
205            None => {
206                None
207            }
208        }
209    }
210
211    pub fn get_mut(&mut self, index: u32) -> Option<&mut T> {
212        if index >= self.size {
213            return None;
214        }
215        match  runtime::get_list_key(self.list_name.as_slice(), index){
216            Some(key) => {
217                self.get_mut_by_key(key)
218            }
219            None => {
220                None
221            }
222        }
223    }
224
225    pub fn is_empty(&self) -> bool {
226        self.size == 0
227    }
228
229    pub fn pop(&mut self) -> Option<T> {
230        if self.len() == 0 {
231            None
232        } else {
233           self.remove(self.len() - 1) 
234        }
235    }
236
237    // remove index value and return old value
238    // index<size,return old value, else return None
239    pub fn remove(&mut self, index: u32) -> Option<T> {
240        // check index
241        if index >= self.size {
242            return None;
243        }
244        match runtime::remove_list_key(self.list_name.as_slice(), index) {
245            Some(key) => {
246                self.remove_by_key(key)
247            }
248            None => {
249                None
250            }
251        }
252    }
253
254    pub fn len(&self) -> u32 {
255        self.size
256    }
257
258    //replace, index<size
259    pub fn replace(&mut self, index: u32, ele :T) -> Option<T> {
260        // check index
261        if index >= self.size {
262            return None;
263        }
264        match runtime::get_list_key(self.list_name.as_slice(), index) {
265            Some(key) => {
266                self.insert_by_key(key, ele)
267            }
268            None => {
269                None
270            }
271        }
272    }
273}
274
275impl<T> Default for HyperList<T> {
276    fn default() -> Self {
277        HyperList::new()
278    }
279}
280
281impl<T> SpreadLayout for HyperList<T>
282    where
283        T: Encode + Decode
284{
285    // deploy will not call this function
286    fn read_ledger(list_name: &[u8], _: &[u8]) -> Self {
287        let mut list: HyperList<T> = HyperList::<T>::new();
288        list.list_name = Vec::from(list_name);
289        // storage_prefix is list_name@K
290        list.storage_prefix = Vec::from([list_name, "@K".as_bytes()].concat());
291        // read the root_info and get size in it
292        let root_info = runtime::storage_read(list_name, "@HyperList".as_bytes()).unwrap();
293        // decode will call u32::from_le_bytes, it is little endian decode
294        list.size = <u32 as scale::Decode>::decode(&mut &root_info[0..4]).unwrap();
295        list
296    }
297
298    fn write_ledger(&self, list_name: &[u8], deploy_flag: &[u8]) {
299        // "write_list_keys_back" check the size and write mapping tables back, if size is not equal in VM, then error happens
300        if deploy_flag == "deploy".as_bytes() {
301            // when deploy self.list_name = id.encode()
302            runtime::write_list_keys_back(self.list_name.as_slice(), list_name, self.size)
303        } else {
304            runtime::write_list_keys_back("".as_bytes(), list_name, self.size);
305        }
306        // write elements back
307        let storage_prefix = Vec::from([list_name, "@K".as_bytes()].concat());
308        self.cache_values.iter().for_each(|(key, value)| {
309            match value.state {
310                EntryState::Changed => {
311                    let storage_key = key.encode();
312                    let storage_value = value.value.as_ref().unwrap().encode();
313                    runtime::storage_write(storage_key.as_slice(), storage_prefix.as_slice(), storage_value.as_slice());
314                }
315                EntryState::Deleted => {
316                    let storage_key = key.encode();
317                    runtime::storage_delete(storage_key.as_slice(), storage_prefix.as_slice());
318                }
319                _ => {}
320            }
321        });
322
323    }
324}
325
326#[cfg(test)]
327mod test {
328    use crate::collections::hyper_list::HyperList;
329    use crate::spread::SpreadLayout;
330    use crate::runtime;
331    use scale::Encode;
332    use scale::Decode;
333    #[test]
334    fn use_list_normal() {
335        let _mock = fvm_mock::build_runtime();
336        // deploy
337        let list: HyperList<String> =  HyperList::new();
338        list.write_ledger("list".as_bytes(), "deploy".as_bytes());
339
340        // invoke
341        let mut list: HyperList<String> = HyperList::read_ledger("list".as_bytes(), "invoke".as_bytes());
342        let res = list.insert(0, String::from("123"));
343        assert_eq!(res, true);
344        let res = list.get(0).unwrap();
345        assert_eq!(res, &String::from("123"));
346    }
347
348    #[test]
349    fn list_add_set() {
350        let _mock = fvm_mock::build_runtime();
351        // deploy
352        let list: HyperList<i32> =  HyperList::new();
353        list.write_ledger("list".as_bytes(), "deploy".as_bytes());
354
355        // invoke
356        let mut list: HyperList<i32> = HyperList::read_ledger("list".as_bytes(), "invoke".as_bytes());
357        for i in 0..100 {
358            let res = list.insert(i, (i+100) as i32);
359            assert_eq!(res, true);
360        }
361        // write back
362        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
363        // clear cache
364        list.cache_values.clear();
365        // get
366        for i in 0..100 {
367            let res = list.get(i);
368            assert_eq!(res, Some(&((i+100) as i32)));
369        }
370        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
371    }
372
373
374    #[test]
375    fn list_delete() {
376        #[derive(Encode, Decode, Eq, PartialEq, Debug)]
377        struct Student {
378            id: u32,
379            name: String,
380        }
381        let _mock = fvm_mock::build_runtime();
382        // deploy
383        let list: HyperList<Student> =  HyperList::new();
384        list.write_ledger("list".as_bytes(), "deploy".as_bytes());
385
386        // invoke
387        let mut list: HyperList<Student> = HyperList::read_ledger("list".as_bytes(), "invoke".as_bytes());
388        // add
389        let res = list.insert(0, Student { id: 1, name: String::from("s1") });
390        assert_eq!(res, true);
391        let res = list.insert(0, Student { id: 0, name: String::from("s0") });
392        assert_eq!(res, true);
393        assert_eq!(list.len(), 2);
394
395        //delete 
396        let old_value = list.remove(0);
397        assert_eq!(old_value, Some(Student{id: 0, name: String::from("s0")}));
398        assert_eq!(list.get(1), None);
399        assert_eq!(list.is_empty(), false);
400        assert_eq!(list.get(0), Some(&Student { id: 1, name: String::from("s1") }));
401
402        // write back and clear cache
403        list.storage_prefix = [list.list_name.as_slice(), "@K".as_bytes()].concat().to_vec();
404        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
405        list.cache_values.clear();
406        // 1.encode get vec length is 4, 1i64.encode is 8
407        assert_eq!(runtime::storage_read(1i64.encode().as_slice(), list.storage_prefix.as_slice()), None);
408        assert_eq!(runtime::storage_read(0i64.encode().as_slice(), list.storage_prefix.as_slice()), Some(Student { id: 1, name: String::from("s1") }.encode()));
409    }
410
411    #[test]
412    fn list_operate_many_times() {
413        let _mock = fvm_mock::build_runtime();
414        // deploy
415        let list: HyperList<i32> =  HyperList::new();
416        list.write_ledger("list".as_bytes(), "deploy".as_bytes());
417
418        // invoke
419        let mut list: HyperList<i32> = HyperList::read_ledger("list".as_bytes(), "invoke".as_bytes());
420        // add(insert)
421        assert_eq!(list.insert(0, 54), true);
422        assert_eq!(list.insert(0, 56), true);
423        assert_eq!(list.insert(4, 33), false);
424        assert_eq!(list.get(0), Some(&56));
425        assert_eq!(list.get_mut(0), Some(&mut 56));
426        // write back and clear cache
427        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
428        list.cache_values.clear();
429
430        // set(replace)
431        assert_eq!(list.replace(0, 101), Some(56));
432        assert_eq!(list.replace(1, 111), Some(54));
433        assert_eq!(list.replace(0, 2331), Some(101));
434        assert_eq!(list.replace(0, 100), Some(2331));
435        // write back and clear cache
436        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
437        list.cache_values.clear();
438
439        // remove
440        assert_eq!(list.remove(1), Some(111));
441        assert_eq!(list.remove(0), Some(100));
442        assert_eq!(list.remove(0), None);
443
444        assert_eq!(list.is_empty(), true);
445        // write back and clear cache
446        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
447        list.cache_values.clear();
448
449        // append
450        assert_eq!(list.push(77), true);
451        assert_eq!(list.push(88), true);
452        assert_eq!(list.len(), 2);
453
454        // write ele back
455        list.write_ledger(list.list_name.as_slice(), "invoke".as_bytes());
456        let  root = vec![0;24];
457        let  first_four = 2.encode();
458        let root = [ first_four, root].concat();
459        runtime::storage_write(list.list_name.as_slice(), "@HyperList".as_bytes(), root.as_slice());
460
461        // test read_ledger
462        let new_list: HyperList<i64> = HyperList::read_ledger(list.list_name.as_slice(), "".as_bytes());
463        assert_eq!(list.list_name, new_list.list_name);
464        assert_eq!(list.storage_prefix, new_list.storage_prefix);
465        assert_eq!(list.size, new_list.size);
466    }
467}