use std::collections::HashMap;
use crate::compact1::number::Number;
use crate::Result;
pub type Operand = Number;
#[derive(Clone, Debug, Default)]
pub struct Operations(pub HashMap<Operator, Vec<Operand>>);
struct Operation(Operator, Vec<Operand>);
impl Operations {
#[inline]
pub fn get(&self, operator: Operator) -> Option<&[Operand]> {
match self.0.get(&operator) {
Some(operands) => Some(operands),
_ => operator.default(),
}
}
#[doc(hidden)]
#[inline]
pub fn get_single(&self, operator: Operator) -> Option<Operand> {
self.get(operator).and_then(|operands| {
if !operands.is_empty() {
Some(operands[0])
} else {
None
}
})
}
#[doc(hidden)]
#[inline]
pub fn get_double(&self, operator: Operator) -> Option<(Operand, Operand)> {
self.get(operator).and_then(|operands| {
if operands.len() > 1 {
Some((operands[0], operands[1]))
} else {
None
}
})
}
}
impl crate::value::Read for Operations {
fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
use std::io::ErrorKind;
let mut operations = HashMap::new();
loop {
match tape.take() {
Ok(Operation(operator, operands)) => {
operations.insert(operator, operands);
}
Err(error) => {
if error.kind() == ErrorKind::UnexpectedEof {
return Ok(Operations(operations));
} else {
return Err(error);
}
}
}
}
}
}
dereference! { Operations::0 => HashMap<Operator, Vec<Operand>> }
impl crate::value::Read for Operation {
fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
let mut operands = vec![];
loop {
match tape.peek::<u8>()? {
0x1c | 0x1d | 0x1e | 0x20..=0xfe => operands.push(tape.take()?),
code => {
let code = if code == 0x0c {
tape.take::<u16>()?
} else {
tape.take::<u8>()? as u16
};
return Ok(Self(Operator::from(code)?, operands));
}
}
}
}
}
macro_rules! default(
([$($operand:expr),+ $(,)?]) => ({
const OPERANDS: &'static [Operand] = &[$($operand),+];
Some(OPERANDS)
});
([]) => (None);
);
macro_rules! operator {
(pub $name:ident { $($code:pat => $variant:ident $default:tt,)+ }) => (
operator! { @define pub $name { $($variant,)+ } }
operator! { @implement pub $name { $($code => $variant $default,)+ } }
);
(@define pub $name:ident { $($variant:ident,)* }) => (
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum $name { $($variant,)* }
);
(@implement pub $name:ident { $($code:pat => $variant:ident $default:tt,)* }) => (impl $name {
#[doc(hidden)]
pub fn from(code: u16) -> Result<Self> {
use self::$name::*;
Ok(match code {
$($code => $variant,)+
code => raise!("found an unknown operator ({code})"),
})
}
pub fn default(&self) -> Option<&'static [Operand]> {
use self::$name::*;
match *self {
$($variant => default!($default),)+
}
}
});
}
operator! {
pub Operator {
0x00 => Version [],
0x01 => Notice [],
0x02 => FullName [],
0x03 => FamilyName [],
0x04 => Weight [],
0x05 => FontBBox [
Number::Integer(0),
Number::Integer(0),
Number::Integer(0),
Number::Integer(0),
],
0x06 => BlueValues [],
0x07 => OtherBlues [],
0x08 => FamilyBlues [],
0x09 => FamilyOtherBlues [],
0x0a => StdHW [],
0x0b => StdVW [],
0x0d => UniqueID [],
0x0e => XUID [],
0x0f => CharSet [Number::Integer(0)],
0x10 => Encoding [Number::Integer(0)],
0x11 => CharStrings [],
0x12 => Private [],
0x13 => Subrs [],
0x14 => DefaultWidthX [Number::Integer(0)],
0x15 => NominalWidthX [Number::Integer(0)],
0x0c00 => Copyright [],
0x0c01 => IsFixedPitch [Number::Integer(false as i32)],
0x0c02 => ItalicAngle [Number::Integer(0)],
0x0c03 => UnderlinePosition [Number::Integer(-100)],
0x0c04 => UnderlineThickness [Number::Integer(50)],
0x0c05 => PaintType [Number::Integer(0)],
0x0c06 => CharStringType [Number::Integer(2)],
0x0c07 => FontMatrix [
Number::Real(0.001),
Number::Real(0.0),
Number::Real(0.0),
Number::Real(0.001),
Number::Real(0.0),
Number::Real(0.0),
],
0x0c08 => StrokeWidth [Number::Integer(0)],
0x0c09 => BlueScale [Number::Real(0.039625)],
0x0c0a => BlueShift [Number::Integer(7)],
0x0c0b => BlueFuzz [Number::Integer(1)],
0x0c0c => StemSnapH [],
0x0c0d => StemSnapV [],
0x0c0e => ForceBold [Number::Integer(false as i32)],
0x0c11 => LanguageGroup [Number::Integer(0)],
0x0c12 => ExpansionFactor [Number::Real(0.06)],
0x0c13 => InitialRandomSeed [Number::Integer(0)],
0x0c14 => SyntheticBase [],
0x0c15 => PostScript [],
0x0c16 => BaseFontName [],
0x0c17 => BaseFontBlend [],
0x0c1e => ROS [],
0x0c1f => CIDFontVersion [Number::Integer(0)],
0x0c20 => CIDFontRevision [Number::Integer(0)],
0x0c21 => CIDFontType [Number::Integer(0)],
0x0c22 => CIDCount [Number::Integer(8720)],
0x0c23 => UIDBase [],
0x0c24 => FDArray [],
0x0c25 => FDSelect [],
0x0c26 => FontName [],
}
}