1use crate::{
4 asm::Word,
5 error::{LenWordsError, StackError, StackResult},
6};
7use essential_types::convert::bool_from_word;
8
9#[cfg(test)]
10mod frame_tests;
11
12#[derive(Clone, Debug, PartialEq, Default)]
17pub struct Stack(Vec<Word>);
18
19impl Stack {
20 pub const SIZE_LIMIT: usize = 4096;
22
23 pub fn push(&mut self, word: Word) -> StackResult<()> {
27 if self.len() >= Self::SIZE_LIMIT {
28 return Err(StackError::Overflow);
29 }
30 self.0.push(word);
31 Ok(())
32 }
33
34 pub fn extend(&mut self, words: impl IntoIterator<Item = Word>) -> StackResult<()> {
38 for word in words {
39 self.push(word)?;
40 }
41 Ok(())
42 }
43
44 pub(crate) fn reserve_zeroed(&mut self) -> StackResult<()> {
46 let len = self.pop()?;
47 let len = usize::try_from(len).map_err(|_| StackError::IndexOutOfBounds)?;
48 let new_len = self.len().saturating_add(len);
49 if new_len > Self::SIZE_LIMIT {
50 return Err(StackError::IndexOutOfBounds);
51 }
52 self.0.resize(new_len, 0);
53 Ok(())
54 }
55
56 pub(crate) fn load(&mut self) -> StackResult<()> {
58 let ix = self.pop()?;
59 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
60 let word = self
61 .0
62 .get(ix)
63 .copied()
64 .ok_or(StackError::IndexOutOfBounds)?;
65 self.push(word)
66 }
67
68 pub(crate) fn store(&mut self) -> StackResult<()> {
70 let [ix, word] = self.pop2()?;
71 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
72 let Some(w) = self.0.get_mut(ix) else {
73 return Err(StackError::IndexOutOfBounds);
74 };
75 *w = word;
76 Ok(())
77 }
78
79 pub(crate) fn dup_from(&mut self) -> StackResult<()> {
81 let rev_ix_w = self.pop()?;
82 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
83 let ix = self
84 .len()
85 .checked_sub(rev_ix)
86 .and_then(|i| i.checked_sub(1))
87 .ok_or(StackError::IndexOutOfBounds)?;
88 let w = *self.get(ix).ok_or(StackError::IndexOutOfBounds)?;
89 self.push(w)?;
90 Ok(())
91 }
92
93 pub(crate) fn swap_index(&mut self) -> StackResult<()> {
95 let rev_ix_w = self.pop()?;
96 let top_ix = self
97 .len()
98 .checked_sub(1)
99 .ok_or(StackError::IndexOutOfBounds)?;
100 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
101 let ix = top_ix
102 .checked_sub(rev_ix)
103 .ok_or(StackError::IndexOutOfBounds)?;
104 self.0.swap(ix, top_ix);
105 Ok(())
106 }
107
108 pub(crate) fn select(&mut self) -> StackResult<()> {
110 self.pop().and_then(|cond_w| {
111 self.pop2_push1(|w0, w1| {
112 Ok(
113 if bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))? {
114 w1
115 } else {
116 w0
117 },
118 )
119 })
120 })?;
121 Ok(())
122 }
123
124 pub(crate) fn select_range(&mut self) -> StackResult<()> {
126 let cond_w = self.pop()?;
127 let cond = bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))?;
128 let len = self.pop_len()?;
129 if len == 0 {
130 return Ok(());
131 }
132 self.len()
134 .checked_sub(len.checked_mul(2).ok_or(StackError::IndexOutOfBounds)?)
135 .ok_or(StackError::IndexOutOfBounds)?;
136 let arr_b_index = self.len() - len;
138 if cond {
139 let arr_a_index = arr_b_index - len;
141 self.0
142 .copy_within(arr_b_index..(arr_b_index + len), arr_a_index);
143 }
144 self.0.truncate(arr_b_index);
146 Ok(())
147 }
148
149 pub fn pop(&mut self) -> StackResult<Word> {
151 self.0.pop().ok_or(StackError::Empty)
152 }
153
154 pub fn pop2(&mut self) -> StackResult<[Word; 2]> {
158 let w1 = self.pop()?;
159 let w0 = self.pop()?;
160 Ok([w0, w1])
161 }
162
163 pub fn pop3(&mut self) -> StackResult<[Word; 3]> {
167 let w2 = self.pop()?;
168 let [w0, w1] = self.pop2()?;
169 Ok([w0, w1, w2])
170 }
171
172 pub fn pop4(&mut self) -> StackResult<[Word; 4]> {
176 let w3 = self.pop()?;
177 let [w0, w1, w2] = self.pop3()?;
178 Ok([w0, w1, w2, w3])
179 }
180
181 pub fn pop8(&mut self) -> StackResult<[Word; 8]> {
185 let [w4, w5, w6, w7] = self.pop4()?;
186 let [w0, w1, w2, w3] = self.pop4()?;
187 Ok([w0, w1, w2, w3, w4, w5, w6, w7])
188 }
189
190 pub fn pop1_push1<F, E>(&mut self, f: F) -> Result<(), E>
192 where
193 F: FnOnce(Word) -> Result<Word, E>,
194 E: From<StackError>,
195 {
196 let w = self.pop()?;
197 let x = f(w)?;
198 self.push(x)?;
199 Ok(())
200 }
201
202 pub fn pop2_push1<F, E>(&mut self, f: F) -> Result<(), E>
204 where
205 F: FnOnce(Word, Word) -> Result<Word, E>,
206 E: From<StackError>,
207 {
208 let [w0, w1] = self.pop2()?;
209 let x = f(w0, w1)?;
210 self.push(x)?;
211 Ok(())
212 }
213
214 pub fn pop8_push1<F, E>(&mut self, f: F) -> Result<(), E>
216 where
217 F: FnOnce([Word; 8]) -> Result<Word, E>,
218 E: From<StackError>,
219 {
220 let ws = self.pop8()?;
221 let x = f(ws)?;
222 self.push(x)?;
223 Ok(())
224 }
225
226 pub fn pop1_push2<F, E>(&mut self, f: F) -> Result<(), E>
228 where
229 F: FnOnce(Word) -> Result<[Word; 2], E>,
230 E: From<StackError>,
231 {
232 let w = self.pop()?;
233 let xs = f(w)?;
234 self.extend(xs)?;
235 Ok(())
236 }
237
238 pub fn pop2_push2<F, E>(&mut self, f: F) -> Result<(), E>
240 where
241 F: FnOnce(Word, Word) -> Result<[Word; 2], E>,
242 E: From<StackError>,
243 {
244 let [w0, w1] = self.pop2()?;
245 let xs = f(w0, w1)?;
246 self.extend(xs)?;
247 Ok(())
248 }
249
250 pub fn pop2_push4<F, E>(&mut self, f: F) -> Result<(), E>
252 where
253 F: FnOnce(Word, Word) -> Result<[Word; 4], E>,
254 E: From<StackError>,
255 {
256 let [w0, w1] = self.pop2()?;
257 let xs = f(w0, w1)?;
258 self.extend(xs)?;
259 Ok(())
260 }
261
262 pub fn pop_len(&mut self) -> StackResult<usize> {
264 let len_word = self.pop()?;
265 let len = usize::try_from(len_word).map_err(|_| StackError::IndexOutOfBounds)?;
266 Ok(len)
267 }
268
269 pub fn pop_len_words<F, O, E>(&mut self, f: F) -> Result<O, E>
272 where
273 F: FnOnce(&[Word]) -> Result<O, E>,
274 E: From<StackError>,
275 {
276 let (rest, slice) = slice_split_len_words(self).map_err(StackError::LenWords)?;
277 let out = f(slice)?;
278 self.0.truncate(rest.len());
279 Ok(out)
280 }
281
282 pub fn pop_words<F, O, E>(&mut self, num_words: usize, f: F) -> Result<O, E>
285 where
286 F: FnOnce(&[Word]) -> Result<O, E>,
287 E: From<StackError>,
288 {
289 let (rest, slice) = slice_split_len(self, num_words).map_err(StackError::LenWords)?;
290 let out = f(slice)?;
291 self.0.truncate(rest.len());
292 Ok(out)
293 }
294
295 pub fn pop_len_words2<F, O, E>(&mut self, f: F) -> Result<O, E>
299 where
300 F: FnOnce(&[Word], &[Word]) -> Result<O, E>,
301 E: From<StackError>,
302 {
303 let (rest, rhs) = slice_split_len_words(self).map_err(StackError::LenWords)?;
304 let (rest, lhs) = slice_split_len_words(rest).map_err(StackError::LenWords)?;
305 let out = f(lhs, rhs)?;
306 self.0.truncate(rest.len());
307 Ok(out)
308 }
309
310 pub fn reserve(&mut self, additional: usize) {
313 self.0.reserve(additional);
314 }
315}
316
317fn slice_split_len_words(slice: &[Word]) -> Result<(&[Word], &[Word]), LenWordsError> {
325 let (len, rest) = slice.split_last().ok_or(LenWordsError::MissingLength)?;
326 let len = usize::try_from(*len).map_err(|_| LenWordsError::InvalidLength(*len))?;
327 slice_split_len(rest, len)
328}
329
330fn slice_split_len(slice: &[Word], len: usize) -> Result<(&[Word], &[Word]), LenWordsError> {
331 let ix = slice
332 .len()
333 .checked_sub(len)
334 .ok_or(LenWordsError::OutOfBounds(len as Word))?;
335 Ok(slice.split_at(ix))
336}
337
338impl From<Stack> for Vec<Word> {
339 fn from(stack: Stack) -> Self {
340 stack.0
341 }
342}
343
344impl TryFrom<Vec<Word>> for Stack {
345 type Error = StackError;
346 fn try_from(vec: Vec<Word>) -> Result<Self, Self::Error> {
347 if vec.len() > Self::SIZE_LIMIT {
348 Err(StackError::Overflow)
349 } else {
350 Ok(Self(vec))
351 }
352 }
353}
354
355impl core::ops::Deref for Stack {
356 type Target = Vec<Word>;
357 fn deref(&self) -> &Self::Target {
358 &self.0
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use crate::{
365 asm::Stack,
366 error::{ExecSyncError, OpSyncError, StackError},
367 sync::{exec_ops, test_util::*},
368 };
369
370 #[test]
371 fn dup_from_1() {
372 let ops = &[
373 Stack::Push(42).into(),
374 Stack::Push(2).into(),
375 Stack::Push(1).into(),
376 Stack::Push(0).into(),
377 Stack::Push(3).into(), Stack::DupFrom.into(),
379 ];
380 let stack = exec_ops(ops, *test_access()).unwrap();
381 assert_eq!(&stack[..], &[42, 2, 1, 0, 42]);
382 }
383
384 #[test]
385 fn dup_from_2() {
386 let ops = &[
387 Stack::Push(3).into(),
388 Stack::Push(2).into(),
389 Stack::Push(1).into(),
390 Stack::Push(42).into(),
391 Stack::Push(0).into(), Stack::DupFrom.into(),
393 ];
394 let stack = exec_ops(ops, *test_access()).unwrap();
395 assert_eq!(&stack[..], &[3, 2, 1, 42, 42]);
396 }
397
398 #[test]
399 fn push1() {
400 let ops = &[Stack::Push(42).into()];
401 let stack = exec_ops(ops, *test_access()).unwrap();
402 assert_eq!(&stack[..], &[42]);
403 }
404
405 #[test]
406 fn push2_pop_push() {
407 let ops = &[
408 Stack::Push(1).into(),
409 Stack::Push(2).into(),
410 Stack::Pop.into(),
411 Stack::Push(3).into(),
412 ];
413 let stack = exec_ops(ops, *test_access()).unwrap();
414 assert_eq!(&stack[..], &[1, 3]);
415 }
416
417 #[test]
418 fn pop_empty() {
419 let ops = &[Stack::Pop.into()];
420 match exec_ops(ops, *test_access()) {
421 Err(ExecSyncError(0, OpSyncError::Stack(StackError::Empty))) => (),
422 _ => panic!("expected empty stack error"),
423 }
424 }
425
426 #[test]
427 fn index_oob() {
428 let ops = &[Stack::Push(0).into(), Stack::DupFrom.into()];
429 match exec_ops(ops, *test_access()) {
430 Err(ExecSyncError(1, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
431 _ => panic!("expected index out-of-bounds stack error"),
432 }
433 }
434
435 #[test]
436 fn swap_index() {
437 let ops = &[
438 Stack::Push(3).into(),
439 Stack::Push(4).into(),
440 Stack::Push(5).into(),
441 Stack::Push(42).into(),
442 Stack::Push(2).into(), Stack::SwapIndex.into(),
444 ];
445 let stack = exec_ops(ops, *test_access()).unwrap();
446 assert_eq!(&stack[..], &[3, 42, 5, 4]);
447 }
448
449 #[test]
450 fn swap_index_oob() {
451 let ops = &[
452 Stack::Push(3).into(),
453 Stack::Push(4).into(),
454 Stack::Push(2).into(), Stack::SwapIndex.into(),
456 ];
457 match exec_ops(ops, *test_access()) {
458 Err(ExecSyncError(3, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
459 _ => panic!("expected index out-of-bounds stack error"),
460 }
461 }
462
463 #[test]
464 fn select() {
465 let ops = &[
466 Stack::Push(3).into(),
467 Stack::Push(4).into(),
468 Stack::Push(1).into(),
469 Stack::Select.into(),
470 ];
471 let stack = exec_ops(ops, *test_access()).unwrap();
472 assert_eq!(&stack[..], &[4]);
473 }
474
475 #[test]
476 fn select_range_cond_1() {
477 let ops = &[
478 Stack::Push(4).into(),
479 Stack::Push(4).into(),
480 Stack::Push(4).into(),
481 Stack::Push(5).into(),
482 Stack::Push(5).into(),
483 Stack::Push(5).into(),
484 Stack::Push(3).into(), Stack::Push(1).into(), Stack::SelectRange.into(),
487 ];
488 let stack = exec_ops(ops, *test_access()).unwrap();
489 assert_eq!(&stack[..], &[5, 5, 5]);
490 }
491
492 #[test]
493 fn select_range_cond_0() {
494 let ops = &[
495 Stack::Push(4).into(),
496 Stack::Push(4).into(),
497 Stack::Push(4).into(),
498 Stack::Push(5).into(),
499 Stack::Push(5).into(),
500 Stack::Push(5).into(),
501 Stack::Push(3).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
504 ];
505 let stack = exec_ops(ops, *test_access()).unwrap();
506 assert_eq!(&stack[..], &[4, 4, 4]);
507 }
508
509 #[test]
510 fn select_range_cond_invalid() {
511 let ops = &[
512 Stack::Push(4).into(),
513 Stack::Push(5).into(),
514 Stack::Push(1).into(), Stack::Push(42).into(), Stack::SelectRange.into(),
517 ];
518 match exec_ops(ops, *test_access()) {
519 Err(ExecSyncError(4, OpSyncError::Stack(StackError::InvalidCondition(42)))) => (),
520 _ => panic!("expected invalid condition stack error"),
521 }
522 }
523
524 #[test]
525 fn select_range_len_0() {
526 let ops = &[
527 Stack::Push(4).into(),
528 Stack::Push(5).into(),
529 Stack::Push(0).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
532 ];
533 let stack = exec_ops(ops, *test_access()).unwrap();
534 assert_eq!(&stack[..], &[4, 5]);
535 }
536
537 #[test]
538 fn select_range_len_negative() {
539 let ops = &[
540 Stack::Push(-42).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
543 ];
544 match exec_ops(ops, *test_access()) {
545 Err(ExecSyncError(2, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
546 _ => panic!("expected index out of bounds stack error"),
547 }
548 }
549
550 #[test]
551 fn select_range_len_too_big() {
552 let ops = &[
553 Stack::Push(4).into(),
554 Stack::Push(4).into(),
555 Stack::Push(5).into(),
556 Stack::Push(2).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
559 ];
560 match exec_ops(ops, *test_access()) {
561 Err(ExecSyncError(5, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
562 _ => panic!("expected index out of bounds stack error"),
563 }
564 }
565}