use super::config::*;
use super::instruction::*;
use crate::error::Result;
use std::collections::HashSet;
pub(crate) mod decoder;
#[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> {
pub fn new(data: &'a [u8], config: Config) -> Self {
Self {
data,
config,
block_decoding: false,
pc: 0,
labels: HashSet::new(),
}
}
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)
}
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))
}
}