Skip to content

Commit a5148db

Browse files
committed
[component_util] Add Component Model elaboration/bindgen utilities
This commit adds a general implementation of WebAssembly Component Model type elaboration, closely derived from the formal specification. It also adds a number of functions which can generate Rust binding code from appropriately-structured (roughly: WIT-like) component types. Signed-off-by: Lucy Menon <[email protected]>
1 parent 57ca927 commit a5148db

File tree

17 files changed

+4470
-0
lines changed

17 files changed

+4470
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ default-members = [
88
members = [
99
"src/hyperlight_guest_capi",
1010
"fuzz",
11+
"src/hyperlight_component_util",
1112
]
1213
# Guests have custom linker flags, so we need to exclude them from the workspace
1314
exclude = [
@@ -30,6 +31,7 @@ hyperlight-common = { path = "src/hyperlight_common", version = "0.2.0", default
3031
hyperlight-host = { path = "src/hyperlight_host", version = "0.2.0", default-features = false }
3132
hyperlight-guest = { path = "src/hyperlight_guest", version = "0.2.0", default-features = false }
3233
hyperlight-testing = { path = "src/hyperlight_testing", default-features = false }
34+
hyperlight-component-util = { path = "src/hyperlight_component_util" }
3335

3436
[workspace.lints.rust]
3537
unsafe_op_in_unsafe_fn = "deny"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "hyperlight-component-util"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
readme.workspace = true
10+
description = """
11+
Shared implementation for the procedural macros that generate Hyperlight host and guest bindings from component types
12+
"""
13+
14+
[lib]
15+
name = "hyperlight_component_util"
16+
17+
[dependencies]
18+
wasmparser = { version = "0.224.0" }
19+
quote = { version = "1.0.38" }
20+
proc-macro2 = { version = "1.0.93" }
21+
syn = { version = "2.0.96" }
22+
itertools = { version = "0.14.0" }
23+
prettyplease = { version = "0.2.31" }
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//! Just enough component parsing support to get at the actual types
2+
3+
use wasmparser::{
4+
ComponentExternalKind,
5+
ComponentType,
6+
ComponentTypeRef,
7+
Payload,
8+
Payload::{
9+
Version,
10+
ComponentExportSection,
11+
ComponentTypeSection,
12+
},
13+
};
14+
15+
use crate::etypes::{Ctx, Component, Defined};
16+
17+
fn raw_type_export_type<'p, 'a, 'c>(
18+
ctx: &'c Ctx<'p, 'a>,
19+
ce: &'c wasmparser::ComponentExport<'a>
20+
) -> &'c Defined<'a> {
21+
match ce.ty {
22+
Some(ComponentTypeRef::Component(n)) => {
23+
match ctx.types.iter().nth(n as usize) {
24+
Some(t) => return t,
25+
t => panic!("bad component type 1 {:?}", t),
26+
}
27+
}
28+
None => {
29+
match ctx.types.iter().nth(ce.index as usize) {
30+
Some(t) => return &t,
31+
t => panic!("bad component type 2 {:?}", t),
32+
}
33+
}
34+
_ => panic!("non-component ascribed type"),
35+
}
36+
}
37+
38+
pub fn read_component_single_exported_type<'a>(
39+
items: impl Iterator<Item = wasmparser::Result<Payload<'a>, >>
40+
) -> Component<'a> {
41+
let mut ctx = Ctx::new(None, false);
42+
let mut last_idx = None;
43+
for x in items {
44+
match x {
45+
Ok(Version{..}) => (),
46+
Ok(ComponentTypeSection(ts)) => {
47+
for t in ts {
48+
match t {
49+
Ok(ComponentType::Component(ct)) => {
50+
let ct_ = ctx.elab_component(&ct);
51+
ctx.types.push(Defined::Component(ct_.unwrap()));
52+
}
53+
_ => panic!("non-component type"),
54+
}
55+
}
56+
},
57+
Ok(ComponentExportSection(es)) => {
58+
for e in es {
59+
match e {
60+
Err(_) => panic!("invalid export section"),
61+
Ok(ce) => if ce.kind == ComponentExternalKind::Type {
62+
last_idx = Some(ctx.types.len());
63+
ctx.types.push(raw_type_export_type(&ctx, &ce).clone());
64+
}
65+
}
66+
}
67+
},
68+
_ => {},
69+
}
70+
}
71+
match last_idx {
72+
None => panic!("no exported type"),
73+
Some(n) => match ctx.types.into_iter().nth(n) {
74+
Some(Defined::Component(c)) => c,
75+
_ => panic!("final export is not component"),
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)