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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user