use crate::bytes::ReturnOutputByteCount;
use crate::error::RunError;
use crate::inspect::RuleView;
use crate::limits::StepCount;
use crate::program::{ReturnOutput, ReturnOutputView};
use crate::rule::RuleAction;
use super::budget::RuntimeBudgetState;
use super::matcher::MatchedRuleApplication;
use super::rewrite::RewriteScratch;
use super::state::State;
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum AppliedRule<'program> {
Rewrite(CommittedRewriteRule<'program>),
Return(CommittedReturnRule<'program>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CommittedRewriteRule<'program> {
step: StepCount,
rule: RuleView<'program>,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct CommittedReturnRule<'program> {
step: StepCount,
rule: RuleView<'program>,
output_view: ReturnOutputView<'program>,
output: ReturnOutput,
}
impl CommittedRewriteRule<'_> {
pub(crate) const fn step(self) -> StepCount {
self.step
}
}
impl<'program> CommittedRewriteRule<'program> {
pub(crate) const fn rule(self) -> RuleView<'program> {
self.rule
}
}
impl CommittedReturnRule<'_> {
pub(crate) const fn step(&self) -> StepCount {
self.step
}
}
impl<'program> CommittedReturnRule<'program> {
pub(crate) const fn rule(&self) -> RuleView<'program> {
self.rule
}
pub(crate) const fn output_view(&self) -> ReturnOutputView<'program> {
self.output_view
}
pub(crate) fn into_output(self) -> ReturnOutput {
self.output
}
}
pub(crate) fn materialize_return_output(
output: ReturnOutputView<'_>,
) -> Result<ReturnOutput, RunError> {
Ok(output.materialize()?)
}
pub(crate) fn apply_matched_rule<'program>(
state: &mut State,
scratch: &mut RewriteScratch,
budget: &mut RuntimeBudgetState,
matched: MatchedRuleApplication<'program, '_>,
) -> Result<AppliedRule<'program>, RunError> {
let permit = budget.reserve_next_step(state.byte_count())?;
match matched.rule().action() {
RuleAction::Rewrite(action) => {
let rewrite = state.rewrite_into(matched.state_match(), action, scratch, *budget)?;
let committed = matched.commit();
let step = budget.commit(permit);
state.commit_rewrite(rewrite, scratch);
Ok(AppliedRule::Rewrite(CommittedRewriteRule {
step,
rule: committed.rule(),
}))
}
RuleAction::Return(output) => {
let output_view = ReturnOutputView::new(output);
let output_len = ReturnOutputByteCount::from_payload_count(output.byte_count());
(*budget).ensure_return_len(output_len)?;
let materialized_output = materialize_return_output(output_view)?;
let committed = matched.commit();
let step = budget.commit(permit);
Ok(AppliedRule::Return(CommittedReturnRule {
step,
rule: committed.rule(),
output_view,
output: materialized_output,
}))
}
}
}