libchisel/
snip.rs

1use parity_wasm::elements::Module;
2
3use super::{ChiselModule, ModuleError, ModuleKind, ModuleTranslator};
4
5#[derive(Clone)]
6pub struct Snip(wasm_snip::Options);
7
8impl Snip {
9    pub fn new() -> Self {
10        let mut options = wasm_snip::Options::default();
11        // TODO: expose these as options
12        options.snip_rust_fmt_code = true;
13        options.snip_rust_panicking_code = true;
14        options.skip_producers_section = true;
15        Snip { 0: options }
16    }
17}
18
19impl<'a> ChiselModule<'a> for Snip {
20    type ObjectReference = &'a dyn ModuleTranslator;
21
22    fn id(&'a self) -> String {
23        "snip".to_string()
24    }
25
26    fn kind(&'a self) -> ModuleKind {
27        ModuleKind::Translator
28    }
29
30    fn as_abstract(&'a self) -> Self::ObjectReference {
31        self as Self::ObjectReference
32    }
33}
34
35impl From<failure::Error> for ModuleError {
36    fn from(error: failure::Error) -> Self {
37        ModuleError::Custom(error.to_string())
38    }
39}
40
41impl ModuleTranslator for Snip {
42    fn translate_inplace(&self, _module: &mut Module) -> Result<bool, ModuleError> {
43        Err(ModuleError::NotSupported)
44    }
45
46    fn translate(&self, module: &Module) -> Result<Option<Module>, ModuleError> {
47        let serialized = module.clone().to_bytes()?;
48
49        // TODO: improve wasm-snip API...
50        let mut options = self.0.clone();
51        options.input = wasm_snip::Input::Buffer(serialized);
52        let ret = wasm_snip::snip(options)?;
53        let output = ret.emit_wasm()?;
54
55        let output = Module::from_bytes(&output[..])?;
56        Ok(Some(output))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use rustc_hex::FromHex;
63
64    use super::*;
65
66    #[test]
67    fn smoke_test() {
68        // (module
69        // (import "env" "ethereum_useGas" (func (param i64)))
70        // (memory 1)
71        // (export "main" (func $main))
72        // (export "memory" (memory 0))
73        // (func $main
74        //     (call $std::panicking::rust_panic_with_hook::h12b7239ed4348eae)
75        //     (call $core::fmt::write::h9f284ae8e8e9b94a)
76        // )
77        // (func $std::panicking::rust_panic_with_hook::h12b7239ed4348eae)
78        // (func $core::fmt::write::h9f284ae8e8e9b94a)
79        // )
80        let wasm: Vec<u8> = FromHex::from_hex(
81            "0061736d0100000001080260017e0060000002170103656e760f65746865
827265756d5f75736547617300000304030101010503010001071102046d61
83696e0001066d656d6f727902000a10030600100210030b0300010b030001
840b007f046e616d650178040011696d706f72742466756e6374696f6e2430
8501046d61696e02377374643a3a70616e69636b696e673a3a727573745f70
86616e69635f776974685f686f6f6b3a3a6831326237323339656434333438
876561650323636f72653a3a666d743a3a77726974653a3a68396632383461
8865386538653962393461",
89        )
90        .unwrap();
91
92        let module = Module::from_bytes(&wasm).unwrap();
93        let module = Snip::new().translate(&module);
94        let module = module
95            .expect("translation to be succesful")
96            .expect("new module to be returned");
97        assert!(module.to_bytes().unwrap().len() < wasm.len());
98    }
99}