use crate::{
format::Id32,
preparation::{InputBinding, ValidatedInput},
};
use core::fmt;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum UnitError {
WrongInput,
Exhausted,
}
impl fmt::Display for UnitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::WrongInput => "execution-unit grant belongs to another prepared packet",
Self::Exhausted => "activation or remaining Episode unit capacity exhausted",
})
}
}
impl core::error::Error for UnitError {}
#[derive(Debug, Eq, PartialEq)]
pub struct UnitBudget {
binding: InputBinding,
admission_id: Id32,
activation: u64,
episode: u64,
reserved: u64,
}
impl UnitBudget {
pub fn from_input(input: &ValidatedInput<'_>) -> Self {
let grant = input.input().budget_admission();
Self {
binding: input.binding(),
admission_id: grant.admission_id,
activation: grant.activation_units,
episode: grant.remaining_episode_units,
reserved: 0,
}
}
pub fn binding(&self) -> InputBinding {
self.binding
}
pub fn admission_id(&self) -> Id32 {
self.admission_id
}
pub fn reserved_units(&self) -> u64 {
self.reserved
}
pub fn remaining_activation_units(&self) -> u64 {
self.activation - self.reserved
}
pub fn remaining_episode_units(&self) -> u64 {
self.episode - self.reserved
}
pub(crate) fn check(&self, binding: InputBinding, quote: u64) -> Result<(), UnitError> {
if self.binding != binding {
return Err(UnitError::WrongInput);
}
let available = self
.remaining_activation_units()
.min(self.remaining_episode_units());
if available == 0 || quote > available {
return Err(UnitError::Exhausted);
}
Ok(())
}
pub(crate) fn commit(&mut self, quote: u64) {
self.reserved = self
.reserved
.checked_add(quote)
.expect("prechecked unit reservation fits u64 capacities");
}
}