Skip to content

Commit 2136234

Browse files
committed
Closes #651:
- adds support to select a specific world from a WIT file if multiple worlds are specified. Signed-off-by: Shailesh Vashishth <[email protected]>
1 parent 9b8ade9 commit 2136234

File tree

6 files changed

+149
-14
lines changed

6 files changed

+149
-14
lines changed

Justfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ guests: build-and-move-rust-guests build-and-move-c-guests
4545
witguest-wit:
4646
cargo install --locked wasm-tools
4747
cd src/tests/rust_guests/witguest && wasm-tools component wit guest.wit -w -o interface.wasm
48+
cd src/tests/rust_guests/witguest && wasm-tools component wit two_worlds.wit -w -o twoworlds.wasm
4849

4950
build-rust-guests target=default-target features="": (witguest-wit)
5051
cd src/tests/rust_guests/simpleguest && cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" { "dev" } else { target } }}

src/hyperlight_component_macro/src/lib.rs

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ limitations under the License.
5050
extern crate proc_macro;
5151

5252
use hyperlight_component_util::*;
53+
use syn::parse::{Parse, ParseStream};
54+
use syn::{Ident, LitStr, Result, Token};
5355

5456
/// Create host bindings for the wasm component type in the file
5557
/// passed in (or `$WIT_WORLD`, if nothing is passed in). This will
@@ -63,14 +65,23 @@ use hyperlight_component_util::*;
6365
/// `instantiate()` method on the component trait that makes
6466
/// instantiating the sandbox particularly ergonomic in core
6567
/// Hyperlight.
68+
6669
#[proc_macro]
6770
pub fn host_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
6871
let _ = env_logger::try_init();
69-
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
70-
let path = path
71-
.map(|x| x.value().into())
72-
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
73-
util::read_wit_type_from_file(path, |kebab_name, ct| {
72+
let parsed_bindgen_input = syn::parse_macro_input!(input as BindgenInputParams);
73+
let path = parsed_bindgen_input.path.unwrap_or_else(|| {
74+
let wit_world_env = std::env::var_os("WIT_WORLD");
75+
76+
if let Some(env) = wit_world_env {
77+
std::path::PathBuf::from(env)
78+
} else {
79+
std::path::PathBuf::new()
80+
}
81+
});
82+
let world_name = parsed_bindgen_input.world_name;
83+
84+
util::read_wit_type_from_file(path, world_name, |kebab_name, ct| {
7485
let decls = emit::run_state(false, false, |s| {
7586
rtypes::emit_toplevel(s, &kebab_name, ct);
7687
host::emit_toplevel(s, &kebab_name, ct);
@@ -89,11 +100,19 @@ pub fn host_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
89100
#[proc_macro]
90101
pub fn guest_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
91102
let _ = env_logger::try_init();
92-
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
93-
let path = path
94-
.map(|x| x.value().into())
95-
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
96-
util::read_wit_type_from_file(path, |kebab_name, ct| {
103+
let parsed_bindgen_input = syn::parse_macro_input!(input as BindgenInputParams);
104+
let path = parsed_bindgen_input.path.unwrap_or_else(|| {
105+
let wit_world_env = std::env::var_os("WIT_WORLD");
106+
107+
if let Some(env) = wit_world_env {
108+
std::path::PathBuf::from(env)
109+
} else {
110+
std::path::PathBuf::new()
111+
}
112+
});
113+
let world_name = parsed_bindgen_input.world_name;
114+
115+
util::read_wit_type_from_file(path, world_name, |kebab_name, ct| {
97116
let decls = emit::run_state(true, false, |s| {
98117
// Emit type/trait definitions for all instances in the world
99118
rtypes::emit_toplevel(s, &kebab_name, ct);
@@ -107,3 +126,52 @@ pub fn guest_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream
107126
util::emit_decls(decls).into()
108127
})
109128
}
129+
130+
#[derive(Debug)]
131+
struct BindgenInputParams {
132+
world_name: Option<String>,
133+
path: Option<std::path::PathBuf>,
134+
}
135+
136+
impl Parse for BindgenInputParams {
137+
fn parse(input: ParseStream) -> Result<Self> {
138+
let mut path = None;
139+
let mut world_name = None;
140+
141+
if input.peek(syn::token::Brace) {
142+
let content;
143+
syn::braced!(content in input);
144+
eprintln!("Content = \n {:?}", content);
145+
146+
// Parse key-value pairs inside the braces
147+
while !content.is_empty() {
148+
let key: Ident = content.parse()?;
149+
content.parse::<Token![:]>()?;
150+
151+
match key.to_string().as_str() {
152+
"world_name" => {
153+
let value: LitStr = content.parse()?;
154+
world_name = Some(value.value());
155+
}
156+
"path" => {
157+
let value: LitStr = content.parse()?;
158+
path = Some(std::path::PathBuf::from(value.value()));
159+
}
160+
_ => {
161+
return Err(syn::Error::new(key.span(), format!("Unknown key: {}", key)));
162+
}
163+
}
164+
// Parse optional comma
165+
if content.peek(Token![,]) {
166+
content.parse::<Token![,]>()?;
167+
}
168+
}
169+
} else {
170+
let option_path_litstr = input.parse::<Option<syn::LitStr>>()?;
171+
if let Some(concrete_path) = option_path_litstr {
172+
path = Some(std::path::PathBuf::from(concrete_path.value()));
173+
}
174+
}
175+
Ok(Self { world_name, path })
176+
}
177+
}

src/hyperlight_component_util/src/component.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ fn raw_type_export_type<'p, 'a, 'c>(
8282
/// export.
8383
pub fn read_component_single_exported_type<'a>(
8484
items: impl Iterator<Item = wasmparser::Result<Payload<'a>>>,
85+
world_name: Option<String>,
8586
) -> Component<'a> {
8687
let mut ctx = Ctx::new(None, false);
87-
let mut last_idx = None;
88+
let mut picks_one_world_or_last_idx = None;
8889
for x in items {
8990
match x {
9091
Ok(Version { num, encoding, .. }) => {
@@ -112,8 +113,23 @@ pub fn read_component_single_exported_type<'a>(
112113
Err(_) => panic!("invalid export section"),
113114
Ok(ce) => {
114115
if ce.kind == ComponentExternalKind::Type {
115-
last_idx = Some(ctx.types.len());
116116
ctx.types.push(raw_type_export_type(&ctx, &ce).clone());
117+
118+
// picks the world index if world is passed in the proc_macro
119+
// else picks the index of last type, exported by core module
120+
if world_name.is_some() {
121+
let world = world_name.clone().unwrap();
122+
match ce.name {
123+
wasmparser::ComponentExportName(name) => {
124+
if name.eq_ignore_ascii_case(&world) {
125+
picks_one_world_or_last_idx =
126+
Some(ctx.types.len() - 1);
127+
}
128+
}
129+
}
130+
} else {
131+
picks_one_world_or_last_idx = Some(ctx.types.len() - 1);
132+
}
117133
}
118134
}
119135
}
@@ -149,7 +165,8 @@ pub fn read_component_single_exported_type<'a>(
149165
_ => {}
150166
}
151167
}
152-
match last_idx {
168+
169+
match picks_one_world_or_last_idx {
153170
None => panic!("no exported type"),
154171
Some(n) => match ctx.types.into_iter().nth(n) {
155172
Some(Defined::Component(c)) => c,

src/hyperlight_component_util/src/util.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::etypes;
2121
/// given filename, relative to the cargo manifest directory.
2222
pub fn read_wit_type_from_file<R, F: FnMut(String, &etypes::Component) -> R>(
2323
filename: impl AsRef<std::ffi::OsStr>,
24+
world_name: Option<String>,
2425
mut cb: F,
2526
) -> R {
2627
let path = std::path::Path::new(&filename);
@@ -30,7 +31,8 @@ pub fn read_wit_type_from_file<R, F: FnMut(String, &etypes::Component) -> R>(
3031

3132
let bytes = std::fs::read(path).unwrap();
3233
let i = wasmparser::Parser::new(0).parse_all(&bytes);
33-
let ct = crate::component::read_component_single_exported_type(i);
34+
// let ct = crate::component::read_component_single_exported_type(i);
35+
let ct = crate::component::read_component_single_exported_type(i, world_name);
3436

3537
// because of the two-level encapsulation scheme, we need to look
3638
// for the single export of the component type that we just read

src/hyperlight_host/tests/wit_test.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,27 @@ mod wit_test {
426426
drop(guard);
427427
}
428428
}
429+
430+
mod pick_world_bindings {
431+
hyperlight_component_macro::host_bindgen!({path: "../tests/rust_guests/witguest/twoworlds.wasm", world_name: "firstworld"});
432+
}
433+
434+
use pick_world_bindings::*;
435+
436+
impl pick_world_bindings::twoworlds::wit::first_import::RecFirstImport {
437+
fn new() -> Option<Self> {
438+
Some(Self {
439+
key: "dummyKey",
440+
value: "dummyValue",
441+
})
442+
}
443+
}
444+
445+
mod pick_world_binding_test {
446+
use crate::pick_world_bindings::twoworlds::wit::first_import::*;
447+
#[test]
448+
fn test_first_import_instance() {
449+
let firstImport = FirstWorldResources::new();
450+
assert!(firstImport.is_some());
451+
}
452+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package twoworlds:wit;
2+
3+
world secondworld {
4+
export second-export;
5+
}
6+
7+
world firstworld {
8+
import first-import;
9+
}
10+
11+
interface second-export {
12+
record rec-second-export {
13+
key : string,
14+
value: string
15+
}
16+
}
17+
18+
interface first-import {
19+
record rec-first-import {
20+
key: string,
21+
value : string
22+
}
23+
}

0 commit comments

Comments
 (0)