use crate::{
host_functions::{virtualization as host_fn, CompiledModule, ExecBuffer, ExecStatus},
CompileStatus, ExecError, ExecResult, InstanceId, InstantiateError, MemoryError, ModuleError,
ModuleId,
};
pub struct Module(ModuleId);
impl Module {
pub fn from_bytes(
bytes: &[u8],
identifier: Option<&[u8]>,
) -> Result<(Self, CompileStatus), ModuleError> {
let CompiledModule { id, status } = host_fn::compile_from_bytes(bytes, identifier)?;
Ok((Self(id), status))
}
pub fn lookup(identifier: &[u8]) -> Result<Self, ModuleError> {
Ok(Self(host_fn::lookup(identifier)?))
}
pub fn from_storage_key(
storage_key: &[u8],
child_trie: &[u8],
) -> Result<(Self, CompileStatus), ModuleError> {
let CompiledModule { id, status } =
host_fn::compile_from_storage_key(storage_key, child_trie)?;
Ok((Self(id), status))
}
pub fn instantiate(&self) -> Result<Instance, InstantiateError> {
Ok(Instance(host_fn::instantiate(self.0)?))
}
}
pub struct Instance(InstanceId);
impl Drop for Instance {
fn drop(&mut self) {
host_fn::destroy(self.0).ok();
}
}
impl core::fmt::Debug for Instance {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Instance").field(&self.0).finish()
}
}
impl Instance {
pub fn prepare(self, function: &[u8]) -> Result<Execution, (Self, ExecError)> {
match host_fn::prepare(self.0, function) {
Ok(()) => {
let instance_id = self.0;
core::mem::forget(self);
Ok(Execution(instance_id))
},
Err(err) => Err((self, err)),
}
}
}
pub struct Execution(InstanceId);
impl Drop for Execution {
fn drop(&mut self) {
host_fn::destroy(self.0).ok();
}
}
impl Execution {
pub fn run(self, gas_left: i64, a0: u64) -> ExecResult<Instance, Self> {
let mut buf = ExecBuffer::default();
let status_byte = match host_fn::run(self.0, gas_left, a0, &mut buf) {
Ok(s) => s,
Err(err) => {
let instance_id = self.0;
core::mem::forget(self);
return ExecResult::Error { instance: Instance(instance_id), error: err };
},
};
let status: ExecStatus = status_byte.try_into().expect("invalid status from host; qed");
match status {
ExecStatus::Finished => {
let instance_id = self.0;
core::mem::forget(self);
ExecResult::Finished { instance: Instance(instance_id), gas_left: buf.gas_left }
},
ExecStatus::Syscall => ExecResult::Syscall {
execution: self,
gas_left: buf.gas_left,
syscall_symbol: buf.syscall_symbol,
a0: buf.a0,
a1: buf.a1,
a2: buf.a2,
a3: buf.a3,
a4: buf.a4,
a5: buf.a5,
},
}
}
pub fn read_memory(&mut self, offset: u32, dest: &mut [u8]) -> Result<(), MemoryError> {
host_fn::read_memory(self.0, offset, dest)
}
pub fn write_memory(&mut self, offset: u32, src: &[u8]) -> Result<(), MemoryError> {
host_fn::write_memory(self.0, offset, src)
}
}