use crate::bytes::ReturnOutputByteCount;
use crate::error::RunStepError;
use crate::limits::StepCount;
use crate::program::{ReturnOutput, ReturnOutputView};
use crate::rule::{ParsedRuleAction, Rule};
use super::budget::{RuntimeBudgetState, StepReservation};
use super::matcher::{MatchedRuleApplication, PreparedMatchedRule};
use super::rewrite::{PreparedRewrite, RewriteScratch};
use super::state::State;
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum AppliedRule<'program> {
Rewrite(CommittedRewriteRule<'program>),
Return(CommittedReturnRule<'program>),
}
#[derive(Debug)]
pub(crate) enum PreparedRuleApplication<'program, 'once, 'budget> {
Rewrite(PreparedRewriteRule<'program, 'once, 'budget>),
Return(PreparedReturnRule<'program, 'once, 'budget>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CommittedRewriteRule<'program> {
step: StepCount,
rule: &'program Rule,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct CommittedReturnRule<'program> {
step: StepCount,
rule: &'program Rule,
output_view: ReturnOutputView<'program>,
output: ReturnOutput,
}
#[derive(Debug)]
pub(crate) struct PreparedRewriteRule<'program, 'once, 'budget> {
matched: PreparedMatchedRule<'program, 'once>,
step: StepReservation<'budget>,
rewrite: PreparedRewrite,
}
#[derive(Debug)]
pub(crate) struct PreparedReturnRule<'program, 'once, 'budget> {
matched: PreparedMatchedRule<'program, 'once>,
step: StepReservation<'budget>,
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) -> &'program Rule {
self.rule
}
}
impl CommittedReturnRule<'_> {
pub(crate) const fn step(&self) -> StepCount {
self.step
}
}
impl<'program> CommittedReturnRule<'program> {
pub(crate) const fn rule(&self) -> &'program Rule {
self.rule
}
pub(crate) const fn output_view(&self) -> ReturnOutputView<'program> {
self.output_view
}
pub(crate) fn into_output(self) -> ReturnOutput {
self.output
}
}
impl<'program> PreparedRuleApplication<'program, '_, '_> {
pub(crate) const fn rule(&self) -> &'program Rule {
match self {
Self::Rewrite(prepared) => prepared.matched.rule(),
Self::Return(prepared) => prepared.matched.rule(),
}
}
pub(crate) fn commit(
self,
state: &mut State,
scratch: &mut RewriteScratch,
) -> AppliedRule<'program> {
match self {
Self::Rewrite(prepared) => {
let committed = prepared.matched.commit();
let step = prepared.step.commit();
state.commit_rewrite(prepared.rewrite, scratch);
AppliedRule::Rewrite(CommittedRewriteRule {
step,
rule: committed.rule(),
})
}
Self::Return(prepared) => {
let committed = prepared.matched.commit();
let step = prepared.step.commit();
AppliedRule::Return(CommittedReturnRule {
step,
rule: committed.rule(),
output_view: prepared.output_view,
output: prepared.output,
})
}
}
}
}
pub(crate) fn materialize_return_output(
output: ReturnOutputView<'_>,
) -> Result<ReturnOutput, RunStepError> {
Ok(ReturnOutput::from_return_output_view(output)?)
}
pub(crate) fn prepare_matched_rule<'program, 'once, 'budget>(
scratch: &mut RewriteScratch,
budget: &'budget mut RuntimeBudgetState,
state_len: crate::bytes::RuntimeStateByteCount,
matched: MatchedRuleApplication<'program, '_, 'once>,
) -> Result<PreparedRuleApplication<'program, 'once, 'budget>, RunStepError> {
let (state_match, matched) = matched.into_prepare_parts();
let step = budget.reserve_next_step(state_len)?;
match matched.rule().action() {
ParsedRuleAction::Rewrite(action) => {
let rewrite = state_match.rewrite_into(action, scratch, &step)?;
Ok(PreparedRuleApplication::Rewrite(PreparedRewriteRule {
matched,
step,
rewrite,
}))
}
ParsedRuleAction::Return(output) => {
let output_view = ReturnOutputView::new(output);
let output_len = ReturnOutputByteCount::from_payload_count(output.byte_count());
step.ensure_return_len(output_len)?;
let materialized_output = materialize_return_output(output_view)?;
Ok(PreparedRuleApplication::Return(PreparedReturnRule {
matched,
step,
output_view,
output: materialized_output,
}))
}
}
}