use clap::Parser;
use std::{fmt::Debug, path::PathBuf};
#[cfg(feature = "additional-libs")]
use wasm_opt::{Feature, OptimizationError, OptimizationOptions};
use crate::wasm;
#[derive(Parser, Debug, Clone)]
#[group(skip)]
pub struct Cmd {
#[arg(long, num_args = 1.., required = true)]
wasm: Vec<PathBuf>,
#[arg(long)]
wasm_out: Option<std::path::PathBuf>,
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Wasm(#[from] wasm::Error),
#[cfg(feature = "additional-libs")]
#[error("optimization error: {0}")]
OptimizationError(OptimizationError),
#[cfg(not(feature = "additional-libs"))]
#[error("must install with \"additional-libs\" feature.")]
Install,
#[error("--wasm-out cannot be used with --wasm option when passing multiple files")]
MultipleFilesOutput,
}
impl Cmd {
#[cfg(not(feature = "additional-libs"))]
pub fn run(&self) -> Result<(), Error> {
Err(Error::Install)
}
#[cfg(feature = "additional-libs")]
pub fn run(&self) -> Result<(), Error> {
optimize(false, self.wasm.clone(), self.wasm_out.clone())
}
}
#[cfg(feature = "additional-libs")]
pub fn optimize(
quiet: bool,
wasm: Vec<PathBuf>,
wasm_out: Option<std::path::PathBuf>,
) -> Result<(), Error> {
if wasm.len() > 1 && wasm_out.is_some() {
return Err(Error::MultipleFilesOutput);
}
for wasm_path in &wasm {
let wasm_arg = wasm::Args {
wasm: wasm_path.into(),
};
if !quiet {
println!(
"Reading: {path} ({wasm_size} bytes)",
path = wasm_arg.wasm.to_string_lossy(),
wasm_size = wasm_arg.len()?
);
}
let wasm_out = wasm_out.clone().unwrap_or_else(|| {
let mut wasm_out = wasm_arg.wasm.clone();
wasm_out.set_extension("optimized.wasm");
wasm_out
});
let mut options = OptimizationOptions::new_optimize_for_size_aggressively();
options.converge = true;
options.mvp_features_only();
options.enable_feature(Feature::MutableGlobals);
options.enable_feature(Feature::SignExt);
options.enable_feature(Feature::BulkMemory);
options
.run(&wasm_arg.wasm, &wasm_out)
.map_err(Error::OptimizationError)?;
if !quiet {
println!(
"Optimized: {path} ({size} bytes)",
path = wasm_out.to_string_lossy(),
size = wasm::len(&wasm_out)?
);
}
}
Ok(())
}