diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift index bae46370f..26a871d22 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -68,6 +68,10 @@ public func globalCallMeIntPredicate(run: (Int32) -> Bool) -> Bool { run(1) } +public func globalCallMeLongPredicate(run: (Int64) -> Bool) -> Bool { + run(1) +} + // ==== 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 22798dc4d..a4cb1714b 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -98,4 +98,10 @@ void call_globalCallMeIntPredicate_noThrow() { boolean result = MySwiftLibrary.globalCallMeIntPredicate((int a) -> { return true; }); assertEquals(true, result); } + + @Test + void call_globalCallMeLongPredicate_noThrow() { + boolean result = MySwiftLibrary.globalCallMeLongPredicate((long a) -> { return true; }); + assertEquals(true, result); + } } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index 849bb9587..f374125d4 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -80,6 +80,10 @@ public func globalCallMeIntPredicate(run: (Int32) -> Bool) -> Bool { run(1) } +public func globalCallMeLongPredicate(run: (Int64) -> Bool) -> Bool { + run(1) +} + 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 18e5c046e..b85b05b02 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -210,4 +210,10 @@ void call_globalCallMeIntPredicate_noThrow() { boolean result = MySwiftLibrary.globalCallMeIntPredicate((int a) -> { return true; }); assertEquals(true, result); } + + @Test + void call_globalCallMeLongPredicate_noThrow() { + boolean result = MySwiftLibrary.globalCallMeLongPredicate((long a) -> { return true; }); + assertEquals(true, result); + } } diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift index ad0f7abb4..e57c50b25 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift @@ -53,6 +53,10 @@ public func globalCallMeIntPredicate(run: (Int32) -> Bool) -> Bool { run(1) } +public func globalCallMeLongPredicate(run: (Int64) -> Bool) -> Bool { + run(1) +} + 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 589de0953..6b53ed31c 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java @@ -92,4 +92,10 @@ void globalCallMeIntPredicate() { boolean result = MySwiftLibrary.globalCallMeIntPredicate((int a) -> { return true; }); assertEquals(true, result); } + + @Test + void globalCallMeLongPredicate() { + boolean result = MySwiftLibrary.globalCallMeLongPredicate((long a) -> { return true; }); + assertEquals(true, result); + } } diff --git a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift index ea12f8344..51540e78b 100644 --- a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift +++ b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift @@ -75,6 +75,10 @@ public func globalCallMeIntPredicate(run: (Int32) -> Bool) -> Bool { run(1) } +public func globalCallMeLongPredicate(run: (Int64) -> Bool) -> Bool { + run(1) +} + 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 7f0b81df4..188241871 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift @@ -70,6 +70,11 @@ extension JavaType { .class(package: "java.util.function", name: "IntPredicate") } + /// The description of the type java.util.function.LongPredicate. + static var javaUtilFunctionLongPredicate: JavaType { + .class(package: "java.util.function", name: "LongPredicate") + } + /// 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 8f8c2901e..7d7fb23e8 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -85,6 +85,13 @@ struct KnownJavaFunctionalInterface: Sendable { result: .boolean ) + static let longPredicate = KnownJavaFunctionalInterface( + JavaType.javaUtilFunctionLongPredicate, + method: "test", + parameters: [.long], + result: .boolean + ) + static let all: [KnownJavaFunctionalInterface] = [ .runnable, .booleanSupplier, @@ -95,6 +102,7 @@ struct KnownJavaFunctionalInterface: Sendable { .longConsumer, .doubleConsumer, .intPredicate, + .longPredicate, ] static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? { @@ -160,6 +168,8 @@ struct KnownJavaFunctionalInterface: Sendable { return switch () { case _ where parameter.isInt32: intPredicate + case _ where parameter.isInt64: + longPredicate default: nil } diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift index 274aae2b4..71b38fced 100644 --- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift +++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift @@ -44,6 +44,7 @@ final class FuncCallbackImportTests { public func callMeDoubleConsumer(callback: (Double) -> Void) public func callMeIntPredicate(callback: (Int32) -> Bool) + public func callMeLongPredicate(callback: (Int64) -> Bool) public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ()) public func withBuffer(body: (UnsafeRawBufferPointer) -> Int) @@ -629,6 +630,49 @@ final class FuncCallbackImportTests { ) } + @Test("Import: public func callMecallMeLongPredicateFunc(callback: (Int64) -> Bool)") + func func_callMecallMeLongPredicateFunc_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 == "callMeLongPredicate" }! + + 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 callMeLongPredicate(callback: (Int64) -> Bool) + * } + */ + public static void callMeLongPredicate(java.util.function.LongPredicate callback) { + try(var arena$ = Arena.ofConfined()) { + swiftjava___FakeModule_callMeLongPredicate_callback.call(callMeLongPredicate.$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 46ca8b5bd..1cd9e976c 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift @@ -30,6 +30,7 @@ struct JNIClosureTests { public func closureDoubleConsumer(closure: (Double) -> Void) {} public func closureIntPredicate(closure: (Int32) -> Bool) {} + public func closureLongPredicate(closure: (Int64) -> Bool) {} public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {} """ @@ -259,6 +260,30 @@ struct JNIClosureTests { ) } + @Test + func closureLongPredicate_javaBindings() throws { + try assertOutput( + input: source, + .jni, + .java, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func closureLongPredicate(closure: (Int64) -> Bool) + * } + */ + public static void closureLongPredicate(java.util.function.LongPredicate closure) { + SwiftModule.$closureLongPredicate(closure); + } + """, + """ + private static native void $closureLongPredicate(java.util.function.LongPredicate closure); + """, + ] + ) + } @Test func emptyClosure_swiftThunks() throws { @@ -460,6 +485,30 @@ struct JNIClosureTests { ) } + @Test + func closureLongPredicate_swiftThunks() throws { + try assertOutput( + input: source, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024closureLongPredicate__Ljava_util_function_LongPredicate_2") + public func Java_com_example_swift_SwiftModule__00024closureLongPredicate__Ljava_util_function_LongPredicate_2(environment: UnsafeMutablePointer!, thisClass: jclass, closure: jobject?) { + SwiftModule.closureLongPredicate(closure: { + let class$ = environment.interface.GetObjectClass(environment, closure) + let methodID$ = environment.interface.GetMethodID(environment, class$, "test", "(J)Z")! + environment.interface.DeleteLocalRef(environment, class$) + let arguments$: [jvalue] = [_0.getJValue(in: environment)] + return Bool(fromJNI: environment.interface.CallBooleanMethodA(environment, closure, methodID$, arguments$), in: environment) + } + ) + } + """ + ] + ) + } @Test func closureDoubleConsumer_swiftThunks() throws {