1 //! TrueType bytecode interpreter. 2 3 mod arith; 4 mod graphics_state; 5 mod logical; 6 mod stack; 7 8 use super::{ 9 code_state::ProgramKind, error::HintErrorKind, graphics_state::GraphicsState, 10 value_stack::ValueStack, 11 }; 12 13 pub type OpResult = Result<(), HintErrorKind>; 14 15 /// TrueType bytecode interpreter. 16 pub struct Engine<'a> { 17 graphics_state: GraphicsState<'a>, 18 value_stack: ValueStack<'a>, 19 initial_program: ProgramKind, 20 } 21 22 #[cfg(test)] 23 use mock::MockEngine; 24 25 #[cfg(test)] 26 mod mock { 27 use super::{Engine, GraphicsState, ProgramKind, ValueStack}; 28 29 /// Mock engine for testing. 30 pub(super) struct MockEngine { 31 value_stack: Vec<i32>, 32 } 33 34 impl MockEngine { new() -> Self35 pub fn new() -> Self { 36 Self { 37 value_stack: vec![0; 32], 38 } 39 } 40 engine(&mut self) -> Engine41 pub fn engine(&mut self) -> Engine { 42 Engine { 43 graphics_state: GraphicsState::default(), 44 value_stack: ValueStack::new(&mut self.value_stack), 45 initial_program: ProgramKind::Font, 46 } 47 } 48 } 49 50 impl Default for MockEngine { default() -> Self51 fn default() -> Self { 52 Self::new() 53 } 54 } 55 56 impl<'a> Engine<'a> { 57 /// Helper to push values to the stack, invoke a callback and check 58 /// the expected result. test_exec( &mut self, push: &[i32], expected_result: impl Into<i32>, mut f: impl FnMut(&mut Engine), )59 pub(super) fn test_exec( 60 &mut self, 61 push: &[i32], 62 expected_result: impl Into<i32>, 63 mut f: impl FnMut(&mut Engine), 64 ) { 65 for &val in push { 66 self.value_stack.push(val).unwrap(); 67 } 68 f(self); 69 assert_eq!(self.value_stack.pop().ok(), Some(expected_result.into())); 70 } 71 } 72 } 73