use crate::InvalidRelease;
use crate::LimitExceeded;
use crate::ResourceLimit;
#[must_use]
#[derive(Debug, PartialEq, Eq)]
pub struct ResourceBudget {
limit: ResourceLimit,
remaining: usize,
}
impl ResourceBudget {
#[inline(always)]
pub const fn new(limit: ResourceLimit) -> Self {
Self {
remaining: limit.maximum(),
limit,
}
}
#[inline(always)]
pub const fn limit(&self) -> ResourceLimit {
self.limit
}
#[inline(always)]
pub const fn maximum(&self) -> usize {
self.limit.maximum()
}
#[inline(always)]
pub const fn remaining(&self) -> usize {
self.remaining
}
#[inline(always)]
pub const fn used(&self) -> usize {
self.maximum() - self.remaining
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.remaining == 0
}
#[inline(always)]
pub const fn is_unused(&self) -> bool {
self.remaining == self.maximum()
}
#[inline]
pub fn check_additional<K>(
&self,
kind: K,
amount: usize,
) -> Result<(), LimitExceeded<K>> {
if amount <= self.remaining {
Ok(())
} else {
Err(LimitExceeded::new(
kind,
self.maximum(),
self.used().saturating_add(amount),
))
}
}
#[inline]
pub fn try_consume<K>(
&mut self,
kind: K,
amount: usize,
) -> Result<(), LimitExceeded<K>> {
self.check_additional(kind, amount)?;
self.remaining -= amount;
Ok(())
}
#[inline]
pub fn consume_or_exhaust<K>(
&mut self,
kind: K,
amount: usize,
) -> Result<(), LimitExceeded<K>> {
if amount <= self.remaining {
self.remaining -= amount;
Ok(())
} else {
let error = LimitExceeded::new(
kind,
self.maximum(),
self.used().saturating_add(amount),
);
self.remaining = 0;
Err(error)
}
}
#[inline]
pub fn consume_available(&mut self, amount: usize) -> usize {
let consumed = amount.min(self.remaining);
self.remaining -= consumed;
consumed
}
#[inline]
pub fn release(&mut self, amount: usize) -> Result<(), InvalidRelease> {
let used = self.used();
if amount > used {
Err(InvalidRelease::new(used, amount))
} else {
self.remaining += amount;
Ok(())
}
}
#[inline]
pub fn exhaust(&mut self) -> usize {
let remaining = self.remaining;
self.remaining = 0;
remaining
}
}