odra_core/
mapping.rs

1use crate::arithmetic::{OverflowingAdd, OverflowingSub};
2use crate::casper_types::{
3    bytesrepr::{FromBytes, ToBytes},
4    CLTyped
5};
6use crate::module::{ModuleComponent, ModulePrimitive};
7use crate::prelude::*;
8use crate::ContractEnv;
9use core::fmt::Debug;
10
11/// Data structure for storing key-value pairs.
12pub struct Mapping<K, V> {
13    parent_env: Rc<ContractEnv>,
14    phantom: core::marker::PhantomData<(K, V)>,
15    index: u8
16}
17
18impl<K: ToBytes, V> ModuleComponent for Mapping<K, V> {
19    /// Creates a new instance of `Mapping` with the given environment and index.
20    fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
21        Self {
22            parent_env: env,
23            phantom: core::marker::PhantomData,
24            index
25        }
26    }
27}
28
29impl<K: ToBytes, V> Revertible for Mapping<K, V> {
30    fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
31        self.parent_env.revert(e)
32    }
33}
34
35impl<K: ToBytes, V> ModulePrimitive for Mapping<K, V> {}
36
37impl<K: ToBytes, V> Mapping<K, V> {
38    fn env_for_key(&self, key: &K) -> ContractEnv {
39        let mut env = (*self.parent_env).clone();
40        let key = key.to_bytes().unwrap_or_default();
41        env.add_to_mapping_data(&key);
42        env
43    }
44}
45
46impl<K: ToBytes, V: FromBytes + CLTyped> Mapping<K, V> {
47    /// Retrieves the value associated with the given key.
48    ///
49    /// Returns an `Option<V>` representing the value associated with the key, or `None` if the key is not found.
50    pub fn get(&self, key: &K) -> Option<V> {
51        let env = self.env_for_key(key);
52        Var::<V>::instance(Rc::new(env), self.index).get()
53    }
54}
55
56impl<K: ToBytes, V: FromBytes + CLTyped + Default> Mapping<K, V> {
57    /// Retrieves the value associated with the given key from the mapping.
58    /// If the key does not exist, returns the default value of type `V`.
59    pub fn get_or_default(&self, key: &K) -> V {
60        let env = self.env_for_key(key);
61        Var::<V>::instance(Rc::new(env), self.index).get_or_default()
62    }
63}
64
65impl<K: ToBytes, V: ToBytes + CLTyped> Mapping<K, V> {
66    /// Sets the value associated with the given key in the mapping.
67    pub fn set(&mut self, key: &K, value: V) {
68        let env = self.env_for_key(key);
69        Var::<V>::instance(Rc::new(env), self.index).set(value)
70    }
71}
72
73impl<K: ToBytes, V: Module> Mapping<K, V> {
74    /// Retrieves the module associated with the given key.
75    ///
76    /// A [`SubModule`] instance containing the module associated with the key.
77    pub fn module(&self, key: &K) -> SubModule<V> {
78        let env = self.env_for_key(key);
79        SubModule::instance(Rc::new(env), self.index)
80    }
81}
82
83impl<K: ToBytes, V: ToBytes + FromBytes + CLTyped + OverflowingAdd + Default> Mapping<K, V> {
84    /// Utility function that gets the current value and adds the passed `value`
85    /// and sets the new value to the storage.
86    ///
87    /// If the operation fails due to overflow, the currently executing contract reverts.
88    pub fn add(&mut self, key: &K, value: V) {
89        let env = self.env_for_key(key);
90        let mut var = Var::<V>::instance(Rc::new(env), self.index);
91        var.add(value);
92    }
93}
94
95impl<
96        K: ToBytes,
97        V: ToBytes + FromBytes + CLTyped + OverflowingSub + Default + Debug + PartialOrd
98    > Mapping<K, V>
99{
100    /// Utility function that gets the current value and subtracts the passed `value`
101    /// and sets the new value to the storage.
102    ///
103    /// If the operation fails due to overflow, the currently executing contract reverts.
104    pub fn subtract(&mut self, key: &K, value: V) {
105        let env = self.env_for_key(key);
106        let mut var = Var::<V>::instance(Rc::new(env), self.index);
107        var.subtract(value);
108    }
109}