scriptful/core/stack.rs
1//! An ordered sequence of values that can be operated in a [LIFO]-alike way.
2//!
3//! This module provides the [`Stack`][Stack] struct which in turn is the core of the [`Machine`][Machine] abstraction.
4//!
5//! For more details on [`Stack`][Stack], how it works and which methods does it provide, please go to the [`struct Stack` documentation][Stack].
6//!
7//! [LIFO]: https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
8//! [Stack]: core/stack/struct.Stack.html
9//! [Script]: core/type.Script.html
10//! [Machine]: core/machine/
11
12use alloc::vec::Vec;
13
14use crate::core::value::Value;
15
16/// An ordered sequence of values that can be operated in a [LIFO]-alike way.
17///
18/// Every `Stack` actually comprises two sequences of values: the `main` sub-stack and the `alt` sub-stack.
19///
20/// As its name indicates, the `main` sub-stack is the one you operate by default.
21/// That is, the `alt` sub-stack cannot be operated directly — you can only move values between both sub-stacks with the [`pop_into_alt`][pop_into_alt] and [`push_from_alt`][push_from_alt] methods.
22/// The `alt` sub-stack is therefore limited for usage as a sort of _clipboard_ for values.
23///
24/// [LIFO]: https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
25/// [pop_into_alt]: #method.pop_into_alt
26/// [push_from_alt]: #method.push_from_alt
27#[derive(Debug)]
28pub struct Stack<Val = Value>
29where
30 Val: core::fmt::Debug,
31{
32 main: Vec<Val>,
33 alt: Vec<Val>,
34}
35
36impl<Val> Stack<Val>
37where
38 Val: core::fmt::Debug,
39{
40 /// Returns the number of values in the `main` sub-stack, also referred to as its 'length'.
41 ///
42 /// # Examples
43 ///
44 /// ```rust
45 /// use scriptful::prelude::*;
46 /// use scriptful::core::value::Value::*;
47 ///
48 /// let mut stack = Stack::default();
49 /// assert_eq!(stack.length(), 0);
50 ///
51 /// stack.push(Integer(i128::default()));
52 /// assert_eq!(stack.length(), 1);
53 ///
54 /// stack.pop();
55 /// assert_eq!(stack.length(), 0);
56 /// ```
57 pub fn length(&self) -> usize {
58 self.main.len()
59 }
60
61 /// Removes the topmost value in the `main` sub-stack and returns it.
62 ///
63 /// # Examples
64 ///
65 /// ```rust
66 /// use scriptful::prelude::*;
67 /// use scriptful::core::value::Value::*;
68 ///
69 /// let value = Integer(i128::default());
70 /// let mut stack = Stack::default();
71 /// stack.push(value.clone());
72 /// let popped = stack.pop();
73 ///
74 /// assert_eq!(value, popped);
75 /// ```
76 pub fn pop(&mut self) -> Option<Val> {
77 self.main.pop()
78 }
79
80 /// Similar to [`pop`][pop], but instead of returning the popped value, it pushes it to the `alt` sub-stack.
81 ///
82 /// # Panics
83 /// Panics if there are no values left in the `main` stack.
84 ///
85 /// [pop]: #method.pop
86 pub fn pop_into_alt(&mut self) {
87 self.alt.push(self.main.pop().unwrap())
88 }
89
90 /// Puts a value on top of the stack.
91 ///
92 /// # Examples
93 ///
94 /// ```rust
95 /// use scriptful::prelude::*;
96 /// use scriptful::core::value::Value::*;
97 ///
98 /// let value = Integer(i128::default());
99 /// let mut stack = Stack::default();
100 /// stack.push(value.clone());
101 /// let topmost = stack.topmost();
102 ///
103 /// assert_eq!(topmost, Some(&value));
104 /// ```
105 pub fn push(&mut self, item: Val) {
106 self.main.push(item)
107 }
108
109 /// Similar to [`push`][push], but instead of receiving the value to be pushed as an argument, it pops it from the `alt` sub-stack.
110 ///
111 /// [push]: #method.push
112 pub fn push_from_alt(&mut self) {
113 self.main.push(self.alt.pop().unwrap())
114 }
115
116 /// Returns a reference to the last value in the `main` sub-stack.
117 ///
118 /// # Examples
119 ///
120 /// ```rust
121 /// use scriptful::prelude::*;
122 /// use scriptful::core::value::Value::*;
123 ///
124 /// let value = Integer(i128::default());
125 /// let mut stack = Stack::default();
126 /// stack.push(value.clone());
127 /// let topmost = stack.topmost();
128 ///
129 /// assert_eq!(topmost, Some(&value));
130 /// ```
131 pub fn topmost(&self) -> Option<&Val> {
132 self.main.last()
133 }
134}
135
136impl<Val> core::default::Default for Stack<Val>
137where
138 Val: core::fmt::Debug,
139{
140 fn default() -> Self {
141 Self {
142 main: Default::default(),
143 alt: Default::default(),
144 }
145 }
146}