1+ use anyhow:: bail;
12use heck:: { ToPascalCase , ToShoutySnakeCase , ToSnakeCase , ToUpperCamelCase } ;
23use std:: {
34 collections:: { HashMap , HashSet } ,
4- fmt:: Write as FmtWrite ,
5+ fmt:: { Display , Write as FmtWrite } ,
56 io:: { Read , Write } ,
67 path:: PathBuf ,
78 process:: { Command , Stdio } ,
@@ -209,32 +210,60 @@ pub struct Opts {
209210 #[ cfg_attr( feature = "clap" , arg( long, default_value_t = Ownership :: Owning ) ) ]
210211 pub ownership : Ownership ,
211212
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
214214 #[ 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+ ) ,
217221 ) ]
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 ,
225223
226224 /// Where to place output files
227225 #[ cfg_attr( feature = "clap" , arg( skip) ) ]
228226 out_dir : Option < PathBuf > ,
229227}
230228
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+
231263impl Opts {
232264 pub fn build ( mut self , out_dir : Option < & PathBuf > ) -> Box < dyn WorldGenerator > {
233265 let mut r = Cpp :: new ( ) ;
234266 self . out_dir = out_dir. cloned ( ) ;
235- if self . _old_api {
236- self . new_api = false ;
237- }
238267 r. opts = self ;
239268 Box :: new ( r)
240269 }
@@ -684,6 +713,7 @@ impl WorldGenerator for Cpp {
684713 . unwrap ( )
685714 . as_slice ( ) ,
686715 ) ;
716+
687717 Ok ( ( ) )
688718 }
689719}
@@ -1183,17 +1213,18 @@ impl CppInterfaceGenerator<'_> {
11831213 let special = is_special_method ( func) ;
11841214 if !matches ! ( special, SpecialMethod :: Allocate ) {
11851215 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+ } ;
11971228 let lift_lower = if export {
11981229 LiftLower :: LiftArgsLowerResults
11991230 } else {
@@ -1402,14 +1433,15 @@ impl CppInterfaceGenerator<'_> {
14021433 "std::string_view" . into ( )
14031434 }
14041435 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 =>
14061438 {
14071439 self . gen . dependencies . needs_string_view = true ;
14081440 "std::string_view" . into ( )
14091441 }
14101442 Flavor :: Argument ( AbiVariant :: GuestExport ) => {
14111443 self . gen . dependencies . needs_wit = true ;
1412- "wit::string && " . into ( )
1444+ "wit::string" . into ( )
14131445 }
14141446 _ => {
14151447 self . gen . dependencies . needs_wit = true ;
@@ -1491,14 +1523,15 @@ impl CppInterfaceGenerator<'_> {
14911523 format ! ( "wit::span<{inner} const>" )
14921524 }
14931525 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 =>
14951528 {
14961529 self . gen . dependencies . needs_wit = true ;
14971530 format ! ( "wit::span<{inner} const>" )
14981531 }
14991532 Flavor :: Argument ( AbiVariant :: GuestExport ) => {
15001533 self . gen . dependencies . needs_wit = true ;
1501- format ! ( "wit::vector<{inner}>&& " )
1534+ format ! ( "wit::vector<{inner}>" )
15021535 }
15031536 _ => {
15041537 self . gen . dependencies . needs_wit = true ;
@@ -2280,7 +2313,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
22802313 . gen
22812314 . type_name ( element, & self . namespace , Flavor :: InStruct ) ;
22822315 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
22842317 && matches ! ( self . variant, AbiVariant :: GuestExport )
22852318 {
22862319 format ! (
@@ -2296,7 +2329,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
22962329 let tmp = self . tmp ( ) ;
22972330 let len = format ! ( "len{}" , tmp) ;
22982331 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
23002333 && matches ! ( self . variant, AbiVariant :: GuestExport )
23012334 {
23022335 assert ! ( self . needs_dealloc) ;
@@ -2316,7 +2349,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
23162349 let tmp = self . tmp ( ) ;
23172350 let size = self . gen . sizes . size ( element) ;
23182351 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
23202353 && matches ! ( self . variant, AbiVariant :: GuestExport )
23212354 {
23222355 Flavor :: BorrowedArgument
@@ -2339,7 +2372,9 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
23392372 r#"auto {result} = wit::vector<{vtype}>::allocate({len});
23402373 "# ,
23412374 ) ) ;
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+ {
23432378 assert ! ( self . needs_dealloc) ;
23442379 self . push_str ( & format ! ( "if ({len}>0) _deallocate.push_back({base});\n " ) ) ;
23452380 }
@@ -2359,9 +2394,12 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
23592394 // inplace construct
23602395 uwriteln ! ( self . src, "{result}.initialize(i, std::move(e{tmp}));" ) ;
23612396 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+ {
23632400 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 )
23652403 {
23662404 self . leak_on_insertion . replace ( format ! (
23672405 "if ({len}>0) _deallocate.push_back((void*){result}.leak());\n "
@@ -2672,9 +2710,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
26722710 }
26732711
26742712 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 ) {
26782714 Flavor :: BorrowedArgument
26792715 } else {
26802716 Flavor :: InStruct
@@ -2697,7 +2733,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
26972733 let ( _none, none_results) = self . blocks . pop ( ) . unwrap ( ) ;
26982734 assert ! ( none_results. is_empty( ) ) ;
26992735 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
27012737 && matches ! ( self . variant, AbiVariant :: GuestExport )
27022738 {
27032739 Flavor :: BorrowedArgument
0 commit comments