use std::collections::BTreeSet;
use std::ops::RangeInclusive;
use aluvm::isa;
use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet};
use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write};
use aluvm::reg::{CoreRegs, Reg};
use super::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO};
use super::{ContractOp, ContractStateAccess, VmContext};
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[display(inner)]
#[non_exhaustive]
pub enum RgbIsa<S: ContractStateAccess> {
Contract(ContractOp<S>),
Fail(u8),
}
impl<S: ContractStateAccess> InstructionSet for RgbIsa<S> {
type Context<'ctx> = VmContext<'ctx, S>;
fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") }
fn src_regs(&self) -> BTreeSet<Reg> {
match self {
RgbIsa::Contract(op) => op.src_regs(),
RgbIsa::Fail(_) => bset![],
}
}
fn dst_regs(&self) -> BTreeSet<Reg> {
match self {
RgbIsa::Contract(op) => op.dst_regs(),
RgbIsa::Fail(_) => bset![],
}
}
fn complexity(&self) -> u64 {
match self {
RgbIsa::Contract(op) => op.complexity(),
RgbIsa::Fail(_) => u64::MAX,
}
}
fn exec(&self, regs: &mut CoreRegs, site: LibSite, context: &Self::Context<'_>) -> ExecStep {
match self {
RgbIsa::Contract(op) => op.exec(regs, site, context),
RgbIsa::Fail(_) => isa::ControlFlowOp::Fail.exec(regs, site, &()),
}
}
}
impl<S: ContractStateAccess> Bytecode for RgbIsa<S> {
fn instr_range() -> RangeInclusive<u8> { INSTR_RGBISA_FROM..=INSTR_RGBISA_TO }
fn instr_byte(&self) -> u8 {
match self {
RgbIsa::Contract(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::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::<S>::instr_range().contains(&instr) => {
RgbIsa::Contract(ContractOp::decode(reader)?)
}
x => RgbIsa::Fail(x),
})
}
}