use core::error::Error;
use crate::allocation::AllocationError;
use crate::bytes::{
NonAsciiInputByte, PayloadByteCount, ReturnOutputByteCount, RuntimeInputByteCount,
RuntimeStateByteCount,
};
use crate::inspect::RulePosition;
use crate::limits::{
ReturnByteLimit, RuleAttemptCount, RuleAttemptLimit, RuntimeInputByteLimit,
RuntimeStateByteLimit, StepCount, StepLimit,
};
#[derive(Debug, PartialEq, Eq)]
pub enum RunError {
Start(RunStartError),
Finish(RunFinishError),
}
impl Error for RunError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Start(error) => Some(error),
Self::Finish(error) => Some(error),
}
}
}
impl From<RunStartError> for RunError {
fn from(value: RunStartError) -> Self {
Self::Start(value)
}
}
impl From<RunFinishError> for RunError {
fn from(value: RunFinishError) -> Self {
Self::Finish(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RunStartError {
Allocation(AllocationError),
}
impl Error for RunStartError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Allocation(error) => Some(error),
}
}
}
impl From<AllocationError> for RunStartError {
fn from(value: AllocationError) -> Self {
Self::Allocation(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RunStepError {
Allocation(AllocationError),
RewriteSize(RewriteSizeError),
RuntimeStateLimit(RuntimeStateLimitError),
ReturnOutputLimit(ReturnOutputLimitError),
StepLimit(StepLimitError),
RuleRuntimeState(RuleRuntimeStateError),
}
impl Error for RunStepError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Allocation(error) => Some(error),
Self::RewriteSize(error) => Some(error),
Self::RuntimeStateLimit(error) => Some(error),
Self::ReturnOutputLimit(error) => Some(error),
Self::StepLimit(error) => Some(error),
Self::RuleRuntimeState(error) => Some(error),
}
}
}
impl From<AllocationError> for RunStepError {
fn from(value: AllocationError) -> Self {
Self::Allocation(value)
}
}
impl From<RewriteSizeError> for RunStepError {
fn from(value: RewriteSizeError) -> Self {
Self::RewriteSize(value)
}
}
impl From<RuntimeStateLimitError> for RunStepError {
fn from(value: RuntimeStateLimitError) -> Self {
Self::RuntimeStateLimit(value)
}
}
impl From<ReturnOutputLimitError> for RunStepError {
fn from(value: ReturnOutputLimitError) -> Self {
Self::ReturnOutputLimit(value)
}
}
impl From<StepLimitError> for RunStepError {
fn from(value: StepLimitError) -> Self {
Self::StepLimit(value)
}
}
impl From<RuleRuntimeStateError> for RunStepError {
fn from(value: RuleRuntimeStateError) -> Self {
Self::RuleRuntimeState(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OwnedRunStepError {
Step(RunStepError),
RuleWitnessAllocation(AllocationError),
}
impl Error for OwnedRunStepError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Step(error) => Some(error),
Self::RuleWitnessAllocation(error) => Some(error),
}
}
}
impl From<RunStepError> for OwnedRunStepError {
fn from(value: RunStepError) -> Self {
Self::Step(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuleAttemptStepError {
Step(RunStepError),
RuleAttemptLimit(RuleAttemptLimitError),
RuleCursor(RuleAttemptCursorError),
}
impl Error for RuleAttemptStepError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Step(error) => Some(error),
Self::RuleAttemptLimit(error) => Some(error),
Self::RuleCursor(error) => Some(error),
}
}
}
impl From<RunStepError> for RuleAttemptStepError {
fn from(value: RunStepError) -> Self {
Self::Step(value)
}
}
impl From<RuleAttemptLimitError> for RuleAttemptStepError {
fn from(value: RuleAttemptLimitError) -> Self {
Self::RuleAttemptLimit(value)
}
}
impl From<RuleAttemptCursorError> for RuleAttemptStepError {
fn from(value: RuleAttemptCursorError) -> Self {
Self::RuleCursor(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OwnedRuleAttemptStepError {
Attempt(RuleAttemptStepError),
RuleWitnessAllocation(AllocationError),
}
impl Error for OwnedRuleAttemptStepError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Attempt(error) => Some(error),
Self::RuleWitnessAllocation(error) => Some(error),
}
}
}
impl From<RuleAttemptStepError> for OwnedRuleAttemptStepError {
fn from(value: RuleAttemptStepError) -> Self {
Self::Attempt(value)
}
}
impl From<RunStepError> for OwnedRuleAttemptStepError {
fn from(value: RunStepError) -> Self {
Self::Attempt(RuleAttemptStepError::Step(value))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RunFinishError {
Step(RunStepError),
FinalOutput(AllocationError),
}
impl Error for RunFinishError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Step(error) => Some(error),
Self::FinalOutput(error) => Some(error),
}
}
}
impl From<RunStepError> for RunFinishError {
fn from(value: RunStepError) -> Self {
Self::Step(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuntimeInputError {
NonAscii {
column: InputColumn,
byte: NonAsciiInputByte,
},
ColumnOverflow,
InputLimit {
limit: RuntimeInputByteLimit,
attempted_len: RuntimeInputByteCount,
},
Allocation(AllocationError),
}
impl RuntimeInputError {
pub(crate) const fn non_ascii(column: InputColumn, byte: NonAsciiInputByte) -> Self {
Self::NonAscii { column, byte }
}
pub(crate) const fn column_overflow() -> Self {
Self::ColumnOverflow
}
pub(crate) const fn input_limit(
limit: RuntimeInputByteLimit,
attempted_len: RuntimeInputByteCount,
) -> Self {
Self::InputLimit {
limit,
attempted_len,
}
}
}
impl Error for RuntimeInputError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Allocation(error) => Some(error),
Self::NonAscii { .. } | Self::ColumnOverflow | Self::InputLimit { .. } => None,
}
}
}
impl From<AllocationError> for RuntimeInputError {
fn from(value: AllocationError) -> Self {
Self::Allocation(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RunAdmissionError {
InitialStateTooLarge {
limit: RuntimeStateByteLimit,
attempted_len: RuntimeStateByteCount,
},
}
impl RunAdmissionError {
pub(crate) const fn initial_state_limit(
limit: RuntimeStateByteLimit,
attempted_len: RuntimeStateByteCount,
) -> Self {
Self::InitialStateTooLarge {
limit,
attempted_len,
}
}
}
impl Error for RunAdmissionError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuleRuntimeStateError {
rule: RulePosition,
}
impl RuleRuntimeStateError {
pub(crate) const fn missing_once_rule_state(rule: RulePosition) -> Self {
Self { rule }
}
#[must_use]
pub const fn rule(&self) -> RulePosition {
self.rule
}
}
impl Error for RuleRuntimeStateError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuleAttemptCursorError {
rule: RulePosition,
}
impl RuleAttemptCursorError {
pub(crate) const fn missing_rule(rule: RulePosition) -> Self {
Self { rule }
}
#[must_use]
pub const fn rule(&self) -> RulePosition {
self.rule
}
}
impl Error for RuleAttemptCursorError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InputColumn {
one_based: usize,
}
impl InputColumn {
pub(crate) fn from_zero_based(zero_based: usize) -> Option<Self> {
let one_based = zero_based.checked_add(1)?;
Some(Self { one_based })
}
#[must_use]
pub const fn get(self) -> usize {
self.one_based
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RewriteSizeError {
state: RuntimeStateByteCount,
lhs: PayloadByteCount,
rhs: PayloadByteCount,
}
impl RewriteSizeError {
pub(crate) const fn new(
state_len: RuntimeStateByteCount,
lhs_len: PayloadByteCount,
rhs_len: PayloadByteCount,
) -> Self {
Self {
state: state_len,
lhs: lhs_len,
rhs: rhs_len,
}
}
#[must_use]
pub const fn state_len(&self) -> RuntimeStateByteCount {
self.state
}
#[must_use]
pub const fn lhs_len(&self) -> PayloadByteCount {
self.lhs
}
#[must_use]
pub const fn rhs_len(&self) -> PayloadByteCount {
self.rhs
}
}
impl Error for RewriteSizeError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuntimeStateLimitError {
limit: RuntimeStateByteLimit,
attempted_len: RuntimeStateByteCount,
}
impl RuntimeStateLimitError {
pub(crate) const fn new(
limit: RuntimeStateByteLimit,
attempted_len: RuntimeStateByteCount,
) -> Self {
Self {
limit,
attempted_len,
}
}
#[must_use]
pub const fn limit(&self) -> RuntimeStateByteLimit {
self.limit
}
#[must_use]
pub const fn attempted_len(&self) -> RuntimeStateByteCount {
self.attempted_len
}
}
impl Error for RuntimeStateLimitError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReturnOutputLimitError {
limit: ReturnByteLimit,
attempted_len: ReturnOutputByteCount,
}
impl ReturnOutputLimitError {
pub(crate) const fn new(limit: ReturnByteLimit, attempted_len: ReturnOutputByteCount) -> Self {
Self {
limit,
attempted_len,
}
}
#[must_use]
pub const fn limit(&self) -> ReturnByteLimit {
self.limit
}
#[must_use]
pub const fn attempted_len(&self) -> ReturnOutputByteCount {
self.attempted_len
}
}
impl Error for ReturnOutputLimitError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StepLimitError {
max_steps: StepLimit,
completed_steps: StepCount,
state_len: RuntimeStateByteCount,
}
impl StepLimitError {
pub(crate) const fn new(
max_steps: StepLimit,
completed_steps: StepCount,
state_len: RuntimeStateByteCount,
) -> Self {
Self {
max_steps,
completed_steps,
state_len,
}
}
#[must_use]
pub const fn max_steps(&self) -> StepLimit {
self.max_steps
}
#[must_use]
pub const fn completed_steps(&self) -> StepCount {
self.completed_steps
}
#[must_use]
pub const fn state_len(&self) -> RuntimeStateByteCount {
self.state_len
}
}
impl Error for StepLimitError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuleAttemptLimitError {
max_attempts: RuleAttemptLimit,
completed_attempts: RuleAttemptCount,
state_len: RuntimeStateByteCount,
}
impl RuleAttemptLimitError {
pub(crate) const fn new(
max_attempts: RuleAttemptLimit,
completed_attempts: RuleAttemptCount,
state_len: RuntimeStateByteCount,
) -> Self {
Self {
max_attempts,
completed_attempts,
state_len,
}
}
#[must_use]
pub const fn max_attempts(&self) -> RuleAttemptLimit {
self.max_attempts
}
#[must_use]
pub const fn completed_attempts(&self) -> RuleAttemptCount {
self.completed_attempts
}
#[must_use]
pub const fn state_len(&self) -> RuntimeStateByteCount {
self.state_len
}
}
impl Error for RuleAttemptLimitError {}
#[cfg(test)]
mod tests {
use super::InputColumn;
use crate::test_support::{TestResult, ensure_eq};
#[test]
fn input_column_rejects_unrepresentable_zero_based_index() -> TestResult {
ensure_eq!(InputColumn::from_zero_based(usize::MAX), None)?;
ensure_eq!(
InputColumn::from_zero_based(0).map(InputColumn::get),
Some(1),
)?;
Ok(())
}
}