use crate::contract_env::ContractEnv;
use crate::module::{ModuleComponent, ModulePrimitive};
use crate::prelude::*;
use crate::{
casper_types::{
bytesrepr::{FromBytes, ToBytes},
CLTyped
},
module::Revertible
};
use crate::{OdraError, UnwrapOrRevert};
pub struct Var<T> {
env: Rc<ContractEnv>,
phantom: core::marker::PhantomData<T>,
index: u8
}
impl<T> Revertible for Var<T> {
fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
self.env.revert(e)
}
}
impl<T> Var<T> {
pub fn env(&self) -> ContractEnv {
self.env.child(self.index)
}
}
impl<T> ModuleComponent for Var<T> {
fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
Self {
env,
phantom: core::marker::PhantomData,
index
}
}
}
impl<T> ModulePrimitive for Var<T> {}
impl<T: FromBytes> Var<T> {
pub fn get(&self) -> Option<T> {
let env = self.env();
env.get_value(&env.current_key())
}
pub fn get_or_revert_with<E: Into<OdraError>>(&self, error: E) -> T {
self.get().unwrap_or_revert_with(self, error)
}
}
impl<T: FromBytes + Default> Var<T> {
pub fn get_or_default(&self) -> T {
self.get().unwrap_or_default()
}
}
impl<T: ToBytes + CLTyped> Var<T> {
pub fn set(&mut self, value: T) {
let env = self.env();
env.set_value(&env.current_key(), value);
}
}
impl<V: ToBytes + FromBytes + CLTyped + OverflowingAdd + Default> Var<V> {
#[inline(always)]
pub fn add(&mut self, value: V) {
let env = self.env();
let key = env.current_key();
let current_value = env.get_value::<V>(&key).unwrap_or_default();
let new_value = current_value.overflowing_add(value).unwrap_or_revert(self);
env.set_value(&key, new_value);
}
}
impl<V: ToBytes + FromBytes + CLTyped + OverflowingSub + Default> Var<V> {
#[inline(always)]
pub fn subtract(&mut self, value: V) {
let env = self.env();
let key = env.current_key();
let current_value = env.get_value::<V>(&key).unwrap_or_default();
let new_value = current_value.overflowing_sub(value).unwrap_or_revert(self);
env.set_value(&key, new_value);
}
}