Skip to main content

casper_contract_sdk/collections/
map.rs

1use crate::{
2    abi::{CasperABI, Declaration, Definition, StructField},
3    casper::{self, read_into_vec},
4    serializers::borsh::{BorshDeserialize, BorshSerialize},
5};
6use casper_executor_wasm_common::keyspace::Keyspace;
7use const_fnv1a_hash::fnv1a_hash_str_64;
8
9use crate::prelude::marker::PhantomData;
10
11#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
12#[borsh(crate = "crate::serializers::borsh")]
13pub struct Map<K, V> {
14    pub(crate) name: String,
15    pub(crate) _marker: PhantomData<(K, V)>,
16}
17
18/// Computes the prefix for a given key.
19#[allow(dead_code)]
20pub(crate) const fn compute_prefix(input: &str) -> [u8; 8] {
21    let hash = fnv1a_hash_str_64(input);
22    hash.to_le_bytes()
23}
24
25impl<K, V> Map<K, V>
26where
27    K: BorshSerialize,
28    V: BorshSerialize + BorshDeserialize,
29{
30    pub fn new<S: Into<String>>(name: S) -> Self {
31        Self {
32            name: name.into(),
33            _marker: PhantomData,
34        }
35    }
36
37    pub fn insert(&mut self, key: &K, value: &V) {
38        let mut context_key = Vec::new();
39        context_key.extend(self.name.as_bytes());
40        // NOTE: We may want to create new keyspace for a hashed context element to avoid hashing in
41        // the wasm.
42        key.serialize(&mut context_key).unwrap();
43        let prefix = Keyspace::Context(&context_key);
44        casper::write(prefix, &borsh::to_vec(value).unwrap()).unwrap();
45    }
46
47    pub fn remove(&mut self, key: &K) {
48        let prefix_bytes = self.compute_prefix_for_key(key);
49        let prefix = Keyspace::Context(&prefix_bytes);
50        casper::remove(prefix).unwrap();
51    }
52
53    pub fn get(&self, key: &K) -> Option<V> {
54        let mut key_bytes = self.name.as_bytes().to_owned();
55        key.serialize(&mut key_bytes).unwrap();
56        let prefix = Keyspace::Context(&key_bytes);
57        read_into_vec(prefix)
58            .unwrap()
59            .map(|vec| borsh::from_slice(&vec).unwrap())
60    }
61
62    fn compute_prefix_for_key(&self, key: &K) -> Vec<u8> {
63        let mut context_key = Vec::new();
64        context_key.extend(self.name.as_bytes());
65        key.serialize(&mut context_key).unwrap();
66        context_key
67    }
68}
69
70impl<K: CasperABI, V: CasperABI> CasperABI for Map<K, V> {
71    fn populate_definitions(definitions: &mut crate::abi::Definitions) {
72        definitions.populate_one::<K>();
73        definitions.populate_one::<V>();
74    }
75
76    fn declaration() -> Declaration {
77        format!("Map<{}, {}>", K::declaration(), V::declaration())
78    }
79    #[inline]
80    fn definition() -> Definition {
81        Definition::Struct {
82            items: vec![StructField {
83                name: "prefix".into(),
84                decl: u64::declaration(),
85            }],
86        }
87    }
88}
89
90#[cfg(test)]
91pub(crate) mod tests {
92    use super::*;
93
94    #[test]
95    fn test_compute_prefix() {
96        let prefix = compute_prefix("hello");
97        assert_eq!(prefix.as_slice(), &[11, 189, 170, 128, 70, 216, 48, 164]);
98        let back = u64::from_le_bytes(prefix);
99        assert_eq!(fnv1a_hash_str_64("hello"), back);
100    }
101
102    #[ignore]
103    #[test]
104    fn test_map() {
105        let mut map = Map::<u64, u64>::new("test");
106        map.insert(&1, &2);
107        assert_eq!(map.get(&1), Some(2));
108        assert_eq!(map.get(&2), None);
109        map.insert(&2, &3);
110        assert_eq!(map.get(&1), Some(2));
111        assert_eq!(map.get(&2), Some(3));
112
113        let mut map = Map::<u64, u64>::new("test2");
114        assert_eq!(map.get(&1), None);
115        map.insert(&1, &22);
116        assert_eq!(map.get(&1), Some(22));
117        assert_eq!(map.get(&2), None);
118        map.insert(&2, &33);
119        assert_eq!(map.get(&1), Some(22));
120        assert_eq!(map.get(&2), Some(33));
121    }
122}