use crate::error::{RunError, RunFinishError, RunStartError, TracedRunError};
use crate::input::RunSeed;
use crate::limits::{RuleAttemptCount, StepCount};
use crate::program::{Program, ReturnOutput, RunResult};
use crate::trace::{BorrowedTraceEvent, RuntimeStateView};
use super::admission::RuleAttemptSeed;
use super::attempt::{RuleAttemptStableReason, RuleMiss};
use super::engine::{
AttemptSession, BorrowedProgram, CoreAppliedRule, CoreRuleAttempt, CoreStep, OwnedProgram,
RunCore, Session,
};
use super::transition::{
BorrowedAppliedStep, BorrowedFailedRun, BorrowedMissedRuleAttempt, BorrowedReturnedRun,
BorrowedRuleAttemptAppliedStep, BorrowedRuleAttemptFailedRun, BorrowedRuleAttemptReturnedRun,
BorrowedRuleAttemptStableRun, BorrowedRuleAttemptTransition, BorrowedStableRun,
BorrowedStepTransition, OwnedAppliedStep, OwnedFailedRun, OwnedMissedRuleAttempt,
OwnedReturnedRun, OwnedRuleAttemptAppliedStep, OwnedRuleAttemptFailedRun,
OwnedRuleAttemptReturnedRun, OwnedRuleAttemptStableRun, OwnedRuleAttemptTransition,
OwnedStableRun, OwnedStepTransition,
};
pub struct BorrowedRunSession<'program> {
pub(super) session: Session<BorrowedProgram<'program>>,
}
pub struct OwnedRunSession {
pub(super) session: Session<OwnedProgram>,
}
pub struct BorrowedRuleAttemptSession<'program> {
pub(super) session: AttemptSession<BorrowedProgram<'program>>,
}
pub struct OwnedRuleAttemptSession {
pub(super) session: AttemptSession<OwnedProgram>,
}
struct BorrowedRunTerminal<'program> {
program: &'program Program,
core: RunCore,
}
struct OwnedRunTerminal {
program: Program,
core: RunCore,
}
struct BorrowedRuleAttemptTerminal<'program> {
program: &'program Program,
core: RunCore,
attempts: RuleAttemptCount,
}
struct OwnedRuleAttemptTerminal {
program: Program,
core: RunCore,
attempts: RuleAttemptCount,
}
enum RunStepParts<Continuation, Terminal, RuleWitness, StepError> {
Applied {
step: StepCount,
rule: RuleWitness,
continuation: Continuation,
},
Returned {
step: StepCount,
rule: RuleWitness,
terminal: Terminal,
output: ReturnOutput,
},
Stable {
steps: StepCount,
terminal: Terminal,
},
Failed {
error: StepError,
terminal: Terminal,
},
}
enum RuleAttemptStepParts<Continuation, Terminal, RuleWitness, StepError> {
Missed {
attempt: RuleAttemptCount,
miss: RuleMiss<RuleWitness>,
continuation: Continuation,
},
Applied {
attempt: RuleAttemptCount,
step: StepCount,
rule: RuleWitness,
continuation: Continuation,
},
Returned {
attempt: RuleAttemptCount,
step: StepCount,
rule: RuleWitness,
terminal: Terminal,
output: ReturnOutput,
},
Stable {
attempts: RuleAttemptCount,
steps: StepCount,
stable_reason: RuleAttemptStableReason<RuleWitness>,
terminal: Terminal,
},
Failed {
error: StepError,
terminal: Terminal,
},
}
pub(crate) fn finish_borrowed_run(program: &Program, seed: RunSeed) -> Result<RunResult, RunError> {
Session::new(BorrowedProgram { program }, seed)
.map_err(RunError::from)?
.finish()
.map_err(RunError::from)
}
pub(crate) fn run_with_borrowed_trace<'program, F, E>(
program: &'program Program,
seed: RunSeed,
trace: F,
) -> Result<RunResult, TracedRunError<E>>
where
F: for<'run> FnMut(BorrowedTraceEvent<'program, 'run>) -> Result<(), E>,
{
Session::new(BorrowedProgram { program }, seed)
.map_err(RunError::from)
.map_err(TracedRunError::Run)?
.run_with_borrowed_trace(trace)
}
impl<'program> BorrowedRunSession<'program> {
pub(crate) fn new(program: &'program Program, seed: RunSeed) -> Result<Self, RunStartError> {
Ok(Self {
session: Session::new(BorrowedProgram { program }, seed)?,
})
}
#[must_use]
pub const fn completed_steps(&self) -> StepCount {
self.session.completed_steps()
}
#[must_use]
pub fn program(&self) -> &'program Program {
self.session.program.program
}
#[must_use]
pub fn state(&self) -> RuntimeStateView<'_> {
self.session.state()
}
#[must_use]
pub fn step(self) -> BorrowedStepTransition<'program> {
step_borrowed_run(self)
}
pub fn finish(self) -> Result<RunResult, RunFinishError> {
self.session.finish()
}
}
impl<'program> BorrowedRuleAttemptSession<'program> {
pub(crate) fn new(
program: &'program Program,
seed: RuleAttemptSeed,
) -> Result<Self, RunStartError> {
let (seed, limit) = seed.into_parts();
Ok(Self {
session: AttemptSession::new(BorrowedProgram { program }, seed, limit)?,
})
}
#[must_use]
pub const fn completed_steps(&self) -> StepCount {
self.session.completed_steps()
}
#[must_use]
pub const fn completed_attempts(&self) -> RuleAttemptCount {
self.session.completed_attempts()
}
#[must_use]
pub fn program(&self) -> &'program Program {
self.session.program.program
}
#[must_use]
pub fn state(&self) -> RuntimeStateView<'_> {
self.session.state()
}
#[must_use]
pub fn step(self) -> BorrowedRuleAttemptTransition<'program> {
step_borrowed_rule_attempt_run(self)
}
}
impl OwnedRunSession {
pub(crate) fn new(program: Program, seed: RunSeed) -> Result<Self, RunStartError> {
Ok(Self {
session: Session::new(OwnedProgram { program }, seed)?,
})
}
#[must_use]
pub const fn completed_steps(&self) -> StepCount {
self.session.completed_steps()
}
#[must_use]
pub fn program(&self) -> &Program {
self.session.program()
}
#[must_use]
pub fn into_program(self) -> Program {
let (program, _core) = self.session.into_program_core();
program
}
#[must_use]
pub fn state(&self) -> RuntimeStateView<'_> {
self.session.state()
}
#[must_use]
pub fn step(self) -> OwnedStepTransition {
step_owned_run(self)
}
pub fn finish(self) -> Result<RunResult, RunFinishError> {
self.session.finish()
}
}
impl OwnedRuleAttemptSession {
pub(crate) fn new(program: Program, seed: RuleAttemptSeed) -> Result<Self, RunStartError> {
let (seed, limit) = seed.into_parts();
Ok(Self {
session: AttemptSession::new(OwnedProgram { program }, seed, limit)?,
})
}
#[must_use]
pub const fn completed_steps(&self) -> StepCount {
self.session.completed_steps()
}
#[must_use]
pub const fn completed_attempts(&self) -> RuleAttemptCount {
self.session.completed_attempts()
}
#[must_use]
pub fn program(&self) -> &Program {
self.session.program()
}
#[must_use]
pub fn into_program(self) -> Program {
let (program, _core) = self.session.into_program_core();
program
}
#[must_use]
pub fn state(&self) -> RuntimeStateView<'_> {
self.session.state()
}
#[must_use]
pub fn step(self) -> OwnedRuleAttemptTransition {
step_owned_rule_attempt_run(self)
}
}
impl<'program> BorrowedRunTerminal<'program> {
fn from_session(session: BorrowedRunSession<'program>) -> Self {
let Session { program, core } = session.session;
Self {
program: program.program,
core,
}
}
}
impl OwnedRunTerminal {
fn from_session(session: OwnedRunSession) -> Self {
let (program, core) = session.session.into_program_core();
Self { program, core }
}
}
impl<'program> BorrowedRuleAttemptTerminal<'program> {
fn from_session(session: BorrowedRuleAttemptSession<'program>) -> Self {
let AttemptSession {
program,
core,
cursor: _,
attempt_budget,
} = session.session;
Self {
program: program.program,
core,
attempts: attempt_budget.completed_attempts(),
}
}
}
impl OwnedRuleAttemptTerminal {
fn from_session(session: OwnedRuleAttemptSession) -> Self {
let AttemptSession {
program,
core,
cursor: _,
attempt_budget,
} = session.session;
Self {
program: program.program,
core,
attempts: attempt_budget.completed_attempts(),
}
}
}
fn borrowed_run_step_parts<'program>(
mut session: BorrowedRunSession<'program>,
) -> RunStepParts<
BorrowedRunSession<'program>,
BorrowedRunTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RunStepError,
> {
match session.session.step_borrowed() {
Ok(CoreStep::Applied(CoreAppliedRule::Rewrite { step, rule })) => RunStepParts::Applied {
step,
rule,
continuation: session,
},
Ok(CoreStep::Applied(CoreAppliedRule::Return { step, rule, output })) => {
RunStepParts::Returned {
step,
rule,
terminal: BorrowedRunTerminal::from_session(session),
output,
}
}
Ok(CoreStep::Stable(steps)) => RunStepParts::Stable {
steps,
terminal: BorrowedRunTerminal::from_session(session),
},
Err(error) => RunStepParts::Failed {
error,
terminal: BorrowedRunTerminal::from_session(session),
},
}
}
fn owned_run_step_parts(
mut session: OwnedRunSession,
) -> RunStepParts<
OwnedRunSession,
OwnedRunTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRunStepError,
> {
match session.session.step_owned() {
Ok(CoreStep::Applied(CoreAppliedRule::Rewrite { step, rule })) => RunStepParts::Applied {
step,
rule,
continuation: session,
},
Ok(CoreStep::Applied(CoreAppliedRule::Return { step, rule, output })) => {
RunStepParts::Returned {
step,
rule,
terminal: OwnedRunTerminal::from_session(session),
output,
}
}
Ok(CoreStep::Stable(steps)) => RunStepParts::Stable {
steps,
terminal: OwnedRunTerminal::from_session(session),
},
Err(error) => RunStepParts::Failed {
error,
terminal: OwnedRunTerminal::from_session(session),
},
}
}
fn borrowed_rule_attempt_step_parts<'program>(
mut session: BorrowedRuleAttemptSession<'program>,
) -> RuleAttemptStepParts<
BorrowedRuleAttemptSession<'program>,
BorrowedRuleAttemptTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RuleAttemptStepError,
> {
match session.session.step_borrowed() {
Ok(CoreRuleAttempt::Missed { attempt, miss }) => RuleAttemptStepParts::Missed {
attempt,
miss,
continuation: session,
},
Ok(CoreRuleAttempt::Applied {
attempt,
applied: CoreAppliedRule::Rewrite { step, rule },
}) => RuleAttemptStepParts::Applied {
attempt,
step,
rule,
continuation: session,
},
Ok(CoreRuleAttempt::Applied {
attempt,
applied: CoreAppliedRule::Return { step, rule, output },
}) => RuleAttemptStepParts::Returned {
attempt,
step,
rule,
terminal: BorrowedRuleAttemptTerminal::from_session(session),
output,
},
Ok(CoreRuleAttempt::Stable {
attempts,
steps,
stable_reason,
}) => RuleAttemptStepParts::Stable {
attempts,
steps,
stable_reason,
terminal: BorrowedRuleAttemptTerminal::from_session(session),
},
Err(error) => RuleAttemptStepParts::Failed {
error,
terminal: BorrowedRuleAttemptTerminal::from_session(session),
},
}
}
fn owned_rule_attempt_step_parts(
mut session: OwnedRuleAttemptSession,
) -> RuleAttemptStepParts<
OwnedRuleAttemptSession,
OwnedRuleAttemptTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRuleAttemptStepError,
> {
match session.session.step_owned() {
Ok(CoreRuleAttempt::Missed { attempt, miss }) => RuleAttemptStepParts::Missed {
attempt,
miss,
continuation: session,
},
Ok(CoreRuleAttempt::Applied {
attempt,
applied: CoreAppliedRule::Rewrite { step, rule },
}) => RuleAttemptStepParts::Applied {
attempt,
step,
rule,
continuation: session,
},
Ok(CoreRuleAttempt::Applied {
attempt,
applied: CoreAppliedRule::Return { step, rule, output },
}) => RuleAttemptStepParts::Returned {
attempt,
step,
rule,
terminal: OwnedRuleAttemptTerminal::from_session(session),
output,
},
Ok(CoreRuleAttempt::Stable {
attempts,
steps,
stable_reason,
}) => RuleAttemptStepParts::Stable {
attempts,
steps,
stable_reason,
terminal: OwnedRuleAttemptTerminal::from_session(session),
},
Err(error) => RuleAttemptStepParts::Failed {
error,
terminal: OwnedRuleAttemptTerminal::from_session(session),
},
}
}
impl<'program>
From<
RunStepParts<
BorrowedRunSession<'program>,
BorrowedRunTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RunStepError,
>,
> for BorrowedStepTransition<'program>
{
fn from(
parts: RunStepParts<
BorrowedRunSession<'program>,
BorrowedRunTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RunStepError,
>,
) -> Self {
match parts {
RunStepParts::Applied {
step,
rule,
continuation,
} => Self::Applied(BorrowedAppliedStep {
step,
rule,
session: continuation,
}),
RunStepParts::Returned {
step,
rule,
terminal,
output,
} => Self::Returned(BorrowedReturnedRun {
step,
rule,
program: terminal.program,
output,
}),
RunStepParts::Stable { steps, terminal } => Self::Stable(BorrowedStableRun {
steps,
program: terminal.program,
core: terminal.core,
}),
RunStepParts::Failed { error, terminal } => Self::Failed(BorrowedFailedRun::new(
error,
terminal.program,
terminal.core,
)),
}
}
}
impl
From<
RunStepParts<
OwnedRunSession,
OwnedRunTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRunStepError,
>,
> for OwnedStepTransition
{
fn from(
parts: RunStepParts<
OwnedRunSession,
OwnedRunTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRunStepError,
>,
) -> Self {
match parts {
RunStepParts::Applied {
step,
rule,
continuation,
} => Self::Applied(OwnedAppliedStep {
step,
rule,
session: continuation,
}),
RunStepParts::Returned {
step,
rule,
terminal,
output,
} => Self::Returned(OwnedReturnedRun {
step,
rule,
program: terminal.program,
output,
}),
RunStepParts::Stable { steps, terminal } => Self::Stable(OwnedStableRun {
steps,
program: terminal.program,
core: terminal.core,
}),
RunStepParts::Failed { error, terminal } => {
Self::Failed(OwnedFailedRun::new(error, terminal.program, terminal.core))
}
}
}
}
impl<'program>
From<
RuleAttemptStepParts<
BorrowedRuleAttemptSession<'program>,
BorrowedRuleAttemptTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RuleAttemptStepError,
>,
> for BorrowedRuleAttemptTransition<'program>
{
fn from(
parts: RuleAttemptStepParts<
BorrowedRuleAttemptSession<'program>,
BorrowedRuleAttemptTerminal<'program>,
crate::inspect::RuleView<'program>,
crate::error::RuleAttemptStepError,
>,
) -> Self {
match parts {
RuleAttemptStepParts::Missed {
attempt,
miss,
continuation,
} => Self::Missed(BorrowedMissedRuleAttempt {
attempt,
miss,
session: continuation,
}),
RuleAttemptStepParts::Applied {
attempt,
step,
rule,
continuation,
} => Self::Applied(BorrowedRuleAttemptAppliedStep {
attempt,
step,
rule,
session: continuation,
}),
RuleAttemptStepParts::Returned {
attempt,
step,
rule,
terminal,
output,
} => Self::Returned(BorrowedRuleAttemptReturnedRun {
attempt,
step,
rule,
program: terminal.program,
output,
}),
RuleAttemptStepParts::Stable {
attempts,
steps,
stable_reason,
terminal,
} => Self::Stable(BorrowedRuleAttemptStableRun {
attempts,
steps,
stable_reason,
program: terminal.program,
core: terminal.core,
}),
RuleAttemptStepParts::Failed { error, terminal } => {
Self::Failed(BorrowedRuleAttemptFailedRun::new(
error,
terminal.attempts,
terminal.program,
terminal.core,
))
}
}
}
}
impl
From<
RuleAttemptStepParts<
OwnedRuleAttemptSession,
OwnedRuleAttemptTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRuleAttemptStepError,
>,
> for OwnedRuleAttemptTransition
{
fn from(
parts: RuleAttemptStepParts<
OwnedRuleAttemptSession,
OwnedRuleAttemptTerminal,
super::witness::OwnedRuleWitness,
crate::error::OwnedRuleAttemptStepError,
>,
) -> Self {
match parts {
RuleAttemptStepParts::Missed {
attempt,
miss,
continuation,
} => Self::Missed(OwnedMissedRuleAttempt {
attempt,
miss,
session: continuation,
}),
RuleAttemptStepParts::Applied {
attempt,
step,
rule,
continuation,
} => Self::Applied(OwnedRuleAttemptAppliedStep {
attempt,
step,
rule,
session: continuation,
}),
RuleAttemptStepParts::Returned {
attempt,
step,
rule,
terminal,
output,
} => Self::Returned(OwnedRuleAttemptReturnedRun {
attempt,
step,
rule,
program: terminal.program,
output,
}),
RuleAttemptStepParts::Stable {
attempts,
steps,
stable_reason,
terminal,
} => Self::Stable(OwnedRuleAttemptStableRun {
attempts,
steps,
stable_reason,
program: terminal.program,
core: terminal.core,
}),
RuleAttemptStepParts::Failed { error, terminal } => {
Self::Failed(OwnedRuleAttemptFailedRun::new(
error,
terminal.attempts,
terminal.program,
terminal.core,
))
}
}
}
}
fn step_borrowed_run<'program>(
session: BorrowedRunSession<'program>,
) -> BorrowedStepTransition<'program> {
borrowed_run_step_parts(session).into()
}
fn step_owned_run(session: OwnedRunSession) -> OwnedStepTransition {
owned_run_step_parts(session).into()
}
fn step_borrowed_rule_attempt_run<'program>(
session: BorrowedRuleAttemptSession<'program>,
) -> BorrowedRuleAttemptTransition<'program> {
borrowed_rule_attempt_step_parts(session).into()
}
fn step_owned_rule_attempt_run(session: OwnedRuleAttemptSession) -> OwnedRuleAttemptTransition {
owned_rule_attempt_step_parts(session).into()
}