diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift index 96617408d..4023de39d 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -84,6 +84,10 @@ public func globalCallMeLongBinaryOperator(run: (Int64, Int64) -> Int64) -> Int6 run(1, 2) } +public func globalCallMeDoubleBinaryOperator(run: (Double, Double) -> Double) -> Double { + run(1.0, 2.0) +} + // ==== Internal helpers func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) { diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java b/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java index f4a8a8ddc..8ebee114b 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -122,4 +122,10 @@ void call_globalCallMeLongBinaryOperator_noThrow() { long result = MySwiftLibrary.globalCallMeLongBinaryOperator((long a, long b) -> { return a + b; }); assertEquals(3L, result); } + + @Test + void call_globalCallMeDoubleBinaryOperator_noThrow() { + double result = MySwiftLibrary.globalCallMeDoubleBinaryOperator((double a, double b) -> { return a + b; }); + assertEquals(3.0, result); + } } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index d9c591d0e..da7cd1eb3 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -96,6 +96,10 @@ public func globalCallMeLongBinaryOperator(run: (Int64, Int64) -> Int64) -> Int6 run(1, 2) } +public func globalCallMeDoubleBinaryOperator(run: (Double, Double) -> Double) -> Double { + run(1.0, 2.0) +} + public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int { buf.count } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java index abdf814b3..0b5ec1c24 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -234,4 +234,10 @@ void call_globalCallMeLongBinaryOperator_noThrow() { long result = MySwiftLibrary.globalCallMeLongBinaryOperator((long a, long b) -> { return a + b; }); assertEquals(3L, result); } + + @Test + void call_globalCallMeDoubleBinaryOperator_noThrow() { + double result = MySwiftLibrary.globalCallMeDoubleBinaryOperator((double a, double b) -> { return a + b; }); + assertEquals(3.0, result); + } } diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift index 8888fa5f4..b67a7427e 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift @@ -69,6 +69,10 @@ public func globalCallMeLongBinaryOperator(run: (Int64, Int64) -> Int64) -> Int6 run(1, 2) } +public func globalCallMeDoubleBinaryOperator(run: (Double, Double) -> Double) -> Double { + run(1.0, 2.0) +} + public func closureMultipleArguments( input1: Int64, input2: Int64, diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java index 8f4a6b01f..9ffb4eaae 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java @@ -116,4 +116,10 @@ void globalCallMeLongBinaryOperator() { long result = MySwiftLibrary.globalCallMeLongBinaryOperator((long a, long b) -> { return a + b; }); assertEquals(3L, result); } + + @Test + void globalCallMeDoubleBinaryOperator() { + double result = MySwiftLibrary.globalCallMeDoubleBinaryOperator((double a, double b) -> { return a + b; }); + assertEquals(3.0, result); + } } diff --git a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift index c5ae2e0c0..02d2cddeb 100644 --- a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift +++ b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift @@ -91,6 +91,10 @@ public func globalCallMeLongBinaryOperator(run: (Int64, Int64) -> Int64) -> Int6 run(1, 2) } +public func globalCallMeDoubleBinaryOperator(run: (Double, Double) -> Double) -> Double { + run(1.0, 2.0) +} + public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int { buf.count } diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift index 8291a0190..93afb2ade 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift @@ -90,6 +90,11 @@ extension JavaType { .class(package: "java.util.function", name: "LongBinaryOperator") } + /// The description of the type java.util.function.DoubleBinaryOperator. + static var javaUtilFunctionDoubleBinaryOperator: JavaType { + .class(package: "java.util.function", name: "DoubleBinaryOperator") + } + /// The description of the type java.lang.Class. static var javaLangClass: JavaType { .class(package: "java.lang", name: "Class") diff --git a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift index d5aac8e62..e639e6305 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -113,6 +113,13 @@ struct KnownJavaFunctionalInterface: Sendable { result: .long ) + static let doubleBinaryOperator = KnownJavaFunctionalInterface( + JavaType.javaUtilFunctionDoubleBinaryOperator, + method: "applyAsDouble", + parameters: [.double, .double], + result: .double + ) + static let all: [KnownJavaFunctionalInterface] = [ .runnable, .booleanSupplier, @@ -127,6 +134,7 @@ struct KnownJavaFunctionalInterface: Sendable { .doublePredicate, .intBinaryOperator, .longBinaryOperator, + .doubleBinaryOperator, ] static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? { @@ -209,6 +217,8 @@ struct KnownJavaFunctionalInterface: Sendable { intBinaryOperator case _ where parameter.isInt64: longBinaryOperator + case _ where parameter.isDouble: + doubleBinaryOperator default: nil } diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift index efecec939..91630da2e 100644 --- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift +++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift @@ -49,6 +49,7 @@ final class FuncCallbackImportTests { public func callMeIntBinaryOperator(callback: (Int32, Int32) -> Int32) public func callMeLongBinaryOperator(callback: (Int64, Int64) -> Int64) + public func callMeDoubleBinaryOperator(callback: (Double, Double) -> Double) public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ()) public func withBuffer(body: (UnsafeRawBufferPointer) -> Int) @@ -806,6 +807,49 @@ final class FuncCallbackImportTests { ) } + @Test("Import: public func callMecallMeDoubleBinaryOperatorFunc(callback: (Double, Double) -> Double)") + func func_callMecallMeDoubleBinaryOperatorFunc_callback() throws { + var config = Configuration() + config.swiftModule = "__FakeModule" + let st = makeSwiftJavaAnalyzer(config: config) + st.log.logLevel = .error + + try st.analyze(path: "Fake.swift", text: Self.class_interfaceFile) + + let funcDecl = st.extractedGlobalFuncs.first { $0.name == "callMeDoubleBinaryOperator" }! + + let generator = FFMSwift2JavaGenerator( + config: config, + translator: st, + javaPackage: "com.example.swift", + swiftOutputDirectory: "/fake", + javaOutputDirectory: "/fake" + ) + + let output = JavaPrinter.toString { printer in + generator.printFunctionDowncallMethods(&printer, funcDecl) + } + + assertOutput( + output, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func callMeDoubleBinaryOperator(callback: (Double, Double) -> Double) + * } + */ + public static void callMeDoubleBinaryOperator(java.util.function.DoubleBinaryOperator callback) { + try(var arena$ = Arena.ofConfined()) { + swiftjava___FakeModule_callMeDoubleBinaryOperator_callback.call(callMeDoubleBinaryOperator.$toUpcallStub(callback, arena$)); + } + } + """ + ] + ) + } + @Test("Import: public func withBuffer(body: (UnsafeRawBufferPointer) -> Int)") func func_withBuffer_body() throws { var config = Configuration() diff --git a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift index 170d262bd..db91dc3bd 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift @@ -35,6 +35,7 @@ struct JNIClosureTests { public func closureIntBinaryOperator(closure: (Int32, Int32) -> Int32) {} public func closureLongBinaryOperator(closure: (Int64, Int64) -> Int64) {} + public func closureDoubleBinaryOperator(closure: (Double, Double) -> Double) {} public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {} """ @@ -364,6 +365,31 @@ struct JNIClosureTests { ) } + @Test + func closureDoubleBinaryOperator_javaBindings() throws { + try assertOutput( + input: source, + .jni, + .java, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func closureDoubleBinaryOperator(closure: (Double, Double) -> Double) + * } + */ + public static void closureDoubleBinaryOperator(java.util.function.DoubleBinaryOperator closure) { + SwiftModule.$closureDoubleBinaryOperator(closure); + } + """, + """ + private static native void $closureDoubleBinaryOperator(java.util.function.DoubleBinaryOperator closure); + """, + ] + ) + } + @Test func emptyClosure_swiftThunks() throws { try assertOutput( @@ -689,6 +715,31 @@ struct JNIClosureTests { ) } + @Test + func closureDoubleBinaryOperator_swiftThunks() throws { + try assertOutput( + input: source, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024closureDoubleBinaryOperator__Ljava_util_function_DoubleBinaryOperator_2") + public func Java_com_example_swift_SwiftModule__00024closureDoubleBinaryOperator__Ljava_util_function_DoubleBinaryOperator_2(environment: UnsafeMutablePointer!, thisClass: jclass, closure: jobject?) { + SwiftModule.closureDoubleBinaryOperator(closure: { + let class$ = environment.interface.GetObjectClass(environment, closure) + let methodID$ = environment.interface.GetMethodID(environment, class$, "applyAsDouble", "(DD)D")! + environment.interface.DeleteLocalRef(environment, class$) + let arguments$: [jvalue] = [_0.getJValue(in: environment), _1.getJValue(in: environment)] + return Double(fromJNI: environment.interface.CallDoubleMethodA(environment, closure, methodID$, arguments$), in: environment) + } + ) + } + """ + ] + ) + } + @Test func closureWithArgumentsAndReturn_javaBindings() throws { try assertOutput(