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}