use super::*;
impl<N: Network> FromBytes for Instruction<N> {
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
macro_rules! instruction_from_bytes_le {
($object:expr, |$reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {{
let index = u16::read_le(&mut $reader)?;
if index as usize >= Instruction::<N>::OPCODES.len() {
return Err(error(format!("Failed to deserialize an instruction: invalid opcode index ({index})")));
}
$(if Instruction::<N>::OPCODES[index as usize] == $variant::<N>::opcode() {
let instruction = $variant::read_le(&mut $reader)?;
return Ok(Self::$variant(instruction));
})+
Err(error(format!("Failed to deserialize an instruction of opcode index '{index}'")))
}};
}
crate::instruction!(instruction_from_bytes_le!(self, reader))
}
}
impl<N: Network> ToBytes for Instruction<N> {
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
macro_rules! instruction_to_bytes_le {
($object:expr, |$writer:ident| $_operation:block, { $( $variant:ident, )+ }) => {{
match $object {
$(Self::$variant(instruction) => {
let index = Instruction::<N>::OPCODES.iter().position(|&opcode| $variant::<N>::opcode() == opcode).unwrap();
#[allow(clippy::cast_possible_truncation)]
u16::write_le(&(index as u16),&mut $writer)?;
instruction.write_le(&mut $writer)?;
}),+
}
Ok(())
}};
}
crate::instruction!(instruction_to_bytes_le!(self, writer))
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::MainnetV0;
type CurrentNetwork = MainnetV0;
#[test]
fn test_bytes() -> Result<()> {
let instruction = "add r0 r1 into r2;";
let expected = Instruction::<CurrentNetwork>::from_str(instruction)?;
let expected_bytes = expected.to_bytes_le()?;
let candidate = Instruction::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
assert_eq!(expected_bytes, candidate.to_bytes_le()?);
Ok(())
}
}