@@ -341,3 +341,151 @@ func __swift_bridge__some_function (_ arg: __swift_bridge__$tuple$I32U8) -> __sw
341
341
. test ( ) ;
342
342
}
343
343
}
344
+
345
+ /// Verify that we can use a (opaque type, String) as Swift function arg and return type.
346
+ mod extern_swift_tuple_opaque_and_string {
347
+ use super :: * ;
348
+
349
+ fn bridge_module_tokens ( ) -> TokenStream {
350
+ quote ! {
351
+ #[ swift_bridge:: bridge]
352
+ mod ffi {
353
+ extern "Rust" {
354
+ type SomeType ;
355
+ }
356
+ extern "Swift" {
357
+ fn some_function( arg: ( SomeType , String ) ) -> ( SomeType , String ) ;
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ fn expected_rust_tokens ( ) -> ExpectedRustTokens {
364
+ ExpectedRustTokens :: ContainsMany ( vec ! [
365
+ quote! {
366
+ pub fn some_function ( arg: ( super :: SomeType , String ) ) -> ( super :: SomeType , String ) {
367
+ {
368
+ let val = unsafe { __swift_bridge__some_function ( { let val = arg ; __swift_bridge__tuple_SomeTypeString ( Box :: into_raw( Box :: new( {
369
+ let val: super :: SomeType = val. 0 ;
370
+ val
371
+ } ) ) as * mut super :: SomeType , swift_bridge:: string:: RustString ( val. 1 ) . box_into_raw( ) ) } ) } ;
372
+ ( unsafe { * Box :: from_raw( val. 0 ) } , unsafe { Box :: from_raw( val. 1 ) . 0 } )
373
+ }
374
+ }
375
+ } ,
376
+ quote! {
377
+ #[ link_name = "__swift_bridge__$some_function" ]
378
+ fn __swift_bridge__some_function( arg: __swift_bridge__tuple_SomeTypeString) -> __swift_bridge__tuple_SomeTypeString;
379
+ } ,
380
+ quote! {
381
+ #[ repr( C ) ]
382
+ #[ doc( hidden) ]
383
+ pub struct __swift_bridge__tuple_SomeTypeString( * mut super :: SomeType , * mut swift_bridge:: string:: RustString ) ;
384
+ } ,
385
+ ] )
386
+ }
387
+
388
+ fn expected_swift_code ( ) -> ExpectedSwiftCode {
389
+ ExpectedSwiftCode :: ContainsManyAfterTrim ( vec ! [
390
+ r#"
391
+ @_cdecl("__swift_bridge__$some_function")
392
+ func __swift_bridge__some_function (_ arg: __swift_bridge__$tuple$SomeTypeString) -> __swift_bridge__$tuple$SomeTypeString {
393
+ { let val = some_function(arg: { let val = arg; return (SomeType(ptr: val._0), RustString(ptr: val._1)); }()); return __swift_bridge__$tuple$SomeTypeString(_0: {val.0.isOwned = false; return val.0.ptr;}(), _1: { let rustString = val.1.intoRustString(); rustString.isOwned = false; return rustString.ptr }()); }()
394
+ }
395
+ "# ,
396
+ ] )
397
+ }
398
+
399
+ fn expected_c_header ( ) -> ExpectedCHeader {
400
+ ExpectedCHeader :: ContainsManyAfterTrim ( vec ! [
401
+ r#"typedef struct __swift_bridge__$tuple$SomeTypeString { void* _0; void* _1; } __swift_bridge__$tuple$SomeTypeString;
402
+ "# ,
403
+ ] )
404
+ }
405
+
406
+ #[ test]
407
+ fn extern_swift_tuple_opaque_and_string ( ) {
408
+ CodegenTest {
409
+ bridge_module : bridge_module_tokens ( ) . into ( ) ,
410
+ expected_rust_tokens : expected_rust_tokens ( ) ,
411
+ expected_swift_code : expected_swift_code ( ) ,
412
+ expected_c_header : expected_c_header ( ) ,
413
+ }
414
+ . test ( ) ;
415
+ }
416
+ }
417
+
418
+ /// Verify that we can use a (transparent struct type, transparent enum type) as Swift function arg and return type.
419
+ mod extern_swift_tuple_transparent_struct_and_transparent_enum {
420
+ use super :: * ;
421
+
422
+ fn bridge_module_tokens ( ) -> TokenStream {
423
+ quote ! {
424
+ #[ swift_bridge:: bridge]
425
+ mod ffi {
426
+ enum SomeEnum {
427
+ Variant1 ,
428
+ Variant2 ,
429
+ }
430
+ #[ swift_bridge( swift_repr = "struct" ) ]
431
+ struct SomeStruct {
432
+ field: u8
433
+ }
434
+ extern "Swift" {
435
+ fn some_function( arg: ( SomeStruct , SomeEnum ) ) -> ( SomeStruct , SomeEnum ) ;
436
+ }
437
+ }
438
+ }
439
+ }
440
+
441
+ fn expected_rust_tokens ( ) -> ExpectedRustTokens {
442
+ ExpectedRustTokens :: ContainsMany ( vec ! [
443
+ quote! {
444
+ pub fn some_function ( arg: ( SomeStruct , SomeEnum ) ) -> ( SomeStruct , SomeEnum ) {
445
+ {
446
+ let val = unsafe { __swift_bridge__some_function ( { let val = arg ; __swift_bridge__tuple_SomeStructSomeEnum ( val. 0 . into_ffi_repr( ) , val. 1 . into_ffi_repr( ) ) } ) } ;
447
+ ( val. 0 . into_rust_repr( ) , val. 1 . into_rust_repr( ) )
448
+ }
449
+ }
450
+ } ,
451
+ quote! {
452
+ #[ link_name = "__swift_bridge__$some_function" ]
453
+ fn __swift_bridge__some_function( arg: __swift_bridge__tuple_SomeStructSomeEnum) -> __swift_bridge__tuple_SomeStructSomeEnum;
454
+ } ,
455
+ quote! {
456
+ #[ repr( C ) ]
457
+ #[ doc( hidden) ]
458
+ pub struct __swift_bridge__tuple_SomeStructSomeEnum( __swift_bridge__SomeStruct, __swift_bridge__SomeEnum) ;
459
+ } ,
460
+ ] )
461
+ }
462
+
463
+ fn expected_swift_code ( ) -> ExpectedSwiftCode {
464
+ ExpectedSwiftCode :: ContainsManyAfterTrim ( vec ! [
465
+ r#"
466
+ @_cdecl("__swift_bridge__$some_function")
467
+ func __swift_bridge__some_function (_ arg: __swift_bridge__$tuple$SomeStructSomeEnum) -> __swift_bridge__$tuple$SomeStructSomeEnum {
468
+ { let val = some_function(arg: { let val = arg; return (val._0.intoSwiftRepr(), val._1.intoSwiftRepr()); }()); return __swift_bridge__$tuple$SomeStructSomeEnum(_0: val.0.intoFfiRepr(), _1: val.1.intoFfiRepr()); }()
469
+ }
470
+ "# ,
471
+ ] )
472
+ }
473
+
474
+ fn expected_c_header ( ) -> ExpectedCHeader {
475
+ ExpectedCHeader :: ContainsManyAfterTrim ( vec ! [
476
+ r#"typedef struct __swift_bridge__$tuple$SomeStructSomeEnum { struct __swift_bridge__$SomeStruct _0; struct __swift_bridge__$SomeEnum _1; } __swift_bridge__$tuple$SomeStructSomeEnum;
477
+ "# ,
478
+ ] )
479
+ }
480
+
481
+ #[ test]
482
+ fn extern_swift_tuple_transparent_struct_and_transparent_enum ( ) {
483
+ CodegenTest {
484
+ bridge_module : bridge_module_tokens ( ) . into ( ) ,
485
+ expected_rust_tokens : expected_rust_tokens ( ) ,
486
+ expected_swift_code : expected_swift_code ( ) ,
487
+ expected_c_header : expected_c_header ( ) ,
488
+ }
489
+ . test ( ) ;
490
+ }
491
+ }
0 commit comments