Skip to content

Commit 4fd3051

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 0b22b8c commit 4fd3051

File tree

18 files changed

+4872
-1
lines changed

18 files changed

+4872
-1
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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! Just enough component parsing support to get at the actual types
2+
3+
use wasmparser::Payload::{ComponentExportSection, ComponentTypeSection, Version};
4+
use wasmparser::{ComponentExternalKind, ComponentType, ComponentTypeRef, Payload};
5+
6+
use crate::etypes::{Component, Ctx, Defined};
7+
8+
fn raw_type_export_type<'p, 'a, 'c>(
9+
ctx: &'c Ctx<'p, 'a>,
10+
ce: &'c wasmparser::ComponentExport<'a>,
11+
) -> &'c Defined<'a> {
12+
match ce.ty {
13+
Some(ComponentTypeRef::Component(n)) => match ctx.types.iter().nth(n as usize) {
14+
Some(t) => return t,
15+
t => panic!("bad component type 1 {:?}", t),
16+
},
17+
None => match ctx.types.iter().nth(ce.index as usize) {
18+
Some(t) => return &t,
19+
t => panic!("bad component type 2 {:?}", t),
20+
},
21+
_ => panic!("non-component ascribed type"),
22+
}
23+
}
24+
25+
pub fn read_component_single_exported_type<'a>(
26+
items: impl Iterator<Item = wasmparser::Result<Payload<'a>>>,
27+
) -> Component<'a> {
28+
let mut ctx = Ctx::new(None, false);
29+
let mut last_idx = None;
30+
for x in items {
31+
match x {
32+
Ok(Version { .. }) => (),
33+
Ok(ComponentTypeSection(ts)) => {
34+
for t in ts {
35+
match t {
36+
Ok(ComponentType::Component(ct)) => {
37+
let ct_ = ctx.elab_component(&ct);
38+
ctx.types.push(Defined::Component(ct_.unwrap()));
39+
}
40+
_ => panic!("non-component type"),
41+
}
42+
}
43+
}
44+
Ok(ComponentExportSection(es)) => {
45+
for e in es {
46+
match e {
47+
Err(_) => panic!("invalid export section"),
48+
Ok(ce) => {
49+
if ce.kind == ComponentExternalKind::Type {
50+
last_idx = Some(ctx.types.len());
51+
ctx.types.push(raw_type_export_type(&ctx, &ce).clone());
52+
}
53+
}
54+
}
55+
}
56+
}
57+
_ => {}
58+
}
59+
}
60+
match last_idx {
61+
None => panic!("no exported type"),
62+
Some(n) => match ctx.types.into_iter().nth(n) {
63+
Some(Defined::Component(c)) => c,
64+
_ => panic!("final export is not component"),
65+
},
66+
}
67+
}

0 commit comments

Comments
 (0)