1extern crate parity_wasm;
2#[macro_use]
3extern crate log;
4extern crate rustc_demangle;
5
6mod gc;
7mod error;
8mod bitvec;
9
10use std::any::Any;
11use std::mem;
12use std::path::Path;
13
14use parity_wasm::elements::{
15 Module,
16 Serialize,
17 Deserialize
18};
19
20pub use error::Error;
21
22pub struct Config {
23 demangle: bool,
24 keep_debug: bool,
25}
26
27pub struct GcResult(Box<Module>);
28
29impl Config {
30 pub fn new() -> Config {
32 Config {
33 demangle: true,
34 keep_debug: false,
35 }
36 }
37
38 pub fn demangle(&mut self, demangle: bool) -> &mut Self {
41 self.demangle = demangle;
42 self
43 }
44
45 pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Self {
47 self.keep_debug = keep_debug;
48 self
49 }
50
51 #[doc(hidden)] pub fn gc(&mut self, bytecode: &[u8]) -> Result<Vec<u8>, Error> {
55 self.run(3, |_| bytecode.to_vec())?.into_bytes()
56 }
57
58 pub fn run<T: Any>(
59 &mut self,
60 mut module: T,
61 into_bytes: impl FnOnce(T) -> Vec<u8>,
62 ) -> Result<GcResult, Error> {
63 if let Some(module) = (&mut module as &mut Any).downcast_mut() {
64 self._gc(module);
65 let module = mem::replace(module, Module::new(Vec::new()));
66 return Ok(GcResult(Box::new(module)))
67 }
68 let bytecode = into_bytes(module);
69 let mut module = Module::deserialize(&mut &bytecode[..])
70 .map_err(error::from)?
71 .parse_names()
72 .map_err(|(mut l, _)| l.remove(0).1)
73 .map_err(error::from)?;
74 self._gc(&mut module);
75 Ok(GcResult(Box::new(module)))
76 }
77
78 fn _gc(&mut self, module: &mut Module) {
79 gc::run(self, module);
80 }
81}
82
83impl GcResult {
84 pub fn into_module<T: Any>(self) -> Result<T, Self> {
91 let module = self.0 as Box<Any>;
92 match module.downcast() {
93 Ok(t) => Ok(*t),
94 Err(box_any) => {
95 match box_any.downcast::<Module>() {
96 Ok(box_module) => Err(GcResult(box_module)),
97 Err(_) => panic!(),
98 }
99 }
100 }
101 }
102
103 pub fn into_bytes(self) -> Result<Vec<u8>, Error> {
108 let mut output = Vec::new();
109 self.0.serialize(&mut output).map_err(error::from)?;
110 Ok(output)
111 }
112}
113
114pub fn garbage_collect_file<I, O>(input_path: I, output_path: O) -> Result<(), Error>
116where
117 I: AsRef<Path>,
118 O: AsRef<Path>,
119{
120 _gc_file(input_path.as_ref(), output_path.as_ref())
121}
122
123fn _gc_file(input: &Path, output: &Path) -> Result<(), Error> {
124 let mut module = parity_wasm::deserialize_file(input)
125 .map_err(error::from)?
126 .parse_names()
127 .map_err(|(mut l, _)| l.remove(0).1)
128 .map_err(error::from)?;
129 Config::new()._gc(&mut module);
130 parity_wasm::serialize_to_file(output, module).map_err(error::from)?;
131
132 Ok(())
133}
134
135pub fn garbage_collect_slice(bytecode: &[u8]) -> Result<Vec<u8>, Error> {
137 Config::new().gc(bytecode)
138}