Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion crates/guest-rust/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use syn::{LitStr, Token, braced, token};
use wit_bindgen_core::AsyncFilterSet;
use wit_bindgen_core::WorldGenerator;
use wit_bindgen_core::wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId};
use wit_bindgen_rust::{Opts, Ownership, WithOption};
use wit_bindgen_rust::{NativeStubMacro, Opts, Ownership, WithOption};

#[proc_macro]
pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
Expand Down Expand Up @@ -49,6 +49,7 @@ struct Config {
world: WorldId,
files: Vec<PathBuf>,
debug: bool,
native_stub_macro: Option<NativeStubMacro>,
}

/// The source of the wit package definition
Expand All @@ -68,6 +69,7 @@ impl Parse for Config {
let mut features = Vec::new();
let mut async_configured = false;
let mut debug = false;
let mut native_stub_macro = None;

if input.peek(token::Brace) {
let content;
Expand Down Expand Up @@ -165,6 +167,12 @@ impl Parse for Config {
}
opts.async_ = val;
}
Opt::NativeStubMacro(path, extra) => {
native_stub_macro = Some(NativeStubMacro {
macro_path: path.to_token_stream().to_string(),
extra_args: extra.map(|t| t.to_string()),
});
}
}
}
} else {
Expand All @@ -186,6 +194,7 @@ impl Parse for Config {
world,
files,
debug,
native_stub_macro,
})
}
}
Expand Down Expand Up @@ -245,6 +254,7 @@ impl Config {
fn expand(mut self) -> Result<TokenStream> {
let mut files = Default::default();
let mut generator = self.opts.build();
generator.native_stub_macro = self.native_stub_macro;
generator
.generate(&mut self.resolve, self.world, &mut files)
.map_err(|e| anyhow_to_syn(Span::call_site(), e))?;
Expand Down Expand Up @@ -317,6 +327,7 @@ mod kw {
syn::custom_keyword!(disable_custom_section_link_helpers);
syn::custom_keyword!(imports);
syn::custom_keyword!(debug);
syn::custom_keyword!(native_stub_macro);
}

#[derive(Clone)]
Expand Down Expand Up @@ -373,6 +384,7 @@ enum Opt {
DisableCustomSectionLinkHelpers(syn::LitBool),
Async(AsyncFilterSet, Span),
Debug(syn::LitBool),
NativeStubMacro(syn::Path, Option<proc_macro2::TokenStream>),
}

impl Parse for Opt {
Expand Down Expand Up @@ -546,6 +558,19 @@ impl Parse for Opt {
}
Ok(Opt::Async(set, span))
}
} else if l.peek(kw::native_stub_macro) {
input.parse::<kw::native_stub_macro>()?;
input.parse::<Token![:]>()?;
let macro_path: syn::Path = input.parse()?;
let extra = if input.peek(Token![!]) {
input.parse::<Token![!]>()?;
let content;
syn::parenthesized!(content in input);
Some(content.parse::<proc_macro2::TokenStream>()?)
} else {
None
};
Ok(Opt::NativeStubMacro(macro_path, extra))
} else {
Err(l.error())
}
Expand Down
2 changes: 2 additions & 0 deletions crates/rust/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
&rust_name,
params,
results,
&self.r#gen.r#gen.native_stub_macro,
&mut self.r#gen.r#gen.native_stub_methods,
));
rust_name
}
Expand Down
8 changes: 8 additions & 0 deletions crates/rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,17 @@ impl<'i> InterfaceGenerator<'i> {
"new",
&[abi::WasmType::Pointer],
&[abi::WasmType::I32],
&self.r#gen.native_stub_macro,
&mut self.r#gen.native_stub_methods,
);
let import_rep = crate::declare_import(
&wasm_import_module,
&format!("[resource-rep]{resource_name}"),
"rep",
&[abi::WasmType::I32],
&[abi::WasmType::Pointer],
&self.r#gen.native_stub_macro,
&mut self.r#gen.native_stub_methods,
);
uwriteln!(
self.src,
Expand Down Expand Up @@ -956,6 +960,8 @@ fn abi_layout(&mut self) -> ::core::alloc::Layout {{
"call",
&sig.params,
&sig.results,
&self.r#gen.native_stub_macro,
&mut self.r#gen.native_stub_methods,
);
let mut args = String::new();
for i in 0..params_lower.len() {
Expand Down Expand Up @@ -2799,6 +2805,8 @@ impl<'a> {camel}Borrow<'a>{{
"drop",
&[abi::WasmType::I32],
&[],
&self.r#gen.native_stub_macro,
&mut self.r#gen.native_stub_methods,
);
uwriteln!(
self.src,
Expand Down
95 changes: 92 additions & 3 deletions crates/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ pub struct RustWasm {

future_payloads: IndexMap<Option<Type>, String>,
stream_payloads: IndexMap<Option<Type>, String>,

pub native_stub_macro: Option<NativeStubMacro>,
pub native_stub_methods: Vec<NativeStubMethod>,
}

pub struct NativeStubMacro {
pub macro_path: String,
pub extra_args: Option<String>,
}

#[derive(Debug, Clone)]
pub struct NativeStubMethod {
pub wasm_import_module: String,
pub wasm_import_name: String,
pub rust_name: String,
pub params: Vec<WasmType>,
pub results: Vec<WasmType>,
}

#[derive(Default)]
Expand Down Expand Up @@ -824,6 +841,50 @@ impl As{upcase} for {to_convert} {{
}
}

fn finish_native_stubs(&mut self) {
let Some(stub) = &self.native_stub_macro else {
return;
};
if self.native_stub_methods.is_empty() {
return;
}

let macro_path = &stub.macro_path;
let extra = match &stub.extra_args {
Some(args) => format!("{args}, "),
None => String::new(),
};

let mut entries = String::new();
for method in self.native_stub_methods.iter() {
let NativeStubMethod {
wasm_import_module,
wasm_import_name,
rust_name,
params,
results,
} = &method;

entries.push_str(&format!(
" \"{wasm_import_module}\", \"{wasm_import_name}\", fn {rust_name}("
));

for (i, param) in params.iter().enumerate() {
if i > 0 {
entries.push_str(", ");
}
entries.push_str(&format!("p{i}: {}", wasm_type(*param)));
}
entries.push(')');
if !method.results.is_empty() {
entries.push_str(&format!(" -> {}", wasm_type(results[0])));
}
entries.push_str(";\n");
}

uwriteln!(self.src, "{macro_path}!(@definitions {extra}{entries});");
}

/// Generates an `export!` macro for the `world_id` specified.
///
/// This will generate a macro which will then itself invoke all the
Expand Down Expand Up @@ -1392,6 +1453,7 @@ impl WorldGenerator for RustWasm {
self.emit_modules(exports);

self.finish_runtime_module();
self.finish_native_stubs();
self.finish_export_macro(resolve, world);

// This is a bit tricky, but we sometimes want to "split" the `world` in
Expand Down Expand Up @@ -1741,10 +1803,12 @@ fn declare_import(
rust_name: &str,
params: &[WasmType],
results: &[WasmType],
native_stub_macro: &Option<NativeStubMacro>,
native_stub_methods: &mut Vec<NativeStubMethod>,
) -> String {
let mut sig = "(".to_owned();
for param in params.iter() {
sig.push_str("_: ");
for (i, param) in params.iter().enumerate() {
sig.push_str(&format!("p{i}: "));
sig.push_str(wasm_type(*param));
sig.push_str(", ");
}
Expand All @@ -1754,6 +1818,31 @@ fn declare_import(
sig.push_str(" -> ");
sig.push_str(wasm_type(*result));
}

let native_stub = if let Some(stub) = native_stub_macro {
native_stub_methods.push(NativeStubMethod {
wasm_import_module: wasm_import_module.to_string(),
wasm_import_name: wasm_import_name.to_string(),
rust_name: rust_name.to_string(),
params: params.to_vec(),
results: results.to_vec(),
});

let macro_path = &stub.macro_path;
let extra = match &stub.extra_args {
Some(args) => format!("{args}, "),
None => String::new(),
};
format!(
"unsafe extern \"C\" fn {rust_name}{sig} {{ \
{macro_path}!({extra} \"{wasm_import_module}\", \
\"{wasm_import_name}\", fn {rust_name}{sig}) \
}}"
)
} else {
format!("unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}")
};

format!(
"
#[cfg(target_arch = \"wasm32\")]
Expand All @@ -1764,7 +1853,7 @@ fn declare_import(
}}

#[cfg(not(target_arch = \"wasm32\"))]
unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
{native_stub}
"
)
}
Expand Down
Loading