read_fonts/tables/glyf/bytecode/
instruction.rs1use super::Opcode;
3
4#[derive(Copy, Clone, Debug)]
6pub struct Instruction<'a> {
7 pub opcode: Opcode,
9 pub inline_operands: InlineOperands<'a>,
11 pub pc: usize,
14}
15
16impl std::fmt::Display for Instruction<'_> {
17 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
18 write!(f, "{}", self.opcode.name())?;
19 for value in self.inline_operands.values() {
20 write!(f, " {value}")?;
21 }
22 Ok(())
23 }
24}
25
26#[derive(Copy, Clone, Default, Debug)]
30pub struct InlineOperands<'a> {
31 pub(super) bytes: &'a [u8],
32 pub(super) is_words: bool,
33}
34
35impl<'a> InlineOperands<'a> {
36 #[inline]
38 pub fn len(&self) -> usize {
39 if self.is_words {
40 self.bytes.len() / 2
41 } else {
42 self.bytes.len()
43 }
44 }
45
46 pub fn is_empty(&self) -> bool {
48 self.bytes.is_empty()
49 }
50
51 #[inline]
53 pub fn values(&self) -> impl Iterator<Item = i32> + 'a + Clone {
54 let (bytes, words) = if self.is_words {
55 (&[][..], self.bytes)
56 } else {
57 (self.bytes, &[][..])
58 };
59 bytes
60 .iter()
61 .map(|byte| *byte as u32 as i32)
62 .chain(words.chunks_exact(2).map(|chunk| {
63 let word = ((chunk[0] as u16) << 8) | chunk[1] as u16;
64 word as i16 as i32
66 }))
67 }
68}
69
70#[cfg(any(test, feature = "scaler_test"))]
72pub struct MockInlineOperands {
73 bytes: Vec<u8>,
74 is_words: bool,
75}
76
77#[cfg(any(test, feature = "scaler_test"))]
78impl MockInlineOperands {
79 pub fn from_bytes(bytes: &[u8]) -> Self {
80 Self {
81 bytes: bytes.into(),
82 is_words: false,
83 }
84 }
85
86 pub fn from_words(words: &[i16]) -> Self {
87 Self {
88 bytes: words
89 .iter()
90 .map(|word| *word as u16)
91 .flat_map(|word| vec![(word >> 8) as u8, word as u8])
92 .collect(),
93 is_words: true,
94 }
95 }
96
97 pub fn operands(&self) -> InlineOperands {
98 InlineOperands {
99 bytes: &self.bytes,
100 is_words: self.is_words,
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::MockInlineOperands;
108
109 #[test]
110 fn byte_operands() {
111 let values = [5, 2, 85, 92, 26, 42, u8::MIN, u8::MAX];
112 let mock = MockInlineOperands::from_bytes(&values);
113 let decoded = mock.operands().values().collect::<Vec<_>>();
114 assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
115 }
116
117 #[test]
118 fn word_operands() {
119 let values = [-5, 2, 2845, 92, -26, 42, i16::MIN, i16::MAX];
120 let mock = MockInlineOperands::from_words(&values);
121 let decoded = mock.operands().values().collect::<Vec<_>>();
122 assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
123 }
124}