diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index 6c22a0ed2..f76a2520b 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -7,8 +7,8 @@ use std::fmt::Write; use std::mem; use wit_bindgen_core::abi::{self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType}; use wit_bindgen_core::{ - dealias, uwrite, uwriteln, wit_parser::*, Direction, Files, InterfaceGenerator as _, Ns, - WorldGenerator, + dealias, uwrite, uwriteln, wit_parser::*, AnonymousTypeGenerator, Direction, Files, + InterfaceGenerator as _, Ns, WorldGenerator, }; use wit_component::StringEncoding; @@ -1341,6 +1341,98 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{ } } +impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> { + fn resolve(&self) -> &'a Resolve { + self.resolve + } + + fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, docs: &Docs) { + self.src.h_defs("\ntypedef "); + let resource = match handle { + Handle::Borrow(id) | Handle::Own(id) => id, + }; + let info = &self.gen.resources[&dealias(self.resolve, *resource)]; + match handle { + Handle::Borrow(_) => self.src.h_defs(&info.borrow), + Handle::Own(_) => self.src.h_defs(&info.own), + } + self.src.h_defs(" "); + self.print_typedef_target(id); + } + + fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, docs: &Docs) { + self.src.h_defs("\ntypedef "); + self.src.h_defs("struct {\n"); + for (i, t) in ty.types.iter().enumerate() { + let ty = self.gen.type_name(t); + uwriteln!(self.src.h_defs, "{ty} f{i};"); + } + self.src.h_defs("}"); + self.src.h_defs(" "); + self.print_typedef_target(id); + } + + fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + self.src.h_defs("\ntypedef "); + self.src.h_defs("struct {\n"); + self.src.h_defs("bool is_some;\n"); + let ty = self.gen.type_name(ty); + uwriteln!(self.src.h_defs, "{ty} val;"); + self.src.h_defs("}"); + self.src.h_defs(" "); + self.print_typedef_target(id); + } + + fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, docs: &Docs) { + self.src.h_defs("\ntypedef "); + self.src.h_defs( + "struct { + bool is_err; + ", + ); + let ok_ty = ty.ok.as_ref(); + let err_ty = ty.err.as_ref(); + if ok_ty.is_some() || err_ty.is_some() { + self.src.h_defs("union {\n"); + if let Some(ok) = ok_ty { + let ty = self.gen.type_name(ok); + uwriteln!(self.src.h_defs, "{ty} ok;"); + } + if let Some(err) = err_ty { + let ty = self.gen.type_name(err); + uwriteln!(self.src.h_defs, "{ty} err;"); + } + self.src.h_defs("} val;\n"); + } + self.src.h_defs("}"); + self.src.h_defs(" "); + self.print_typedef_target(id); + } + + fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + self.src.h_defs("\ntypedef "); + self.src.h_defs("struct {\n"); + let ty = self.gen.type_name(ty); + uwriteln!(self.src.h_defs, "{ty} *ptr;"); + self.src.h_defs("size_t len;\n"); + self.src.h_defs("}"); + self.src.h_defs(" "); + self.print_typedef_target(id); + } + + fn anonymous_type_future(&mut self, id: TypeId, ty: &Option, docs: &Docs) { + todo!("print_anonymous_type for future"); + } + + fn anonymous_type_stream(&mut self, id: TypeId, ty: &Stream, docs: &Docs) { + todo!("print_anonymous_type for stream"); + } + + fn anonymous_typ_type(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + todo!("print_anonymous_type for typ"); + } +} + pub enum CTypeNameInfo<'a> { Named { name: &'a str }, Anonymous { is_prim: bool }, @@ -1413,6 +1505,17 @@ impl InterfaceGenerator<'_> { continue; } + let kind = &self.resolve.types[ty].kind; + if let TypeDefKind::Handle(handle) = kind { + let resource = match handle { + Handle::Borrow(id) | Handle::Own(id) => id, + }; + let origin = dealias(self.resolve, *resource); + if origin == *resource { + continue; + } + } + self.define_anonymous_type(ty) } } @@ -1421,89 +1524,6 @@ impl InterfaceGenerator<'_> { } } - fn define_anonymous_type(&mut self, ty: TypeId) { - // skip `typedef handle_x handle_y` where `handle_x` is the same as `handle_y` - let kind = &self.resolve.types[ty].kind; - if let TypeDefKind::Handle(handle) = kind { - let resource = match handle { - Handle::Borrow(id) | Handle::Own(id) => id, - }; - let origin = dealias(self.resolve, *resource); - if origin == *resource { - return; - } - } - - self.src.h_defs("\ntypedef "); - let name = &self.gen.type_names[&ty]; - match kind { - TypeDefKind::Type(_) - | TypeDefKind::Flags(_) - | TypeDefKind::Record(_) - | TypeDefKind::Resource - | TypeDefKind::Enum(_) - | TypeDefKind::Variant(_) => { - unreachable!() - } - TypeDefKind::Handle(handle) => { - let resource = match handle { - Handle::Borrow(id) | Handle::Own(id) => id, - }; - let info = &self.gen.resources[&dealias(self.resolve, *resource)]; - match handle { - Handle::Borrow(_) => self.src.h_defs(&info.borrow), - Handle::Own(_) => self.src.h_defs(&info.own), - } - } - TypeDefKind::Tuple(t) => { - self.src.h_defs(&format!("struct {name} {{\n")); - for (i, t) in t.types.iter().enumerate() { - let ty = self.gen.type_name(t); - uwriteln!(self.src.h_defs, "{ty} f{i};"); - } - self.src.h_defs("}"); - } - TypeDefKind::Option(t) => { - self.src.h_defs(&format!("struct {name} {{\n")); - self.src.h_defs("bool is_some;\n"); - let ty = self.gen.type_name(t); - uwriteln!(self.src.h_defs, "{ty} val;"); - self.src.h_defs("}"); - } - TypeDefKind::Result(r) => { - self.src.h_defs(&format!("struct {name} {{\n")); - self.src.h_defs("bool is_err;\n"); - let ok_ty = r.ok.as_ref(); - let err_ty = r.err.as_ref(); - if ok_ty.is_some() || err_ty.is_some() { - self.src.h_defs("union {\n"); - if let Some(ok) = ok_ty { - let ty = self.gen.type_name(ok); - uwriteln!(self.src.h_defs, "{ty} ok;"); - } - if let Some(err) = err_ty { - let ty = self.gen.type_name(err); - uwriteln!(self.src.h_defs, "{ty} err;"); - } - self.src.h_defs("} val;\n"); - } - self.src.h_defs("}"); - } - TypeDefKind::List(t) => { - self.src.h_defs(&format!("struct {name} {{\n")); - let ty = self.gen.type_name(t); - uwriteln!(self.src.h_defs, "{ty} *ptr;"); - self.src.h_defs("size_t len;\n"); - self.src.h_defs("}"); - } - TypeDefKind::Future(_) => todo!("print_anonymous_type for future"), - TypeDefKind::Stream(_) => todo!("print_anonymous_type for stream"), - TypeDefKind::Unknown => unreachable!(), - } - self.src.h_defs(" "); - self.print_typedef_target(ty); - } - fn define_dtor(&mut self, id: TypeId) { let h_helpers_start = self.src.h_helpers.len(); let c_helpers_start = self.src.c_helpers.len(); diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 07ed228f0..773707d85 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -152,7 +152,6 @@ pub trait InterfaceGenerator<'a> { fn type_alias(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs); fn type_list(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs); fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs); - fn types(&mut self, iface: InterfaceId) { let iface = &self.resolve().interfaces[iface]; for (name, id) in iface.types.iter() { @@ -181,6 +180,41 @@ pub trait InterfaceGenerator<'a> { } } +pub trait AnonymousTypeGenerator<'a> { + fn resolve(&self) -> &'a Resolve; + + fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, docs: &Docs); + fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, docs: &Docs); + fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, docs: &Docs); + fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, docs: &Docs); + fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs); + fn anonymous_type_future(&mut self, id: TypeId, ty: &Option, docs: &Docs); + fn anonymous_type_stream(&mut self, id: TypeId, ty: &Stream, docs: &Docs); + fn anonymous_typ_type(&mut self, id: TypeId, ty: &Type, docs: &Docs); + + fn define_anonymous_type(&mut self, id: TypeId) { + let ty = &self.resolve().types[id]; + match &ty.kind { + TypeDefKind::Flags(_) + | TypeDefKind::Record(_) + | TypeDefKind::Resource + | TypeDefKind::Enum(_) + | TypeDefKind::Variant(_) => { + unreachable!() + } + TypeDefKind::Type(t) => self.anonymous_typ_type(id, t, &ty.docs), + TypeDefKind::Tuple(tuple) => self.anonymous_type_tuple(id, tuple, &ty.docs), + TypeDefKind::Option(t) => self.anonymous_type_option(id, t, &ty.docs), + TypeDefKind::Result(r) => self.anonymous_type_result(id, r, &ty.docs), + TypeDefKind::List(t) => self.anonymous_type_list(id, t, &ty.docs), + TypeDefKind::Future(f) => self.anonymous_type_future(id, f, &ty.docs), + TypeDefKind::Stream(s) => self.anonymous_type_stream(id, s, &ty.docs), + TypeDefKind::Handle(handle) => self.anonymous_type_handle(id, handle, &ty.docs), + TypeDefKind::Unknown => unreachable!(), + } + } +} + pub fn generated_preamble(src: &mut Source, version: &str) { uwriteln!(src, "// Generated by `wit-bindgen` {version}. DO NOT EDIT!") } diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index 69407f760..73e7cdcc4 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -9,7 +9,9 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Write as _; use std::mem; use wit_bindgen_core::abi::{self, AbiVariant, LiftLower}; -use wit_bindgen_core::{dealias, uwrite, uwriteln, wit_parser::*, Source, TypeInfo}; +use wit_bindgen_core::{ + dealias, uwrite, uwriteln, wit_parser::*, AnonymousTypeGenerator, Source, TypeInfo, +}; pub struct InterfaceGenerator<'a> { pub src: Source, @@ -1198,97 +1200,12 @@ macro_rules! {macro_name} {{ return; } - match &ty.kind { - TypeDefKind::List(t) => self.print_list(t, mode), - - TypeDefKind::Option(t) => { - self.push_str("Option<"); - let mode = self.filter_mode_preserve_top(t, mode); - self.print_ty(t, mode); - self.push_str(">"); - } - - TypeDefKind::Result(r) => { - self.push_str("Result<"); - self.print_optional_ty(r.ok.as_ref(), mode); - self.push_str(","); - self.print_optional_ty(r.err.as_ref(), mode); - self.push_str(">"); - } - - TypeDefKind::Variant(_) => panic!("unsupported anonymous variant"), - - // Tuple-like records are mapped directly to Rust tuples of - // types. Note the trailing comma after each member to - // appropriately handle 1-tuples. - TypeDefKind::Tuple(t) => { - self.push_str("("); - for ty in t.types.iter() { - let mode = self.filter_mode_preserve_top(ty, mode); - self.print_ty(ty, mode); - self.push_str(","); - } - self.push_str(")"); - } - TypeDefKind::Resource => { - panic!("unsupported anonymous type reference: resource") - } - TypeDefKind::Record(_) => { - panic!("unsupported anonymous type reference: record") - } - TypeDefKind::Flags(_) => { - panic!("unsupported anonymous type reference: flags") - } - TypeDefKind::Enum(_) => { - panic!("unsupported anonymous type reference: enum") - } - TypeDefKind::Future(ty) => { - self.push_str("Future<"); - self.print_optional_ty(ty.as_ref(), mode); - self.push_str(">"); - } - TypeDefKind::Stream(stream) => { - self.push_str("Stream<"); - self.print_optional_ty(stream.element.as_ref(), mode); - self.push_str(","); - self.print_optional_ty(stream.end.as_ref(), mode); - self.push_str(">"); - } - - TypeDefKind::Handle(Handle::Own(ty)) => { - self.print_ty(&Type::Id(*ty), mode); - } - - TypeDefKind::Handle(Handle::Borrow(ty)) => { - assert!(mode.lifetime.is_some()); - let lt = mode.lifetime.unwrap(); - if self.is_exported_resource(*ty) { - let camel = self.resolve.types[*ty] - .name - .as_deref() - .unwrap() - .to_upper_camel_case(); - let name = format!("{camel}Borrow"); - self.push_str(&self.type_path_with_name(*ty, name)); - self.push_str("<"); - self.push_str(lt); - self.push_str(">"); - } else { - self.push_str("&"); - if lt != "'_" { - self.push_str(lt); - self.push_str(" "); - } - let ty = &Type::Id(*ty); - let mode = self.filter_mode(ty, mode); - self.print_ty(ty, mode); - } - } - - TypeDefKind::Type(t) => self.print_ty(t, mode), - - TypeDefKind::Unknown => unreachable!(), - } + let mut anonymous_type_gen = AnonTypeGenerator { + mode, + resolve: self.resolve, + interface: self, + }; + anonymous_type_gen.define_anonymous_type(id); } fn print_list(&mut self, ty: &Type, mode: TypeMode) { @@ -2259,3 +2176,98 @@ impl<'a> {camel}Borrow<'a>{{ self.src.push_str(";\n"); } } + +struct AnonTypeGenerator<'a, 'b> { + mode: TypeMode, + resolve: &'a Resolve, + interface: &'a mut InterfaceGenerator<'b>, +} + +impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator<'a, 'b> { + fn resolve(&self) -> &'a Resolve { + self.resolve + } + + fn anonymous_typ_type(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + self.interface.print_ty(ty, self.mode); + } + + fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, docs: &Docs) { + match handle { + Handle::Own(ty) => { + self.interface.print_ty(&Type::Id(*ty), self.mode); + } + Handle::Borrow(ty) => { + assert!(self.mode.lifetime.is_some()); + let lt = self.mode.lifetime.unwrap(); + if self.interface.is_exported_resource(*ty) { + let camel = self.resolve.types[*ty] + .name + .as_deref() + .unwrap() + .to_upper_camel_case(); + let name = format!("{camel}Borrow"); + self.interface + .push_str(&self.interface.type_path_with_name(*ty, name)); + self.interface.push_str("<"); + self.interface.push_str(lt); + self.interface.push_str(">"); + } else { + self.interface.push_str("&"); + if lt != "'_" { + self.interface.push_str(lt); + self.interface.push_str(" "); + } + let ty = &Type::Id(*ty); + let mode = self.interface.filter_mode(ty, self.mode); + self.interface.print_ty(ty, mode); + } + } + } + } + + fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, docs: &Docs) { + self.interface.push_str("("); + for ty in ty.types.iter() { + let mode = self.interface.filter_mode_preserve_top(ty, self.mode); + self.interface.print_ty(ty, mode); + self.interface.push_str(","); + } + self.interface.push_str(")"); + } + + fn anonymous_type_option(&mut self, id: TypeId, t: &Type, docs: &Docs) { + self.interface.push_str("Option<"); + let mode = self.interface.filter_mode_preserve_top(t, self.mode); + self.interface.print_ty(t, mode); + self.interface.push_str(">"); + } + + fn anonymous_type_result(&mut self, id: TypeId, r: &Result_, docs: &Docs) { + self.interface.push_str("Result<"); + self.interface.print_optional_ty(r.ok.as_ref(), self.mode); + self.interface.push_str(","); + self.interface.print_optional_ty(r.err.as_ref(), self.mode); + self.interface.push_str(">"); + } + + fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + self.interface.print_list(ty, self.mode) + } + + fn anonymous_type_future(&mut self, id: TypeId, ty: &Option, docs: &Docs) { + self.interface.push_str("Future<"); + self.interface.print_optional_ty(ty.as_ref(), self.mode); + self.interface.push_str(">"); + } + + fn anonymous_type_stream(&mut self, id: TypeId, stream: &Stream, docs: &Docs) { + self.interface.push_str("Stream<"); + self.interface + .print_optional_ty(stream.element.as_ref(), self.mode); + self.interface.push_str(","); + self.interface + .print_optional_ty(stream.end.as_ref(), self.mode); + self.interface.push_str(">"); + } +}