component_opt/
component.rs

1use std::{fs, path::Path};
2
3use wasmparser::{Parser, Payload::*};
4use wasm_encoder::{Component, RawSection, ComponentSectionId};
5
6use crate::{module, ComponentOptError};
7
8pub fn optimize_bytes(input_bytes: Vec<u8>) -> Result<Vec<u8>, ComponentOptError> {
9    let parser = Parser::new(0);
10    let mut output = Component::new();
11
12    for payload in parser.parse_all(input_bytes.as_slice()) {
13        let payload = payload?;
14        match payload {
15            ModuleSection { parser, range } => {
16                let id = ComponentSectionId::CoreModule.into();
17                let module_bytes = &input_bytes.as_slice()[range];
18                for _ in parser.parse_all(module_bytes) {
19                    // DO NOTHING
20                }
21                let module_bytes = module::optimize_bytes(module_bytes)?;
22                output.section(&RawSection { id, data: module_bytes.as_slice() });
23            },
24
25            // Skip all Module sections
26            Version { .. } => { /* ... */ }
27            TypeSection(_) => { /* ... */ }
28            ImportSection(_) => { /* ... */ }
29            FunctionSection(_) => { /* ... */ }
30            TableSection(_) => { /* ... */ }
31            MemorySection(_) => { /* ... */ }
32            TagSection(_) => { /* ... */ }
33            GlobalSection(_) => { /* ... */ }
34            ExportSection(_) => { /* ... */ }
35            StartSection { .. } => { /* ... */ }
36            ElementSection(_) => { /* ... */ }
37            DataCountSection { .. } => { /* ... */ }
38            DataSection(_) => { /* ... */ }
39            CodeSectionStart { .. } => { /* ... */ }
40            CodeSectionEntry(_) => { /* ... */ }
41
42            payload => {
43                match payload.as_section() {
44                    Some((id, range)) => {
45                        let data = &input_bytes.as_slice()[range];
46                        output.section(&RawSection { id, data });
47                    },
48                    None => {
49                        // No op, should only ever be version which we already encode
50                    }
51                }
52            }
53        }
54    }
55    Ok(output.finish())
56}
57
58pub fn optimize_file(input_path: impl AsRef<Path>, output_path: impl AsRef<Path>) -> Result<(), ComponentOptError> {
59    let input_bytes = fs::read(input_path)?;
60    let output_bytes = optimize_bytes(input_bytes)?;
61    fs::write(output_path, output_bytes)?;
62    Ok(())
63}