use arbitrary::Arbitrary;
use std::fs;
use std::io::{stdin, stdout, Read, Write};
use std::path::PathBuf;
use std::process;
use structopt::StructOpt;
use wasm_smith::Module;
#[derive(StructOpt)]
struct Options {
#[structopt(parse(from_os_str))]
input: Option<PathBuf>,
#[structopt(short = "o", long = "output", parse(from_os_str))]
output: Option<PathBuf>,
#[structopt(short = "t", long = "ensure-termination")]
ensure_termination: bool,
#[structopt(short = "f", long = "fuel", default_value = "100")]
fuel: u32,
}
fn main() {
let opts = Options::from_args();
let stdin = stdin();
let (mut input, input_name): (Box<dyn Read>, _) = match &opts.input {
Some(f) => {
let input = Box::new(fs::File::open(f).unwrap_or_else(|e| {
eprintln!("error: failed to open '{}': {}", f.display(), e);
process::exit(1);
}));
(input, f.display().to_string())
}
None => {
let input = Box::new(stdin.lock());
(input, "<stdin>".to_string())
}
};
let stdout = stdout();
let (mut output, output_name): (Box<dyn Write>, _) = match &opts.output {
Some(f) => {
let output = Box::new(fs::File::create(f).unwrap_or_else(|e| {
eprintln!("error: failed to create '{}': {}", f.display(), e);
process::exit(1);
}));
(output, f.display().to_string())
}
None => {
let output = Box::new(stdout.lock());
(output, "<stdout>".to_string())
}
};
let mut seed = vec![];
input.read_to_end(&mut seed).unwrap_or_else(|e| {
eprintln!("error: failed to '{}': {}", input_name, e);
process::exit(1);
});
let mut u = arbitrary::Unstructured::new(&seed);
let mut module = Module::arbitrary(&mut u).unwrap_or_else(|e| {
eprintln!("error: failed to generate module: {}", e);
process::exit(2);
});
if opts.ensure_termination {
module.ensure_termination(opts.fuel);
}
let wasm_bytes = module.to_bytes();
output.write_all(&wasm_bytes).unwrap_or_else(|e| {
eprintln!("error: failed to write to '{}': {}", output_name, e);
process::exit(1);
});
drop(output);
process::exit(0);
}