1
+ use anyhow:: bail;
1
2
use heck:: { ToPascalCase , ToShoutySnakeCase , ToSnakeCase , ToUpperCamelCase } ;
2
3
use std:: {
3
4
collections:: { HashMap , HashSet } ,
4
- fmt:: Write as FmtWrite ,
5
+ fmt:: { Display , Write as FmtWrite } ,
5
6
io:: { Read , Write } ,
6
7
path:: PathBuf ,
7
8
process:: { Command , Stdio } ,
@@ -209,32 +210,60 @@ pub struct Opts {
209
210
#[ cfg_attr( feature = "clap" , arg( long, default_value_t = Ownership :: Owning ) ) ]
210
211
pub ownership : Ownership ,
211
212
212
- /// Symmetric API, same API for imported and exported functions.
213
- /// Reduces the allocation overhead for symmetric ABI.
213
+ /// Set API style to symmetric or asymmetric
214
214
#[ cfg_attr(
215
- feature = "clap" ,
216
- arg( long, default_value_t = true , overrides_with = "_old_api" )
215
+ feature = "clap" ,
216
+ arg(
217
+ long,
218
+ default_value_t = APIStyle :: default ( ) ,
219
+ value_name = "STYLE" ,
220
+ ) ,
217
221
) ]
218
- pub new_api : bool ,
219
-
220
- /// Asymmetric API: Imported functions borrow arguments (const&),
221
- /// while exported functions received owned arguments (&&).
222
- /// Reduces the allocation overhead for canonical ABI.
223
- #[ cfg_attr( feature = "clap" , arg( long) ) ]
224
- pub _old_api : bool ,
222
+ pub api_style : APIStyle ,
225
223
226
224
/// Where to place output files
227
225
#[ cfg_attr( feature = "clap" , arg( skip) ) ]
228
226
out_dir : Option < PathBuf > ,
229
227
}
230
228
229
+ /// Supported API styles for the generated bindings.
230
+ #[ derive( Default , Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
231
+ pub enum APIStyle {
232
+ /// Imported functions borrow arguments, while exported functions receive owned arguments. Reduces the allocation overhead for the canonical ABI.
233
+ #[ default]
234
+ Asymmetric ,
235
+ /// Same API for imported and exported functions. Reduces the allocation overhead for symmetric ABI.
236
+ Symmetric ,
237
+ }
238
+
239
+ impl Display for APIStyle {
240
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
241
+ match self {
242
+ APIStyle :: Asymmetric => write ! ( f, "asymmetric" ) ,
243
+ APIStyle :: Symmetric => write ! ( f, "symmetric" ) ,
244
+ }
245
+ }
246
+ }
247
+
248
+ impl FromStr for APIStyle {
249
+ type Err = anyhow:: Error ;
250
+
251
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
252
+ match s {
253
+ "asymmetric" => Ok ( APIStyle :: Asymmetric ) ,
254
+ "symmetric" => Ok ( APIStyle :: Symmetric ) ,
255
+ _ => bail ! (
256
+ "unrecognized API style: `{}`; expected `asymmetric` or `symmetric`" ,
257
+ s
258
+ ) ,
259
+ }
260
+ }
261
+ }
262
+
231
263
impl Opts {
232
264
pub fn build ( mut self , out_dir : Option < & PathBuf > ) -> Box < dyn WorldGenerator > {
233
265
let mut r = Cpp :: new ( ) ;
234
266
self . out_dir = out_dir. cloned ( ) ;
235
- if self . _old_api {
236
- self . new_api = false ;
237
- }
238
267
r. opts = self ;
239
268
Box :: new ( r)
240
269
}
@@ -684,6 +713,7 @@ impl WorldGenerator for Cpp {
684
713
. unwrap ( )
685
714
. as_slice ( ) ,
686
715
) ;
716
+
687
717
Ok ( ( ) )
688
718
}
689
719
}
@@ -1183,17 +1213,18 @@ impl CppInterfaceGenerator<'_> {
1183
1213
let special = is_special_method ( func) ;
1184
1214
if !matches ! ( special, SpecialMethod :: Allocate ) {
1185
1215
self . gen . c_src . src . push_str ( "{\n " ) ;
1186
- let needs_dealloc =
1187
- if self . gen . opts . new_api && matches ! ( variant, AbiVariant :: GuestExport ) {
1188
- self . gen
1189
- . c_src
1190
- . src
1191
- . push_str ( "std::vector<void*> _deallocate;\n " ) ;
1192
- self . gen . dependencies . needs_vector = true ;
1193
- true
1194
- } else {
1195
- false
1196
- } ;
1216
+ let needs_dealloc = if self . gen . opts . api_style == APIStyle :: Symmetric
1217
+ && matches ! ( variant, AbiVariant :: GuestExport )
1218
+ {
1219
+ self . gen
1220
+ . c_src
1221
+ . src
1222
+ . push_str ( "std::vector<void*> _deallocate;\n " ) ;
1223
+ self . gen . dependencies . needs_vector = true ;
1224
+ true
1225
+ } else {
1226
+ false
1227
+ } ;
1197
1228
let lift_lower = if export {
1198
1229
LiftLower :: LiftArgsLowerResults
1199
1230
} else {
@@ -1402,14 +1433,15 @@ impl CppInterfaceGenerator<'_> {
1402
1433
"std::string_view" . into ( )
1403
1434
}
1404
1435
Flavor :: Argument ( var)
1405
- if matches ! ( var, AbiVariant :: GuestImport ) || self . gen . opts . new_api =>
1436
+ if matches ! ( var, AbiVariant :: GuestImport )
1437
+ || self . gen . opts . api_style == APIStyle :: Symmetric =>
1406
1438
{
1407
1439
self . gen . dependencies . needs_string_view = true ;
1408
1440
"std::string_view" . into ( )
1409
1441
}
1410
1442
Flavor :: Argument ( AbiVariant :: GuestExport ) => {
1411
1443
self . gen . dependencies . needs_wit = true ;
1412
- "wit::string && " . into ( )
1444
+ "wit::string" . into ( )
1413
1445
}
1414
1446
_ => {
1415
1447
self . gen . dependencies . needs_wit = true ;
@@ -1491,14 +1523,15 @@ impl CppInterfaceGenerator<'_> {
1491
1523
format ! ( "wit::span<{inner} const>" )
1492
1524
}
1493
1525
Flavor :: Argument ( var)
1494
- if matches ! ( var, AbiVariant :: GuestImport ) || self . gen . opts . new_api =>
1526
+ if matches ! ( var, AbiVariant :: GuestImport )
1527
+ || self . gen . opts . api_style == APIStyle :: Symmetric =>
1495
1528
{
1496
1529
self . gen . dependencies . needs_wit = true ;
1497
1530
format ! ( "wit::span<{inner} const>" )
1498
1531
}
1499
1532
Flavor :: Argument ( AbiVariant :: GuestExport ) => {
1500
1533
self . gen . dependencies . needs_wit = true ;
1501
- format ! ( "wit::vector<{inner}>&& " )
1534
+ format ! ( "wit::vector<{inner}>" )
1502
1535
}
1503
1536
_ => {
1504
1537
self . gen . dependencies . needs_wit = true ;
@@ -2280,7 +2313,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2280
2313
. gen
2281
2314
. type_name ( element, & self . namespace , Flavor :: InStruct ) ;
2282
2315
self . push_str ( & format ! ( "auto {} = {};\n " , len, operands[ 1 ] ) ) ;
2283
- let result = if self . gen . gen . opts . new_api
2316
+ let result = if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2284
2317
&& matches ! ( self . variant, AbiVariant :: GuestExport )
2285
2318
{
2286
2319
format ! (
@@ -2296,7 +2329,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2296
2329
let tmp = self . tmp ( ) ;
2297
2330
let len = format ! ( "len{}" , tmp) ;
2298
2331
uwriteln ! ( self . src, "auto {} = {};\n " , len, operands[ 1 ] ) ;
2299
- let result = if self . gen . gen . opts . new_api
2332
+ let result = if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2300
2333
&& matches ! ( self . variant, AbiVariant :: GuestExport )
2301
2334
{
2302
2335
assert ! ( self . needs_dealloc) ;
@@ -2316,7 +2349,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2316
2349
let tmp = self . tmp ( ) ;
2317
2350
let size = self . gen . sizes . size ( element) ;
2318
2351
let _align = self . gen . sizes . align ( element) ;
2319
- let flavor = if self . gen . gen . opts . new_api
2352
+ let flavor = if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2320
2353
&& matches ! ( self . variant, AbiVariant :: GuestExport )
2321
2354
{
2322
2355
Flavor :: BorrowedArgument
@@ -2339,7 +2372,9 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2339
2372
r#"auto {result} = wit::vector<{vtype}>::allocate({len});
2340
2373
"# ,
2341
2374
) ) ;
2342
- if self . gen . gen . opts . new_api && matches ! ( self . variant, AbiVariant :: GuestExport ) {
2375
+ if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2376
+ && matches ! ( self . variant, AbiVariant :: GuestExport )
2377
+ {
2343
2378
assert ! ( self . needs_dealloc) ;
2344
2379
self . push_str ( & format ! ( "if ({len}>0) _deallocate.push_back({base});\n " ) ) ;
2345
2380
}
@@ -2359,9 +2394,12 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2359
2394
// inplace construct
2360
2395
uwriteln ! ( self . src, "{result}.initialize(i, std::move(e{tmp}));" ) ;
2361
2396
uwriteln ! ( self . src, "}}" ) ;
2362
- if self . gen . gen . opts . new_api && matches ! ( self . variant, AbiVariant :: GuestExport ) {
2397
+ if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2398
+ && matches ! ( self . variant, AbiVariant :: GuestExport )
2399
+ {
2363
2400
results. push ( format ! ( "{result}.get_const_view()" ) ) ;
2364
- if self . gen . gen . opts . new_api && matches ! ( self . variant, AbiVariant :: GuestExport )
2401
+ if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2402
+ && matches ! ( self . variant, AbiVariant :: GuestExport )
2365
2403
{
2366
2404
self . leak_on_insertion . replace ( format ! (
2367
2405
"if ({len}>0) _deallocate.push_back((void*){result}.leak());\n "
@@ -2672,9 +2710,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2672
2710
}
2673
2711
2674
2712
let op0 = & operands[ 0 ] ;
2675
- let flavor = if self . gen . gen . opts . new_api
2676
- && matches ! ( self . variant, AbiVariant :: GuestImport )
2677
- {
2713
+ let flavor = if matches ! ( self . variant, AbiVariant :: GuestImport ) {
2678
2714
Flavor :: BorrowedArgument
2679
2715
} else {
2680
2716
Flavor :: InStruct
@@ -2697,7 +2733,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2697
2733
let ( _none, none_results) = self . blocks . pop ( ) . unwrap ( ) ;
2698
2734
assert ! ( none_results. is_empty( ) ) ;
2699
2735
assert ! ( some_results. len( ) == 1 ) ;
2700
- let flavor = if self . gen . gen . opts . new_api
2736
+ let flavor = if self . gen . gen . opts . api_style == APIStyle :: Symmetric
2701
2737
&& matches ! ( self . variant, AbiVariant :: GuestExport )
2702
2738
{
2703
2739
Flavor :: BorrowedArgument
0 commit comments