use core::error::Error;
use crate::allocation::AllocationError;
use crate::bytes::{
NonAsciiInputByte, PayloadByteCount, ReturnOutputByteCount, RuntimeStateByteCount,
};
use crate::program::{ReturnByteLimit, StateByteLimit, StepCount, StepLimit};
#[derive(Debug, PartialEq, Eq)]
pub enum RunError {
Allocation(AllocationError),
StateSize(StateSizeError),
Limit(LimitError),
}
impl Error for RunError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Allocation(error) => Some(error),
Self::StateSize(error) => Some(error),
Self::Limit(error) => Some(error),
}
}
}
impl From<AllocationError> for RunError {
fn from(value: AllocationError) -> Self {
Self::Allocation(value)
}
}
impl From<StateSizeError> for RunError {
fn from(value: StateSizeError) -> Self {
Self::StateSize(value)
}
}
impl From<LimitError> for RunError {
fn from(value: LimitError) -> Self {
Self::Limit(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InputError {
NonAscii {
column: InputColumn,
byte: NonAsciiInputByte,
},
Allocation(AllocationError),
}
impl InputError {
pub(crate) const fn non_ascii(column: InputColumn, byte: NonAsciiInputByte) -> Self {
Self::NonAscii { column, byte }
}
}
impl From<AllocationError> for InputError {
fn from(value: AllocationError) -> Self {
Self::Allocation(value)
}
}
impl Error for InputError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::NonAscii { .. } => None,
Self::Allocation(error) => Some(error),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InputColumn {
one_based: usize,
}
impl InputColumn {
#[expect(
clippy::expect_used,
reason = "slice enumeration cannot produce usize::MAX as a valid byte index"
)]
pub(crate) fn from_zero_based(zero_based: usize) -> Self {
Self {
one_based: zero_based
.checked_add(1)
.expect("input column index from slice enumeration must fit usize"),
}
}
#[must_use]
pub const fn get(self) -> usize {
self.one_based
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StateSizeError {
state: RuntimeStateByteCount,
lhs: PayloadByteCount,
rhs: PayloadByteCount,
}
impl StateSizeError {
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 StateSizeError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateLimitContext {
Input,
Rewrite,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LimitError {
State {
context: StateLimitContext,
limit: StateByteLimit,
attempted_len: RuntimeStateByteCount,
},
Return {
limit: ReturnByteLimit,
attempted_len: ReturnOutputByteCount,
},
Step {
max_steps: StepLimit,
completed_steps: StepCount,
state_len: RuntimeStateByteCount,
},
}
impl LimitError {
pub(crate) const fn state(
context: StateLimitContext,
limit: StateByteLimit,
attempted_len: RuntimeStateByteCount,
) -> Self {
Self::State {
context,
limit,
attempted_len,
}
}
pub(crate) const fn return_output(
limit: ReturnByteLimit,
attempted_len: ReturnOutputByteCount,
) -> Self {
Self::Return {
limit,
attempted_len,
}
}
pub(crate) const fn step(
max_steps: StepLimit,
completed_steps: StepCount,
state_len: RuntimeStateByteCount,
) -> Self {
Self::Step {
max_steps,
completed_steps,
state_len,
}
}
}
impl Error for LimitError {}