use super::Opcode;
#[derive(Copy, Clone, Debug)]
pub struct Instruction<'a> {
pub opcode: Opcode,
pub inline_operands: InlineOperands<'a>,
pub pc: usize,
}
impl std::fmt::Display for Instruction<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.opcode.name())?;
for value in self.inline_operands.values() {
write!(f, " {value}")?;
}
Ok(())
}
}
#[derive(Copy, Clone, Default, Debug)]
pub struct InlineOperands<'a> {
pub(super) bytes: &'a [u8],
pub(super) is_words: bool,
}
impl<'a> InlineOperands<'a> {
#[inline]
pub fn len(&self) -> usize {
if self.is_words {
self.bytes.len() / 2
} else {
self.bytes.len()
}
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
#[inline]
pub fn values(&self) -> impl Iterator<Item = i32> + 'a + Clone {
let (bytes, words) = if self.is_words {
(&[][..], self.bytes)
} else {
(self.bytes, &[][..])
};
bytes
.iter()
.map(|byte| *byte as u32 as i32)
.chain(words.chunks_exact(2).map(|chunk| {
let word = ((chunk[0] as u16) << 8) | chunk[1] as u16;
word as i16 as i32
}))
}
}
#[cfg(any(test, feature = "scaler_test"))]
pub struct MockInlineOperands {
bytes: Vec<u8>,
is_words: bool,
}
#[cfg(any(test, feature = "scaler_test"))]
impl MockInlineOperands {
pub fn from_bytes(bytes: &[u8]) -> Self {
Self {
bytes: bytes.into(),
is_words: false,
}
}
pub fn from_words(words: &[i16]) -> Self {
Self {
bytes: words
.iter()
.map(|word| *word as u16)
.flat_map(|word| vec![(word >> 8) as u8, word as u8])
.collect(),
is_words: true,
}
}
pub fn operands(&self) -> InlineOperands {
InlineOperands {
bytes: &self.bytes,
is_words: self.is_words,
}
}
}
#[cfg(test)]
mod tests {
use super::MockInlineOperands;
#[test]
fn byte_operands() {
let values = [5, 2, 85, 92, 26, 42, u8::MIN, u8::MAX];
let mock = MockInlineOperands::from_bytes(&values);
let decoded = mock.operands().values().collect::<Vec<_>>();
assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
}
#[test]
fn word_operands() {
let values = [-5, 2, 2845, 92, -26, 42, i16::MIN, i16::MAX];
let mock = MockInlineOperands::from_words(&values);
let decoded = mock.operands().values().collect::<Vec<_>>();
assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
}
}