use fuel_asm::{
PanicReason,
RegId,
};
use crate::{
constraints::reg_key::{
split_registers,
SystemRegisters,
},
error::SimpleResult,
interpreter::NotSupportedEcal,
};
use super::{
internal::inc_pc,
Interpreter,
Memory,
};
pub trait EcalHandler: Clone
where
Self: Sized,
{
const INC_PC: bool = true;
fn ecal<M, S, Tx>(
vm: &mut Interpreter<M, S, Tx, Self>,
a: RegId,
b: RegId,
c: RegId,
d: RegId,
) -> SimpleResult<()>
where
M: Memory;
}
impl EcalHandler for NotSupportedEcal {
fn ecal<M, S, Tx>(
_: &mut Interpreter<M, S, Tx, Self>,
_: RegId,
_: RegId,
_: RegId,
_: RegId,
) -> SimpleResult<()> {
Err(PanicReason::EcalError)?
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct PredicateErrorEcal;
impl EcalHandler for PredicateErrorEcal {
fn ecal<M, S, Tx>(
_vm: &mut Interpreter<M, S, Tx, Self>,
_: RegId,
_: RegId,
_: RegId,
_: RegId,
) -> SimpleResult<()> {
Err(PanicReason::ContractInstructionNotAllowed)?
}
}
impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
where
M: Memory,
Ecal: EcalHandler,
{
pub(crate) fn external_call(
&mut self,
a: RegId,
b: RegId,
c: RegId,
d: RegId,
) -> SimpleResult<()> {
Ecal::ecal(self, a, b, c, d)?;
let (SystemRegisters { pc, .. }, _) = split_registers(&mut self.registers);
if Ecal::INC_PC {
Ok(inc_pc(pc)?)
} else {
Ok(())
}
}
}
impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
where
Ecal: EcalHandler,
{
pub fn ecal_state(&self) -> &Ecal {
&self.ecal_state
}
pub fn ecal_state_mut(&mut self) -> &mut Ecal {
&mut self.ecal_state
}
}