use std::time::Duration;
use crate::resource::InsufficientBudgetError;
use crate::resource::ResourceLimit;
#[derive(Debug, PartialEq, Eq)]
pub struct DurationBudget<R> {
limit: ResourceLimit<R, Duration>,
remaining: Duration,
}
impl<R> DurationBudget<R> {
#[inline]
#[must_use]
pub const fn new(resource: R, limit: Duration) -> Self {
Self {
limit: ResourceLimit::new(resource, limit),
remaining: limit,
}
}
#[inline]
#[must_use]
pub fn from_limit(limit: ResourceLimit<R, Duration>) -> Self {
let remaining = limit.maximum();
Self { limit, remaining }
}
pub fn check_available(&self, duration: Duration) -> Result<(), InsufficientBudgetError<R, Duration>>
where
R: Clone,
{
if duration <= self.remaining {
Ok(())
} else {
Err(InsufficientBudgetError {
resource: self.limit.resource().clone(),
limit: self.limit.maximum(),
remaining: self.remaining,
requested: duration,
})
}
}
#[inline]
pub fn try_consume(&mut self, duration: Duration) -> Result<(), InsufficientBudgetError<R, Duration>>
where
R: Clone,
{
self.check_available(duration)?;
self.remaining -= duration;
Ok(())
}
#[inline]
#[must_use]
pub fn consume_available(&mut self, requested: Duration) -> Duration {
let consumed = requested.min(self.remaining);
self.remaining -= consumed;
consumed
}
#[must_use]
#[inline(always)]
pub const fn resource(&self) -> &R {
self.limit.resource()
}
#[must_use]
#[inline(always)]
pub const fn resource_limit(&self) -> &ResourceLimit<R, Duration> {
&self.limit
}
#[must_use]
#[inline(always)]
pub const fn limit(&self) -> Duration {
self.limit.maximum()
}
#[must_use]
#[inline(always)]
pub const fn remaining(&self) -> Duration {
self.remaining
}
#[must_use]
#[inline(always)]
pub const fn used(&self) -> Duration {
self.limit.maximum().saturating_sub(self.remaining)
}
}