@@ -949,3 +949,103 @@ void __swift_bridge__$some_function(void* callback_wrapper, void __swift_bridge_
949
949
. test ( ) ;
950
950
}
951
951
}
952
+
953
+ /// Verify that we generate the correct code for extern "Rust" async functions that returns a Result<(), OpaqueRustType>.
954
+ mod extern_rust_async_function_returns_result_null_opaque {
955
+ use super :: * ;
956
+
957
+ fn bridge_module ( ) -> TokenStream {
958
+ quote ! {
959
+ #[ swift_bridge:: bridge]
960
+ mod ffi {
961
+ extern "Rust" {
962
+ type ErrorType ;
963
+ async fn some_function( ) -> Result <( ) , ErrorType >;
964
+ }
965
+ }
966
+ }
967
+ }
968
+
969
+ fn expected_rust_tokens ( ) -> ExpectedRustTokens {
970
+ ExpectedRustTokens :: Contains ( quote ! {
971
+ pub extern "C" fn __swift_bridge__some_function(
972
+ callback_wrapper: * mut std:: ffi:: c_void,
973
+ callback: extern "C" fn ( * mut std:: ffi:: c_void, * mut super :: ErrorType ) -> ( ) ,
974
+ ) {
975
+ let callback_wrapper = swift_bridge:: async_support:: SwiftCallbackWrapper ( callback_wrapper) ;
976
+ let fut = super :: some_function( ) ;
977
+ let task = async move {
978
+ let val = match fut. await {
979
+ Ok ( ok) => std:: ptr:: null_mut( ) ,
980
+ Err ( err) => Box :: into_raw( Box :: new( {
981
+ let val: super :: ErrorType = err;
982
+ val
983
+ } ) ) as * mut super :: ErrorType
984
+ } ;
985
+ let callback_wrapper = callback_wrapper;
986
+ let callback_wrapper = callback_wrapper. 0 ;
987
+ ( callback) ( callback_wrapper, val)
988
+ } ;
989
+ swift_bridge:: async_support:: ASYNC_RUNTIME . spawn_task( Box :: pin( task) )
990
+ }
991
+ } )
992
+ }
993
+
994
+ // TODO: Replace `Error` with the concrete error type `ErrorType`.
995
+ // As of Feb 2023 using the concrete error type leads to a compile time error.
996
+ // This seems like a bug in the Swift compiler.
997
+
998
+ fn expected_swift_code ( ) -> ExpectedSwiftCode {
999
+ ExpectedSwiftCode :: ContainsAfterTrim (
1000
+ r#"
1001
+ public func some_function() async throws -> () {
1002
+ func onComplete(cbWrapperPtr: UnsafeMutableRawPointer?, rustFnRetVal: UnsafeMutableRawPointer?) {
1003
+ let wrapper = Unmanaged<CbWrapper$some_function>.fromOpaque(cbWrapperPtr!).takeRetainedValue()
1004
+ if rustFnRetVal == nil {
1005
+ wrapper.cb(.success(()))
1006
+ } else {
1007
+ wrapper.cb(.failure(ErrorType(ptr: rustFnRetVal!)))
1008
+ }
1009
+ }
1010
+
1011
+ return try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<(), Error>) in
1012
+ let callback = { rustFnRetVal in
1013
+ continuation.resume(with: rustFnRetVal)
1014
+ }
1015
+
1016
+ let wrapper = CbWrapper$some_function(cb: callback)
1017
+ let wrapperPtr = Unmanaged.passRetained(wrapper).toOpaque()
1018
+
1019
+ __swift_bridge__$some_function(wrapperPtr, onComplete)
1020
+ })
1021
+ }
1022
+ class CbWrapper$some_function {
1023
+ var cb: (Result<(), Error>) -> ()
1024
+
1025
+ public init(cb: @escaping (Result<(), Error>) -> ()) {
1026
+ self.cb = cb
1027
+ }
1028
+ }
1029
+ "# ,
1030
+ )
1031
+ }
1032
+
1033
+ fn expected_c_header ( ) -> ExpectedCHeader {
1034
+ ExpectedCHeader :: ContainsAfterTrim (
1035
+ r#"
1036
+ void __swift_bridge__$some_function(void* callback_wrapper, void __swift_bridge__$some_function$async(void* callback_wrapper, void* ret));
1037
+ "# ,
1038
+ )
1039
+ }
1040
+
1041
+ #[ test]
1042
+ fn extern_rust_async_function_returns_result_null_opaque ( ) {
1043
+ CodegenTest {
1044
+ bridge_module : bridge_module ( ) . into ( ) ,
1045
+ expected_rust_tokens : expected_rust_tokens ( ) ,
1046
+ expected_swift_code : expected_swift_code ( ) ,
1047
+ expected_c_header : expected_c_header ( ) ,
1048
+ }
1049
+ . test ( ) ;
1050
+ }
1051
+ }
0 commit comments