standard_plugin_cli/
component.rs1use wasmparser::{Parser, Payload};
4
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6pub struct ComponentShape {
7 pub imports: Vec<String>,
10 pub type_imports: Vec<String>,
13 pub exports: Vec<String>,
15 pub function_imports: Vec<String>,
19}
20
21fn function_imports(bytes: &[u8], imports: &[String]) -> Vec<String> {
25 use wasmparser::component_types::ComponentEntityType;
26 let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::all());
27 let Ok(types) = validator.validate_all(bytes) else {
28 return imports.to_vec();
29 };
30 imports
31 .iter()
32 .filter(
33 |name| match types.component_item_for_import(name).map(|item| &item.ty) {
34 Some(ComponentEntityType::Instance(id)) => types[*id]
35 .exports
36 .values()
37 .any(|item| matches!(item.ty, ComponentEntityType::Func(_))),
38 _ => true,
39 },
40 )
41 .cloned()
42 .collect()
43}
44
45pub fn inspect(bytes: &[u8]) -> Result<ComponentShape, String> {
48 let mut shape = ComponentShape::default();
49 let mut depth = 0usize;
50 for payload in Parser::new(0).parse_all(bytes) {
51 let payload = payload.map_err(|error| format!("not a valid wasm binary: {error}"))?;
52 match payload {
53 Payload::Version { encoding, .. } if depth == 0 => {
54 if encoding != wasmparser::Encoding::Component {
55 return Err(
56 "a core wasm module, not a component: build for wasm32-wasip2".into(),
57 );
58 }
59 }
60 Payload::ModuleSection { .. } | Payload::ComponentSection { .. } => depth += 1,
61 Payload::End(_) => depth = depth.saturating_sub(1),
62 Payload::ComponentImportSection(reader) if depth == 0 => {
63 for import in reader {
64 let import = import.map_err(|error| error.to_string())?;
65 let name = import.name.name.to_string();
66 if matches!(import.ty, wasmparser::ComponentTypeRef::Type(_)) {
67 shape.type_imports.push(name);
68 } else {
69 shape.imports.push(name);
70 }
71 }
72 }
73 Payload::ComponentExportSection(reader) if depth == 0 => {
74 for export in reader {
75 let export = export.map_err(|error| error.to_string())?;
76 shape.exports.push(export.name.name.to_string());
77 }
78 }
79 _ => {}
80 }
81 }
82 shape.function_imports = function_imports(bytes, &shape.imports);
83 Ok(shape)
84}