skrifa/outline/glyf/hint/
call_stack.rs
1use super::{definition::Definition, error::HintErrorKind, program::Program};
4
5const MAX_DEPTH: usize = 32;
8
9#[derive(Copy, Clone, Default)]
14pub struct CallRecord {
15 pub caller_program: Program,
16 pub return_pc: usize,
17 pub current_count: u32,
18 pub definition: Definition,
19}
20
21#[derive(Default)]
23pub struct CallStack {
24 records: [CallRecord; MAX_DEPTH],
25 len: usize,
26}
27
28impl CallStack {
29 pub fn clear(&mut self) {
30 self.len = 0;
31 }
32
33 pub fn push(&mut self, record: CallRecord) -> Result<(), HintErrorKind> {
34 let top = self
35 .records
36 .get_mut(self.len)
37 .ok_or(HintErrorKind::CallStackOverflow)?;
38 *top = record;
39 self.len += 1;
40 Ok(())
41 }
42
43 pub fn peek(&self) -> Option<&CallRecord> {
44 self.records.get(self.len.checked_sub(1)?)
45 }
46
47 pub fn pop(&mut self) -> Result<CallRecord, HintErrorKind> {
48 let record = *self.peek().ok_or(HintErrorKind::CallStackUnderflow)?;
49 self.len -= 1;
50 Ok(record)
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn stack_overflow() {
60 let mut stack = CallStack::default();
61 for i in 0..MAX_DEPTH {
62 stack.push(record_with_key(i)).unwrap();
63 }
64 assert!(matches!(
65 stack.push(CallRecord::default()),
66 Err(HintErrorKind::CallStackOverflow)
67 ));
68 }
69
70 #[test]
71 fn stack_underflow() {
72 assert!(matches!(
73 CallStack::default().pop(),
74 Err(HintErrorKind::CallStackUnderflow)
75 ));
76 }
77
78 #[test]
79 fn stack_push_pop() {
80 let mut stack = CallStack::default();
81 for i in 0..MAX_DEPTH {
82 stack.push(record_with_key(i)).unwrap();
83 }
84 for i in (0..MAX_DEPTH).rev() {
85 assert_eq!(stack.pop().unwrap().definition.key(), i as i32);
86 }
87 }
88
89 fn record_with_key(key: usize) -> CallRecord {
90 CallRecord {
91 caller_program: Program::Glyph,
92 return_pc: 0,
93 current_count: 1,
94 definition: Definition::new(Program::Font, 0..0, key as i32),
95 }
96 }
97}