use qubit_budget::MeasuredBudgetError;
use qubit_budget::ResourceBudget;
use qubit_budget::ResourceQuantity;
use crate::decode::JsonSyntaxError;
use crate::encode::JsonSerializationError;
use crate::encode::JsonSerializationErrorKind;
pub(in crate::encode) struct JsonOutputAccounting<'a, R, Q>
where
Q: ResourceQuantity,
{
output: Option<&'a mut ResourceBudget<R, Q>>,
violation: Option<MeasuredBudgetError<R, Q>>,
syntax_error: Option<JsonSyntaxError>,
serialization_error: Option<JsonSerializationError>,
}
impl<'a, R, Q> JsonOutputAccounting<'a, R, Q>
where
Q: ResourceQuantity,
{
#[inline]
pub(in crate::encode) const fn new(output: Option<&'a mut ResourceBudget<R, Q>>) -> Self {
Self {
output,
violation: None,
syntax_error: None,
serialization_error: None,
}
}
#[must_use]
#[inline(always)]
pub(in crate::encode) const fn has_output_budget(&self) -> bool {
self.output.is_some()
}
#[must_use]
#[inline(always)]
pub(in crate::encode) fn remaining(&self) -> Option<Q> {
self.output.as_deref().map(ResourceBudget::remaining)
}
pub(in crate::encode) fn check_available(
&self,
amount: usize,
) -> Result<(), MeasuredBudgetError<R, Q>>
where
R: Clone,
{
self.output.as_deref().map_or(Ok(()), |output| {
let amount = Q::try_from_usize(amount).map_err(|source| {
MeasuredBudgetError::quantity(output.resource().clone(), source)
})?;
output
.check_available(amount)
.map_err(MeasuredBudgetError::from)
})
}
pub(in crate::encode) fn consume(
&mut self,
amount: usize,
) -> Result<(), MeasuredBudgetError<R, Q>>
where
R: Clone,
{
self.output.as_deref_mut().map_or(Ok(()), |output| {
let amount = Q::try_from_usize(amount).map_err(|source| {
MeasuredBudgetError::quantity(output.resource().clone(), source)
})?;
output
.try_consume(amount)
.map_err(MeasuredBudgetError::from)
})
}
pub(in crate::encode) fn record_violation(&mut self, error: MeasuredBudgetError<R, Q>) {
if self.violation.is_none() {
self.violation = Some(error);
}
}
#[must_use]
#[inline(always)]
pub(in crate::encode) fn take_violation(&mut self) -> Option<MeasuredBudgetError<R, Q>> {
self.violation.take()
}
pub(in crate::encode) fn record_syntax_error(&mut self, error: JsonSyntaxError) {
if self.syntax_error.is_none() {
self.syntax_error = Some(error);
}
}
#[must_use]
#[inline(always)]
pub(in crate::encode) fn take_syntax_error(&mut self) -> Option<JsonSyntaxError> {
self.syntax_error.take()
}
pub(in crate::encode) fn record_serialization_error(&mut self, error: JsonSerializationError) {
if self.serialization_error.is_none() {
self.serialization_error = Some(error);
}
}
#[inline]
pub(in crate::encode) fn record_custom_serialization_error(&mut self) {
self.record_serialization_error(JsonSerializationError::new(
JsonSerializationErrorKind::CustomSerialization,
));
}
#[must_use]
#[inline(always)]
pub(in crate::encode) fn take_serialization_error(&mut self) -> Option<JsonSerializationError> {
self.serialization_error.take()
}
pub(in crate::encode) fn take_serialization_error_or_custom(
&mut self,
) -> JsonSerializationError {
self.take_serialization_error().unwrap_or_else(|| {
JsonSerializationError::new(JsonSerializationErrorKind::CustomSerialization)
})
}
}