use crate::error::{VmError, VmResult};
use crate::native::NativeRegistry;
use crate::state::{VmState, MAX_INSTRUCTIONS};
use crate::handlers::dispatch::dispatch_indirect;
pub fn execute(code: &[u8], input: &[u8]) -> VmResult<u64> {
let mut state = VmState::new(code, input);
run(&mut state)?;
Ok(state.result)
}
pub fn execute_with_natives(code: &[u8], input: &[u8], registry: &NativeRegistry) -> VmResult<u64> {
let mut state = VmState::new(code, input);
run_with_natives(&mut state, registry)?;
Ok(state.result)
}
pub fn execute_with_native_table(code: &[u8], input: &[u8], native_table: &[fn(&[u64]) -> u64]) -> VmResult<u64> {
let mut state = VmState::new(code, input);
state.set_native_table(native_table);
run_with_native_table(&mut state)?;
Ok(state.result)
}
pub fn run_with_native_table(state: &mut VmState) -> VmResult<()> {
let empty_registry = NativeRegistry::new();
while !state.halted && state.ip < state.code.len() {
state.instruction_count += 1;
if state.instruction_count > MAX_INSTRUCTIONS {
return Err(VmError::MaxInstructionsExceeded);
}
let opcode = state.read_u8()?;
dispatch_indirect(state, opcode, &empty_registry)?;
}
Ok(())
}
pub fn execute_with_state<'a>(code: &'a [u8], input: &'a [u8]) -> VmResult<VmState<'a>> {
let mut state = VmState::new(code, input);
run(&mut state)?;
Ok(state)
}
pub fn run(state: &mut VmState) -> VmResult<()> {
let empty_registry = NativeRegistry::new();
run_with_natives(state, &empty_registry)
}
pub fn run_with_natives(state: &mut VmState, registry: &NativeRegistry) -> VmResult<()> {
while !state.halted && state.ip < state.code.len() {
state.instruction_count += 1;
if state.instruction_count > MAX_INSTRUCTIONS {
return Err(VmError::MaxInstructionsExceeded);
}
let opcode = state.read_u8()?;
dispatch_indirect(state, opcode, registry)?;
}
Ok(())
}