use super::StructureLimits;
use super::StructureResource;
use crate::resource::BudgetError;
use crate::resource::ResourceBudget;
use crate::resource::ResourceQuantity;
use crate::resource::check_limit;
#[derive(Debug, PartialEq, Eq)]
pub struct StructureBudget<R = StructureResource, Q = usize>
where
Q: ResourceQuantity,
{
limits: StructureLimits<R, Q>,
nodes: Option<ResourceBudget<R, Q>>,
}
impl<R, Q> StructureBudget<R, Q>
where
R: Clone,
Q: ResourceQuantity,
{
#[inline]
#[must_use]
pub(crate) fn new(limits: StructureLimits<R, Q>) -> Self {
Self {
nodes: limits.nodes_limit().cloned().map(ResourceBudget::from_limit),
limits,
}
}
#[inline]
pub fn check_depth(&self, actual: Q) -> Result<(), BudgetError<R, Q>> {
check_limit(self.limits.depth_limit(), actual)
}
#[inline]
pub fn charge_node(&mut self) -> Result<(), BudgetError<R, Q>> {
self.charge_nodes(Q::ONE)
}
#[inline]
pub fn charge_nodes(&mut self, amount: Q) -> Result<(), BudgetError<R, Q>> {
match &mut self.nodes {
Some(nodes) => nodes.try_consume(amount).map_err(BudgetError::from),
None => Ok(()),
}
}
#[inline]
pub fn check_sequence_items(&self, actual: Q) -> Result<(), BudgetError<R, Q>> {
check_limit(self.limits.sequence_items_limit(), actual)
}
#[inline]
pub fn check_map_entries(&self, actual: Q) -> Result<(), BudgetError<R, Q>> {
check_limit(self.limits.map_entries_limit(), actual)
}
#[inline]
pub fn check_key_bytes(&self, actual: Q) -> Result<(), BudgetError<R, Q>> {
check_limit(self.limits.key_bytes_limit(), actual)
}
#[inline]
pub fn enter_node(&mut self, depth: Q) -> Result<(), BudgetError<R, Q>> {
self.check_depth(depth)?;
self.charge_node()
}
#[inline]
pub fn enter_sequence(&mut self, depth: Q, items: Q) -> Result<(), BudgetError<R, Q>> {
self.check_depth(depth)?;
self.check_sequence_items(items)?;
self.charge_node()
}
#[inline]
pub fn enter_map(&mut self, depth: Q, entries: Q) -> Result<(), BudgetError<R, Q>> {
self.check_depth(depth)?;
self.check_map_entries(entries)?;
self.charge_node()
}
#[must_use]
#[inline(always)]
pub const fn limits(&self) -> &StructureLimits<R, Q> {
&self.limits
}
#[inline(always)]
#[must_use]
pub fn used_nodes(&self) -> Q {
match &self.nodes {
Some(nodes) => nodes.used(),
None => Q::ZERO,
}
}
}