//! TrueType hinting opcodes.

/// Operation code for a TrueType instruction.
///
/// See [the TrueType instruction set](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions)
/// from the OpenType specification for more detail.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u8)]
pub enum Opcode {
    SVTCA0 = 0x00,
    SVTCA1 = 0x01,
    SPVTCA0 = 0x02,
    SPVTCA1 = 0x03,
    SFVTCA0 = 0x04,
    SFVTCA1 = 0x05,
    SPVTL0 = 0x06,
    SPVTL1 = 0x07,
    SFVTL0 = 0x08,
    SFVTL1 = 0x09,
    SPVFS = 0x0A,
    SFVFS = 0x0B,
    GPV = 0x0C,
    GFV = 0x0D,
    SFVTPV = 0x0E,
    ISECT = 0x0F,
    SRP0 = 0x10,
    SRP1 = 0x11,
    SRP2 = 0x12,
    SZP0 = 0x13,
    SZP1 = 0x14,
    SZP2 = 0x15,
    SZPS = 0x16,
    SLOOP = 0x17,
    RTG = 0x18,
    RTHG = 0x19,
    SMD = 0x1A,
    ELSE = 0x1B,
    JMPR = 0x1C,
    SCVTCI = 0x1D,
    SSWCI = 0x1E,
    SSW = 0x1F,
    DUP = 0x20,
    POP = 0x21,
    CLEAR = 0x22,
    SWAP = 0x23,
    DEPTH = 0x24,
    CINDEX = 0x25,
    MINDEX = 0x26,
    ALIGNPTS = 0x27,
    INS28 = 0x28,
    UTP = 0x29,
    LOOPCALL = 0x2A,
    CALL = 0x2B,
    FDEF = 0x2C,
    ENDF = 0x2D,
    MDAP0 = 0x2E,
    MDAP1 = 0x2F,
    IUP0 = 0x30,
    IUP1 = 0x31,
    SHP0 = 0x32,
    SHP1 = 0x33,
    SHC0 = 0x34,
    SHC1 = 0x35,
    SHZ0 = 0x36,
    SHZ1 = 0x37,
    SHPIX = 0x38,
    IP = 0x39,
    MSIRP0 = 0x3A,
    MSIRP1 = 0x3B,
    ALIGNRP = 0x3C,
    RTDG = 0x3D,
    MIAP0 = 0x3E,
    MIAP1 = 0x3F,
    NPUSHB = 0x40,
    NPUSHW = 0x41,
    WS = 0x42,
    RS = 0x43,
    WCVTP = 0x44,
    RCVT = 0x45,
    GC0 = 0x46,
    GC1 = 0x47,
    SCFS = 0x48,
    MD0 = 0x49,
    MD1 = 0x4A,
    MPPEM = 0x4B,
    MPS = 0x4C,
    FLIPON = 0x4D,
    FLIPOFF = 0x4E,
    DEBUG = 0x4F,
    LT = 0x50,
    LTEQ = 0x51,
    GT = 0x52,
    GTEQ = 0x53,
    EQ = 0x54,
    NEQ = 0x55,
    ODD = 0x56,
    EVEN = 0x57,
    IF = 0x58,
    EIF = 0x59,
    AND = 0x5A,
    OR = 0x5B,
    NOT = 0x5C,
    DELTAP1 = 0x5D,
    SDB = 0x5E,
    SDS = 0x5F,
    ADD = 0x60,
    SUB = 0x61,
    DIV = 0x62,
    MUL = 0x63,
    ABS = 0x64,
    NEG = 0x65,
    FLOOR = 0x66,
    CEILING = 0x67,
    ROUND00 = 0x68,
    ROUND01 = 0x69,
    ROUND10 = 0x6A,
    ROUND11 = 0x6B,
    NROUND00 = 0x6C,
    NROUND01 = 0x6D,
    NROUND10 = 0x6E,
    NROUND11 = 0x6F,
    WCVTF = 0x70,
    DELTAP2 = 0x71,
    DELTAP3 = 0x72,
    DELTAC1 = 0x73,
    DELTAC2 = 0x74,
    DELTAC3 = 0x75,
    SROUND = 0x76,
    S45ROUND = 0x77,
    JROT = 0x78,
    JROF = 0x79,
    ROFF = 0x7A,
    INS7B = 0x7B,
    RUTG = 0x7C,
    RDTG = 0x7D,
    SANGW = 0x7E,
    AA = 0x7F,
    FLIPPT = 0x80,
    FLIPRGON = 0x81,
    FLIPRGOFF = 0x82,
    INS83 = 0x83,
    INS84 = 0x84,
    SCANCTRL = 0x85,
    SDPVTL0 = 0x86,
    SDPVTL1 = 0x87,
    GETINFO = 0x88,
    IDEF = 0x89,
    ROLL = 0x8A,
    MAX = 0x8B,
    MIN = 0x8C,
    SCANTYPE = 0x8D,
    INSTCTRL = 0x8E,
    INS8F = 0x8F,
    INS90 = 0x90,
    GETVARIATION = 0x91,
    GETDATA = 0x92,
    INS93 = 0x93,
    INS94 = 0x94,
    INS95 = 0x95,
    INS96 = 0x96,
    INS97 = 0x97,
    INS98 = 0x98,
    INS99 = 0x99,
    INS9A = 0x9A,
    INS9B = 0x9B,
    INS9C = 0x9C,
    INS9D = 0x9D,
    INS9E = 0x9E,
    INS9F = 0x9F,
    INSA0 = 0xA0,
    INSA1 = 0xA1,
    INSA2 = 0xA2,
    INSA3 = 0xA3,
    INSA4 = 0xA4,
    INSA5 = 0xA5,
    INSA6 = 0xA6,
    INSA7 = 0xA7,
    INSA8 = 0xA8,
    INSA9 = 0xA9,
    INSAA = 0xAA,
    INSAB = 0xAB,
    INSAC = 0xAC,
    INSAD = 0xAD,
    INSAE = 0xAE,
    INSAF = 0xAF,
    PUSHB000 = 0xB0,
    PUSHB001 = 0xB1,
    PUSHB010 = 0xB2,
    PUSHB011 = 0xB3,
    PUSHB100 = 0xB4,
    PUSHB101 = 0xB5,
    PUSHB110 = 0xB6,
    PUSHB111 = 0xB7,
    PUSHW000 = 0xB8,
    PUSHW001 = 0xB9,
    PUSHW010 = 0xBA,
    PUSHW011 = 0xBB,
    PUSHW100 = 0xBC,
    PUSHW101 = 0xBD,
    PUSHW110 = 0xBE,
    PUSHW111 = 0xBF,
    MDRP00000 = 0xC0,
    MDRP00001 = 0xC1,
    MDRP00010 = 0xC2,
    MDRP00011 = 0xC3,
    MDRP00100 = 0xC4,
    MDRP00101 = 0xC5,
    MDRP00110 = 0xC6,
    MDRP00111 = 0xC7,
    MDRP01000 = 0xC8,
    MDRP01001 = 0xC9,
    MDRP01010 = 0xCA,
    MDRP01011 = 0xCB,
    MDRP01100 = 0xCC,
    MDRP01101 = 0xCD,
    MDRP01110 = 0xCE,
    MDRP01111 = 0xCF,
    MDRP10000 = 0xD0,
    MDRP10001 = 0xD1,
    MDRP10010 = 0xD2,
    MDRP10011 = 0xD3,
    MDRP10100 = 0xD4,
    MDRP10101 = 0xD5,
    MDRP10110 = 0xD6,
    MDRP10111 = 0xD7,
    MDRP11000 = 0xD8,
    MDRP11001 = 0xD9,
    MDRP11010 = 0xDA,
    MDRP11011 = 0xDB,
    MDRP11100 = 0xDC,
    MDRP11101 = 0xDD,
    MDRP11110 = 0xDE,
    MDRP11111 = 0xDF,
    MIRP00000 = 0xE0,
    MIRP00001 = 0xE1,
    MIRP00010 = 0xE2,
    MIRP00011 = 0xE3,
    MIRP00100 = 0xE4,
    MIRP00101 = 0xE5,
    MIRP00110 = 0xE6,
    MIRP00111 = 0xE7,
    MIRP01000 = 0xE8,
    MIRP01001 = 0xE9,
    MIRP01010 = 0xEA,
    MIRP01011 = 0xEB,
    MIRP01100 = 0xEC,
    MIRP01101 = 0xED,
    MIRP01110 = 0xEE,
    MIRP01111 = 0xEF,
    MIRP10000 = 0xF0,
    MIRP10001 = 0xF1,
    MIRP10010 = 0xF2,
    MIRP10011 = 0xF3,
    MIRP10100 = 0xF4,
    MIRP10101 = 0xF5,
    MIRP10110 = 0xF6,
    MIRP10111 = 0xF7,
    MIRP11000 = 0xF8,
    MIRP11001 = 0xF9,
    MIRP11010 = 0xFA,
    MIRP11011 = 0xFB,
    MIRP11100 = 0xFC,
    MIRP11101 = 0xFD,
    MIRP11110 = 0xFE,
    MIRP11111 = 0xFF,
}

impl Opcode {
    /// Creates an opcode from the given byte.
    ///
    /// There is a 1:1 mapping between bytes and opcodes.
    #[inline]
    pub fn from_byte(byte: u8) -> Self {
        use Opcode::*;
        match byte {
            0x00 => SVTCA0,
            0x01 => SVTCA1,
            0x02 => SPVTCA0,
            0x03 => SPVTCA1,
            0x04 => SFVTCA0,
            0x05 => SFVTCA1,
            0x06 => SPVTL0,
            0x07 => SPVTL1,
            0x08 => SFVTL0,
            0x09 => SFVTL1,
            0x0A => SPVFS,
            0x0B => SFVFS,
            0x0C => GPV,
            0x0D => GFV,
            0x0E => SFVTPV,
            0x0F => ISECT,
            0x10 => SRP0,
            0x11 => SRP1,
            0x12 => SRP2,
            0x13 => SZP0,
            0x14 => SZP1,
            0x15 => SZP2,
            0x16 => SZPS,
            0x17 => SLOOP,
            0x18 => RTG,
            0x19 => RTHG,
            0x1A => SMD,
            0x1B => ELSE,
            0x1C => JMPR,
            0x1D => SCVTCI,
            0x1E => SSWCI,
            0x1F => SSW,
            0x20 => DUP,
            0x21 => POP,
            0x22 => CLEAR,
            0x23 => SWAP,
            0x24 => DEPTH,
            0x25 => CINDEX,
            0x26 => MINDEX,
            0x27 => ALIGNPTS,
            0x28 => INS28,
            0x29 => UTP,
            0x2A => LOOPCALL,
            0x2B => CALL,
            0x2C => FDEF,
            0x2D => ENDF,
            0x2E => MDAP0,
            0x2F => MDAP1,
            0x30 => IUP0,
            0x31 => IUP1,
            0x32 => SHP0,
            0x33 => SHP1,
            0x34 => SHC0,
            0x35 => SHC1,
            0x36 => SHZ0,
            0x37 => SHZ1,
            0x38 => SHPIX,
            0x39 => IP,
            0x3A => MSIRP0,
            0x3B => MSIRP1,
            0x3C => ALIGNRP,
            0x3D => RTDG,
            0x3E => MIAP0,
            0x3F => MIAP1,
            0x40 => NPUSHB,
            0x41 => NPUSHW,
            0x42 => WS,
            0x43 => RS,
            0x44 => WCVTP,
            0x45 => RCVT,
            0x46 => GC0,
            0x47 => GC1,
            0x48 => SCFS,
            0x49 => MD0,
            0x4A => MD1,
            0x4B => MPPEM,
            0x4C => MPS,
            0x4D => FLIPON,
            0x4E => FLIPOFF,
            0x4F => DEBUG,
            0x50 => LT,
            0x51 => LTEQ,
            0x52 => GT,
            0x53 => GTEQ,
            0x54 => EQ,
            0x55 => NEQ,
            0x56 => ODD,
            0x57 => EVEN,
            0x58 => IF,
            0x59 => EIF,
            0x5A => AND,
            0x5B => OR,
            0x5C => NOT,
            0x5D => DELTAP1,
            0x5E => SDB,
            0x5F => SDS,
            0x60 => ADD,
            0x61 => SUB,
            0x62 => DIV,
            0x63 => MUL,
            0x64 => ABS,
            0x65 => NEG,
            0x66 => FLOOR,
            0x67 => CEILING,
            0x68 => ROUND00,
            0x69 => ROUND01,
            0x6A => ROUND10,
            0x6B => ROUND11,
            0x6C => NROUND00,
            0x6D => NROUND01,
            0x6E => NROUND10,
            0x6F => NROUND11,
            0x70 => WCVTF,
            0x71 => DELTAP2,
            0x72 => DELTAP3,
            0x73 => DELTAC1,
            0x74 => DELTAC2,
            0x75 => DELTAC3,
            0x76 => SROUND,
            0x77 => S45ROUND,
            0x78 => JROT,
            0x79 => JROF,
            0x7A => ROFF,
            0x7B => INS7B,
            0x7C => RUTG,
            0x7D => RDTG,
            0x7E => SANGW,
            0x7F => AA,
            0x80 => FLIPPT,
            0x81 => FLIPRGON,
            0x82 => FLIPRGOFF,
            0x83 => INS83,
            0x84 => INS84,
            0x85 => SCANCTRL,
            0x86 => SDPVTL0,
            0x87 => SDPVTL1,
            0x88 => GETINFO,
            0x89 => IDEF,
            0x8A => ROLL,
            0x8B => MAX,
            0x8C => MIN,
            0x8D => SCANTYPE,
            0x8E => INSTCTRL,
            0x8F => INS8F,
            0x90 => INS90,
            0x91 => GETVARIATION,
            0x92 => GETDATA,
            0x93 => INS93,
            0x94 => INS94,
            0x95 => INS95,
            0x96 => INS96,
            0x97 => INS97,
            0x98 => INS98,
            0x99 => INS99,
            0x9A => INS9A,
            0x9B => INS9B,
            0x9C => INS9C,
            0x9D => INS9D,
            0x9E => INS9E,
            0x9F => INS9F,
            0xA0 => INSA0,
            0xA1 => INSA1,
            0xA2 => INSA2,
            0xA3 => INSA3,
            0xA4 => INSA4,
            0xA5 => INSA5,
            0xA6 => INSA6,
            0xA7 => INSA7,
            0xA8 => INSA8,
            0xA9 => INSA9,
            0xAA => INSAA,
            0xAB => INSAB,
            0xAC => INSAC,
            0xAD => INSAD,
            0xAE => INSAE,
            0xAF => INSAF,
            0xB0 => PUSHB000,
            0xB1 => PUSHB001,
            0xB2 => PUSHB010,
            0xB3 => PUSHB011,
            0xB4 => PUSHB100,
            0xB5 => PUSHB101,
            0xB6 => PUSHB110,
            0xB7 => PUSHB111,
            0xB8 => PUSHW000,
            0xB9 => PUSHW001,
            0xBA => PUSHW010,
            0xBB => PUSHW011,
            0xBC => PUSHW100,
            0xBD => PUSHW101,
            0xBE => PUSHW110,
            0xBF => PUSHW111,
            0xC0 => MDRP00000,
            0xC1 => MDRP00001,
            0xC2 => MDRP00010,
            0xC3 => MDRP00011,
            0xC4 => MDRP00100,
            0xC5 => MDRP00101,
            0xC6 => MDRP00110,
            0xC7 => MDRP00111,
            0xC8 => MDRP01000,
            0xC9 => MDRP01001,
            0xCA => MDRP01010,
            0xCB => MDRP01011,
            0xCC => MDRP01100,
            0xCD => MDRP01101,
            0xCE => MDRP01110,
            0xCF => MDRP01111,
            0xD0 => MDRP10000,
            0xD1 => MDRP10001,
            0xD2 => MDRP10010,
            0xD3 => MDRP10011,
            0xD4 => MDRP10100,
            0xD5 => MDRP10101,
            0xD6 => MDRP10110,
            0xD7 => MDRP10111,
            0xD8 => MDRP11000,
            0xD9 => MDRP11001,
            0xDA => MDRP11010,
            0xDB => MDRP11011,
            0xDC => MDRP11100,
            0xDD => MDRP11101,
            0xDE => MDRP11110,
            0xDF => MDRP11111,
            0xE0 => MIRP00000,
            0xE1 => MIRP00001,
            0xE2 => MIRP00010,
            0xE3 => MIRP00011,
            0xE4 => MIRP00100,
            0xE5 => MIRP00101,
            0xE6 => MIRP00110,
            0xE7 => MIRP00111,
            0xE8 => MIRP01000,
            0xE9 => MIRP01001,
            0xEA => MIRP01010,
            0xEB => MIRP01011,
            0xEC => MIRP01100,
            0xED => MIRP01101,
            0xEE => MIRP01110,
            0xEF => MIRP01111,
            0xF0 => MIRP10000,
            0xF1 => MIRP10001,
            0xF2 => MIRP10010,
            0xF3 => MIRP10011,
            0xF4 => MIRP10100,
            0xF5 => MIRP10101,
            0xF6 => MIRP10110,
            0xF7 => MIRP10111,
            0xF8 => MIRP11000,
            0xF9 => MIRP11001,
            0xFA => MIRP11010,
            0xFB => MIRP11011,
            0xFC => MIRP11100,
            0xFD => MIRP11101,
            0xFE => MIRP11110,
            0xFF => MIRP11111,
        }
    }

    /// Returns a more descriptive name for the opcode.
    pub fn name(self) -> &'static str {
        OPCODE_NAMES[self as usize]
    }

    /// Returns true if this is an instruction that pushes values onto the
    /// stack.
    #[inline]
    pub fn is_push(self) -> bool {
        (self >= Self::PUSHB000 && self <= Self::PUSHW111)
            || self == Self::NPUSHB
            || self == Self::NPUSHW
    }

    pub(super) fn is_push_words(self) -> bool {
        (self >= Self::PUSHW000 && self <= Self::PUSHW111) || self == Self::NPUSHW
    }

    pub(super) fn len(self) -> i32 {
        OPCODE_LENGTHS[self as usize] as i32
    }
}

impl std::fmt::Display for Opcode {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "{}", self.name())
    }
}

/// There doesn't seem to be any prevailing set of mnemonics for these
/// instructions. These are pulled from FreeType with the justification
/// that diffing FreeType hinting traces with our own is the most
/// efficient way to track down discrepancies.
/// <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttinterp.c#L837>
const OPCODE_NAMES: [&str; 256] = [
    "SVTCA[y]",
    "SVTCA[x]",
    "SPVTCA[y]",
    "SPVTCA[x]",
    "SFVTCA[y]",
    "SFVTCA[x]",
    "SPVTL[||]",
    "SPVTL[+]",
    "SFVTL[||]",
    "SFVTL[+]",
    "SPVFS",
    "SFVFS",
    "GPV",
    "GFV",
    "SFVTPV",
    "ISECT",
    "SRP0",
    "SRP1",
    "SRP2",
    "SZP0",
    "SZP1",
    "SZP2",
    "SZPS",
    "SLOOP",
    "RTG",
    "RTHG",
    "SMD",
    "ELSE",
    "JMPR",
    "SCVTCI",
    "SSWCI",
    "SSW",
    "DUP",
    "POP",
    "CLEAR",
    "SWAP",
    "DEPTH",
    "CINDEX",
    "MINDEX",
    "ALIGNPTS",
    "INS_$28",
    "UTP",
    "LOOPCALL",
    "CALL",
    "FDEF",
    "ENDF",
    "MDAP[]",
    "MDAP[rnd]",
    "IUP[y]",
    "IUP[x]",
    "SHP[rp2]",
    "SHP[rp1]",
    "SHC[rp2]",
    "SHC[rp1]",
    "SHZ[rp2]",
    "SHZ[rp1]",
    "SHPIX",
    "IP",
    "MSIRP[]",
    "MSIRP[rp0]",
    "ALIGNRP",
    "RTDG",
    "MIAP[]",
    "MIAP[rnd]",
    "NPUSHB",
    "NPUSHW",
    "WS",
    "RS",
    "WCVTP",
    "RCVT",
    "GC[curr]",
    "GC[orig]",
    "SCFS",
    "MD[curr]",
    "MD[orig]",
    "MPPEM",
    "MPS",
    "FLIPON",
    "FLIPOFF",
    "DEBUG",
    "LT",
    "LTEQ",
    "GT",
    "GTEQ",
    "EQ",
    "NEQ",
    "ODD",
    "EVEN",
    "IF",
    "EIF",
    "AND",
    "OR",
    "NOT",
    "DELTAP1",
    "SDB",
    "SDS",
    "ADD",
    "SUB",
    "DIV",
    "MUL",
    "ABS",
    "NEG",
    "FLOOR",
    "CEILING",
    "ROUND[G]",
    "ROUND[B]",
    "ROUND[W]",
    "ROUND[]",
    "NROUND[G]",
    "NROUND[B]",
    "NROUND[W]",
    "NROUND[]",
    "WCVTF",
    "DELTAP2",
    "DELTAP3",
    "DELTAC1",
    "DELTAC2",
    "DELTAC3",
    "SROUND",
    "S45ROUND",
    "JROT",
    "JROF",
    "ROFF",
    "INS_$7B",
    "RUTG",
    "RDTG",
    "SANGW",
    "AA",
    "FLIPPT",
    "FLIPRGON",
    "FLIPRGOFF",
    "INS_$83",
    "INS_$84",
    "SCANCTRL",
    "SDPVTL[||]",
    "SDPVTL[+]",
    "GETINFO",
    "IDEF",
    "ROLL",
    "MAX",
    "MIN",
    "SCANTYPE",
    "INSTCTRL",
    "INS_$8F",
    "INS_$90",
    "GETVARIATION",
    "GETDATA",
    "INS_$93",
    "INS_$94",
    "INS_$95",
    "INS_$96",
    "INS_$97",
    "INS_$98",
    "INS_$99",
    "INS_$9A",
    "INS_$9B",
    "INS_$9C",
    "INS_$9D",
    "INS_$9E",
    "INS_$9F",
    "INS_$A0",
    "INS_$A1",
    "INS_$A2",
    "INS_$A3",
    "INS_$A4",
    "INS_$A5",
    "INS_$A6",
    "INS_$A7",
    "INS_$A8",
    "INS_$A9",
    "INS_$AA",
    "INS_$AB",
    "INS_$AC",
    "INS_$AD",
    "INS_$AE",
    "INS_$AF",
    "PUSHB[0]",
    "PUSHB[1]",
    "PUSHB[2]",
    "PUSHB[3]",
    "PUSHB[4]",
    "PUSHB[5]",
    "PUSHB[6]",
    "PUSHB[7]",
    "PUSHW[0]",
    "PUSHW[1]",
    "PUSHW[2]",
    "PUSHW[3]",
    "PUSHW[4]",
    "PUSHW[5]",
    "PUSHW[6]",
    "PUSHW[7]",
    "MDRP[G]",
    "MDRP[B]",
    "MDRP[W]",
    "MDRP[]",
    "MDRP[rG]",
    "MDRP[rB]",
    "MDRP[rW]",
    "MDRP[r]",
    "MDRP[mG]",
    "MDRP[mB]",
    "MDRP[mW]",
    "MDRP[m]",
    "MDRP[mrG]",
    "MDRP[mrB]",
    "MDRP[mrW]",
    "MDRP[mr]",
    "MDRP[pG]",
    "MDRP[pB]",
    "MDRP[pW]",
    "MDRP[p]",
    "MDRP[prG]",
    "MDRP[prB]",
    "MDRP[prW]",
    "MDRP[pr]",
    "MDRP[pmG]",
    "MDRP[pmB]",
    "MDRP[pmW]",
    "MDRP[pm]",
    "MDRP[pmrG]",
    "MDRP[pmrB]",
    "MDRP[pmrW]",
    "MDRP[pmr]",
    "MIRP[G]",
    "MIRP[B]",
    "MIRP[W]",
    "MIRP[]",
    "MIRP[rG]",
    "MIRP[rB]",
    "MIRP[rW]",
    "MIRP[r]",
    "MIRP[mG]",
    "MIRP[mB]",
    "MIRP[mW]",
    "MIRP[m]",
    "MIRP[mrG]",
    "MIRP[mrB]",
    "MIRP[mrW]",
    "MIRP[mr]",
    "MIRP[pG]",
    "MIRP[pB]",
    "MIRP[pW]",
    "MIRP[p]",
    "MIRP[prG]",
    "MIRP[prB]",
    "MIRP[prW]",
    "MIRP[pr]",
    "MIRP[pmG]",
    "MIRP[pmB]",
    "MIRP[pmW]",
    "MIRP[pm]",
    "MIRP[pmrG]",
    "MIRP[pmrB]",
    "MIRP[pmrW]",
    "MIRP[pmr]",
];

/// Size in bytes of an instruction.
///
/// The negative values represent variable length instructions where the
/// next byte in the stream is the count of following operands and the
/// absolute value of the length in this table is the size in bytes of
/// each operand. These are just the NPUSHB and NPUSHW instructions.
/// <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttinterp.c#L1137>
const OPCODE_LENGTHS: [i8; 256] = [
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    -1, -2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11, 13,
    15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1,
];
