odra_core/
var.rs

1use crate::casper_types::{
2    bytesrepr::{FromBytes, ToBytes},
3    CLTyped
4};
5use crate::contract_env::ContractEnv;
6use crate::module::{ModuleComponent, ModulePrimitive};
7use crate::prelude::*;
8
9/// Data structure for storing a single value.
10pub struct Var<T> {
11    env: Rc<ContractEnv>,
12    phantom: core::marker::PhantomData<T>,
13    index: u8
14}
15
16impl<T> Revertible for Var<T> {
17    fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
18        self.env.revert(e)
19    }
20}
21
22impl<T> Var<T> {
23    /// Returns the contract environment associated with the variable.
24    pub fn env(&self) -> ContractEnv {
25        self.env.child(self.index)
26    }
27}
28
29/// Implements the `ModuleComponent` trait for the `Var` struct.
30impl<T> ModuleComponent for Var<T> {
31    /// Creates a new instance of `Var` with the given environment and index.
32    fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
33        Self {
34            env,
35            phantom: core::marker::PhantomData,
36            index
37        }
38    }
39}
40
41impl<T> ModulePrimitive for Var<T> {}
42
43impl<T: FromBytes> Var<T> {
44    /// Retrieves the value of the variable.
45    ///
46    /// Returns `Some(value)` if the variable has a value, or `None` if it is unset.
47    pub fn get(&self) -> Option<T> {
48        let env = self.env();
49        env.get_value(&env.current_key())
50    }
51
52    /// Retrieves the value of the variable or reverts with an error.
53    ///
54    /// If the variable has a value, it is returned. Otherwise, the provided error is reverted.
55    pub fn get_or_revert_with<E: Into<OdraError>>(&self, error: E) -> T {
56        self.get().unwrap_or_revert_with(self, error)
57    }
58}
59
60impl<T: FromBytes + Default> Var<T> {
61    /// Returns the value of the variable, or the default value of the type if the variable is None.
62    pub fn get_or_default(&self) -> T {
63        self.get().unwrap_or_default()
64    }
65}
66
67impl<T: ToBytes + CLTyped> Var<T> {
68    /// Sets the value of the variable.
69    pub fn set(&mut self, value: T) {
70        let env = self.env();
71        env.set_value(&env.current_key(), value);
72    }
73}
74
75impl<V: ToBytes + FromBytes + CLTyped + OverflowingAdd + Default> Var<V> {
76    /// Utility function that gets the current value and adds the passed `value`
77    /// and sets the new value to the storage.
78    ///
79    /// If the operation fails due to overflow, the currently executing contract reverts.
80    #[inline(always)]
81    pub fn add(&mut self, value: V) {
82        let env = self.env();
83        let key = env.current_key();
84        let current_value = env.get_value::<V>(&key).unwrap_or_default();
85        let new_value = current_value.overflowing_add(value).unwrap_or_revert(self);
86        env.set_value(&key, new_value);
87    }
88}
89
90impl<V: ToBytes + FromBytes + CLTyped + OverflowingSub + Default> Var<V> {
91    /// Utility function that gets the current value and subtracts the passed `value`
92    /// and sets the new value to the storage.
93    ///
94    /// If the operation fails due to overflow, the currently executing contract reverts.
95    #[inline(always)]
96    pub fn subtract(&mut self, value: V) {
97        let env = self.env();
98        let key = env.current_key();
99        let current_value = env.get_value::<V>(&key).unwrap_or_default();
100        let new_value = current_value.overflowing_sub(value).unwrap_or_revert(self);
101        env.set_value(&key, new_value);
102    }
103}