#[cfg(feature = "wasm-runtime")]
use crate::wasm::WasmError;
#[cfg(feature = "wasm-runtime")]
use std::path::Path;
#[cfg(feature = "wasm-runtime")]
use wasmtime::{Engine, Instance, Linker, Module, Store, Val};
#[cfg(feature = "wasm-runtime")]
pub struct WasmRuntime {
engine: Engine,
}
#[cfg(feature = "wasm-runtime")]
impl WasmRuntime {
pub fn new() -> Result<Self, WasmError> {
let engine = Engine::default();
Ok(Self { engine })
}
pub fn load(&self, wasm_bytes: &[u8]) -> Result<WasmModule, WasmError> {
let module = Module::from_binary(&self.engine, wasm_bytes)?;
let linker = Linker::new(&self.engine);
let mut store = Store::new(&self.engine, ());
let instance = linker.instantiate(&mut store, &module)?;
Ok(WasmModule { instance, store })
}
pub fn load_file(&self, path: impl AsRef<Path>) -> Result<WasmModule, WasmError> {
let wasm_bytes = std::fs::read(path)?;
self.load(&wasm_bytes)
}
}
#[cfg(feature = "wasm-runtime")]
impl Default for WasmRuntime {
fn default() -> Self {
Self::new().expect("Failed to create default WasmRuntime")
}
}
#[cfg(feature = "wasm-runtime")]
pub struct WasmModule {
instance: Instance,
store: Store<()>,
}
#[cfg(feature = "wasm-runtime")]
impl WasmModule {
pub fn call(&mut self, name: &str, args: &[Val]) -> Result<Vec<Val>, WasmError> {
let func = self
.instance
.get_func(&mut self.store, name)
.ok_or_else(|| WasmError::new(format!("Function '{}' not found", name)))?;
let mut results = vec![Val::I32(0); func.ty(&self.store).results().len()];
func.call(&mut self.store, args, &mut results)?;
Ok(results)
}
pub fn instance(&self) -> &Instance {
&self.instance
}
pub fn store_mut(&mut self) -> &mut Store<()> {
&mut self.store
}
}
#[cfg(test)]
#[cfg(feature = "wasm-runtime")]
mod tests {
use super::*;
#[test]
fn test_runtime_new() {
let runtime = WasmRuntime::new();
assert!(runtime.is_ok());
}
#[test]
fn test_runtime_default() {
let runtime = WasmRuntime::default();
drop(runtime);
}
#[test]
fn test_load_invalid_wasm() {
let runtime = WasmRuntime::new().unwrap();
let result = runtime.load(&[0x00, 0x01, 0x02, 0x03]);
assert!(result.is_err());
}
}