charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
//! Instructions decoder.

use super::config::*;
use super::instruction::*;
use crate::error::Result;
use std::collections::HashSet;

pub(crate) mod decoder;

/// Main decoder object.
#[derive(Clone, Debug)]
pub struct Decoder<'a> {
    pub(crate) data: &'a [u8],
    pub(crate) config: Config,
    pub(crate) block_decoding: bool,
    pub(crate) pc: u64,
    pub(crate) labels: HashSet<u64>,
}

impl<'a> Decoder<'a> {
    /// Creates a new decoder.
    pub fn new(data: &'a [u8], config: Config) -> Self {
        Self {
            data,
            config,
            block_decoding: false,
            pc: 0,
            labels: HashSet::new(),
        }
    }

    /// Decodes one instruction.
    pub fn decode(&mut self) -> Result<Instruction> {
        let mut instruction = decoder::decode(self)?;
        instruction.pc = self.pc;
        self.pc += instruction.size as u64;
        Ok(instruction)
    }

    /// Decodes an instruction block.
    pub fn decode_block(&mut self, pc: u64) -> Result<InstructionBlock> {
        self.pc = pc;
        self.labels.clear();
        self.block_decoding = true;
        let mut block = InstructionBlock::new(pc);
        while !self.data.is_empty() {
            block.push_instruction(self.decode()?);
        }
        self.block_decoding = false;

        let instructions = block
            .instructions
            .into_iter()
            .fold(vec![], |mut v, element| match element {
                InstructionBlockElement::Label(_) => unreachable!(),
                InstructionBlockElement::Instruction(i) => {
                    if self.labels.contains(&i.pc) {
                        v.push(InstructionBlockElement::Label(i.pc as u64));
                    }
                    v.push(element);
                    v
                }
            });

        Ok(InstructionBlock::with_instructions(pc, instructions))
    }
}