Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public func globalCallMeDoublePredicate(run: (Double) -> Bool) -> Bool {
run(1.0)
}

public func globalCallMeIntBinaryOperator(run: (Int32, Int32) -> Int32) -> Int32 {
run(1, 2)
}

// ==== Internal helpers

func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,10 @@ void call_globalCallMeDoublePredicate_noThrow() {
boolean result = MySwiftLibrary.globalCallMeDoublePredicate((double a) -> { return true; });
assertEquals(true, result);
}

@Test
void call_globalCallMeIntBinaryOperator_noThrow() {
int result = MySwiftLibrary.globalCallMeIntBinaryOperator((int a, int b) -> { return a + b; });
assertEquals(3, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public func globalCallMeDoublePredicate(run: (Double) -> Bool) -> Bool {
run(1.0)
}

public func globalCallMeIntBinaryOperator(run: (Int32, Int32) -> Int32) -> Int32 {
run(1, 2)
}

public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int {
buf.count
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,10 @@ void call_globalCallMeDoublePredicate_noThrow() {
boolean result = MySwiftLibrary.globalCallMeDoublePredicate((double a) -> { return true; });
assertEquals(true, result);
}

@Test
void call_globalCallMeIntBinaryOperator_noThrow() {
int result = MySwiftLibrary.globalCallMeIntBinaryOperator((int a, int b) -> { return a + b; });
assertEquals(3, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public func globalCallMeDoublePredicate(run: (Double) -> Bool) -> Bool {
run(1.0)
}

public func globalCallMeIntBinaryOperator(run: (Int32, Int32) -> Int32) -> Int32 {
run(1, 2)
}

public func closureMultipleArguments(
input1: Int64,
input2: Int64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,10 @@ void globalCallMeDoublePredicate() {
boolean result = MySwiftLibrary.globalCallMeDoublePredicate((double a) -> { return true; });
assertEquals(true, result);
}

@Test
void globalCallMeIntBinaryOperator() {
int result = MySwiftLibrary.globalCallMeIntBinaryOperator((int a, int b) -> { return a + b; });
assertEquals(3, result);
}
}
4 changes: 4 additions & 0 deletions Sources/ExampleSwiftLibrary/MySwiftLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ public func globalCallMeDoublePredicate(run: (Double) -> Bool) -> Bool {
run(1.0)
}

public func globalCallMeIntBinaryOperator(run: (Int32, Int32) -> Int32) -> Int32 {
run(1, 2)
}

public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int {
buf.count
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ extension JavaType {
.class(package: "java.util.function", name: "DoublePredicate")
}

/// The description of the type java.util.function.IntBinaryOperator.
static var javaUtilFunctionIntBinaryOperator: JavaType {
.class(package: "java.util.function", name: "IntBinaryOperator")
}

/// The description of the type java.lang.Class.
static var javaLangClass: JavaType {
.class(package: "java.lang", name: "Class")
Expand Down
19 changes: 19 additions & 0 deletions Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ struct KnownJavaFunctionalInterface: Sendable {
result: .boolean
)

static let intBinaryOperator = KnownJavaFunctionalInterface(
JavaType.javaUtilFunctionIntBinaryOperator,
method: "applyAsInt",
parameters: [.int, .int],
result: .int
)

static let all: [KnownJavaFunctionalInterface] = [
.runnable,
.booleanSupplier,
Expand All @@ -111,6 +118,7 @@ struct KnownJavaFunctionalInterface: Sendable {
.intPredicate,
.longPredicate,
.doublePredicate,
.intBinaryOperator,
]

static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? {
Expand Down Expand Up @@ -185,6 +193,17 @@ struct KnownJavaFunctionalInterface: Sendable {
}
}

// Binary operators
if parameters.count == 2 && parameters[0].type == result && parameters[1].type == result {
let parameter = parameters[0].type
return switch () {
case _ where parameter.isInt32:
intBinaryOperator
default:
nil
}
}

return nil
}

Expand Down
45 changes: 45 additions & 0 deletions Tests/JExtractSwiftTests/FuncCallbackImportTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ final class FuncCallbackImportTests {
public func callMeLongPredicate(callback: (Int64) -> Bool)
public func callMeDoublePredicate(callback: (Double) -> Bool)

public func callMeIntBinaryOperator(callback: (Int32, Int32) -> Int32)

public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ())
public func withBuffer(body: (UnsafeRawBufferPointer) -> Int)
"""
Expand Down Expand Up @@ -717,6 +719,49 @@ final class FuncCallbackImportTests {
)
}

@Test("Import: public func callMecallMeIntBinaryOperatorFunc(callback: (Int32, Int32) -> Int32)")
func func_callMecallMeIntBinaryOperatorFunc_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 == "callMeIntBinaryOperator" }!

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 callMeIntBinaryOperator(callback: (Int32, Int32) -> Int32)
* }
*/
public static void callMeIntBinaryOperator(java.util.function.IntBinaryOperator callback) {
try(var arena$ = Arena.ofConfined()) {
swiftjava___FakeModule_callMeIntBinaryOperator_callback.call(callMeIntBinaryOperator.$toUpcallStub(callback, arena$));
}
}
"""
]
)
}

@Test("Import: public func withBuffer(body: (UnsafeRawBufferPointer) -> Int)")
func func_withBuffer_body() throws {
var config = Configuration()
Expand Down
52 changes: 52 additions & 0 deletions Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ struct JNIClosureTests {
public func closureLongPredicate(closure: (Int64) -> Bool) {}
public func closureDoublePredicate(closure: (Double) -> Bool) {}

public func closureIntBinaryOperator(closure: (Int32, Int32) -> Int32) {}

public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {}
"""

Expand Down Expand Up @@ -311,6 +313,31 @@ struct JNIClosureTests {
)
}

@Test
func closureIntBinaryOperator_javaBindings() throws {
try assertOutput(
input: source,
.jni,
.java,
expectedChunks: [
"""
/**
* Downcall to Swift:
* {@snippet lang=swift :
* public func closureIntBinaryOperator(closure: (Int32, Int32) -> Int32)
* }
*/
public static void closureIntBinaryOperator(java.util.function.IntBinaryOperator closure) {
SwiftModule.$closureIntBinaryOperator(closure);
}
""",
"""
private static native void $closureIntBinaryOperator(java.util.function.IntBinaryOperator closure);
""",
]
)
}

@Test
func emptyClosure_swiftThunks() throws {
try assertOutput(
Expand Down Expand Up @@ -586,6 +613,31 @@ struct JNIClosureTests {
)
}

@Test
func closureIntBinaryOperator_swiftThunks() throws {
try assertOutput(
input: source,
.jni,
.swift,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
@_cdecl("Java_com_example_swift_SwiftModule__00024closureIntBinaryOperator__Ljava_util_function_IntBinaryOperator_2")
public func Java_com_example_swift_SwiftModule__00024closureIntBinaryOperator__Ljava_util_function_IntBinaryOperator_2(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, closure: jobject?) {
SwiftModule.closureIntBinaryOperator(closure: {
let class$ = environment.interface.GetObjectClass(environment, closure)
let methodID$ = environment.interface.GetMethodID(environment, class$, "applyAsInt", "(II)I")!
environment.interface.DeleteLocalRef(environment, class$)
let arguments$: [jvalue] = [_0.getJValue(in: environment), _1.getJValue(in: environment)]
return Int32(fromJNI: environment.interface.CallIntMethodA(environment, closure, methodID$, arguments$), in: environment)
}
)
}
"""
]
)
}

@Test
func closureWithArgumentsAndReturn_javaBindings() throws {
try assertOutput(
Expand Down
Loading