Skip to main content

greentic_runner/gen_bindings/
component.rs

1use anyhow::{Context, Result};
2use wasmparser::{Parser, Payload};
3
4#[derive(Debug, Default, Clone)]
5pub struct ComponentFeatures {
6    pub http: bool,
7    pub secrets: bool,
8    pub filesystem: bool,
9}
10
11pub fn analyze_component(path: &std::path::Path) -> Result<ComponentFeatures> {
12    let wasm = std::fs::read(path)
13        .with_context(|| format!("failed to read component {}", path.display()))?;
14    let mut features = ComponentFeatures::default();
15    for payload in Parser::new(0).parse_all(&wasm) {
16        if let Payload::ImportSection(section) = payload? {
17            for imports in section {
18                let imports = imports?;
19                let module = match imports {
20                    wasmparser::Imports::Single(_, import) => import.module,
21                    wasmparser::Imports::Compact1 { module, .. } => module,
22                    wasmparser::Imports::Compact2 { module, .. } => module,
23                };
24                match module {
25                    "greentic:host/http-v1" => features.http = true,
26                    "greentic:host/secrets-v1" => features.secrets = true,
27                    "greentic:host/filesystem-v1" | "greentic:host/kv-v1" => {
28                        features.filesystem = true;
29                    }
30                    _ => (),
31                }
32            }
33        }
34    }
35    Ok(features)
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn analyze_component_reports_read_errors() {
44        let err = analyze_component(std::path::Path::new("does-not-exist.wasm"))
45            .expect_err("missing component should error");
46        assert!(err.to_string().contains("failed to read component"));
47    }
48}