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
191 changes: 88 additions & 103 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ prettyplease = "0.2.20"
syn = { version = "2.0.89", features = ["printing"] }
futures = "0.3.31"

wat = "1.245.1"
wasmparser = "0.245.1"
wasm-encoder = "0.245.1"
wasm-metadata = { version = "0.245.1", default-features = false }
wit-parser = "0.245.1"
wit-component = "0.245.1"
wasm-compose = "0.245.1"
wat = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }
wasmparser = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }
wasm-encoder = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }
wasm-metadata = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements", default-features = false }
wit-parser = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }
wit-component = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }
wasm-compose = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" }

wit-bindgen-core = { path = 'crates/core', version = '0.53.1' }
wit-bindgen-c = { path = 'crates/c', version = '0.53.1' }
Expand Down
45 changes: 34 additions & 11 deletions crates/c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,18 +211,27 @@ impl WorldGenerator for C {
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
implements: Option<InterfaceId>,
_files: &mut Files,
) -> Result<()> {
let wasm_import_module = resolve.name_world_key(name);
let wasm_import_module =
wit_bindgen_core::wasm_import_module_name(resolve, name, implements);
let mut r#gen = self.interface(resolve, true, Some(&wasm_import_module));
r#gen.interface = Some((id, name));
r#gen.implements = implements;
r#gen.define_interface_types(id);

for (i, (_name, func)) in resolve.interfaces[id].functions.iter().enumerate() {
if i == 0 {
let name = resolve.name_world_key(name);
uwriteln!(r#gen.src.h_fns, "\n// Imported Functions from `{name}`");
uwriteln!(r#gen.src.c_fns, "\n// Imported Functions from `{name}`");
let display_name = resolve.name_world_key(name);
uwriteln!(
r#gen.src.h_fns,
"\n// Imported Functions from `{display_name}`"
);
uwriteln!(
r#gen.src.c_fns,
"\n// Imported Functions from `{display_name}`"
);
}
r#gen.import(Some(name), func);
}
Expand Down Expand Up @@ -259,17 +268,25 @@ impl WorldGenerator for C {
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
implements: Option<InterfaceId>,
_files: &mut Files,
) -> Result<()> {
let mut r#gen = self.interface(resolve, false, None);
r#gen.interface = Some((id, name));
r#gen.implements = implements;
r#gen.define_interface_types(id);

for (i, (_name, func)) in resolve.interfaces[id].functions.iter().enumerate() {
if i == 0 {
let name = resolve.name_world_key(name);
uwriteln!(r#gen.src.h_fns, "\n// Exported Functions from `{name}`");
uwriteln!(r#gen.src.c_fns, "\n// Exported Functions from `{name}`");
let display_name = resolve.name_world_key(name);
uwriteln!(
r#gen.src.h_fns,
"\n// Exported Functions from `{display_name}`"
);
uwriteln!(
r#gen.src.c_fns,
"\n// Exported Functions from `{display_name}`"
);
}
r#gen.export(func, Some(name));
}
Expand Down Expand Up @@ -601,6 +618,7 @@ impl C {
interface: None,
in_import,
wasm_import_module,
implements: None,
}
}

Expand Down Expand Up @@ -1297,6 +1315,7 @@ struct InterfaceGenerator<'a> {
resolve: &'a Resolve,
interface: Option<(InterfaceId, &'a WorldKey)>,
wasm_import_module: Option<&'a str>,
implements: Option<InterfaceId>,
}

impl C {
Expand Down Expand Up @@ -1893,6 +1912,10 @@ pub fn gen_type_name(resolve: &Resolve, ty: TypeId) -> (CTypeNameInfo<'_>, Strin
}

impl InterfaceGenerator<'_> {
fn wasm_name_world_key(&self, key: &WorldKey) -> String {
wit_bindgen_core::wasm_import_module_name(self.resolve, key, self.implements)
}

fn define_interface_types(&mut self, id: InterfaceId) {
let mut live = LiveTypes::default();
live.add_interface(self.resolve, id);
Expand Down Expand Up @@ -2122,7 +2145,7 @@ impl InterfaceGenerator<'_> {
self.src.c_fns,
"__attribute__((__import_module__(\"{}\"), __import_name__(\"{import_prefix}{}\")))",
match interface_name {
Some(name) => self.resolve.name_world_key(name),
Some(name) => self.wasm_name_world_key(name),
None => "$root".to_string(),
},
func.name
Expand Down Expand Up @@ -2282,7 +2305,7 @@ impl InterfaceGenerator<'_> {

self.src.c_fns("\n");

let core_module_name = interface_name.map(|s| self.resolve.name_world_key(s));
let core_module_name = interface_name.map(|s| self.wasm_name_world_key(s));
let export_name = func.legacy_core_export_name(core_module_name.as_deref());

// Print the actual header for this function into the header file, and
Expand Down Expand Up @@ -2368,7 +2391,7 @@ impl InterfaceGenerator<'_> {
);
uwriteln!(self.src.h_helpers, "void {name}_return({return_ty});");
let import_module = match interface_name {
Some(name) => self.resolve.name_world_key(name),
Some(name) => self.wasm_name_world_key(name),
None => "$root".to_string(),
};
uwriteln!(
Expand Down Expand Up @@ -2755,7 +2778,7 @@ void {name}_return({return_ty}) {{
let module = format!(
"{prefix}{}",
interface
.map(|name| self.resolve.name_world_key(name))
.map(|name| self.wasm_name_world_key(name))
.unwrap_or_else(|| "$root".into())
);
for (index, ty) in func
Expand Down
36 changes: 31 additions & 5 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ pub enum Direction {
Export,
}

/// Compute the wasm-level import/export module name for an interface,
/// accounting for `implements` items.
///
/// For `implements` items, this produces the `[implements=<I>]label` encoding
/// required by the component model binary format. Otherwise delegates to
/// `resolve.name_world_key(name)`.
pub fn wasm_import_module_name(
resolve: &Resolve,
name: &WorldKey,
implements: Option<InterfaceId>,
) -> String {
match (name, implements) {
(WorldKey::Name(label), Some(impl_id)) => {
let iface_name = resolve
.id_of(impl_id)
.expect("unexpected anonymous interface");
format!("[implements=<{iface_name}>]{label}")
}
_ => resolve.name_world_key(name),
}
}

pub trait WorldGenerator {
fn generate(&mut self, resolve: &mut Resolve, id: WorldId, files: &mut Files) -> Result<()> {
if self.uses_nominal_type_ids() {
Expand All @@ -42,8 +64,8 @@ pub trait WorldGenerator {
for (name, import) in world.imports.iter() {
match import {
WorldItem::Function(f) => funcs.push((unwrap_name(name), f)),
WorldItem::Interface { id, .. } => {
self.import_interface(resolve, name, *id, files)?
WorldItem::Interface { id, implements, .. } => {
self.import_interface(resolve, name, *id, *implements, files)?
}
WorldItem::Type { id, .. } => types.push((unwrap_name(name), *id)),
}
Expand All @@ -68,7 +90,9 @@ pub trait WorldGenerator {
for (name, export) in world.exports.iter() {
match export {
WorldItem::Function(f) => funcs.push((unwrap_name(name), f)),
WorldItem::Interface { id, .. } => interfaces.push((name, id)),
WorldItem::Interface { id, implements, .. } => {
interfaces.push((name, id, implements))
}
WorldItem::Type { .. } => unreachable!(),
}
}
Expand All @@ -78,8 +102,8 @@ pub trait WorldGenerator {

self.pre_export_interface(resolve, files)?;

for (name, id) in interfaces {
self.export_interface(resolve, name, *id, files)?;
for (name, id, implements) in interfaces {
self.export_interface(resolve, name, *id, *implements, files)?;
}
self.finish(resolve, id, files)
}
Expand All @@ -104,6 +128,7 @@ pub trait WorldGenerator {
resolve: &Resolve,
name: &WorldKey,
iface: InterfaceId,
implements: Option<InterfaceId>,
files: &mut Files,
) -> Result<()>;

Expand All @@ -118,6 +143,7 @@ pub trait WorldGenerator {
resolve: &Resolve,
name: &WorldKey,
iface: InterfaceId,
implements: Option<InterfaceId>,
files: &mut Files,
) -> Result<()>;
fn import_funcs(
Expand Down
74 changes: 65 additions & 9 deletions crates/cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ struct Cpp {
// needed for symmetric disambiguation
interface_prefixes: HashMap<(Direction, WorldKey), String>,
import_prefix: Option<String>,
/// Tracks InterfaceIds whose types have already been generated (for implements dedup).
implements_types_generated: HashSet<InterfaceId>,
}

#[cfg(feature = "clap")]
Expand Down Expand Up @@ -330,6 +332,7 @@ impl Cpp {
sizes,
in_guest_import,
wasm_import_module,
implements_label: None,
}
}

Expand Down Expand Up @@ -513,6 +516,7 @@ impl WorldGenerator for Cpp {
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
implements: Option<InterfaceId>,
_files: &mut Files,
) -> anyhow::Result<()> {
self.imported_interfaces.insert(id);
Expand All @@ -528,13 +532,19 @@ impl WorldGenerator for Cpp {
}

let store = self.start_new_file(None);
let wasm_import_module = resolve.name_world_key(name);
let wasm_import_module =
wit_bindgen_core::wasm_import_module_name(resolve, name, implements);
let binding = Some(name);
let should_gen_types = self.implements_types_generated.insert(id);
let mut r#gen = self.interface(resolve, binding, true, Some(wasm_import_module));
r#gen.interface = Some(id);
r#gen.types(id);
let namespace =
namespace(resolve, &TypeOwner::Interface(id), false, &r#gen.r#gen.opts);
if let (WorldKey::Name(label), Some(_)) = (name, implements) {
r#gen.implements_label = Some((label.clone(), false));
}
if should_gen_types {
r#gen.types(id);
}
let namespace = r#gen.freestanding_namespace(id, false);

for (_name, func) in resolve.interfaces[id].functions.iter() {
if matches!(func.kind, FunctionKind::Freestanding) {
Expand Down Expand Up @@ -564,6 +574,7 @@ impl WorldGenerator for Cpp {
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
implements: Option<InterfaceId>,
_files: &mut Files,
) -> anyhow::Result<()> {
let old_prefix = self.opts.export_prefix.clone();
Expand All @@ -579,12 +590,19 @@ impl WorldGenerator for Cpp {
.src
.push_str(&format!("// export_interface {name:?}\n"));
self.imported_interfaces.remove(&id);
let wasm_import_module = resolve.name_world_key(name);
let wasm_import_module =
wit_bindgen_core::wasm_import_module_name(resolve, name, implements);
let binding = Some(name);
let should_gen_types = self.implements_types_generated.insert(id);
let mut r#gen = self.interface(resolve, binding, false, Some(wasm_import_module));
r#gen.interface = Some(id);
r#gen.types(id);
let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &r#gen.r#gen.opts);
if let (WorldKey::Name(label), Some(_)) = (name, implements) {
r#gen.implements_label = Some((label.clone(), true));
}
if should_gen_types {
r#gen.types(id);
}
let namespace = r#gen.freestanding_namespace(id, true);

for (_name, func) in resolve.interfaces[id].functions.iter() {
if matches!(func.kind, FunctionKind::Freestanding) {
Expand Down Expand Up @@ -762,7 +780,6 @@ impl WorldGenerator for Cpp {
}
}

// determine namespace (for the lifted C++ function)
fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, opts: &Opts) -> Vec<String> {
let mut result = Vec::default();
if let Some(prefix) = &opts.internal_prefix {
Expand Down Expand Up @@ -850,9 +867,35 @@ struct CppInterfaceGenerator<'a> {
sizes: SizeAlign,
in_guest_import: bool,
pub wasm_import_module: Option<String>,
/// When generating for an implements item, the label and whether it's an export.
implements_label: Option<(String, bool)>,
}

impl CppInterfaceGenerator<'_> {
/// Compute the namespace for freestanding functions in an interface.
/// Uses `implements_label` when set, otherwise falls back to the standard
/// namespace computation.
fn freestanding_namespace(&self, iface: InterfaceId, guest_export: bool) -> Vec<String> {
if let Some((label, is_export)) = &self.implements_label {
let mut ns = Vec::new();
if let Some(prefix) = &self.r#gen.opts.internal_prefix {
ns.push(prefix.clone());
}
if *is_export {
ns.push(String::from("exports"));
}
ns.push(to_c_ident(label));
ns
} else {
namespace(
self.resolve,
&TypeOwner::Interface(iface),
guest_export,
&self.r#gen.opts,
)
}
}

fn types(&mut self, iface: InterfaceId) {
let iface_data = &self.resolve().interfaces[iface];

Expand Down Expand Up @@ -923,7 +966,20 @@ impl CppInterfaceGenerator<'_> {
.map(TypeOwner::Interface)
.unwrap_or(TypeOwner::World(self.r#gen.world_id.unwrap())),
));
let mut namespace = namespace(self.resolve, &owner, guest_export, &self.r#gen.opts);
let mut namespace = if let Some((label, is_export)) = &self.implements_label {
// For implements items, use the label as namespace
let mut ns = Vec::new();
if let Some(prefix) = &self.r#gen.opts.internal_prefix {
ns.push(prefix.clone());
}
if *is_export {
ns.push(String::from("exports"));
}
ns.push(to_c_ident(label));
ns
} else {
namespace(self.resolve, &owner, guest_export, &self.r#gen.opts)
};
let is_drop = is_special_method(func);
let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) {
namespace.push(object.clone());
Expand Down
Loading
Loading