use std::fmt::Debug;
use thiserror::Error;
use super::InsufficientBudgetError;
use super::LimitExceededError;
use crate::resource::Observation;
#[must_use]
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum BudgetError<R, Q = u64>
where
Q: Copy + Debug,
{
#[error("resource {resource:?} measured {observed}, exceeding the maximum of {maximum:?}")]
LimitExceeded {
resource: R,
observed: Observation<Q>,
maximum: Q,
},
#[error("resource {resource:?} requested {requested:?}, but only {remaining:?} of {limit:?} remains")]
Insufficient {
resource: R,
limit: Q,
remaining: Q,
requested: Q,
},
}
impl<R, Q> BudgetError<R, Q>
where
Q: Copy + Debug,
{
#[must_use]
#[inline(always)]
pub const fn resource(&self) -> &R {
match self {
Self::LimitExceeded { resource, .. } | Self::Insufficient { resource, .. } => resource,
}
}
#[inline(always)]
#[must_use]
pub fn into_resource(self) -> R {
match self {
Self::LimitExceeded { resource, .. } | Self::Insufficient { resource, .. } => resource,
}
}
#[must_use]
#[inline(always)]
pub const fn limit(&self) -> Option<Q> {
match self {
Self::LimitExceeded { .. } => None,
Self::Insufficient { limit, .. } => Some(*limit),
}
}
#[must_use]
#[inline(always)]
pub const fn observation(&self) -> Option<Observation<Q>> {
match self {
Self::LimitExceeded { observed, .. } => Some(*observed),
Self::Insufficient { .. } => None,
}
}
#[inline(always)]
#[must_use]
pub const fn exact_observed(&self) -> Option<Q> {
match self.observation() {
Some(Observation::Exact(value)) => Some(value),
Some(Observation::AtLeast(_)) | None => None,
}
}
#[inline(always)]
#[must_use]
pub const fn observed_lower_bound(&self) -> Option<Q> {
match self.observation() {
Some(observed) => Some(observed.lower_bound()),
None => None,
}
}
#[inline(always)]
#[must_use]
pub const fn maximum(&self) -> Option<Q> {
match self {
Self::LimitExceeded { maximum, .. } => Some(*maximum),
Self::Insufficient { .. } => None,
}
}
#[inline(always)]
#[must_use]
pub const fn remaining(&self) -> Option<Q> {
match self {
Self::Insufficient { remaining, .. } => Some(*remaining),
Self::LimitExceeded { .. } => None,
}
}
#[inline(always)]
#[must_use]
pub const fn requested(&self) -> Option<Q> {
match self {
Self::LimitExceeded { .. } => None,
Self::Insufficient { requested, .. } => Some(*requested),
}
}
}
impl<R, Q> BudgetError<R, Q>
where
Q: crate::ResourceQuantity,
{
#[must_use]
#[inline]
pub const fn configured_limit(&self) -> Q {
match self {
Self::LimitExceeded { maximum, .. } => *maximum,
Self::Insufficient { limit, .. } => *limit,
}
}
#[must_use]
#[inline]
pub fn used(&self) -> Option<Q> {
match self {
Self::LimitExceeded { .. } => None,
Self::Insufficient { limit, remaining, .. } => Some(*limit - *remaining),
}
}
}
impl<R, Q> From<LimitExceededError<R, Q>> for BudgetError<R, Q>
where
Q: Copy + Debug,
{
#[inline(always)]
fn from(error: LimitExceededError<R, Q>) -> Self {
let LimitExceededError {
resource,
observed,
maximum,
} = error;
Self::LimitExceeded {
resource,
observed,
maximum,
}
}
}
impl<R, Q> From<InsufficientBudgetError<R, Q>> for BudgetError<R, Q>
where
Q: Copy + Debug,
{
#[inline(always)]
fn from(error: InsufficientBudgetError<R, Q>) -> Self {
let InsufficientBudgetError {
resource,
limit,
remaining,
requested,
} = error;
Self::Insufficient {
resource,
limit,
remaining,
requested,
}
}
}