miden_core/program/stack/
outputs.rs1use alloc::vec::Vec;
2use core::ops::Deref;
3
4use super::{MIN_STACK_DEPTH, get_num_stack_values};
5use crate::{
6 Felt, WORD_SIZE, Word, ZERO,
7 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
8};
9
10#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
17#[cfg_attr(
18 all(feature = "arbitrary", test),
19 miden_test_serialization_macros::serialization_test
20)]
21pub struct StackOutputs {
22 elements: [Felt; MIN_STACK_DEPTH],
23}
24
25impl StackOutputs {
26 pub fn new(values: &[Felt]) -> Result<Self, OutputError> {
34 if values.len() > MIN_STACK_DEPTH {
35 return Err(OutputError::OutputStackTooBig(MIN_STACK_DEPTH, values.len()));
36 }
37
38 let mut elements = [ZERO; MIN_STACK_DEPTH];
39 elements[..values.len()].copy_from_slice(values);
40
41 Ok(Self { elements })
42 }
43
44 pub fn get_element(&self, idx: usize) -> Option<Felt> {
50 self.elements.get(idx).cloned()
51 }
52
53 pub fn get_word(&self, idx: usize) -> Option<Word> {
62 if idx > MIN_STACK_DEPTH - WORD_SIZE {
63 return None;
64 }
65
66 Some(Word::from([
67 self.elements[idx],
68 self.elements[idx + 1],
69 self.elements[idx + 2],
70 self.elements[idx + 3],
71 ]))
72 }
73
74 pub fn get_num_elements(&self, num_outputs: usize) -> &[Felt] {
76 let len = self.elements.len().min(num_outputs);
77 &self.elements[..len]
78 }
79
80 #[cfg(any(test, feature = "testing"))]
90 pub fn try_from_ints<I>(iter: I) -> Result<Self, OutputError>
91 where
92 I: IntoIterator<Item = u64>,
93 {
94 use miden_crypto::field::QuotientMap;
95
96 let values = iter
98 .into_iter()
99 .map(|v| Felt::from_canonical_checked(v).ok_or(OutputError::InvalidStackElement(v)))
100 .collect::<Result<Vec<Felt>, _>>()?;
101
102 Self::new(&values)
103 }
104
105 #[cfg(any(test, feature = "testing"))]
107 pub fn as_int_vec(&self) -> Vec<u64> {
108 self.elements.iter().map(|e| (*e).as_canonical_u64()).collect()
109 }
110}
111
112impl Deref for StackOutputs {
113 type Target = [Felt; MIN_STACK_DEPTH];
114
115 fn deref(&self) -> &Self::Target {
116 &self.elements
117 }
118}
119
120impl From<[Felt; MIN_STACK_DEPTH]> for StackOutputs {
121 fn from(value: [Felt; MIN_STACK_DEPTH]) -> Self {
122 Self { elements: value }
123 }
124}
125
126#[cfg(any(test, feature = "testing"))]
127impl AsMut<[Felt]> for StackOutputs {
128 fn as_mut(&mut self) -> &mut [Felt] {
130 &mut self.elements
131 }
132}
133
134impl Serializable for StackOutputs {
138 fn write_into<W: ByteWriter>(&self, target: &mut W) {
139 let num_stack_values = get_num_stack_values(self);
140 target.write_u8(num_stack_values);
141 target.write_many(&self.elements[..num_stack_values as usize]);
142 }
143}
144
145impl Deserializable for StackOutputs {
146 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
147 let num_elements = source.read_u8()?;
148
149 let elements: Vec<Felt> =
150 source.read_many_iter::<Felt>(num_elements.into())?.collect::<Result<_, _>>()?;
151
152 StackOutputs::new(&elements).map_err(|err| {
153 DeserializationError::InvalidValue(format!("failed to create stack outputs: {err}",))
154 })
155 }
156}
157
158#[derive(Clone, Debug, thiserror::Error)]
162pub enum OutputError {
163 #[error("value {0} exceeds field modulus")]
164 InvalidStackElement(u64),
165 #[error("number of output values on the stack cannot exceed {0}, but was {1}")]
166 OutputStackTooBig(usize, usize),
167}
168
169#[cfg(any(test, feature = "arbitrary"))]
173mod arbitrary {
174 use proptest::prelude::*;
175
176 use super::{MIN_STACK_DEPTH, StackOutputs};
177 use crate::Felt;
178
179 impl Arbitrary for StackOutputs {
180 type Parameters = ();
181 type Strategy = BoxedStrategy<Self>;
182
183 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
184 any::<[Felt; MIN_STACK_DEPTH]>().prop_map(StackOutputs::from).boxed()
188 }
189 }
190}