use super::keypath::{Keypath, LeafKey};
use crate::exn::LibraryExn;
use crate::re_throw::OrReThrow;
use crate::sys_exn::nnint_internal as nnint;
pub struct CapacityConstraint {
key: LeafKey,
capacity: Option<i128>,
delta: i128,
_live: crate::storage::live_guards::LiveGuard,
}
impl From<Keypath> for CapacityConstraint {
fn from(keypath: Keypath) -> Self {
Self {
key: LeafKey::from(keypath),
capacity: None,
delta: 0,
_live: crate::storage::live_guards::LiveGuard::new(),
}
}
}
impl CapacityConstraint {
pub fn try_get_remaining_capacity(
&self,
) -> Result<i128, crate::exn::LibraryExn> {
let (s, a) = match nnint::try_get_values_force(self.key.get()) {
Ok(values) => values,
Err(e) if e.is_storage_missing() => (0, 0),
Err(e) => return Err(e),
};
self.capacity
.unwrap_or(s)
.checked_add(a)
.and_then(|r| r.checked_add(self.delta))
.ok_or(LibraryExn::NonNegativeIntOverflow)
}
pub fn get_remaining_capacity(&self) -> i128 {
self.try_get_remaining_capacity().or_re_throw()
}
pub fn consume_capacity(&mut self, amount: i128) {
self.try_consume_capacity(amount).or_re_throw();
}
pub fn try_consume_capacity(
&mut self,
amount: i128,
) -> Result<(), crate::exn::LibraryExn> {
self.delta = self.delta.checked_sub(amount).ok_or(if amount > 0 {
LibraryExn::NonNegativeIntUnderflow
} else {
LibraryExn::NonNegativeIntOverflow
})?;
Ok(())
}
pub fn set_capacity(&mut self, capacity: i128) {
self.try_set_capacity(capacity).or_re_throw();
}
pub fn try_set_capacity(
&mut self,
capacity: i128,
) -> Result<(), crate::exn::LibraryExn> {
if let Some(staged) = self.capacity {
return if staged == capacity {
Ok(())
} else {
Err(LibraryExn::CapacityConstraintAlreadyWritten)
};
}
let (s, a) = nnint::try_get_values(self.key.get())?;
if let Some(pending) = s {
return if pending == capacity {
Ok(())
} else {
Err(LibraryExn::CapacityConstraintAlreadyWritten)
};
}
if self.delta != 0 || a != 0 {
return Err(LibraryExn::CapacityConstraintAlreadyWritten);
}
self.capacity = Some(capacity);
Ok(())
}
pub fn flush(&mut self) {
self.try_flush().or_re_throw()
}
pub fn try_flush(&mut self) -> Result<(), crate::exn::LibraryExn> {
if self.capacity.is_none() && self.delta == 0 {
return Ok(());
}
let key = self.key.get();
let (s, a) = nnint::try_get_values(key)?;
let add_value = a
.checked_add(self.delta)
.ok_or(LibraryExn::NonNegativeIntOverflow)?;
nnint::try_set_add(
key,
self.capacity.or(s),
add_value,
self.key.is_exclusive(),
)?;
self.capacity = None;
self.delta = 0;
Ok(())
}
}
impl Drop for CapacityConstraint {
fn drop(&mut self) {
self.try_flush().or_re_throw();
}
}
impl super::sealed::Sealed for CapacityConstraint {}
impl super::node::StorageType for CapacityConstraint {}
impl super::deletable::Deletable for CapacityConstraint {
fn delete_internal(&mut self, exclusive: bool) {
self.capacity = None;
self.delta = 0;
let exclusive = exclusive || self.key.is_exclusive();
crate::sys_exn::delete::delete(self.key.get(), exclusive);
}
}