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:
Trevor Elliott
2023-04-10 16:28:52 -07:00
committed by GitHub
parent 4053ae9e08
commit 85f0c68008
5 changed files with 257 additions and 8 deletions

View File

@@ -25,6 +25,15 @@ mod source;
mod types;
use source::Source;
struct InterfaceName {
/// True when this interface name has been remapped through the use of `with` in the `bindgen!`
/// macro invocation.
remapped: bool,
/// The string name for this interface.
name: String,
}
#[derive(Default)]
struct Wasmtime {
src: Source,
@@ -33,7 +42,7 @@ struct Wasmtime {
exports: Exports,
types: Types,
sizes: SizeAlign,
interface_names: HashMap<InterfaceId, String>,
interface_names: HashMap<InterfaceId, InterfaceName>,
}
enum Import {
@@ -66,6 +75,13 @@ pub struct Opts {
/// WIT type if necessary, for example if it's used as both an import and an
/// export.
pub duplicate_if_necessary: bool,
/// Whether or not to generate code for only the interfaces of this wit file or not.
pub only_interfaces: bool,
/// Remapping of interface names to rust module names.
/// TODO: is there a better type to use for the value of this map?
pub with: HashMap<String, String>,
}
#[derive(Debug, Clone)]
@@ -95,14 +111,37 @@ impl Opts {
}
impl Wasmtime {
fn name_interface(&mut self, id: InterfaceId, name: String) -> bool {
let entry = if let Some(remapped_name) = self.opts.with.get(&name) {
InterfaceName {
remapped: true,
name: remapped_name.clone(),
}
} else {
InterfaceName {
remapped: false,
name,
}
};
let remapped = entry.remapped;
self.interface_names.insert(id, entry);
remapped
}
fn generate(&mut self, resolve: &Resolve, id: WorldId) -> String {
self.types.analyze(resolve, id);
let world = &resolve.worlds[id];
for (name, import) in world.imports.iter() {
self.import(resolve, name, import);
if !self.opts.only_interfaces || matches!(import, WorldItem::Interface(_)) {
self.import(resolve, name, import);
}
}
for (name, export) in world.exports.iter() {
self.export(resolve, name, export);
if !self.opts.only_interfaces || matches!(export, WorldItem::Interface(_)) {
self.export(resolve, name, export);
}
}
self.finish(resolve, id)
}
@@ -119,7 +158,9 @@ impl Wasmtime {
Import::Function { sig, add_to_linker }
}
WorldItem::Interface(id) => {
gen.gen.interface_names.insert(*id, snake.clone());
if gen.gen.name_interface(*id, snake.clone()) {
return;
}
gen.current_interface = Some(*id);
gen.types(*id);
gen.generate_trappable_error_types(TypeOwner::Interface(*id));
@@ -166,7 +207,7 @@ impl Wasmtime {
}
WorldItem::Type(_) => unreachable!(),
WorldItem::Interface(id) => {
gen.gen.interface_names.insert(*id, snake.clone());
gen.gen.name_interface(*id, snake.clone());
gen.current_interface = Some(*id);
gen.types(*id);
gen.generate_trappable_error_types(TypeOwner::Interface(*id));
@@ -246,7 +287,7 @@ impl Wasmtime {
assert!(prev.is_none());
}
fn finish(&mut self, resolve: &Resolve, world: WorldId) -> String {
fn build_struct(&mut self, resolve: &Resolve, world: WorldId) {
let camel = to_rust_upper_camel_case(&resolve.worlds[world].name);
uwriteln!(self.src, "pub struct {camel} {{");
for (name, (ty, _)) in self.exports.fields.iter() {
@@ -327,6 +368,12 @@ impl Wasmtime {
uwriteln!(self.src, "}}"); // close `impl {camel}`
uwriteln!(self.src, "}};"); // close `const _: () = ...
}
fn finish(&mut self, resolve: &Resolve, world: WorldId) -> String {
if !self.opts.only_interfaces {
self.build_struct(resolve, world)
}
let mut src = mem::take(&mut self.src);
if self.opts.rustfmt {
@@ -1398,8 +1445,8 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
match self.current_interface {
Some(id) if id == interface => None,
_ => {
let name = &self.gen.interface_names[&interface];
Some(if self.current_interface.is_some() {
let InterfaceName { remapped, name } = &self.gen.interface_names[&interface];
Some(if self.current_interface.is_some() && !remapped {
format!("super::{name}")
} else {
name.clone()