11use crate :: interface:: InterfaceGenerator ;
22use anyhow:: { bail, Result } ;
3+ use core:: panic;
34use heck:: * ;
45use indexmap:: { IndexMap , IndexSet } ;
56use std:: collections:: { BTreeMap , HashMap , HashSet } ;
@@ -8,8 +9,8 @@ use std::mem;
89use std:: str:: FromStr ;
910use wit_bindgen_core:: abi:: { Bitcast , WasmType } ;
1011use wit_bindgen_core:: {
11- name_package_module, uwrite, uwriteln, wit_parser:: * , Files , InterfaceGenerator as _, Source ,
12- Types , WorldGenerator ,
12+ dealias , name_package_module, uwrite, uwriteln, wit_parser:: * , Files , InterfaceGenerator as _,
13+ Source , Types , WorldGenerator ,
1314} ;
1415
1516mod bindgen;
@@ -38,15 +39,15 @@ struct RustWasm {
3839 interface_last_seen_as_import : HashMap < InterfaceId , bool > ,
3940 import_funcs_called : bool ,
4041 with_name_counter : usize ,
41- // Track which interfaces were generated. Remapped interfaces provided via `with`
42+ // Track which interfaces and types are generated. Remapped interfaces and types provided via `with`
4243 // are required to be used.
43- generated_interfaces : HashSet < String > ,
44+ generated_types : HashSet < String > ,
4445 world : Option < WorldId > ,
4546
4647 rt_module : IndexSet < RuntimeItem > ,
4748 export_macros : Vec < ( String , String ) > ,
4849
49- /// Interface names to how they should be generated
50+ /// Maps wit interface and type names to their Rust identifiers
5051 with : GenerationConfiguration ,
5152
5253 future_payloads : IndexMap < String , String > ,
@@ -55,35 +56,45 @@ struct RustWasm {
5556
5657#[ derive( Default ) ]
5758struct GenerationConfiguration {
58- map : HashMap < String , InterfaceGeneration > ,
59+ map : HashMap < String , TypeGeneration > ,
5960 generate_by_default : bool ,
6061}
6162
6263impl GenerationConfiguration {
63- fn get ( & self , key : & str ) -> Option < & InterfaceGeneration > {
64+ fn get ( & self , key : & str ) -> Option < & TypeGeneration > {
6465 self . map . get ( key) . or_else ( || {
6566 self . generate_by_default
66- . then_some ( & InterfaceGeneration :: Generate )
67+ . then_some ( & TypeGeneration :: Generate )
6768 } )
6869 }
6970
70- fn insert ( & mut self , name : String , generate : InterfaceGeneration ) {
71+ fn insert ( & mut self , name : String , generate : TypeGeneration ) {
7172 self . map . insert ( name, generate) ;
7273 }
7374
74- fn iter ( & self ) -> impl Iterator < Item = ( & String , & InterfaceGeneration ) > {
75+ fn iter ( & self ) -> impl Iterator < Item = ( & String , & TypeGeneration ) > {
7576 self . map . iter ( )
7677 }
7778}
7879
79- /// How an interface should be generated.
80- enum InterfaceGeneration {
81- /// Remapped to some other type
80+ /// How a wit interface or type should be rendered in Rust
81+ enum TypeGeneration {
82+ /// Uses a Rust identifier defined elsewhere
8283 Remap ( String ) ,
83- /// Generate the interface
84+ /// Define the interface or type with this bindgen invocation
8485 Generate ,
8586}
8687
88+ impl TypeGeneration {
89+ /// Returns true if the interface or type should be defined with this bindgen invocation
90+ fn generated ( & self ) -> bool {
91+ match self {
92+ TypeGeneration :: Generate => true ,
93+ TypeGeneration :: Remap ( _) => false ,
94+ }
95+ }
96+ }
97+
8798#[ derive( PartialEq , Eq , Clone , Copy , Hash , Debug ) ]
8899enum RuntimeItem {
89100 AllocCrate ,
@@ -237,7 +248,7 @@ pub struct Opts {
237248 #[ cfg_attr( feature = "clap" , arg( long = "additional_derive_attribute" , short = 'd' , default_values_t = Vec :: <String >:: new( ) ) ) ]
238249 pub additional_derive_attributes : Vec < String > ,
239250
240- /// Remapping of interface names to rust module names.
251+ /// Remapping of wit interface and type names to Rust module names and types .
241252 ///
242253 /// Argument must be of the form `k=v` and this option can be passed
243254 /// multiple times or one option can be comma separated, for example
@@ -410,9 +421,9 @@ impl RustWasm {
410421 let Some ( remapping) = self . with . get ( & with_name) else {
411422 bail ! ( MissingWith ( with_name) ) ;
412423 } ;
413- self . generated_interfaces . insert ( with_name) ;
424+ self . generated_types . insert ( with_name) ;
414425 let entry = match remapping {
415- InterfaceGeneration :: Remap ( remapped_path) => {
426+ TypeGeneration :: Remap ( remapped_path) => {
416427 let name = format ! ( "__with_name{}" , self . with_name_counter) ;
417428 self . with_name_counter += 1 ;
418429 uwriteln ! ( self . src, "use {remapped_path} as {name};" ) ;
@@ -421,7 +432,7 @@ impl RustWasm {
421432 path : name,
422433 }
423434 }
424- InterfaceGeneration :: Generate => {
435+ TypeGeneration :: Generate => {
425436 let path = compute_module_path ( name, resolve, is_export) . join ( "::" ) ;
426437
427438 InterfaceName {
@@ -1086,7 +1097,7 @@ impl WorldGenerator for RustWasm {
10861097 if resolve. interfaces [ * id] . package == world. package {
10871098 let name = resolve. name_world_key ( key) ;
10881099 if self . with . get ( & name) . is_none ( ) {
1089- self . with . insert ( name, InterfaceGeneration :: Generate ) ;
1100+ self . with . insert ( name, TypeGeneration :: Generate ) ;
10901101 }
10911102 }
10921103 }
@@ -1105,6 +1116,20 @@ impl WorldGenerator for RustWasm {
11051116 id : InterfaceId ,
11061117 _files : & mut Files ,
11071118 ) -> Result < ( ) > {
1119+ let mut to_define = Vec :: new ( ) ;
1120+ for ( name, ty_id) in resolve. interfaces [ id] . types . iter ( ) {
1121+ let full_name = full_wit_type_name ( resolve, * ty_id) ;
1122+ if let Some ( type_gen) = self . with . get ( & full_name) {
1123+ // skip type definition generation for remapped types
1124+ if type_gen. generated ( ) {
1125+ to_define. push ( ( name, ty_id) ) ;
1126+ }
1127+ } else {
1128+ to_define. push ( ( name, ty_id) ) ;
1129+ }
1130+ self . generated_types . insert ( full_name) ;
1131+ }
1132+
11081133 self . interface_last_seen_as_import . insert ( id, true ) ;
11091134 let wasm_import_module = resolve. name_world_key ( name) ;
11101135 let mut gen = self . interface (
@@ -1117,7 +1142,10 @@ impl WorldGenerator for RustWasm {
11171142 if gen. gen . name_interface ( resolve, id, name, false ) ? {
11181143 return Ok ( ( ) ) ;
11191144 }
1120- gen. types ( id) ;
1145+
1146+ for ( name, ty_id) in to_define {
1147+ gen. define_type ( & name, * ty_id) ;
1148+ }
11211149
11221150 gen. generate_imports ( resolve. interfaces [ id] . functions . values ( ) , Some ( name) ) ;
11231151
@@ -1152,6 +1180,20 @@ impl WorldGenerator for RustWasm {
11521180 id : InterfaceId ,
11531181 _files : & mut Files ,
11541182 ) -> Result < ( ) > {
1183+ let mut to_define = Vec :: new ( ) ;
1184+ for ( name, ty_id) in resolve. interfaces [ id] . types . iter ( ) {
1185+ let full_name = full_wit_type_name ( resolve, * ty_id) ;
1186+ if let Some ( type_gen) = self . with . get ( & full_name) {
1187+ // skip type definition generation for remapped types
1188+ if type_gen. generated ( ) {
1189+ to_define. push ( ( name, ty_id) ) ;
1190+ }
1191+ } else {
1192+ to_define. push ( ( name, ty_id) ) ;
1193+ }
1194+ self . generated_types . insert ( full_name) ;
1195+ }
1196+
11551197 self . interface_last_seen_as_import . insert ( id, false ) ;
11561198 let wasm_import_module = format ! ( "[export]{}" , resolve. name_world_key( name) ) ;
11571199 let mut gen = self . interface (
@@ -1164,7 +1206,11 @@ impl WorldGenerator for RustWasm {
11641206 if gen. gen . name_interface ( resolve, id, name, true ) ? {
11651207 return Ok ( ( ) ) ;
11661208 }
1167- gen. types ( id) ;
1209+
1210+ for ( name, ty_id) in to_define {
1211+ gen. define_type ( & name, * ty_id) ;
1212+ }
1213+
11681214 let macro_name =
11691215 gen. generate_exports ( Some ( ( id, name) ) , resolve. interfaces [ id] . functions . values ( ) ) ?;
11701216
@@ -1218,8 +1264,21 @@ impl WorldGenerator for RustWasm {
12181264 types : & [ ( & str , TypeId ) ] ,
12191265 _files : & mut Files ,
12201266 ) {
1267+ let mut to_define = Vec :: new ( ) ;
1268+ for ( name, ty_id) in types {
1269+ let full_name = full_wit_type_name ( resolve, * ty_id) ;
1270+ if let Some ( type_gen) = self . with . get ( & full_name) {
1271+ // skip type definition generation for remapped types
1272+ if type_gen. generated ( ) {
1273+ to_define. push ( ( name, ty_id) ) ;
1274+ }
1275+ } else {
1276+ to_define. push ( ( name, ty_id) ) ;
1277+ }
1278+ self . generated_types . insert ( full_name) ;
1279+ }
12211280 let mut gen = self . interface ( Identifier :: World ( world) , "$root" , resolve, true ) ;
1222- for ( name, ty) in types {
1281+ for ( name, ty) in to_define {
12231282 gen. define_type ( name, * ty) ;
12241283 }
12251284 let src = gen. finish ( ) ;
@@ -1333,7 +1392,7 @@ impl WorldGenerator for RustWasm {
13331392 . collect :: < HashSet < String > > ( ) ;
13341393
13351394 let mut unused_keys = remapped_keys
1336- . difference ( & self . generated_interfaces )
1395+ . difference ( & self . generated_types )
13371396 . collect :: < Vec < & String > > ( ) ;
13381397
13391398 unused_keys. sort ( ) ;
@@ -1457,11 +1516,11 @@ impl std::fmt::Display for WithOption {
14571516 }
14581517}
14591518
1460- impl From < WithOption > for InterfaceGeneration {
1519+ impl From < WithOption > for TypeGeneration {
14611520 fn from ( opt : WithOption ) -> Self {
14621521 match opt {
1463- WithOption :: Path ( p) => InterfaceGeneration :: Remap ( p) ,
1464- WithOption :: Generate => InterfaceGeneration :: Generate ,
1522+ WithOption :: Path ( p) => TypeGeneration :: Remap ( p) ,
1523+ WithOption :: Generate => TypeGeneration :: Generate ,
14651524 }
14661525 }
14671526}
@@ -1682,3 +1741,18 @@ impl std::error::Error for MissingWith {}
16821741// ```
16831742// with: {{\n\t{with_name:?}: generate\n}}
16841743// ```")
1744+
1745+ /// Returns the full WIT type name with fully qualified interface name
1746+ fn full_wit_type_name ( resolve : & Resolve , id : TypeId ) -> String {
1747+ let id = dealias ( resolve, id) ;
1748+ let type_def = & resolve. types [ id] ;
1749+ let interface_name = match type_def. owner {
1750+ TypeOwner :: World ( w) => Some ( resolve. worlds [ w] . name . clone ( ) ) ,
1751+ TypeOwner :: Interface ( id) => resolve. id_of ( id) ,
1752+ TypeOwner :: None => None ,
1753+ } ;
1754+ match interface_name {
1755+ Some ( interface_name) => format ! ( "{}/{}" , interface_name, type_def. name. clone( ) . unwrap( ) ) ,
1756+ None => type_def. name . clone ( ) . unwrap ( ) ,
1757+ }
1758+ }
0 commit comments