use corevm_types::{RecvHostMessageOutcome, RecvMessageOutcome};
#[derive(Debug)]
pub struct InvokeArgs {
pub gas: i64,
pub regs: [u64; 13],
}
impl InvokeArgs {
pub fn new(gas: i64) -> Self {
Self { gas, regs: Default::default() }
}
pub fn reg(&self, reg: Reg) -> u64 {
self.regs[reg as usize]
}
pub fn set_reg(&mut self, reg: Reg, value: u64) {
self.regs[reg as usize] = value;
}
pub fn set_return_value<T: SetReturnValue>(&mut self, value: T) {
value.set_return_value(self);
}
pub fn get_arg_reg(&self, i: usize) -> u64 {
self.reg(Reg::ARG_REGS[i])
}
pub fn get_arg<T: Arg>(&mut self, i: &mut usize) -> T {
Arg::get(self, i)
}
pub fn set_arg_reg(&mut self, i: usize, value: u64) {
self.set_reg(Reg::ARG_REGS[i], value)
}
pub fn set_arg<T: Arg>(&mut self, i: &mut usize, value: T) {
value.set(self, i)
}
}
impl From<jam_types::InvokeArgs> for InvokeArgs {
fn from(other: jam_types::InvokeArgs) -> Self {
Self { gas: other.gas, regs: other.regs }
}
}
impl From<InvokeArgs> for jam_types::InvokeArgs {
fn from(other: InvokeArgs) -> Self {
Self { gas: other.gas, regs: other.regs }
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u32)]
pub enum Reg {
RA = 0,
SP = 1,
T0 = 2,
T1 = 3,
T2 = 4,
S0 = 5,
S1 = 6,
A0 = 7,
A1 = 8,
A2 = 9,
A3 = 10,
A4 = 11,
A5 = 12,
}
impl Reg {
pub const ARG_REGS: [Reg; 9] =
[Reg::A0, Reg::A1, Reg::A2, Reg::A3, Reg::A4, Reg::A5, Reg::T0, Reg::T1, Reg::T2];
}
pub trait SetReturnValue {
fn set_return_value(self, args: &mut InvokeArgs);
}
impl SetReturnValue for () {
fn set_return_value(self, _args: &mut InvokeArgs) {}
}
impl SetReturnValue for u64 {
fn set_return_value(self, args: &mut InvokeArgs) {
args.set_reg(Reg::A0, self);
}
}
impl SetReturnValue for RecvMessageOutcome {
fn set_return_value(self, args: &mut InvokeArgs) {
args.set_reg(Reg::A0, self.to_reg());
}
}
impl SetReturnValue for RecvHostMessageOutcome {
fn set_return_value(self, args: &mut InvokeArgs) {
args.set_reg(Reg::A0, self.to_reg());
}
}
set_return_value_impl_as! {
bool => u64,
u8 => u64,
u16 => u64,
u32 => u64,
i8 => u64,
i16 => u64,
i32 => u64,
i64 => u64
}
pub trait Arg {
fn get(args: &InvokeArgs, i: &mut usize) -> Self
where
Self: Sized;
fn set(self, args: &mut InvokeArgs, i: &mut usize);
}
impl Arg for u64 {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
let value = args.get_arg_reg(*i);
*i += 1;
value
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
args.set_arg_reg(*i, self);
*i += 1;
}
}
impl Arg for usize {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
u64::get(args, i) as usize
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
(self as u64).set(args, i);
}
}
impl<T> Arg for *const T {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
usize::get(args, i) as Self
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
(self as usize).set(args, i);
}
}
impl<T> Arg for *mut T {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
usize::get(args, i) as Self
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
(self as usize).set(args, i);
}
}
impl Arg for bool {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
u64::get(args, i) != 0
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
(self as u64).set(args, i);
}
}
arg_impl_as! {
u8 => u64,
u16 => u64,
u32 => u64,
i8 => u64,
i16 => u64,
i32 => u64,
i64 => u64
}
macro_rules! set_return_value_impl_as {
($($type:ty => $as_type:ty),+) => {
$(
impl SetReturnValue for $type {
fn set_return_value(self, args: &mut InvokeArgs) {
(self as $as_type).set_return_value(args);
}
}
)+
};
}
use set_return_value_impl_as;
macro_rules! arg_impl_as {
($($type:ty => $as_type:ty),+) => {
$(
impl Arg for $type {
fn get(args: &InvokeArgs, i: &mut usize) -> Self {
<$as_type>::get(args, i) as Self
}
fn set(self, args: &mut InvokeArgs, i: &mut usize) {
(self as $as_type).set(args, i);
}
}
)+
};
}
use arg_impl_as;