use alloc::vec::Vec;
use crate::allocation::{AllocationContext, try_push, try_reserve_total_exact};
use crate::bytes::{RuntimeByte, RuntimeStateByteCount};
use crate::error::{InputError, LimitError, RunError, RuntimeInvariantError, StateLimitContext};
use crate::program::RunLimits;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RuntimeInput<'input> {
bytes: &'input [u8],
}
impl<'input> RuntimeInput<'input> {
pub fn validate(input: &'input [u8]) -> Result<Self, InputError> {
for (zero_based_column, byte) in input.iter().copied().enumerate() {
RuntimeByte::validate_input(byte, zero_based_column)?;
}
Ok(Self { bytes: input })
}
#[must_use]
pub const fn as_bytes(self) -> &'input [u8] {
self.bytes
}
#[must_use]
pub const fn byte_count(self) -> RuntimeStateByteCount {
RuntimeStateByteCount::new(self.bytes.len())
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.bytes.is_empty()
}
pub(super) fn runtime_bytes(
self,
) -> impl Iterator<Item = Result<RuntimeByte, RuntimeInvariantError>> + 'input {
self.bytes
.iter()
.copied()
.map(RuntimeByte::from_validated_input)
}
}
#[derive(Debug, PartialEq, Eq)]
pub(super) struct InitialStateBytes {
pub(super) bytes: Vec<RuntimeByte>,
}
impl InitialStateBytes {
pub(super) fn materialize(
input: RuntimeInput<'_>,
limits: RunLimits,
) -> Result<Self, RunError> {
let byte_count = input.byte_count();
if byte_count.get() > limits.state_byte_limit().get() {
return Err(LimitError::state(
StateLimitContext::Input,
limits.state_byte_limit(),
byte_count,
)
.into());
}
let mut bytes = Vec::new();
try_reserve_total_exact(
&mut bytes,
input.as_bytes().len(),
AllocationContext::RuntimeInput,
)?;
for byte in input.runtime_bytes() {
try_push(&mut bytes, byte?, AllocationContext::RuntimeInput)?;
}
Ok(Self { bytes })
}
}