Skip to content

Commit e067cc1

Browse files
authored
Update how async configuration is processed (#1278)
This commit updates the Rust bindings generator for async to respect the `async` annotations in WIT by default. The `--async` flag and `async: { ... }` configuration have changed as well to be modeled as "this is an override" where the fallback is "what the WIT says".
1 parent 1e8b241 commit e067cc1

File tree

5 files changed

+186
-147
lines changed

5 files changed

+186
-147
lines changed

crates/guest-rust/macro/src/lib.rs

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syn::punctuated::Punctuated;
88
use syn::spanned::Spanned;
99
use syn::{braced, token, LitStr, Token};
1010
use wit_bindgen_core::wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId};
11-
use wit_bindgen_rust::{AsyncConfig, Opts, Ownership, WithOption};
11+
use wit_bindgen_rust::{Async, AsyncFilter, Opts, Ownership, WithOption};
1212

1313
#[proc_macro]
1414
pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
@@ -155,7 +155,7 @@ impl Parse for Config {
155155
return Err(Error::new(span, "cannot specify second async config"));
156156
}
157157
async_configured = true;
158-
if !matches!(val, AsyncConfig::None) && !cfg!(feature = "async") {
158+
if val.iter().any(|v| v.enabled) && !cfg!(feature = "async") {
159159
return Err(Error::new(
160160
span,
161161
"must enable `async` feature to enable async imports and/or exports",
@@ -369,11 +369,6 @@ impl From<ExportKey> for wit_bindgen_rust::ExportKey {
369369
}
370370
}
371371

372-
enum AsyncConfigSomeKind {
373-
Imports,
374-
Exports,
375-
}
376-
377372
enum Opt {
378373
World(syn::LitStr),
379374
Path(Span, Vec<syn::LitStr>),
@@ -399,7 +394,7 @@ enum Opt {
399394
GenerateUnusedTypes(syn::LitBool),
400395
Features(Vec<syn::LitStr>),
401396
DisableCustomSectionLinkHelpers(syn::LitBool),
402-
Async(AsyncConfig, Span),
397+
Async(Vec<Async>, Span),
403398
Debug(syn::LitBool),
404399
}
405400

@@ -563,25 +558,22 @@ impl Parse for Opt {
563558
let span = input.parse::<Token![async]>()?.span;
564559
input.parse::<Token![:]>()?;
565560
if input.peek(syn::LitBool) {
566-
if input.parse::<syn::LitBool>()?.value {
567-
Ok(Opt::Async(AsyncConfig::All, span))
568-
} else {
569-
Ok(Opt::Async(AsyncConfig::None, span))
570-
}
561+
let enabled = input.parse::<syn::LitBool>()?.value;
562+
Ok(Opt::Async(
563+
vec![Async {
564+
enabled,
565+
filter: AsyncFilter::All,
566+
}],
567+
span,
568+
))
571569
} else {
572-
let mut imports = Vec::new();
573-
let mut exports = Vec::new();
570+
let mut vals = Vec::new();
574571
let contents;
575-
syn::braced!(contents in input);
576-
for (kind, values) in
577-
contents.parse_terminated(parse_async_some_field, Token![,])?
578-
{
579-
match kind {
580-
AsyncConfigSomeKind::Imports => imports = values,
581-
AsyncConfigSomeKind::Exports => exports = values,
582-
}
572+
syn::bracketed!(contents in input);
573+
for val in contents.parse_terminated(parse_async, Token![,])? {
574+
vals.push(val);
583575
}
584-
Ok(Opt::Async(AsyncConfig::Some { imports, exports }, span))
576+
Ok(Opt::Async(vals, span))
585577
}
586578
} else {
587579
Err(l.error())
@@ -642,26 +634,7 @@ fn fmt(input: &str) -> Result<String> {
642634
Ok(prettyplease::unparse(&syntax_tree))
643635
}
644636

645-
fn parse_async_some_field(input: ParseStream<'_>) -> Result<(AsyncConfigSomeKind, Vec<String>)> {
646-
let lookahead = input.lookahead1();
647-
let kind = if lookahead.peek(kw::imports) {
648-
input.parse::<kw::imports>()?;
649-
input.parse::<Token![:]>()?;
650-
AsyncConfigSomeKind::Imports
651-
} else if lookahead.peek(kw::exports) {
652-
input.parse::<kw::exports>()?;
653-
input.parse::<Token![:]>()?;
654-
AsyncConfigSomeKind::Exports
655-
} else {
656-
return Err(lookahead.error());
657-
};
658-
659-
let list;
660-
syn::bracketed!(list in input);
661-
let fields = list.parse_terminated(Parse::parse, Token![,])?;
662-
663-
Ok((
664-
kind,
665-
fields.iter().map(|s: &syn::LitStr| s.value()).collect(),
666-
))
637+
fn parse_async(input: ParseStream<'_>) -> Result<Async> {
638+
let value = input.parse::<syn::LitStr>()?.value();
639+
Ok(Async::parse(&value))
667640
}

crates/guest-rust/src/lib.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -839,18 +839,19 @@
839839
/// //
840840
/// // The resulting bindings will use the component model
841841
/// // [async ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md).
842-
/// // This may be specified either as a boolean (e.g. `async: true`, meaning
843-
/// // all imports and exports should use the async ABI) or as lists of
844-
/// // specific imports and/or exports as shown here:
845-
/// async: {
846-
/// imports: [
847-
/// "wasi:http/[email protected]#[static]body.finish",
848-
/// "wasi:http/[email protected]#handle",
849-
/// ],
850-
/// exports: [
851-
/// "wasi:http/[email protected]#handle",
852-
/// ]
853-
/// }
842+
/// //
843+
/// // If this option is not provided then the WIT's source annotation will
844+
/// // be used instead.
845+
/// async: true, // all bindings are async
846+
/// async: false, // all bindings are sync
847+
/// // With an array per-function configuration can be specified. A leading
848+
/// // '-' will disable async for that particular function.
849+
/// async: [
850+
/// "wasi:http/[email protected]#[static]body.finish",
851+
/// "import:wasi:http/[email protected]#handle",
852+
/// "-export:wasi:http/[email protected]#handle",
853+
/// "all",
854+
/// ],
854855
/// });
855856
/// ```
856857
///

crates/rust/src/bindgen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
885885
self.push_str(&prev_src);
886886
let constructor_type = match &func.kind {
887887
FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
888-
self.push_str(&format!("T::{}", to_rust_ident(&func.name)));
888+
self.push_str(&format!("T::{}", to_rust_ident(func.item_name())));
889889
None
890890
}
891891
FunctionKind::Method(_)

crates/rust/src/interface.rs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::bindgen::{FunctionBindgen, POINTER_SIZE_EXPRESSION};
22
use crate::{
3-
full_wit_type_name, int_repr, to_rust_ident, to_upper_camel_case, wasm_type, AsyncConfig,
4-
FnSig, Identifier, InterfaceName, Ownership, RuntimeItem, RustFlagsRepr, RustWasm,
5-
TypeGeneration,
3+
full_wit_type_name, int_repr, to_rust_ident, to_upper_camel_case, wasm_type, FnSig, Identifier,
4+
InterfaceName, Ownership, RuntimeItem, RustFlagsRepr, RustWasm, TypeGeneration,
65
};
76
use anyhow::Result;
87
use heck::*;
@@ -162,17 +161,9 @@ impl<'i> InterfaceGenerator<'i> {
162161
continue;
163162
}
164163

165-
let async_ = match &self.r#gen.opts.async_ {
166-
AsyncConfig::None => false,
167-
AsyncConfig::All => true,
168-
AsyncConfig::Some { exports, .. } => {
169-
exports.contains(&if let Some((_, key)) = interface {
170-
format!("{}#{}", self.resolve.name_world_key(key), func.name)
171-
} else {
172-
func.name.clone()
173-
})
174-
}
175-
};
164+
let async_ = self
165+
.r#gen
166+
.is_async(self.resolve, interface.map(|p| p.1), func, false);
176167
let resource = func.kind.resource();
177168

178169
funcs_to_export.push((func, resource, async_));
@@ -712,15 +703,7 @@ pub mod vtable{ordinal} {{
712703

713704
self.generate_payloads("", func, interface);
714705

715-
let async_ = match &self.r#gen.opts.async_ {
716-
AsyncConfig::None => false,
717-
AsyncConfig::All => true,
718-
AsyncConfig::Some { imports, .. } => imports.contains(&if let Some(key) = interface {
719-
format!("{}#{}", self.resolve.name_world_key(key), func.name)
720-
} else {
721-
func.name.clone()
722-
}),
723-
};
706+
let async_ = self.r#gen.is_async(self.resolve, interface, func, true);
724707
let mut sig = FnSig {
725708
async_,
726709
..Default::default()
@@ -1227,17 +1210,9 @@ unsafe fn call_import(params: *mut u8, results: *mut u8) -> u32 {{
12271210
if self.r#gen.skip.contains(&func.name) {
12281211
continue;
12291212
}
1230-
let async_ = match &self.r#gen.opts.async_ {
1231-
AsyncConfig::None => false,
1232-
AsyncConfig::All => true,
1233-
AsyncConfig::Some { exports, .. } => {
1234-
exports.contains(&if let Some((_, key)) = interface {
1235-
format!("{}#{}", self.resolve.name_world_key(key), func.name)
1236-
} else {
1237-
func.name.clone()
1238-
})
1239-
}
1240-
};
1213+
let async_ = self
1214+
.r#gen
1215+
.is_async(self.resolve, interface.map(|p| p.1), func, false);
12411216
let mut sig = FnSig {
12421217
async_,
12431218
use_item_name: true,
@@ -1349,7 +1324,7 @@ unsafe fn call_import(params: *mut u8, results: *mut u8) -> u32 {{
13491324
func.item_name()
13501325
}
13511326
} else {
1352-
&func.name
1327+
func.item_name()
13531328
};
13541329
self.push_str(&to_rust_ident(func_name));
13551330
if let Some(generics) = &sig.generics {

0 commit comments

Comments
 (0)