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 @@ -36,6 +36,10 @@ public func globalCallMeRunnable(run: () -> Void) {
run()
}

public func globalCallMeBooleanSupplier(run: () -> Bool) -> Bool {
run()
}

// ==== 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 @@ -54,4 +54,9 @@ public void apply() {
assertEquals(0, countDownLatch.getCount());
}

@Test
void call_globalCallMeBooleanSupplier_noThrow() {
boolean result = MySwiftLibrary.globalCallMeBooleanSupplier(() -> { return true; });
assertEquals(true, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public func globalCallMeRunnable(run: () -> Void) {
run()
}

public func globalCallMeBooleanSupplier(run: () -> Bool) -> Bool {
run()
}

public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int {
buf.count
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ void call_globalStringIdentity_empty() {
assertEquals("", result);
}



@Test
@Disabled("Upcalls not yet implemented in new scheme")
@SuppressWarnings({"Convert2Lambda", "Convert2MethodRef"})
Expand Down Expand Up @@ -148,4 +146,9 @@ void call_globalThrowingString_throws_checkMessage() {
);
}

@Test
void call_globalCallMeBooleanSupplier_noThrow() {
boolean result = MySwiftLibrary.globalCallMeBooleanSupplier(() -> { return true; });
assertEquals(true, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public func closureWithInt(input: Int64, closure: (Int64) -> Int64) -> Int64 {
closure(input)
}

public func globalCallMeBooleanSupplier(run: () -> Bool) -> Bool {
run()
}

public func closureMultipleArguments(
input1: Int64,
input2: Int64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ void closureMultipleArguments() {
long result = MySwiftLibrary.closureMultipleArguments(5, 10, (a, b) -> a + b);
assertEquals(15, result);
}
}

@Test
void globalCallMeBooleanSupplier() {
boolean result = MySwiftLibrary.globalCallMeBooleanSupplier(() -> true);
assertEquals(true, result);
}
}
4 changes: 4 additions & 0 deletions Sources/ExampleSwiftLibrary/MySwiftLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public func globalCallMeRunnable(run: () -> Void) {
run()
}

public func globalCallMeBooleanSupplier(run: () -> Bool) -> Bool {
run()
}

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 @@ -30,6 +30,11 @@ extension JavaType {
.class(package: "java.lang", name: "Runnable")
}

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

/// The description of the type java.lang.Class.
static var javaLangClass: JavaType {
.class(package: "java.lang", name: "Class")
Expand Down
12 changes: 11 additions & 1 deletion Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,16 @@ struct KnownJavaFunctionalInterface: Sendable {
result: .void
)

static let booleanSupplier = KnownJavaFunctionalInterface(
JavaType.javaUtilFunctionBooleanSupplier,
method: "getAsBoolean",
parameters: [],
result: .boolean
)

static let all: [KnownJavaFunctionalInterface] = [
.runnable
.runnable,
.booleanSupplier,
]

static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? {
Expand Down Expand Up @@ -59,6 +67,8 @@ struct KnownJavaFunctionalInterface: Sendable {
return switch (parameters, result) {
case ([], _) where result.isVoid:
runnable
case ([], _) where result.isBoolean:
booleanSupplier
default:
nil
}
Expand Down
7 changes: 7 additions & 0 deletions Sources/SwiftExtract/SwiftTypes/SwiftType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ public enum SwiftType: Equatable {
}
}

public var isBoolean: Bool {
if case let .nominal(nominal) = self {
return nominal.nominalTypeDecl.knownTypeKind == .bool
}
return false
}

/// Whether this is a pointer type. I.e 'Unsafe[Mutable][Raw]Pointer'
public var isPointer: Bool {
switch self {
Expand Down
87 changes: 87 additions & 0 deletions Tests/JExtractSwiftTests/FuncCallbackImportTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ final class FuncCallbackImportTests {
import _SwiftConcurrencyShims

public func callMe(callback: () -> Void)
public func callMeBoolSupplier(callback: () -> Bool)
public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ())
public func withBuffer(body: (UnsafeRawBufferPointer) -> Int)
"""
Expand Down Expand Up @@ -122,6 +123,92 @@ final class FuncCallbackImportTests {
)
}

@Test("Import: public func callMeBoolSupplier(callback: () -> Bool)")
func func_callMeBoolSupplierFunc_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 == "callMeBoolSupplier" }!

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,
expected:
"""
// ==== --------------------------------------------------
// callMeBoolSupplier
/**
* {@snippet lang=c :
* void swiftjava___FakeModule_callMeBoolSupplier_callback(_Bool (*callback)(void))
* }
*/
private static class swiftjava___FakeModule_callMeBoolSupplier_callback {
private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
/* callback: */SwiftValueLayout.SWIFT_POINTER
);
private static final MemorySegment ADDR =
__FakeModule.findOrThrow("swiftjava___FakeModule_callMeBoolSupplier_callback");
private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
public static void call(java.lang.foreign.MemorySegment callback) {
try {
if (CallTraces.TRACE_DOWNCALLS) {
CallTraces.traceDowncall(callback);
}
HANDLE.invokeExact(callback);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}
}
/**
* {snippet lang=c :
* _Bool (*)(void)
* }
*/
private static class $callback {
private static final FunctionDescriptor DESC = FunctionDescriptor.of(
/* -> */SwiftValueLayout.SWIFT_BOOL
);
private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(java.util.function.BooleanSupplier.class, "getAsBoolean", DESC);
private static MemorySegment toUpcallStub(java.util.function.BooleanSupplier fi, Arena arena) {
return Linker.nativeLinker().upcallStub(HANDLE.bindTo(fi), DESC, arena);
}
}
}
public static class callMeBoolSupplier {
private static MemorySegment $toUpcallStub(java.util.function.BooleanSupplier fi, Arena arena) {
return swiftjava___FakeModule_callMeBoolSupplier_callback.$callback.toUpcallStub(fi, arena);
}
}
/**
* Downcall to Swift:
* {@snippet lang=swift :
* public func callMeBoolSupplier(callback: () -> Bool)
* }
*/
public static void callMeBoolSupplier(java.util.function.BooleanSupplier callback) {
try(var arena$ = Arena.ofConfined()) {
swiftjava___FakeModule_callMeBoolSupplier_callback.call(callMeBoolSupplier.$toUpcallStub(callback, arena$));
}
}
"""
)
}

@Test("Import: public func callMeMore(callback: (UnsafeRawPointer, Float) -> Int, fn: () -> ())")
func func_callMeMoreFunc_callback() throws {
var config = Configuration()
Expand Down
51 changes: 51 additions & 0 deletions Tests/JExtractSwiftTests/JNI/JNIClosureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct JNIClosureTests {
let source =
"""
public func emptyClosure(closure: () -> ()) {}
public func closureBoolSupplier(closure: () -> Bool) {}
public func closureWithArgumentsAndReturn(closure: (Int64, Bool) -> Int64) {}
"""

Expand Down Expand Up @@ -48,6 +49,31 @@ struct JNIClosureTests {
)
}

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

@Test
func emptyClosure_swiftThunks() throws {
try assertOutput(
Expand All @@ -73,6 +99,31 @@ struct JNIClosureTests {
)
}

@Test
func closureBoolSupplier_swiftThunks() throws {
try assertOutput(
input: source,
.jni,
.swift,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
@_cdecl("Java_com_example_swift_SwiftModule__00024closureBoolSupplier__Ljava_util_function_BooleanSupplier_2")
public func Java_com_example_swift_SwiftModule__00024closureBoolSupplier__Ljava_util_function_BooleanSupplier_2(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, closure: jobject?) {
SwiftModule.closureBoolSupplier(closure: {
let class$ = environment.interface.GetObjectClass(environment, closure)
let methodID$ = environment.interface.GetMethodID(environment, class$, "getAsBoolean", "()Z")!
environment.interface.DeleteLocalRef(environment, class$)
let arguments$: [jvalue] = []
return Bool(fromJNI: environment.interface.CallBooleanMethodA(environment, closure, methodID$, arguments$), in: environment)
}
)
}
"""
]
)
}

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