greentic_component/
wasm.rs1use anyhow::{Result, anyhow};
2use wasmparser::Parser;
3use wit_component::{DecodedWasm, metadata};
4use wit_parser::{Resolve, WorldId};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum WorldSource {
9 Metadata,
11 Component,
13}
14
15pub struct DecodedWorld {
17 pub resolve: Resolve,
18 pub world: WorldId,
19 pub source: WorldSource,
20}
21
22pub fn decode_world(bytes: &[u8]) -> Result<DecodedWorld> {
24 if Parser::is_component(bytes) {
25 match wit_component::decode(bytes) {
26 Ok(DecodedWasm::Component(resolve, world)) => Ok(DecodedWorld {
27 resolve,
28 world,
29 source: WorldSource::Component,
30 }),
31 Ok(DecodedWasm::WitPackage(_, _)) | Err(_) => match metadata::decode(bytes) {
32 Ok((_maybe_module, bindgen)) => Ok(DecodedWorld {
33 resolve: bindgen.resolve,
34 world: bindgen.world,
35 source: WorldSource::Metadata,
36 }),
37 Err(module_err) => Err(anyhow!(
38 "failed to decode component and module metadata ({module_err})"
39 )),
40 },
41 }
42 } else {
43 match metadata::decode(bytes) {
44 Ok((_maybe_module, bindgen)) => Ok(DecodedWorld {
45 resolve: bindgen.resolve,
46 world: bindgen.world,
47 source: WorldSource::Metadata,
48 }),
49 Err(module_err) => match wit_component::decode(bytes) {
50 Ok(DecodedWasm::Component(resolve, world)) => Ok(DecodedWorld {
51 resolve,
52 world,
53 source: WorldSource::Component,
54 }),
55 Ok(DecodedWasm::WitPackage(_, _)) => Err(module_err),
56 Err(component_err) => Err(anyhow!(
57 "failed to decode module metadata ({module_err}) and component ({component_err})"
58 )),
59 },
60 }
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use std::path::Path;
68
69 #[test]
70 fn decode_world_rejects_invalid_binary_with_combined_error() {
71 match decode_world(b"not a wasm") {
72 Ok(_) => panic!("invalid input should fail"),
73 Err(err) => {
74 let message = err.to_string();
75 assert!(
76 message.contains("failed to decode")
77 || message.contains("unexpected end-of-file")
78 || message.contains("invalid")
79 );
80 }
81 }
82 }
83
84 #[test]
85 fn decode_world_accepts_contract_fixture_component() {
86 let path = Path::new(env!("CARGO_MANIFEST_DIR"))
87 .join("tests")
88 .join("contract")
89 .join("fixtures")
90 .join("component_v0_6_0")
91 .join("component.wasm");
92 let bytes = std::fs::read(path).expect("read contract fixture");
93
94 let decoded = decode_world(&bytes).expect("decode fixture component");
95
96 assert_eq!(decoded.source, WorldSource::Component);
97 }
98}