1
1
use crate :: interface:: InterfaceGenerator ;
2
2
use anyhow:: { bail, Result } ;
3
+ use core:: panic;
3
4
use heck:: * ;
4
5
use indexmap:: { IndexMap , IndexSet } ;
5
6
use std:: collections:: { BTreeMap , HashMap , HashSet } ;
@@ -8,8 +9,8 @@ use std::mem;
8
9
use std:: str:: FromStr ;
9
10
use wit_bindgen_core:: abi:: { Bitcast , WasmType } ;
10
11
use 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 ,
13
14
} ;
14
15
15
16
mod bindgen;
@@ -38,15 +39,15 @@ struct RustWasm {
38
39
interface_last_seen_as_import : HashMap < InterfaceId , bool > ,
39
40
import_funcs_called : bool ,
40
41
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`
42
43
// are required to be used.
43
- generated_interfaces : HashSet < String > ,
44
+ generated_types : HashSet < String > ,
44
45
world : Option < WorldId > ,
45
46
46
47
rt_module : IndexSet < RuntimeItem > ,
47
48
export_macros : Vec < ( String , String ) > ,
48
49
49
- /// Interface names to how they should be generated
50
+ /// Maps wit interface and type names to their Rust identifiers
50
51
with : GenerationConfiguration ,
51
52
52
53
future_payloads : IndexMap < String , String > ,
@@ -55,35 +56,45 @@ struct RustWasm {
55
56
56
57
#[ derive( Default ) ]
57
58
struct GenerationConfiguration {
58
- map : HashMap < String , InterfaceGeneration > ,
59
+ map : HashMap < String , TypeGeneration > ,
59
60
generate_by_default : bool ,
60
61
}
61
62
62
63
impl GenerationConfiguration {
63
- fn get ( & self , key : & str ) -> Option < & InterfaceGeneration > {
64
+ fn get ( & self , key : & str ) -> Option < & TypeGeneration > {
64
65
self . map . get ( key) . or_else ( || {
65
66
self . generate_by_default
66
- . then_some ( & InterfaceGeneration :: Generate )
67
+ . then_some ( & TypeGeneration :: Generate )
67
68
} )
68
69
}
69
70
70
- fn insert ( & mut self , name : String , generate : InterfaceGeneration ) {
71
+ fn insert ( & mut self , name : String , generate : TypeGeneration ) {
71
72
self . map . insert ( name, generate) ;
72
73
}
73
74
74
- fn iter ( & self ) -> impl Iterator < Item = ( & String , & InterfaceGeneration ) > {
75
+ fn iter ( & self ) -> impl Iterator < Item = ( & String , & TypeGeneration ) > {
75
76
self . map . iter ( )
76
77
}
77
78
}
78
79
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
82
83
Remap ( String ) ,
83
- /// Generate the interface
84
+ /// Define the interface or type with this bindgen invocation
84
85
Generate ,
85
86
}
86
87
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
+
87
98
#[ derive( PartialEq , Eq , Clone , Copy , Hash , Debug ) ]
88
99
enum RuntimeItem {
89
100
AllocCrate ,
@@ -237,7 +248,7 @@ pub struct Opts {
237
248
#[ cfg_attr( feature = "clap" , arg( long = "additional_derive_attribute" , short = 'd' , default_values_t = Vec :: <String >:: new( ) ) ) ]
238
249
pub additional_derive_attributes : Vec < String > ,
239
250
240
- /// Remapping of interface names to rust module names.
251
+ /// Remapping of wit interface and type names to Rust module names and types .
241
252
///
242
253
/// Argument must be of the form `k=v` and this option can be passed
243
254
/// multiple times or one option can be comma separated, for example
@@ -410,9 +421,9 @@ impl RustWasm {
410
421
let Some ( remapping) = self . with . get ( & with_name) else {
411
422
bail ! ( MissingWith ( with_name) ) ;
412
423
} ;
413
- self . generated_interfaces . insert ( with_name) ;
424
+ self . generated_types . insert ( with_name) ;
414
425
let entry = match remapping {
415
- InterfaceGeneration :: Remap ( remapped_path) => {
426
+ TypeGeneration :: Remap ( remapped_path) => {
416
427
let name = format ! ( "__with_name{}" , self . with_name_counter) ;
417
428
self . with_name_counter += 1 ;
418
429
uwriteln ! ( self . src, "use {remapped_path} as {name};" ) ;
@@ -421,7 +432,7 @@ impl RustWasm {
421
432
path : name,
422
433
}
423
434
}
424
- InterfaceGeneration :: Generate => {
435
+ TypeGeneration :: Generate => {
425
436
let path = compute_module_path ( name, resolve, is_export) . join ( "::" ) ;
426
437
427
438
InterfaceName {
@@ -1086,7 +1097,7 @@ impl WorldGenerator for RustWasm {
1086
1097
if resolve. interfaces [ * id] . package == world. package {
1087
1098
let name = resolve. name_world_key ( key) ;
1088
1099
if self . with . get ( & name) . is_none ( ) {
1089
- self . with . insert ( name, InterfaceGeneration :: Generate ) ;
1100
+ self . with . insert ( name, TypeGeneration :: Generate ) ;
1090
1101
}
1091
1102
}
1092
1103
}
@@ -1105,6 +1116,20 @@ impl WorldGenerator for RustWasm {
1105
1116
id : InterfaceId ,
1106
1117
_files : & mut Files ,
1107
1118
) -> 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
+
1108
1133
self . interface_last_seen_as_import . insert ( id, true ) ;
1109
1134
let wasm_import_module = resolve. name_world_key ( name) ;
1110
1135
let mut gen = self . interface (
@@ -1117,7 +1142,10 @@ impl WorldGenerator for RustWasm {
1117
1142
if gen. gen . name_interface ( resolve, id, name, false ) ? {
1118
1143
return Ok ( ( ) ) ;
1119
1144
}
1120
- gen. types ( id) ;
1145
+
1146
+ for ( name, ty_id) in to_define {
1147
+ gen. define_type ( & name, * ty_id) ;
1148
+ }
1121
1149
1122
1150
gen. generate_imports ( resolve. interfaces [ id] . functions . values ( ) , Some ( name) ) ;
1123
1151
@@ -1152,6 +1180,20 @@ impl WorldGenerator for RustWasm {
1152
1180
id : InterfaceId ,
1153
1181
_files : & mut Files ,
1154
1182
) -> 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
+
1155
1197
self . interface_last_seen_as_import . insert ( id, false ) ;
1156
1198
let wasm_import_module = format ! ( "[export]{}" , resolve. name_world_key( name) ) ;
1157
1199
let mut gen = self . interface (
@@ -1164,7 +1206,11 @@ impl WorldGenerator for RustWasm {
1164
1206
if gen. gen . name_interface ( resolve, id, name, true ) ? {
1165
1207
return Ok ( ( ) ) ;
1166
1208
}
1167
- gen. types ( id) ;
1209
+
1210
+ for ( name, ty_id) in to_define {
1211
+ gen. define_type ( & name, * ty_id) ;
1212
+ }
1213
+
1168
1214
let macro_name =
1169
1215
gen. generate_exports ( Some ( ( id, name) ) , resolve. interfaces [ id] . functions . values ( ) ) ?;
1170
1216
@@ -1218,8 +1264,21 @@ impl WorldGenerator for RustWasm {
1218
1264
types : & [ ( & str , TypeId ) ] ,
1219
1265
_files : & mut Files ,
1220
1266
) {
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
+ }
1221
1280
let mut gen = self . interface ( Identifier :: World ( world) , "$root" , resolve, true ) ;
1222
- for ( name, ty) in types {
1281
+ for ( name, ty) in to_define {
1223
1282
gen. define_type ( name, * ty) ;
1224
1283
}
1225
1284
let src = gen. finish ( ) ;
@@ -1333,7 +1392,7 @@ impl WorldGenerator for RustWasm {
1333
1392
. collect :: < HashSet < String > > ( ) ;
1334
1393
1335
1394
let mut unused_keys = remapped_keys
1336
- . difference ( & self . generated_interfaces )
1395
+ . difference ( & self . generated_types )
1337
1396
. collect :: < Vec < & String > > ( ) ;
1338
1397
1339
1398
unused_keys. sort ( ) ;
@@ -1457,11 +1516,11 @@ impl std::fmt::Display for WithOption {
1457
1516
}
1458
1517
}
1459
1518
1460
- impl From < WithOption > for InterfaceGeneration {
1519
+ impl From < WithOption > for TypeGeneration {
1461
1520
fn from ( opt : WithOption ) -> Self {
1462
1521
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 ,
1465
1524
}
1466
1525
}
1467
1526
}
@@ -1682,3 +1741,18 @@ impl std::error::Error for MissingWith {}
1682
1741
// ```
1683
1742
// with: {{\n\t{with_name:?}: generate\n}}
1684
1743
// ```")
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