use super::keypath::{Keypath, LeafKey};
use crate::exn::LibraryExn;
use crate::re_throw::OrReThrow;
use crate::sys_exn::nnint_internal as nnint;
#[derive(Debug)]
pub struct Balance {
key: LeafKey,
}
impl From<Keypath> for Balance {
fn from(keypath: Keypath) -> Self {
Self {
key: LeafKey::from(keypath),
}
}
}
impl Balance {
pub const MAX: i128 = i128::MAX;
pub fn get(&self) -> i128 {
self.try_get().or_re_throw()
}
pub fn try_get(&self) -> Result<i128, LibraryExn> {
match nnint::try_get_values_force(self.key.get()) {
Ok((set, add)) => {
let value = set
.checked_add(add)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
if value < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
Ok(value)
}
Err(e) if e.is_storage_missing() => Ok(0),
Err(e) => Err(e),
}
}
pub fn increase(&mut self, amount: i128) {
self.try_increase(amount).or_re_throw()
}
pub fn try_increase(&mut self, amount: i128) -> Result<(), LibraryExn> {
if amount == 0 {
return Ok(());
}
if amount < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
let key = self.key.get();
let (set, add) = match nnint::try_get_values_force(key) {
Ok(values) => values,
Err(e) if e.is_storage_missing() => (0, 0),
Err(e) => return Err(e),
};
let add = add
.checked_add(amount)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
let total = set
.checked_add(add)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
if total < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
nnint::try_set_add(key, Some(set), add, self.key.is_exclusive())
}
pub fn decrease(&mut self, amount: i128) {
self.try_decrease(amount).or_re_throw()
}
pub fn try_decrease(&mut self, amount: i128) -> Result<(), LibraryExn> {
if amount == 0 {
return Ok(());
}
if amount < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
let key = self.key.get();
let (set, add) = match nnint::try_get_values_force(key) {
Ok(values) => values,
Err(e) if e.is_storage_missing() => (0, 0),
Err(e) => return Err(e),
};
let add = add
.checked_sub(amount)
.ok_or(LibraryExn::NonNegativeIntUnderflow)?;
let total = set
.checked_add(add)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
if total < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
nnint::try_set_add(key, Some(set), add, self.key.is_exclusive())
}
pub fn lazy_increase(&mut self, amount: i128) {
self.try_lazy_increase(amount).or_re_throw()
}
pub fn try_lazy_increase(
&mut self,
amount: i128,
) -> Result<(), LibraryExn> {
if amount == 0 {
return Ok(());
}
if amount < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
let key = self.key.get();
let (set, add) = nnint::try_get_values(key)?;
let add = add
.checked_add(amount)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
nnint::try_set_add(key, set, add, self.key.is_exclusive())
}
pub fn lazy_decrease(&mut self, amount: i128) {
self.try_lazy_decrease(amount).or_re_throw()
}
pub fn try_lazy_decrease(
&mut self,
amount: i128,
) -> Result<(), LibraryExn> {
if amount == 0 {
return Ok(());
}
if amount < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
let key = self.key.get();
let (set, add) = nnint::try_get_values(key)?;
let add = add
.checked_sub(amount)
.ok_or(LibraryExn::NonNegativeIntUnderflow)?;
if let Some(set) = set {
let total = set
.checked_add(add)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
if total < 0 {
return Err(LibraryExn::NonNegativeIntUnderflow);
}
}
nnint::try_set_add(key, set, add, self.key.is_exclusive())
}
}
impl super::sealed::Sealed for Balance {}
impl super::node::StorageType for Balance {}
impl super::flags::Flaggable for Balance {
fn storage_key(&self) -> &crate::types::StorageKey {
self.key.get()
}
}
impl super::deletable::Deletable for Balance {
fn delete_internal(&mut self, exclusive: bool) {
let exclusive = exclusive || self.key.is_exclusive();
crate::sys_exn::delete::delete(self.key.get(), exclusive);
}
}