use std::collections::BTreeSet;
use std::ops::RangeInclusive;
use aluvm::isa;
use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet};
use aluvm::library::{CodeEofError, LibSite, Read, Write};
use aluvm::reg::CoreRegs;
use super::opcodes::{INSTR_ISAE_FROM, INSTR_ISAE_TO};
use super::{ContractOp, TimechainOp};
use crate::validation::OpInfo;
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[display(inner)]
#[non_exhaustive]
pub enum RgbIsa {
Contract(ContractOp),
Timechain(TimechainOp),
Fail(u8),
}
impl InstructionSet for RgbIsa {
type Context<'ctx> = OpInfo<'ctx>;
fn isa_ids() -> BTreeSet<&'static str> {
bset! {"RGB"}
}
fn exec(&self, regs: &mut CoreRegs, site: LibSite, context: &Self::Context<'_>) -> ExecStep {
match self {
RgbIsa::Contract(op) => op.exec(regs, site, context),
RgbIsa::Timechain(op) => op.exec(regs, site, &()),
RgbIsa::Fail(_) => {
isa::ControlFlowOp::Fail.exec(regs, site, &());
ExecStep::Stop
}
}
}
}
impl Bytecode for RgbIsa {
fn byte_count(&self) -> u16 {
match self {
RgbIsa::Contract(op) => op.byte_count(),
RgbIsa::Timechain(op) => op.byte_count(),
RgbIsa::Fail(_) => 0,
}
}
fn instr_range() -> RangeInclusive<u8> { INSTR_ISAE_FROM..=INSTR_ISAE_TO }
fn instr_byte(&self) -> u8 {
match self {
RgbIsa::Contract(op) => op.instr_byte(),
RgbIsa::Timechain(op) => op.instr_byte(),
RgbIsa::Fail(code) => *code,
}
}
fn encode_args<W>(&self, writer: &mut W) -> Result<(), BytecodeError>
where W: Write {
match self {
RgbIsa::Contract(op) => op.encode_args(writer),
RgbIsa::Timechain(op) => op.encode_args(writer),
RgbIsa::Fail(_) => Ok(()),
}
}
fn decode<R>(reader: &mut R) -> Result<Self, CodeEofError>
where
Self: Sized,
R: Read,
{
let instr = reader.peek_u8()?;
Ok(match instr {
instr if ContractOp::instr_range().contains(&instr) => {
RgbIsa::Contract(ContractOp::decode(reader)?)
}
instr if TimechainOp::instr_range().contains(&instr) => {
RgbIsa::Timechain(TimechainOp::decode(reader)?)
}
x => RgbIsa::Fail(x),
})
}
}