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 start = self.len();
49 let new_len = start.saturating_add(len);
50 if new_len > Self::SIZE_LIMIT {
51 return Err(StackError::IndexOutOfBounds);
52 }
53 self.0.resize(new_len, 0);
54 let start = Word::try_from(start).map_err(|_| StackError::IndexOutOfBounds)?;
55 self.push(start)?;
56 Ok(())
57 }
58
59 pub(crate) fn load(&mut self) -> StackResult<()> {
61 let ix = self.pop()?;
62 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
63 let word = self
64 .0
65 .get(ix)
66 .copied()
67 .ok_or(StackError::IndexOutOfBounds)?;
68 self.push(word)
69 }
70
71 pub(crate) fn store(&mut self) -> StackResult<()> {
73 let [word, ix] = self.pop2()?;
74 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
75 let Some(w) = self.0.get_mut(ix) else {
76 return Err(StackError::IndexOutOfBounds);
77 };
78 *w = word;
79 Ok(())
80 }
81
82 pub(crate) fn dup_from(&mut self) -> StackResult<()> {
84 let rev_ix_w = self.pop()?;
85 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
86 let ix = self
87 .len()
88 .checked_sub(rev_ix)
89 .and_then(|i| i.checked_sub(1))
90 .ok_or(StackError::IndexOutOfBounds)?;
91 let w = *self.get(ix).ok_or(StackError::IndexOutOfBounds)?;
92 self.push(w)?;
93 Ok(())
94 }
95
96 pub(crate) fn swap_index(&mut self) -> StackResult<()> {
98 let rev_ix_w = self.pop()?;
99 let top_ix = self
100 .len()
101 .checked_sub(1)
102 .ok_or(StackError::IndexOutOfBounds)?;
103 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
104 let ix = top_ix
105 .checked_sub(rev_ix)
106 .ok_or(StackError::IndexOutOfBounds)?;
107 self.0.swap(ix, top_ix);
108 Ok(())
109 }
110
111 pub(crate) fn select(&mut self) -> StackResult<()> {
113 self.pop().and_then(|cond_w| {
114 self.pop2_push1(|w0, w1| {
115 Ok(
116 if bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))? {
117 w1
118 } else {
119 w0
120 },
121 )
122 })
123 })?;
124 Ok(())
125 }
126
127 pub(crate) fn select_range(&mut self) -> StackResult<()> {
129 let cond_w = self.pop()?;
130 let cond = bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))?;
131 let len = self.pop_len()?;
132 if len == 0 {
133 return Ok(());
134 }
135 self.len()
137 .checked_sub(len.checked_mul(2).ok_or(StackError::IndexOutOfBounds)?)
138 .ok_or(StackError::IndexOutOfBounds)?;
139 let arr_b_index = self.len() - len;
141 if cond {
142 let arr_a_index = arr_b_index - len;
144 self.0
145 .copy_within(arr_b_index..(arr_b_index + len), arr_a_index);
146 }
147 self.0.truncate(arr_b_index);
149 Ok(())
150 }
151
152 pub fn pop(&mut self) -> StackResult<Word> {
154 self.0.pop().ok_or(StackError::Empty)
155 }
156
157 pub fn pop2(&mut self) -> StackResult<[Word; 2]> {
161 let w1 = self.pop()?;
162 let w0 = self.pop()?;
163 Ok([w0, w1])
164 }
165
166 pub fn pop3(&mut self) -> StackResult<[Word; 3]> {
170 let w2 = self.pop()?;
171 let [w0, w1] = self.pop2()?;
172 Ok([w0, w1, w2])
173 }
174
175 pub fn pop4(&mut self) -> StackResult<[Word; 4]> {
179 let w3 = self.pop()?;
180 let [w0, w1, w2] = self.pop3()?;
181 Ok([w0, w1, w2, w3])
182 }
183
184 pub fn pop8(&mut self) -> StackResult<[Word; 8]> {
188 let [w4, w5, w6, w7] = self.pop4()?;
189 let [w0, w1, w2, w3] = self.pop4()?;
190 Ok([w0, w1, w2, w3, w4, w5, w6, w7])
191 }
192
193 pub fn pop1_push1<F, E>(&mut self, f: F) -> Result<(), E>
195 where
196 F: FnOnce(Word) -> Result<Word, E>,
197 E: From<StackError>,
198 {
199 let w = self.pop()?;
200 let x = f(w)?;
201 self.push(x)?;
202 Ok(())
203 }
204
205 pub fn pop2_push1<F, E>(&mut self, f: F) -> Result<(), E>
207 where
208 F: FnOnce(Word, Word) -> Result<Word, E>,
209 E: From<StackError>,
210 {
211 let [w0, w1] = self.pop2()?;
212 let x = f(w0, w1)?;
213 self.push(x)?;
214 Ok(())
215 }
216
217 pub fn pop8_push1<F, E>(&mut self, f: F) -> Result<(), E>
219 where
220 F: FnOnce([Word; 8]) -> Result<Word, E>,
221 E: From<StackError>,
222 {
223 let ws = self.pop8()?;
224 let x = f(ws)?;
225 self.push(x)?;
226 Ok(())
227 }
228
229 pub fn pop1_push2<F, E>(&mut self, f: F) -> Result<(), E>
231 where
232 F: FnOnce(Word) -> Result<[Word; 2], E>,
233 E: From<StackError>,
234 {
235 let w = self.pop()?;
236 let xs = f(w)?;
237 self.extend(xs)?;
238 Ok(())
239 }
240
241 pub fn pop2_push2<F, E>(&mut self, f: F) -> Result<(), E>
243 where
244 F: FnOnce(Word, Word) -> Result<[Word; 2], E>,
245 E: From<StackError>,
246 {
247 let [w0, w1] = self.pop2()?;
248 let xs = f(w0, w1)?;
249 self.extend(xs)?;
250 Ok(())
251 }
252
253 pub fn pop2_push4<F, E>(&mut self, f: F) -> Result<(), E>
255 where
256 F: FnOnce(Word, Word) -> Result<[Word; 4], E>,
257 E: From<StackError>,
258 {
259 let [w0, w1] = self.pop2()?;
260 let xs = f(w0, w1)?;
261 self.extend(xs)?;
262 Ok(())
263 }
264
265 pub fn pop_len(&mut self) -> StackResult<usize> {
267 let len_word = self.pop()?;
268 let len = usize::try_from(len_word).map_err(|_| StackError::IndexOutOfBounds)?;
269 Ok(len)
270 }
271
272 pub fn pop_len_words<F, O, E>(&mut self, f: F) -> Result<O, E>
275 where
276 F: FnOnce(&[Word]) -> Result<O, E>,
277 E: From<StackError>,
278 {
279 let (rest, slice) = slice_split_len_words(self).map_err(StackError::LenWords)?;
280 let out = f(slice)?;
281 self.0.truncate(rest.len());
282 Ok(out)
283 }
284
285 pub fn pop_words<F, O, E>(&mut self, num_words: usize, f: F) -> Result<O, E>
288 where
289 F: FnOnce(&[Word]) -> Result<O, E>,
290 E: From<StackError>,
291 {
292 let (rest, slice) = slice_split_len(self, num_words).map_err(StackError::LenWords)?;
293 let out = f(slice)?;
294 self.0.truncate(rest.len());
295 Ok(out)
296 }
297
298 pub fn pop_len_words2<F, O, E>(&mut self, f: F) -> Result<O, E>
302 where
303 F: FnOnce(&[Word], &[Word]) -> Result<O, E>,
304 E: From<StackError>,
305 {
306 let (rest, rhs) = slice_split_len_words(self).map_err(StackError::LenWords)?;
307 let (rest, lhs) = slice_split_len_words(rest).map_err(StackError::LenWords)?;
308 let out = f(lhs, rhs)?;
309 self.0.truncate(rest.len());
310 Ok(out)
311 }
312
313 pub fn reserve(&mut self, additional: usize) {
316 self.0.reserve(additional);
317 }
318}
319
320fn slice_split_len_words(slice: &[Word]) -> Result<(&[Word], &[Word]), LenWordsError> {
328 let (len, rest) = slice.split_last().ok_or(LenWordsError::MissingLength)?;
329 let len = usize::try_from(*len).map_err(|_| LenWordsError::InvalidLength(*len))?;
330 slice_split_len(rest, len)
331}
332
333fn slice_split_len(slice: &[Word], len: usize) -> Result<(&[Word], &[Word]), LenWordsError> {
334 let ix = slice
335 .len()
336 .checked_sub(len)
337 .ok_or(LenWordsError::OutOfBounds(len as Word))?;
338 Ok(slice.split_at(ix))
339}
340
341impl From<Stack> for Vec<Word> {
342 fn from(stack: Stack) -> Self {
343 stack.0
344 }
345}
346
347impl TryFrom<Vec<Word>> for Stack {
348 type Error = StackError;
349 fn try_from(vec: Vec<Word>) -> Result<Self, Self::Error> {
350 if vec.len() > Self::SIZE_LIMIT {
351 Err(StackError::Overflow)
352 } else {
353 Ok(Self(vec))
354 }
355 }
356}
357
358impl core::ops::Deref for Stack {
359 type Target = Vec<Word>;
360 fn deref(&self) -> &Self::Target {
361 &self.0
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use crate::{
368 asm::Stack,
369 error::{ExecSyncError, OpSyncError, StackError},
370 sync::{exec_ops, test_util::*},
371 };
372
373 #[test]
374 fn dup_from_1() {
375 let ops = &[
376 Stack::Push(42).into(),
377 Stack::Push(2).into(),
378 Stack::Push(1).into(),
379 Stack::Push(0).into(),
380 Stack::Push(3).into(), Stack::DupFrom.into(),
382 ];
383 let stack = exec_ops(ops, *test_access()).unwrap();
384 assert_eq!(&stack[..], &[42, 2, 1, 0, 42]);
385 }
386
387 #[test]
388 fn dup_from_2() {
389 let ops = &[
390 Stack::Push(3).into(),
391 Stack::Push(2).into(),
392 Stack::Push(1).into(),
393 Stack::Push(42).into(),
394 Stack::Push(0).into(), Stack::DupFrom.into(),
396 ];
397 let stack = exec_ops(ops, *test_access()).unwrap();
398 assert_eq!(&stack[..], &[3, 2, 1, 42, 42]);
399 }
400
401 #[test]
402 fn push1() {
403 let ops = &[Stack::Push(42).into()];
404 let stack = exec_ops(ops, *test_access()).unwrap();
405 assert_eq!(&stack[..], &[42]);
406 }
407
408 #[test]
409 fn push2_pop_push() {
410 let ops = &[
411 Stack::Push(1).into(),
412 Stack::Push(2).into(),
413 Stack::Pop.into(),
414 Stack::Push(3).into(),
415 ];
416 let stack = exec_ops(ops, *test_access()).unwrap();
417 assert_eq!(&stack[..], &[1, 3]);
418 }
419
420 #[test]
421 fn pop_empty() {
422 let ops = &[Stack::Pop.into()];
423 match exec_ops(ops, *test_access()) {
424 Err(ExecSyncError(0, OpSyncError::Stack(StackError::Empty))) => (),
425 _ => panic!("expected empty stack error"),
426 }
427 }
428
429 #[test]
430 fn index_oob() {
431 let ops = &[Stack::Push(0).into(), Stack::DupFrom.into()];
432 match exec_ops(ops, *test_access()) {
433 Err(ExecSyncError(1, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
434 _ => panic!("expected index out-of-bounds stack error"),
435 }
436 }
437
438 #[test]
439 fn swap_index() {
440 let ops = &[
441 Stack::Push(3).into(),
442 Stack::Push(4).into(),
443 Stack::Push(5).into(),
444 Stack::Push(42).into(),
445 Stack::Push(2).into(), Stack::SwapIndex.into(),
447 ];
448 let stack = exec_ops(ops, *test_access()).unwrap();
449 assert_eq!(&stack[..], &[3, 42, 5, 4]);
450 }
451
452 #[test]
453 fn swap_index_oob() {
454 let ops = &[
455 Stack::Push(3).into(),
456 Stack::Push(4).into(),
457 Stack::Push(2).into(), Stack::SwapIndex.into(),
459 ];
460 match exec_ops(ops, *test_access()) {
461 Err(ExecSyncError(3, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
462 _ => panic!("expected index out-of-bounds stack error"),
463 }
464 }
465
466 #[test]
467 fn select() {
468 let ops = &[
469 Stack::Push(3).into(),
470 Stack::Push(4).into(),
471 Stack::Push(1).into(),
472 Stack::Select.into(),
473 ];
474 let stack = exec_ops(ops, *test_access()).unwrap();
475 assert_eq!(&stack[..], &[4]);
476 }
477
478 #[test]
479 fn select_range_cond_1() {
480 let ops = &[
481 Stack::Push(4).into(),
482 Stack::Push(4).into(),
483 Stack::Push(4).into(),
484 Stack::Push(5).into(),
485 Stack::Push(5).into(),
486 Stack::Push(5).into(),
487 Stack::Push(3).into(), Stack::Push(1).into(), Stack::SelectRange.into(),
490 ];
491 let stack = exec_ops(ops, *test_access()).unwrap();
492 assert_eq!(&stack[..], &[5, 5, 5]);
493 }
494
495 #[test]
496 fn select_range_cond_0() {
497 let ops = &[
498 Stack::Push(4).into(),
499 Stack::Push(4).into(),
500 Stack::Push(4).into(),
501 Stack::Push(5).into(),
502 Stack::Push(5).into(),
503 Stack::Push(5).into(),
504 Stack::Push(3).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
507 ];
508 let stack = exec_ops(ops, *test_access()).unwrap();
509 assert_eq!(&stack[..], &[4, 4, 4]);
510 }
511
512 #[test]
513 fn select_range_cond_invalid() {
514 let ops = &[
515 Stack::Push(4).into(),
516 Stack::Push(5).into(),
517 Stack::Push(1).into(), Stack::Push(42).into(), Stack::SelectRange.into(),
520 ];
521 match exec_ops(ops, *test_access()) {
522 Err(ExecSyncError(4, OpSyncError::Stack(StackError::InvalidCondition(42)))) => (),
523 _ => panic!("expected invalid condition stack error"),
524 }
525 }
526
527 #[test]
528 fn select_range_len_0() {
529 let ops = &[
530 Stack::Push(4).into(),
531 Stack::Push(5).into(),
532 Stack::Push(0).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
535 ];
536 let stack = exec_ops(ops, *test_access()).unwrap();
537 assert_eq!(&stack[..], &[4, 5]);
538 }
539
540 #[test]
541 fn select_range_len_negative() {
542 let ops = &[
543 Stack::Push(-42).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
546 ];
547 match exec_ops(ops, *test_access()) {
548 Err(ExecSyncError(2, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
549 _ => panic!("expected index out of bounds stack error"),
550 }
551 }
552
553 #[test]
554 fn select_range_len_too_big() {
555 let ops = &[
556 Stack::Push(4).into(),
557 Stack::Push(4).into(),
558 Stack::Push(5).into(),
559 Stack::Push(2).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
562 ];
563 match exec_ops(ops, *test_access()) {
564 Err(ExecSyncError(5, OpSyncError::Stack(StackError::IndexOutOfBounds))) => (),
565 _ => panic!("expected index out of bounds stack error"),
566 }
567 }
568}