use crate::display::DisplayValueType;
use anyhow::{anyhow, bail, Error};
use std::{ffi::OsStr, fs, path::Path};
use wasmi::{
core::{ValType, F32, F64},
FuncType,
Val,
};
fn wat2wasm(wat: &str) -> Result<Vec<u8>, wat::Error> {
wat::parse_str(wat)
}
pub fn read_wasm_or_wat(wasm_file: &Path) -> Result<Vec<u8>, Error> {
let mut wasm_bytes =
fs::read(wasm_file).map_err(|_| anyhow!("failed to read Wasm file {wasm_file:?}"))?;
if wasm_file.extension().and_then(OsStr::to_str) == Some("wat") {
let wat = String::from_utf8(wasm_bytes)
.map_err(|error| anyhow!("failed to read UTF-8 file {wasm_file:?}: {error}"))?;
wasm_bytes = wat2wasm(&wat)
.map_err(|error| anyhow!("failed to parse .wat file {wasm_file:?}: {error}"))?;
}
Ok(wasm_bytes)
}
pub fn prepare_func_results(ty: &FuncType) -> Box<[Val]> {
ty.results().iter().copied().map(Val::default).collect()
}
pub fn decode_func_args(ty: &FuncType, args: &[String]) -> Result<Box<[Val]>, Error> {
ty.params()
.iter()
.zip(args)
.enumerate()
.map(|(n, (param_type, arg))| {
macro_rules! make_err {
() => {
|_| {
anyhow!(
"failed to parse function argument \
{arg} at index {n} as {}",
DisplayValueType::from(param_type)
)
}
};
}
match param_type {
ValType::I32 => arg.parse::<i32>().map(Val::from).map_err(make_err!()),
ValType::I64 => arg.parse::<i64>().map(Val::from).map_err(make_err!()),
ValType::F32 => arg
.parse::<f32>()
.map(F32::from)
.map(Val::from)
.map_err(make_err!()),
ValType::F64 => arg
.parse::<f64>()
.map(F64::from)
.map(Val::from)
.map_err(make_err!()),
ValType::FuncRef => {
bail!("the wasmi CLI cannot take arguments of type funcref")
}
ValType::ExternRef => {
bail!("the wasmi CLI cannot take arguments of type externref")
}
}
})
.collect::<Result<Box<[_]>, _>>()
}