1 //! Value stack for TrueType interpreter.
2 
3 use super::{code_state::Args, error::HintErrorKind};
4 
5 use HintErrorKind::{ValueStackOverflow, ValueStackUnderflow};
6 
7 /// Value stack for the TrueType interpreter.
8 ///
9 /// This uses a slice as the backing store rather than a `Vec` to enable
10 /// support for allocation from user buffers.
11 ///
12 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#managing-the-stack>
13 pub struct ValueStack<'a> {
14     values: &'a mut [i32],
15     top: usize,
16 }
17 
18 impl<'a> ValueStack<'a> {
new(values: &'a mut [i32]) -> Self19     pub fn new(values: &'a mut [i32]) -> Self {
20         Self { values, top: 0 }
21     }
22 
23     /// Returns the depth of the stack
24     /// <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#returns-the-depth-of-the-stack>
len(&self) -> usize25     pub fn len(&self) -> usize {
26         self.top
27     }
28 
is_empty(&self) -> bool29     pub fn is_empty(&self) -> bool {
30         self.top == 0
31     }
32 
values(&self) -> &[i32]33     pub fn values(&self) -> &[i32] {
34         &self.values[..self.top]
35     }
36 
push(&mut self, value: i32) -> Result<(), HintErrorKind>37     pub fn push(&mut self, value: i32) -> Result<(), HintErrorKind> {
38         let ptr = self
39             .values
40             .get_mut(self.top)
41             .ok_or(HintErrorKind::ValueStackOverflow)?;
42         *ptr = value;
43         self.top += 1;
44         Ok(())
45     }
46 
47     /// Pushes values that have been decoded from the instruction stream
48     /// onto the stack.
49     ///
50     /// Implements the PUSHB[], PUSHW[], NPUSHB[] and NPUSHW[] instructions.
51     ///
52     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#pushing-data-onto-the-interpreter-stack>
push_args(&mut self, args: &Args) -> Result<(), HintErrorKind>53     pub fn push_args(&mut self, args: &Args) -> Result<(), HintErrorKind> {
54         let push_count = args.len();
55         let stack_base = self.top;
56         for (stack_value, value) in self
57             .values
58             .get_mut(stack_base..stack_base + push_count)
59             .ok_or(ValueStackOverflow)?
60             .iter_mut()
61             .zip(args.values())
62         {
63             *stack_value = value;
64         }
65         self.top += push_count;
66         Ok(())
67     }
68 
peek(&mut self) -> Option<i32>69     pub fn peek(&mut self) -> Option<i32> {
70         if self.top > 0 {
71             self.values.get(self.top - 1).copied()
72         } else {
73             None
74         }
75     }
76 
77     /// Pops a value from the stack.
78     ///
79     /// Implements the POP[] instruction.
80     ///
81     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#pop-top-stack-element>
pop(&mut self) -> Result<i32, HintErrorKind>82     pub fn pop(&mut self) -> Result<i32, HintErrorKind> {
83         let value = self.peek().ok_or(ValueStackUnderflow)?;
84         self.top -= 1;
85         Ok(value)
86     }
87 
88     /// Convenience method for instructions that pop values that are used as an
89     /// index.
pop_usize(&mut self) -> Result<usize, HintErrorKind>90     pub fn pop_usize(&mut self) -> Result<usize, HintErrorKind> {
91         Ok(self.pop()? as usize)
92     }
93 
94     /// Applies a unary operation.
95     ///
96     /// Pops `a` from the stack and pushes `op(a)`.
apply_unary( &mut self, mut op: impl FnMut(i32) -> Result<i32, HintErrorKind>, ) -> Result<(), HintErrorKind>97     pub fn apply_unary(
98         &mut self,
99         mut op: impl FnMut(i32) -> Result<i32, HintErrorKind>,
100     ) -> Result<(), HintErrorKind> {
101         let a = self.pop()?;
102         self.push(op(a)?)
103     }
104 
105     /// Applies a binary operation.
106     ///
107     /// Pops `b` and `a` from the stack and pushes `op(a, b)`.
apply_binary( &mut self, mut op: impl FnMut(i32, i32) -> Result<i32, HintErrorKind>, ) -> Result<(), HintErrorKind>108     pub fn apply_binary(
109         &mut self,
110         mut op: impl FnMut(i32, i32) -> Result<i32, HintErrorKind>,
111     ) -> Result<(), HintErrorKind> {
112         let b = self.pop()?;
113         let a = self.pop()?;
114         self.push(op(a, b)?)
115     }
116 
117     /// Clear the entire stack.
118     ///
119     /// Implements the CLEAR[] instruction.
120     ///
121     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#clear-the-entire-stack>
clear(&mut self)122     pub fn clear(&mut self) {
123         self.top = 0;
124     }
125 
126     /// Duplicate top stack element.
127     ///
128     /// Implements the DUP[] instruction.
129     ///
130     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#duplicate-top-stack-element>
dup(&mut self) -> Result<(), HintErrorKind>131     pub fn dup(&mut self) -> Result<(), HintErrorKind> {
132         let value = self.peek().ok_or(ValueStackUnderflow)?;
133         self.push(value)
134     }
135 
136     /// Swap the top two elements on the stack.
137     ///
138     /// Implements the SWAP[] instruction.
139     ///
140     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#swap-the-top-two-elements-on-the-stack>
swap(&mut self) -> Result<(), HintErrorKind>141     pub fn swap(&mut self) -> Result<(), HintErrorKind> {
142         let a = self.pop()?;
143         let b = self.pop()?;
144         self.push(a)?;
145         self.push(b)
146     }
147 
148     /// Copy the indexed element to the top of the stack.
149     ///
150     /// Implements the CINDEX[] instruction.
151     ///
152     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#copy-the-indexed-element-to-the-top-of-the-stack>
copy_index(&mut self) -> Result<(), HintErrorKind>153     pub fn copy_index(&mut self) -> Result<(), HintErrorKind> {
154         let top_ix = self.top.checked_sub(1).ok_or(ValueStackUnderflow)?;
155         let index = *self.values.get(top_ix).ok_or(ValueStackUnderflow)? as usize;
156         let element_ix = top_ix.checked_sub(index).ok_or(ValueStackUnderflow)?;
157         self.values[top_ix] = self.values[element_ix];
158         Ok(())
159     }
160 
161     /// Moves the indexed element to the top of the stack.
162     ///
163     /// Implements the MINDEX[] instruction.
164     ///
165     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#move-the-indexed-element-to-the-top-of-the-stack>
move_index(&mut self) -> Result<(), HintErrorKind>166     pub fn move_index(&mut self) -> Result<(), HintErrorKind> {
167         let top_ix = self.top.checked_sub(1).ok_or(ValueStackUnderflow)?;
168         let index = *self.values.get(top_ix).ok_or(ValueStackUnderflow)? as usize;
169         let element_ix = top_ix.checked_sub(index).ok_or(ValueStackUnderflow)?;
170         let value = self.values[element_ix];
171         self.values
172             .copy_within(element_ix + 1..self.top, element_ix);
173         self.values[top_ix - 1] = value;
174         self.top -= 1;
175         Ok(())
176     }
177 
178     /// Roll the top three stack elements.
179     ///
180     /// Implements the ROLL[] instruction.
181     ///
182     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#roll-the-top-three-stack-elements>
roll(&mut self) -> Result<(), HintErrorKind>183     pub fn roll(&mut self) -> Result<(), HintErrorKind> {
184         let a = self.pop()?;
185         let b = self.pop()?;
186         let c = self.pop()?;
187         self.push(b)?;
188         self.push(a)?;
189         self.push(c)?;
190         Ok(())
191     }
192 
get(&mut self, index: usize) -> Option<i32>193     fn get(&mut self, index: usize) -> Option<i32> {
194         self.values.get(index).copied()
195     }
196 
get_mut(&mut self, index: usize) -> Option<&mut i32>197     fn get_mut(&mut self, index: usize) -> Option<&mut i32> {
198         self.values.get_mut(index)
199     }
200 }
201 
202 #[cfg(test)]
203 mod tests {
204     use super::{super::code_state::MockArgs, HintErrorKind, ValueStack};
205 
206     // The following are macros because functions can't return a new ValueStack
207     // with a borrowed parameter.
208     macro_rules! make_stack {
209         ($values:expr) => {
210             ValueStack {
211                 values: $values,
212                 top: $values.len(),
213             }
214         };
215     }
216     macro_rules! make_empty_stack {
217         ($values:expr) => {
218             ValueStack {
219                 values: $values,
220                 top: 0,
221             }
222         };
223     }
224 
225     #[test]
push()226     fn push() {
227         let mut stack = make_empty_stack!(&mut [0; 4]);
228         for i in 0..4 {
229             stack.push(i).unwrap();
230             assert_eq!(stack.peek(), Some(i));
231         }
232         assert!(matches!(
233             stack.push(0),
234             Err(HintErrorKind::ValueStackOverflow)
235         ));
236     }
237 
238     #[test]
push_args()239     fn push_args() {
240         let mut stack = make_empty_stack!(&mut [0; 32]);
241         let values = [-5, 2, 2845, 92, -26, 42, i16::MIN, i16::MAX];
242         let mock_args = MockArgs::from_words(&values);
243         stack.push_args(&mock_args.args()).unwrap();
244         let mut popped = vec![];
245         while !stack.is_empty() {
246             popped.push(stack.pop().unwrap());
247         }
248         assert!(values
249             .iter()
250             .rev()
251             .map(|x| *x as i32)
252             .eq(popped.iter().copied()));
253     }
254 
255     #[test]
pop()256     fn pop() {
257         let mut stack = make_stack!(&mut [0, 1, 2, 3]);
258         for i in (0..4).rev() {
259             assert_eq!(stack.pop().ok(), Some(i));
260         }
261         assert!(matches!(
262             stack.pop(),
263             Err(HintErrorKind::ValueStackUnderflow)
264         ));
265     }
266 
267     #[test]
dup()268     fn dup() {
269         let mut stack = make_stack!(&mut [1, 2, 3, 0]);
270         // pop extra element so we have room for dup
271         stack.pop().unwrap();
272         stack.dup().unwrap();
273         assert_eq!(stack.values(), &[1, 2, 3, 3]);
274     }
275 
276     #[test]
swap()277     fn swap() {
278         let mut stack = make_stack!(&mut [1, 2, 3]);
279         stack.swap().unwrap();
280         assert_eq!(stack.values(), &[1, 3, 2]);
281     }
282 
283     #[test]
copy_index()284     fn copy_index() {
285         let mut stack = make_stack!(&mut [4, 10, 2, 1, 3]);
286         stack.copy_index().unwrap();
287         assert_eq!(stack.values(), &[4, 10, 2, 1, 10]);
288     }
289 
290     #[test]
move_index()291     fn move_index() {
292         let mut stack = make_stack!(&mut [4, 10, 2, 1, 3]);
293         stack.move_index().unwrap();
294         assert_eq!(stack.values(), &[4, 2, 1, 10]);
295     }
296 
297     #[test]
roll()298     fn roll() {
299         let mut stack = make_stack!(&mut [1, 2, 3]);
300         stack.roll().unwrap();
301         assert_eq!(stack.values(), &[2, 3, 1]);
302     }
303 
304     #[test]
unnop()305     fn unnop() {
306         let mut stack = make_stack!(&mut [42]);
307         stack.apply_unary(|a| Ok(-a)).unwrap();
308         assert_eq!(stack.peek(), Some(-42));
309         stack.apply_unary(|a| Ok(!a)).unwrap();
310         assert_eq!(stack.peek(), Some(!-42));
311     }
312 
313     #[test]
binop()314     fn binop() {
315         let mut stack = make_empty_stack!(&mut [0; 32]);
316         for value in 1..=5 {
317             stack.push(value).unwrap();
318         }
319         stack.apply_binary(|a, b| Ok(a + b)).unwrap();
320         assert_eq!(stack.peek(), Some(9));
321         stack.apply_binary(|a, b| Ok(a * b)).unwrap();
322         assert_eq!(stack.peek(), Some(27));
323         stack.apply_binary(|a, b| Ok(a - b)).unwrap();
324         assert_eq!(stack.peek(), Some(-25));
325         stack.apply_binary(|a, b| Ok(a / b)).unwrap();
326         assert_eq!(stack.peek(), Some(0));
327     }
328 }
329