Add only_interfaces and with to the bindgen! macro. (#6160)
* Add `only_interfaces` and `with` to the `bindgen!` macro. * Add a version of the empty_error test for `only_interfaces` and `with` * Review feedback * Add docs
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use syn::parse::{Error, Parse, ParseStream, Result};
|
||||
use syn::punctuated::Punctuated;
|
||||
@@ -77,6 +78,8 @@ impl Parse for Config {
|
||||
Opt::Async(val) => opts.async_ = val,
|
||||
Opt::TrappableErrorType(val) => opts.trappable_error_type = val,
|
||||
Opt::DuplicateIfNecessary(val) => opts.duplicate_if_necessary = val,
|
||||
Opt::OnlyInterfaces(val) => opts.only_interfaces = val,
|
||||
Opt::With(val) => opts.with.extend(val),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -133,6 +136,8 @@ mod kw {
|
||||
syn::custom_keyword!(trappable_error_type);
|
||||
syn::custom_keyword!(world);
|
||||
syn::custom_keyword!(duplicate_if_necessary);
|
||||
syn::custom_keyword!(only_interfaces);
|
||||
syn::custom_keyword!(with);
|
||||
}
|
||||
|
||||
enum Opt {
|
||||
@@ -143,6 +148,8 @@ enum Opt {
|
||||
Async(bool),
|
||||
TrappableErrorType(Vec<TrappableError>),
|
||||
DuplicateIfNecessary(bool),
|
||||
OnlyInterfaces(bool),
|
||||
With(HashMap<String, String>),
|
||||
}
|
||||
|
||||
impl Parse for Opt {
|
||||
@@ -191,6 +198,18 @@ impl Parse for Opt {
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
} else if l.peek(kw::only_interfaces) {
|
||||
input.parse::<kw::only_interfaces>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
Ok(Opt::OnlyInterfaces(input.parse::<syn::LitBool>()?.value))
|
||||
} else if l.peek(kw::with) {
|
||||
input.parse::<kw::with>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
let contents;
|
||||
let _lbrace = braced!(contents in input);
|
||||
let fields: Punctuated<(String, String), Token![,]> =
|
||||
contents.parse_terminated(with_field_parse)?;
|
||||
Ok(Opt::With(HashMap::from_iter(fields.into_iter())))
|
||||
} else {
|
||||
Err(l.error())
|
||||
}
|
||||
@@ -219,3 +238,46 @@ fn trappable_error_field_parse(input: ParseStream<'_>) -> Result<(String, String
|
||||
let rust_type = input.parse::<Ident>()?.to_string();
|
||||
Ok((interface, type_, rust_type))
|
||||
}
|
||||
|
||||
fn with_field_parse(input: ParseStream<'_>) -> Result<(String, String)> {
|
||||
let interface = input.parse::<syn::LitStr>()?.value();
|
||||
input.parse::<Token![:]>()?;
|
||||
let start = input.span();
|
||||
let path = input.parse::<syn::Path>()?;
|
||||
|
||||
// It's not possible for the segments of a path to be empty
|
||||
let span = start
|
||||
.join(path.segments.last().unwrap().ident.span())
|
||||
.unwrap_or(start);
|
||||
|
||||
let mut buf = String::new();
|
||||
let append = |buf: &mut String, segment: syn::PathSegment| -> Result<()> {
|
||||
if segment.arguments != syn::PathArguments::None {
|
||||
return Err(Error::new(
|
||||
span,
|
||||
"Module path must not contain angles or parens",
|
||||
));
|
||||
}
|
||||
|
||||
buf.push_str(&segment.ident.to_string());
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if path.leading_colon.is_some() {
|
||||
buf.push_str("::");
|
||||
}
|
||||
|
||||
let mut segments = path.segments.into_iter();
|
||||
|
||||
if let Some(segment) = segments.next() {
|
||||
append(&mut buf, segment)?;
|
||||
}
|
||||
|
||||
for segment in segments {
|
||||
buf.push_str("::");
|
||||
append(&mut buf, segment)?;
|
||||
}
|
||||
|
||||
Ok((interface, buf))
|
||||
}
|
||||
|
||||
@@ -21,9 +21,17 @@ macro_rules! gentest {
|
||||
duplicate_if_necessary: true,
|
||||
});
|
||||
}
|
||||
mod interfaces_only {
|
||||
wasmtime::component::bindgen!({
|
||||
path: $path,
|
||||
world: $name,
|
||||
only_interfaces: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
component_macro_test_helpers::foreach!(gentest);
|
||||
|
||||
Reference in New Issue
Block a user