extern crate parity_wasm;
#[macro_use]
extern crate log;
extern crate rustc_demangle;
mod gc;
mod error;
mod bitvec;
use std::any::Any;
use std::mem;
use std::path::Path;
use parity_wasm::elements::{
Module,
Serialize,
Deserialize
};
pub use error::Error;
pub struct Config {
demangle: bool,
keep_debug: bool,
}
pub struct GcResult(Box<Module>);
impl Config {
pub fn new() -> Config {
Config {
demangle: true,
keep_debug: false,
}
}
pub fn demangle(&mut self, demangle: bool) -> &mut Self {
self.demangle = demangle;
self
}
pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Self {
self.keep_debug = keep_debug;
self
}
#[doc(hidden)] pub fn gc(&mut self, bytecode: &[u8]) -> Result<Vec<u8>, Error> {
self.run(3, |_| bytecode.to_vec())?.into_bytes()
}
pub fn run<T: Any>(
&mut self,
mut module: T,
into_bytes: impl FnOnce(T) -> Vec<u8>,
) -> Result<GcResult, Error> {
if let Some(module) = (&mut module as &mut Any).downcast_mut() {
self._gc(module);
let module = mem::replace(module, Module::new(Vec::new()));
return Ok(GcResult(Box::new(module)))
}
let bytecode = into_bytes(module);
let mut module = Module::deserialize(&mut &bytecode[..])
.map_err(error::from)?
.parse_names()
.map_err(|(mut l, _)| l.remove(0).1)
.map_err(error::from)?;
self._gc(&mut module);
Ok(GcResult(Box::new(module)))
}
fn _gc(&mut self, module: &mut Module) {
gc::run(self, module);
}
}
impl GcResult {
pub fn into_module<T: Any>(self) -> Result<T, Self> {
let module = self.0 as Box<Any>;
match module.downcast() {
Ok(t) => Ok(*t),
Err(box_any) => {
match box_any.downcast::<Module>() {
Ok(box_module) => Err(GcResult(box_module)),
Err(_) => panic!(),
}
}
}
}
pub fn into_bytes(self) -> Result<Vec<u8>, Error> {
let mut output = Vec::new();
self.0.serialize(&mut output).map_err(error::from)?;
Ok(output)
}
}
pub fn garbage_collect_file<I, O>(input_path: I, output_path: O) -> Result<(), Error>
where
I: AsRef<Path>,
O: AsRef<Path>,
{
_gc_file(input_path.as_ref(), output_path.as_ref())
}
fn _gc_file(input: &Path, output: &Path) -> Result<(), Error> {
let mut module = parity_wasm::deserialize_file(input)
.map_err(error::from)?
.parse_names()
.map_err(|(mut l, _)| l.remove(0).1)
.map_err(error::from)?;
Config::new()._gc(&mut module);
parity_wasm::serialize_to_file(output, module).map_err(error::from)?;
Ok(())
}
pub fn garbage_collect_slice(bytecode: &[u8]) -> Result<Vec<u8>, Error> {
Config::new().gc(bytecode)
}