use alloc::vec::Vec;
use core::ops::Deref;
use miden_crypto::{WORD_SIZE, Word, ZERO};
use super::{ByteWriter, Felt, MIN_STACK_DEPTH, OutputError, Serializable, get_num_stack_values};
use crate::utils::{ByteReader, Deserializable, DeserializationError, range};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct StackOutputs {
elements: [Felt; MIN_STACK_DEPTH],
}
impl StackOutputs {
pub fn new(mut stack: Vec<Felt>) -> Result<Self, OutputError> {
if stack.len() > MIN_STACK_DEPTH {
return Err(OutputError::OutputSizeTooBig(stack.len()));
}
stack.resize(MIN_STACK_DEPTH, ZERO);
Ok(Self { elements: stack.try_into().unwrap() })
}
pub fn try_from_ints<I>(iter: I) -> Result<Self, OutputError>
where
I: IntoIterator<Item = u64>,
{
let stack = iter
.into_iter()
.map(Felt::try_from)
.collect::<Result<Vec<Felt>, _>>()
.map_err(OutputError::InvalidStackElement)?;
Self::new(stack)
}
pub fn get_stack_item(&self, idx: usize) -> Option<Felt> {
self.elements.get(idx).cloned()
}
pub fn get_stack_word_be(&self, idx: usize) -> Option<Word> {
let word_elements: [Felt; WORD_SIZE] = {
let word_elements: Vec<Felt> = range(idx, 4)
.map(|idx| self.get_stack_item(idx))
.rev()
.collect::<Option<_>>()?;
word_elements.try_into().expect("a Word contains 4 elements")
};
Some(word_elements.into())
}
pub fn get_stack_word_le(&self, idx: usize) -> Option<Word> {
self.get_stack_word_be(idx).map(|mut word| {
word.reverse();
word
})
}
#[deprecated(
since = "0.19.0",
note = "Use `get_stack_word_be()` or `get_stack_word_le()` to make endianness explicit"
)]
pub fn get_stack_word(&self, idx: usize) -> Option<Word> {
self.get_stack_word_be(idx)
}
pub fn stack_truncated(&self, num_outputs: usize) -> &[Felt] {
let len = self.elements.len().min(num_outputs);
&self.elements[..len]
}
pub fn stack_mut(&mut self) -> &mut [Felt] {
&mut self.elements
}
pub fn as_int_vec(&self) -> Vec<u64> {
self.elements.iter().map(|e| (*e).as_int()).collect()
}
}
impl Deref for StackOutputs {
type Target = [Felt; MIN_STACK_DEPTH];
fn deref(&self) -> &Self::Target {
&self.elements
}
}
impl From<[Felt; MIN_STACK_DEPTH]> for StackOutputs {
fn from(value: [Felt; MIN_STACK_DEPTH]) -> Self {
Self { elements: value }
}
}
impl Serializable for StackOutputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
let num_stack_values = get_num_stack_values(self);
target.write_u8(num_stack_values);
target.write_many(&self.elements[..num_stack_values as usize]);
}
}
impl Deserializable for StackOutputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let num_elements = source.read_u8()?;
let elements = source.read_many::<Felt>(num_elements.into())?;
StackOutputs::new(elements).map_err(|err| {
DeserializationError::InvalidValue(format!("failed to create stack outputs: {err}",))
})
}
}