1use std::collections::HashMap;
4
5use crate::compact1::number::Number;
6use crate::Result;
7
8pub type Operand = Number;
10
11#[derive(Clone, Debug, Default)]
13pub struct Operations(pub HashMap<Operator, Vec<Operand>>);
14
15struct Operation(Operator, Vec<Operand>);
16
17impl Operations {
18 #[inline]
20 pub fn get(&self, operator: Operator) -> Option<&[Operand]> {
21 match self.0.get(&operator) {
22 Some(operands) => Some(operands),
23 _ => operator.default(),
24 }
25 }
26
27 #[doc(hidden)]
28 #[inline]
29 pub fn get_single(&self, operator: Operator) -> Option<Operand> {
30 self.get(operator).and_then(|operands| {
31 if !operands.is_empty() {
32 Some(operands[0])
33 } else {
34 None
35 }
36 })
37 }
38
39 #[doc(hidden)]
40 #[inline]
41 pub fn get_double(&self, operator: Operator) -> Option<(Operand, Operand)> {
42 self.get(operator).and_then(|operands| {
43 if operands.len() > 1 {
44 Some((operands[0], operands[1]))
45 } else {
46 None
47 }
48 })
49 }
50}
51
52impl crate::value::Read for Operations {
53 fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
54 use std::io::ErrorKind;
55
56 let mut operations = HashMap::new();
57 loop {
58 match tape.take() {
59 Ok(Operation(operator, operands)) => {
60 operations.insert(operator, operands);
61 }
62 Err(error) => {
63 if error.kind() == ErrorKind::UnexpectedEof {
64 return Ok(Operations(operations));
65 } else {
66 return Err(error);
67 }
68 }
69 }
70 }
71 }
72}
73
74dereference! { Operations::0 => HashMap<Operator, Vec<Operand>> }
75
76impl crate::value::Read for Operation {
77 fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
78 let mut operands = vec![];
79 loop {
80 match tape.peek::<u8>()? {
81 0x1c | 0x1d | 0x1e | 0x20..=0xfe => operands.push(tape.take()?),
82 code => {
83 let code = if code == 0x0c {
84 tape.take::<u16>()?
85 } else {
86 tape.take::<u8>()? as u16
87 };
88 return Ok(Self(Operator::from(code)?, operands));
89 }
90 }
91 }
92 }
93}
94
95macro_rules! default(
96 ([$($operand:expr),+ $(,)?]) => ({
97 const OPERANDS: &'static [Operand] = &[$($operand),+];
98 Some(OPERANDS)
99 });
100 ([]) => (None);
101);
102
103macro_rules! operator {
104 (pub $name:ident { $($code:pat => $variant:ident $default:tt,)+ }) => (
105 operator! { @define pub $name { $($variant,)+ } }
106 operator! { @implement pub $name { $($code => $variant $default,)+ } }
107 );
108 (@define pub $name:ident { $($variant:ident,)* }) => (
109 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
111 pub enum $name { $($variant,)* }
112 );
113 (@implement pub $name:ident { $($code:pat => $variant:ident $default:tt,)* }) => (impl $name {
114 #[doc(hidden)]
115 pub fn from(code: u16) -> Result<Self> {
116 use self::$name::*;
117
118 Ok(match code {
119 $($code => $variant,)+
120 code => raise!("found an unknown operator ({code})"),
121 })
122 }
123
124 pub fn default(&self) -> Option<&'static [Operand]> {
126 use self::$name::*;
127
128 match *self {
129 $($variant => default!($default),)+
130 }
131 }
132 });
133}
134
135operator! {
136 pub Operator {
137 0x00 => Version [],
138 0x01 => Notice [],
139 0x02 => FullName [],
140 0x03 => FamilyName [],
141 0x04 => Weight [],
142 0x05 => FontBBox [
143 Number::Integer(0),
144 Number::Integer(0),
145 Number::Integer(0),
146 Number::Integer(0),
147 ],
148 0x06 => BlueValues [],
149 0x07 => OtherBlues [],
150 0x08 => FamilyBlues [],
151 0x09 => FamilyOtherBlues [],
152 0x0a => StdHW [],
153 0x0b => StdVW [],
154 0x0d => UniqueID [],
156 0x0e => XUID [],
157 0x0f => CharSet [Number::Integer(0)],
158 0x10 => Encoding [Number::Integer(0)],
159 0x11 => CharStrings [],
160 0x12 => Private [],
161 0x13 => Subrs [],
162 0x14 => DefaultWidthX [Number::Integer(0)],
163 0x15 => NominalWidthX [Number::Integer(0)],
164 0x0c00 => Copyright [],
173 0x0c01 => IsFixedPitch [Number::Integer(false as i32)],
174 0x0c02 => ItalicAngle [Number::Integer(0)],
175 0x0c03 => UnderlinePosition [Number::Integer(-100)],
176 0x0c04 => UnderlineThickness [Number::Integer(50)],
177 0x0c05 => PaintType [Number::Integer(0)],
178 0x0c06 => CharStringType [Number::Integer(2)],
179 0x0c07 => FontMatrix [
180 Number::Real(0.001),
181 Number::Real(0.0),
182 Number::Real(0.0),
183 Number::Real(0.001),
184 Number::Real(0.0),
185 Number::Real(0.0),
186 ],
187 0x0c08 => StrokeWidth [Number::Integer(0)],
188 0x0c09 => BlueScale [Number::Real(0.039625)],
189 0x0c0a => BlueShift [Number::Integer(7)],
190 0x0c0b => BlueFuzz [Number::Integer(1)],
191 0x0c0c => StemSnapH [],
192 0x0c0d => StemSnapV [],
193 0x0c0e => ForceBold [Number::Integer(false as i32)],
194 0x0c11 => LanguageGroup [Number::Integer(0)],
196 0x0c12 => ExpansionFactor [Number::Real(0.06)],
197 0x0c13 => InitialRandomSeed [Number::Integer(0)],
198 0x0c14 => SyntheticBase [],
199 0x0c15 => PostScript [],
200 0x0c16 => BaseFontName [],
201 0x0c17 => BaseFontBlend [],
202 0x0c1e => ROS [],
204 0x0c1f => CIDFontVersion [Number::Integer(0)],
205 0x0c20 => CIDFontRevision [Number::Integer(0)],
206 0x0c21 => CIDFontType [Number::Integer(0)],
207 0x0c22 => CIDCount [Number::Integer(8720)],
208 0x0c23 => UIDBase [],
209 0x0c24 => FDArray [],
210 0x0c25 => FDSelect [],
211 0x0c26 => FontName [],
212 }
214}