diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift index fd2cbd037..88a277b4a 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftAndJavaJarFFMSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -44,6 +44,10 @@ public func globalCallMeIntSupplier(run: () -> Int32) -> Int32 { run() } +public func globalCallMeLongSupplier(run: () -> Int64) -> Int64 { + run() +} + public func globalCallMeDoubleSupplier(run: () -> Double) -> Double { run() } 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 500421125..9eb8ff147 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftAndJavaJarFFMSampleLib/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -66,6 +66,12 @@ void call_globalCallMeIntSupplier_noThrow() { assertEquals(1, result); } + @Test + void call_globalCallMeLongSupplier_noThrow() { + long result = MySwiftLibrary.globalCallMeLongSupplier(() -> { return 1L; }); + assertEquals(1L, result); + } + @Test void call_globalCallMeDoubleSupplier_noThrow() { double result = MySwiftLibrary.globalCallMeBooleanSupplier(() -> { return 2.0; }); diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index cd14afcc2..f2dc75125 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -56,6 +56,10 @@ public func globalCallMeIntSupplier(run: () -> Int32) -> Int32 { run() } +public func globalCallMeLongSupplier(run: () -> Int64) -> Int64 { + run() +} + public func globalCallMeDoubleSupplier(run: () -> Double) -> Double { run() } 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 f081c859e..5375017d5 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java @@ -178,6 +178,12 @@ void call_globalCallMeIntSupplier_noThrow() { assertEquals(2, result); } + @Test + void call_globalCallMeLongSupplier_noThrow() { + long result = MySwiftLibrary.globalCallMeLongSupplier(() -> { return 2L; }); + assertEquals(2L, result); + } + @Test void call_globalCallMeDoubleSupplier_noThrow() { double result = MySwiftLibrary.globalCallMeDoubleSupplier(() -> { return 2.0; }); diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift index fb9356026..17d61d506 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Closures.swift @@ -29,6 +29,10 @@ public func globalCallMeIntSupplier(run: () -> Int32) -> Int32 { run() } +public func globalCallMeLongSupplier(run: () -> Int64) -> Int64 { + run() +} + public func globalCallMeDoubleSupplier(run: () -> Double) -> Double { run() } 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 65ecb26d2..bb414e33b 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/ClosuresTest.java @@ -60,6 +60,12 @@ void globalCallMeIntSupplier() { assertEquals(2, result); } + @Test + void globalCallMeLongSupplier() { + long result = MySwiftLibrary.globalCallMeLongSupplier(() -> 2L); + assertEquals(2L, result); + } + @Test void globalCallMeDoubleSupplier() { double result = MySwiftLibrary.globalCallMeDoubleSupplier(() -> 2.0); diff --git a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift index 0365930c6..132da25a8 100644 --- a/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift +++ b/Sources/ExampleSwiftLibrary/MySwiftLibrary.swift @@ -51,6 +51,10 @@ public func globalCallMeIntSupplier(run: () -> Int32) -> Int32 { run() } +public func globalCallMeLongSupplier(run: () -> Int64) -> Int64 { + run() +} + public func globalCallMeDoubleSupplier(run: () -> Double) -> Double { run() } diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift index 35c87a34b..1859c970e 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift @@ -40,6 +40,11 @@ extension JavaType { .class(package: "java.util.function", name: "IntSupplier") } + /// The description of the type java.util.function.LongSupplier. + static var javaUtilFunctionLongSupplier: JavaType { + .class(package: "java.util.function", name: "LongSupplier") + } + /// The description of the type java.util.function.DoubleSupplier. static var javaUtilFunctionDoubleSupplier: JavaType { .class(package: "java.util.function", name: "DoubleSupplier") diff --git a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift index 03115245f..dc276c68a 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -43,6 +43,13 @@ struct KnownJavaFunctionalInterface: Sendable { result: .int ) + static let longSupplier = KnownJavaFunctionalInterface( + JavaType.javaUtilFunctionLongSupplier, + method: "getAsLong", + parameters: [], + result: .long + ) + static let doubleSupplier = KnownJavaFunctionalInterface( JavaType.javaUtilFunctionDoubleSupplier, method: "getAsDouble", @@ -54,6 +61,7 @@ struct KnownJavaFunctionalInterface: Sendable { .runnable, .booleanSupplier, .intSupplier, + .longSupplier, .doubleSupplier, ] @@ -87,6 +95,8 @@ struct KnownJavaFunctionalInterface: Sendable { booleanSupplier case ([], _) where result.isInt32: intSupplier + case ([], _) where result.isInt64: + longSupplier case ([], _) where result.isDouble: doubleSupplier default: diff --git a/Sources/SwiftExtract/SwiftTypes/SwiftType.swift b/Sources/SwiftExtract/SwiftTypes/SwiftType.swift index 17443c06a..a4e21518e 100644 --- a/Sources/SwiftExtract/SwiftTypes/SwiftType.swift +++ b/Sources/SwiftExtract/SwiftTypes/SwiftType.swift @@ -151,6 +151,17 @@ public enum SwiftType: Equatable { } } + public var isInt64: Bool { + switch self { + case .nominal(let nominal): + switch nominal.nominalTypeDecl.knownTypeKind { + case .int64, .uint64: true + default: false + } + default: false + } + } + public var isUnsignedInteger: Bool { switch self { case .nominal(let nominal): diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift index 2ef66778a..2d552fe6f 100644 --- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift +++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift @@ -36,6 +36,7 @@ final class FuncCallbackImportTests { public func callMe(callback: () -> Void) public func callMeBoolSupplier(callback: () -> Bool) public func callMeIntSupplier(callback: () -> Int32) + public func callMeLongSupplier(callback: () -> Int64) public func callMeDoubleSupplier(callback: () -> Double) public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ()) public func withBuffer(body: (UnsafeRawBufferPointer) -> Int) @@ -254,6 +255,49 @@ final class FuncCallbackImportTests { ) } + @Test("Import: public func callMeLongSupplier(callback: () -> Int64)") + func func_callMeLongSupplierFunc_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 == "callMeLongSupplier" }! + + 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 callMeLongSupplier(callback: () -> Int64) + * } + */ + public static void callMeLongSupplier(java.util.function.LongSupplier callback) { + try(var arena$ = Arena.ofConfined()) { + swiftjava___FakeModule_callMeLongSupplier_callback.call(callMeLongSupplier.$toUpcallStub(callback, arena$)); + } + } + """ + ] + ) + } + @Test("Import: public func callMeDoubleSupplier(callback: () -> Double)") func func_callMeDoubleSupplierFunc_callback() throws { var config = Configuration() diff --git a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift index a8d1b40c1..c5bfcd3ef 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift @@ -22,6 +22,7 @@ struct JNIClosureTests { public func emptyClosure(closure: () -> ()) {} public func closureBoolSupplier(closure: () -> Bool) {} public func closureIntSupplier(closure: () -> Int32) {} + public func closureLongSupplier(closure: () -> Int64) {} public func closureDoubleSupplier(closure: () -> Double) {} public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {} """ @@ -101,6 +102,31 @@ struct JNIClosureTests { ) } + @Test + func closureLongSupplier_javaBindings() throws { + try assertOutput( + input: source, + .jni, + .java, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func closureLongSupplier(closure: () -> Int64) + * } + */ + public static void closureLongSupplier(java.util.function.LongSupplier closure) { + SwiftModule.$closureLongSupplier(closure); + } + """, + """ + private static native void $closureLongSupplier(java.util.function.LongSupplier closure); + """, + ] + ) + } + @Test func closureDoubleSupplier_javaBindings() throws { try assertOutput( @@ -201,6 +227,31 @@ struct JNIClosureTests { ) } + @Test + func closureLongSupplier_swiftThunks() throws { + try assertOutput( + input: source, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024closureLongSupplier__Ljava_util_function_LongSupplier_2") + public func Java_com_example_swift_SwiftModule__00024closureLongSupplier__Ljava_util_function_LongSupplier_2(environment: UnsafeMutablePointer!, thisClass: jclass, closure: jobject?) { + SwiftModule.closureLongSupplier(closure: { + let class$ = environment.interface.GetObjectClass(environment, closure) + let methodID$ = environment.interface.GetMethodID(environment, class$, "getAsLong", "()J")! + environment.interface.DeleteLocalRef(environment, class$) + let arguments$: [jvalue] = [] + return Int64(fromJNI: environment.interface.CallLongMethodA(environment, closure, methodID$, arguments$), in: environment) + } + ) + } + """ + ] + ) + } + @Test func closureDoubleSupplier_swiftThunks() throws { try assertOutput(