extern crate casper_wasm;
extern crate casper_wasmi;
use std::env::args;
use casper_wasm::elements::{External, FunctionType, Internal, Module, Type, ValueType};
use casper_wasmi::{ImportsBuilder, ModuleInstance, NopExternals, RuntimeValue};
fn main() {
let args: Vec<_> = args().collect();
if args.len() < 3 {
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
return;
}
let func_name = &args[2];
let (_, program_args) = args.split_at(3);
let module = load_module(&args[1]);
let args = {
let export_section = module.export_section().expect("No export section found");
let function_section = module
.function_section()
.expect("No function section found");
let type_section = module.type_section().expect("No type section found");
let found_entry = export_section
.entries()
.iter()
.find(|entry| func_name == entry.field())
.unwrap_or_else(|| panic!("No export with name {} found", func_name));
let function_index: usize = match found_entry.internal() {
Internal::Function(index) => *index as usize,
_ => panic!("Founded export is not a function"),
};
let import_section_len: usize = match module.import_section() {
Some(import) => import
.entries()
.iter()
.filter(|entry| matches!(entry.external(), External::Function(_)))
.count(),
None => 0,
};
let function_index_in_section = function_index - import_section_len;
let func_type_ref: usize =
function_section.entries()[function_index_in_section].type_ref() as usize;
#[allow(clippy::infallible_destructuring_match)]
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
Type::Function(ref func_type) => func_type,
};
function_type
.params()
.iter()
.enumerate()
.map(|(i, value)| match value {
ValueType::I32 => RuntimeValue::I32(
program_args[i]
.parse::<i32>()
.unwrap_or_else(|_| panic!("Can't parse arg #{} as i32", program_args[i])),
),
ValueType::I64 => RuntimeValue::I64(
program_args[i]
.parse::<i64>()
.unwrap_or_else(|_| panic!("Can't parse arg #{} as i64", program_args[i])),
),
ValueType::F32 => RuntimeValue::F32(
program_args[i]
.parse::<f32>()
.unwrap_or_else(|_| panic!("Can't parse arg #{} as f32", program_args[i]))
.into(),
),
ValueType::F64 => RuntimeValue::F64(
program_args[i]
.parse::<f64>()
.unwrap_or_else(|_| panic!("Can't parse arg #{} as f64", program_args[i]))
.into(),
),
})
.collect::<Vec<RuntimeValue>>()
};
let loaded_module =
casper_wasmi::Module::from_casper_wasm_module(module).expect("Module to be valid");
let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default())
.expect("Failed to instantiate module")
.run_start(&mut NopExternals)
.expect("Failed to run start function in module");
println!(
"Result: {:?}",
main.invoke_export(func_name, &args, &mut NopExternals)
.expect("")
);
}
#[cfg(feature = "std")]
fn load_module(file: &str) -> Module {
casper_wasm::deserialize_file(file).expect("File to be deserialized")
}
#[cfg(not(feature = "std"))]
fn load_module(file: &str) -> Module {
let mut buf = std::fs::read(file).expect("Read file");
casper_wasm::deserialize_buffer(&mut buf).expect("Deserialize module")
}