Skip to content

Commit

Permalink
CLI: Improve CLI parsing (#596)
Browse files Browse the repository at this point in the history
* use PathBuf instead of String in CLI

* use Path::extension to filter .wat files
  • Loading branch information
Robbepop authored Dec 28, 2022
1 parent da8e4a6 commit 2b5a486
Showing 1 changed file with 26 additions and 22 deletions.
48 changes: 26 additions & 22 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use anyhow::{anyhow, bail, Result};
use clap::Parser;
use core::fmt::Write;
use std::fs;
use std::{
ffi::OsStr,
fs,
path::{Path, PathBuf},
};
use wasmi::{
core::{Value, ValueType, F32, F64},
ExportItemKind,
Expand All @@ -15,18 +19,18 @@ use wasmi::{
#[clap(author, version, about, long_about = None)]
struct Args {
/// The WebAssembly file to execute.
#[clap(value_parser)]
wasm_file: String,
#[clap(value_hint = clap::ValueHint::FilePath)]
wasm_file: PathBuf,

/// The exported name of the Wasm function to call.
///
/// If this argument is missing the wasmi CLI will print out all
/// exported functions and their parameters of the given Wasm module.
#[clap(value_parser)]
#[clap()]
func_name: Option<String>,

/// The arguments provided to the called function.
#[clap(value_parser)]
#[clap()]
func_args: Vec<String>,
}

Expand Down Expand Up @@ -64,28 +68,28 @@ fn wat2wasm(wat: &str) -> Result<Vec<u8>, wat::Error> {
///
/// If the Wasm file `wasm_file` does not exist.
/// If the Wasm file `wasm_file` is not a valid `.wasm` or `.wat` format.
fn read_wasm_or_wat(wasm_file: &str) -> Result<Vec<u8>> {
let mut file_contents =
fs::read(wasm_file).map_err(|_| anyhow!("failed to read Wasm file {wasm_file}"))?;
if wasm_file.ends_with(".wat") {
let wat = String::from_utf8(file_contents)
.map_err(|error| anyhow!("failed to read UTF-8 file {wasm_file}: {error}"))?;
file_contents = wat2wasm(&wat)
.map_err(|error| anyhow!("failed to parse .wat file {wasm_file}: {error}"))?;
fn read_wasm_or_wat(wasm_file: &Path) -> Result<Vec<u8>> {
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(file_contents)
Ok(wasm_bytes)
}

/// Returns the contents of the given `.wasm` or `.wat` file.
///
/// # Errors
///
/// If the Wasm module fails to parse or validate.
fn load_wasm_module(wasm_file: &str) -> Result<wasmi::Module> {
fn load_wasm_module(wasm_file: &Path) -> Result<wasmi::Module> {
let wasm_bytes = read_wasm_or_wat(wasm_file)?;
let engine = wasmi::Engine::default();
let module = wasmi::Module::new(&engine, &mut &wasm_bytes[..]).map_err(|error| {
anyhow!("failed to parse and validate Wasm module {wasm_file}: {error}")
anyhow!("failed to parse and validate Wasm module {wasm_file:?}: {error}")
})?;
Ok(module)
}
Expand All @@ -97,15 +101,15 @@ fn load_wasm_module(wasm_file: &str) -> Result<wasmi::Module> {
/// If the given `func_name` is none and also displays the
/// list of exported functions from the Wasm module.
fn extract_wasm_func(
wasm_file: &str,
wasm_file: &Path,
module: &wasmi::Module,
func_name: Option<String>,
) -> Result<String> {
match func_name {
Some(func_name) => Ok(func_name),
None => {
let exported_funcs = display_exported_funcs(module);
bail!("missing function name argument for {wasm_file}\n\n{exported_funcs}")
bail!("missing function name argument for {wasm_file:?}\n\n{exported_funcs}")
}
}
}
Expand All @@ -120,7 +124,7 @@ fn extract_wasm_func(
/// - If the Wasm module fails to instantiate or start.
/// - If the Wasm module does not have an exported function `func_name`.
fn load_wasm_func(
wasm_file: &str,
wasm_file: &Path,
module: &wasmi::Module,
func_name: &str,
) -> Result<(Func, String, Store<()>)> {
Expand All @@ -136,7 +140,7 @@ fn load_wasm_func(
.and_then(|ext| ext.into_func())
.ok_or_else(|| {
let exported_funcs = display_exported_funcs(module);
anyhow!("could not find function \"{func_name}\" in {wasm_file}\n\n{exported_funcs}")
anyhow!("could not find function \"{func_name}\" in {wasm_file:?}\n\n{exported_funcs}")
})?;
Ok((func, func_name.into(), store))
}
Expand Down Expand Up @@ -268,8 +272,8 @@ fn prepare_results_buffer(func_type: &FuncType) -> Vec<Value> {
}

/// Prints a signalling text that Wasm execution has started.
fn print_execution_start(wasm_file: &str, func_name: &str, func_args: &[Value]) {
print!("executing {wasm_file}::{func_name}(");
fn print_execution_start(wasm_file: &Path, func_name: &str, func_args: &[Value]) {
print!("executing {wasm_file:?}::{func_name}(");
if let Some((first_arg, rest_args)) = func_args.split_first() {
print!("{first_arg}");
for arg in rest_args {
Expand Down

0 comments on commit 2b5a486

Please sign in to comment.