1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
use crate::{FromBytes, Opcode, ReadResult, ToBytes}; use std::iter::Peekable; use std::slice::Iter; use crate::errors::ReadError; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Instr { ZeroOp(Opcode), OneOp(Opcode, usize), TwoOp(Opcode, usize, usize), } impl Instr { pub fn size_bytes(&self) -> usize { match &self { Self::ZeroOp(_) => 1, Self::OneOp(_, _) => 5, Self::TwoOp(_, _, _) => 9, } } pub fn opcode(&self) -> Opcode { match self { Self::ZeroOp(opcode) => *opcode, Self::OneOp(opcode, _) => *opcode, Self::TwoOp(opcode, _, _) => *opcode, } } } impl ToBytes for Instr { fn to_bytes(&self, buf: &mut Vec<u8>) { match self { Self::ZeroOp(opcode) => { opcode.to_bytes(buf); } Self::OneOp(opcode, operand) => { opcode.to_bytes(buf); (*operand as u32).to_bytes(buf); } Self::TwoOp(opcode, operand1, operand2) => { opcode.to_bytes(buf); (*operand1 as u32).to_bytes(buf); (*operand2 as u32).to_bytes(buf); } } } } impl FromBytes for Instr { fn from_bytes(source: &mut Peekable<Iter<u8>>, debug: bool) -> ReadResult<Self> { let opcode = Opcode::from_bytes(source, debug)?; Ok(match opcode.num_operands() { 0 => Instr::ZeroOp(opcode), 1 => { let op1 = u32::from_bytes(source, debug).map_err(|_| ReadError::OperandReadError)?; Instr::OneOp(opcode, op1 as usize) } _ => { let op1 = u32::from_bytes(source, debug).map_err(|_| ReadError::OperandReadError)?; let op2 = u32::from_bytes(source, debug).map_err(|_| ReadError::OperandReadError)?; Instr::TwoOp(opcode, op1 as usize, op2 as usize) } }) } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_push() { let mnemonic = "push"; let opcode: Opcode = mnemonic.into(); assert_eq!(opcode, Opcode::Push); } #[test] fn write_push() { let instr = Instr::OneOp(Opcode::Push, 1); let mut buf = Vec::with_capacity(4); instr.to_bytes(&mut buf); assert_eq!(buf, vec![0x4e, 0x01, 0x00, 0x00, 0x00]); } }