charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
//! Main instruction objects.

use super::config::*;
use super::consts::*;
use super::formatter::*;
use super::operand::*;
use crate::error::*;

/// Type that represents an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct Instruction {
    //TODO: change visibility
    pub code: Code,
    pub mnemonic: Mnemonic,
    pub pc: u64,
    pub size: usize,
    pub operands: [Operand; MAX_OPERAND_COUNT],
}

impl Instruction {
    /// Instruction builder.
    pub fn builder(code: Code) -> InstructionBuilder {
        let mut instruction = Instruction::default();
        instruction.code = code;
        instruction.mnemonic = code.mnemonic(&instruction);
        instruction.pc = 0;
        instruction.size = code.size(&instruction);
        InstructionBuilder { inner: instruction }
    }

    /// Creates an instruction with no operands.
    pub fn with_0(code: Code) -> Instruction {
        Instruction::builder(code).build()
    }

    /// Creates an instruction with one operand.
    pub fn with_1(code: Code, op0: impl Into<Operand>) -> Result<Instruction> {
        Ok(Instruction::builder(code).op0(op0)?.build())
    }

    /// Creates an instruction with two operands.
    pub fn with_2(
        code: Code,
        op0: impl Into<Operand>,
        op1: impl Into<Operand>,
    ) -> Result<Instruction> {
        Ok(Instruction::builder(code).op0(op0)?.op1(op1)?.build())
    }

    /// Creates an instruction with three operands.
    pub fn with_3(
        code: Code,
        op0: impl Into<Operand>,
        op1: impl Into<Operand>,
        op2: impl Into<Operand>,
    ) -> Result<Instruction> {
        Ok(Instruction::builder(code)
            .op0(op0)?
            .op1(op1)?
            .op2(op2)?
            .build())
    }

    /// Creates an instruction with four operands.
    pub fn with_4(
        code: Code,
        op0: impl Into<Operand>,
        op1: impl Into<Operand>,
        op2: impl Into<Operand>,
        op3: impl Into<Operand>,
    ) -> Result<Instruction> {
        Ok(Instruction::builder(code)
            .op0(op0)?
            .op1(op1)?
            .op2(op2)?
            .op3(op3)?
            .build())
    }

    /// Returns operand #0.
    pub fn op0(&self) -> &Operand {
        &self.operands[0]
    }

    /// Returns operand #1.
    pub fn op1(&self) -> &Operand {
        &self.operands[1]
    }

    /// Returns operand #2.
    pub fn op2(&self) -> &Operand {
        &self.operands[2]
    }

    /// Returns operand #3.
    pub fn op3(&self) -> &Operand {
        &self.operands[3]
    }

    /// Returns operand #4.
    pub fn op4(&self) -> &Operand {
        &self.operands[4]
    }

    /// Sets the operand at `index`.
    pub fn set_op(&mut self, index: usize, operand: impl Into<Operand>) -> Result<()> {
        if index >= MAX_OPERAND_COUNT {
            return Err(OperandError::OperandIndexOutOfRange(
                index,
                MAX_OPERAND_COUNT,
            ))?;
        }
        let operand = operand.into();
        self.code.check_op(index, &self, &operand)?;
        self.operands[index] = operand;
        Ok(())
    }

    /// Formats the instruction.
    pub fn format(
        &self,
        fmt: &mut impl Formatter,
        output: &mut impl FormatterOutput,
        config: &Config,
    ) -> Result<()> {
        self.code.format(self, fmt, output, config)
    }
}

impl Default for Instruction {
    fn default() -> Self {
        Self {
            code: Code::Invalid,
            mnemonic: Mnemonic::Invalid,
            pc: 0,
            size: 0,
            operands: [Operand::default(); MAX_OPERAND_COUNT],
        }
    }
}

/// Type that represents an instruction builder.
pub struct InstructionBuilder {
    inner: Instruction,
}

impl From<Instruction> for InstructionBuilder {
    fn from(value: Instruction) -> Self {
        Self { inner: value }
    }
}

impl InstructionBuilder {
    /// Sets the operand at `index`.
    pub fn operand(mut self, index: usize, operand: impl Into<Operand>) -> Result<Self> {
        if index >= MAX_OPERAND_COUNT {
            return Err(OperandError::OperandIndexOutOfRange(
                index,
                MAX_OPERAND_COUNT,
            ))?;
        }
        let operand = operand.into();
        self.inner.code.check_op(index, &self.inner, &operand)?;
        self.inner.operands[index] = operand;
        Ok(self)
    }

    /// Sets operand #0.
    pub fn op0(self, operand: impl Into<Operand>) -> Result<Self> {
        self.operand(0, operand)
    }

    /// Sets operand #1.
    pub fn op1(self, operand: impl Into<Operand>) -> Result<Self> {
        self.operand(1, operand)
    }

    /// Sets operand #2.
    pub fn op2(self, operand: impl Into<Operand>) -> Result<Self> {
        self.operand(2, operand)
    }

    /// Sets operand #3.
    pub fn op3(self, operand: impl Into<Operand>) -> Result<Self> {
        self.operand(3, operand)
    }

    /// Sets operand #4.
    pub fn op4(self, operand: impl Into<Operand>) -> Result<Self> {
        self.operand(4, operand)
    }

    /// Consumes the builder and creates the instruction.
    pub fn build(self) -> Instruction {
        self.inner
    }
}

/// Type that represents an element of an [`InstructionBlock`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum InstructionBlockElement {
    /// Contains an instruction.
    Instruction(Instruction),
    /// Contains a label.
    Label(u64),
}

impl From<Instruction> for InstructionBlockElement {
    fn from(value: Instruction) -> Self {
        InstructionBlockElement::Instruction(value)
    }
}

impl From<u64> for InstructionBlockElement {
    fn from(value: u64) -> Self {
        InstructionBlockElement::Label(value)
    }
}

/// Type that represents an instruction block, which is a list of consecutive instructions starting
/// from a given address.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct InstructionBlock {
    pub pc: u64,
    pub instructions: Vec<InstructionBlockElement>,
}

impl InstructionBlock {
    /// Creates a new instruction block starting at `pc`.
    pub fn new(pc: u64) -> Self {
        Self {
            pc,
            instructions: vec![],
        }
    }

    /// Creates an instruction block at address `pc` from a vector of instructions.
    pub fn with_instructions(pc: u64, instructions: Vec<InstructionBlockElement>) -> Self {
        Self { pc, instructions }
    }

    /// Adds an instruction to the end of the block.
    pub fn push_instruction(&mut self, instruction: Instruction) {
        self.instructions.push(instruction.into())
    }

    /// Adds a label to the end of the block.
    pub fn push_label(&mut self, label: u64) {
        self.instructions.push(label.into())
    }
}