diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift index 9fad48d20..0de06d630 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -56,6 +56,10 @@ public func globalCallMeIntConsumer(run: (Int32) -> Void) { run(1) } +public func globalCallMeLongConsumer(run: (Int64) -> Void) { + 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 503da60f3..2a07bd45b 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -82,4 +82,9 @@ void call_globalCallMeDoubleSupplier_noThrow() { void call_globalCallMeIntConsumer_noThrow() { MySwiftLibrary.globalCallMeIntConsumer((int a) -> { }); } + + @Test + void call_globalCallMeLongConsumer_noThrow() { + MySwiftLibrary.globalCallMeLongConsumer((long a) -> { }); + } } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index a0fd01681..a3237d144 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -68,6 +68,10 @@ public func globalCallMeIntConsumer(run: (Int32) -> Void) { run(1) } +public func globalCallMeLongConsumer(run: (Int64) -> Void) { + 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 cb60b1c62..b9a5d949b 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -194,4 +194,9 @@ void call_globalCallMeDoubleSupplier_noThrow() { void call_globalCallMeIntConsumer_noThrow() { MySwiftLibrary.globalCallMeIntConsumer((int a) -> { }); } + + @Test + void call_globalCallMeLongConsumer_noThrow() { + MySwiftLibrary.globalCallMeLongConsumer((long a) -> { }); + } } diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift index 48d117554..f5254bb54 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift @@ -41,6 +41,10 @@ public func globalCallMeIntConsumer(run: (Int32) -> Void) { run(1) } +public func globalCallMeLongConsumer(run: (Int64) -> Void) { + 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 75b9f3a0e..afa0ee19c 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java @@ -76,4 +76,9 @@ void globalCallMeDoubleSupplier() { void globalCallMeIntConsumer() { MySwiftLibrary.globalCallMeIntConsumer((int a) -> {}); } + + @Test + void globalCallMeLongConsumer() { + MySwiftLibrary.globalCallMeLongConsumer((long a) -> {}); + } } diff --git a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift index b34d4135e..9fb67eda5 100644 --- a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift +++ b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift @@ -63,6 +63,10 @@ public func globalCallMeIntConsumer(run: (Int32) -> Void) { run(1) } +public func globalCallMeLongConsumer(run: (Int64) -> Void) { + 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 a9bb11818..316c1878d 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift @@ -55,6 +55,11 @@ extension JavaType { .class(package: "java.util.function", name: "IntConsumer") } + /// The description of the type java.util.function.LongConsumer. + static var javaUtilFunctionLongConsumer: JavaType { + .class(package: "java.util.function", name: "LongConsumer") + } + /// 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 b6ce713be..9b4daf286 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -64,6 +64,13 @@ struct KnownJavaFunctionalInterface: Sendable { result: .void ) + static let longConsumer = KnownJavaFunctionalInterface( + JavaType.javaUtilFunctionLongConsumer, + method: "accept", + parameters: [.long], + result: .void + ) + static let all: [KnownJavaFunctionalInterface] = [ .runnable, .booleanSupplier, @@ -71,6 +78,7 @@ struct KnownJavaFunctionalInterface: Sendable { .longSupplier, .doubleSupplier, .intConsumer, + .longConsumer, ] static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? { @@ -121,6 +129,8 @@ struct KnownJavaFunctionalInterface: Sendable { return switch () { case _ where parameter.isInt32: intConsumer + case _ where parameter.isInt64: + longConsumer default: nil } diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift index a39feea48..768000c4a 100644 --- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift +++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift @@ -40,6 +40,7 @@ final class FuncCallbackImportTests { public func callMeDoubleSupplier(callback: () -> Double) public func callMeIntConsumer(callback: (Int32) -> Void) + public func callMeLongConsumer(callback: (Int64) -> Void) public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ()) public func withBuffer(body: (UnsafeRawBufferPointer) -> Int) @@ -344,7 +345,7 @@ final class FuncCallbackImportTests { ) } - @Test("Import: public func callMeDoubleSupplier(callback: (Int32) -> Void)") + @Test("Import: public func callMeIntConsumerFunc(callback: (Int32) -> Void)") func func_callMeIntConsumerFunc_callback() throws { var config = Configuration() config.swiftModule = "__FakeModule" @@ -387,6 +388,48 @@ final class FuncCallbackImportTests { ) } + @Test("Import: public func callMeLongConsumerFunc(callback: (Int64) -> Void)") + func func_callMeLongConsumerFunc_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 == "callMeLongConsumer" }! + + 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 callMeLongConsumer(callback: (Int64) -> Void) + * } + */ + public static void callMeLongConsumer(java.util.function.LongConsumer callback) { + try(var arena$ = Arena.ofConfined()) { + swiftjava___FakeModule_callMeLongConsumer_callback.call(callMeLongConsumer.$toUpcallStub(callback, arena$)); + } + } + """ + ] + ) + } @Test("Import: public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ())") func func_callMeMoreFunc_callback() throws { diff --git a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift index 1635f1a9b..ec304b562 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift @@ -26,6 +26,7 @@ struct JNIClosureTests { public func closureDoubleSupplier(closure: () -> Double) {} public func closureIntConsumer(closure: (Int32) -> Void) {} + public func closureLongConsumer(closure: (Int64) -> Void) {} public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {} """ @@ -180,6 +181,31 @@ struct JNIClosureTests { ) } + @Test + func closureLongConsumer_javaBindings() throws { + try assertOutput( + input: source, + .jni, + .java, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func closureLongConsumer(closure: (Int64) -> Void) + * } + */ + public static void closureLongConsumer(java.util.function.LongConsumer closure) { + SwiftModule.$closureLongConsumer(closure); + } + """, + """ + private static native void $closureLongConsumer(java.util.function.LongConsumer closure); + """, + ] + ) + } + @Test func emptyClosure_swiftThunks() throws { try assertOutput( @@ -330,6 +356,31 @@ struct JNIClosureTests { ) } + @Test + func closureLongConsumer_swiftThunks() throws { + try assertOutput( + input: source, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024closureLongConsumer__Ljava_util_function_LongConsumer_2") + public func Java_com_example_swift_SwiftModule__00024closureLongConsumer__Ljava_util_function_LongConsumer_2(environment: UnsafeMutablePointer!, thisClass: jclass, closure: jobject?) { + SwiftModule.closureLongConsumer(closure: { + let class$ = environment.interface.GetObjectClass(environment, closure) + let methodID$ = environment.interface.GetMethodID(environment, class$, "accept", "(J)V")! + environment.interface.DeleteLocalRef(environment, class$) + let arguments$: [jvalue] = [_0.getJValue(in: environment)] + environment.interface.CallVoidMethodA(environment, closure, methodID$, arguments$) + } + ) + } + """ + ] + ) + } + @Test func closureWithArgumentsAndReturn_javaBindings() throws { try assertOutput(