-
Notifications
You must be signed in to change notification settings - Fork 66
[JExtract/JNI] Add support for async Swift methods
#413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
0869e55
7a75d45
d8db270
850225a
3fe6636
1117faf
4b04da2
f187e2a
7ce00dd
adfdea8
d693691
f6db47e
1251307
2d0e79b
26bb992
a774558
e0b3930
e7c8619
c94b250
736a48d
23b837e
cd5011f
136bd14
d64ceca
997f14b
49f7788
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -573,7 +573,8 @@ extension JNISwift2JavaGenerator { | |
| NativeSwiftConversionStep, | ||
| swiftFunctionResultType: SwiftType, | ||
| nativeReturnType: JavaType, | ||
| outParameters: [JavaParameter] | ||
| outParameters: [JavaParameter], | ||
| isThrowing: Bool | ||
| ) | ||
|
|
||
| /// Returns the conversion string applied to the placeholder. | ||
|
|
@@ -808,7 +809,8 @@ extension JNISwift2JavaGenerator { | |
| let inner, | ||
| let swiftFunctionResultType, | ||
| let nativeReturnType, | ||
| let outParameters | ||
| let outParameters, | ||
| let isThrowing | ||
| ): | ||
| // Global ref all indirect returns | ||
| for outParameter in outParameters { | ||
|
|
@@ -818,71 +820,66 @@ extension JNISwift2JavaGenerator { | |
| printer.print( | ||
| """ | ||
| let globalFuture = environment.interface.NewGlobalRef(environment, result_future) | ||
| let completableFutureClazz$ = environment.interface.FindClass(environment, "java/util/concurrent/CompletableFuture")! | ||
| let completeMethodID = environment.interface.GetMethodID(environment, completableFutureClazz$, "complete", "(Ljava/lang/Object;)Z")! | ||
| """ | ||
| ) | ||
|
|
||
| printer.printBraceBlock("Task") { printer in | ||
| func printDo(printer: inout CodePrinter) { | ||
| printer.print("let swiftResult$ = await \(placeholder)") | ||
| printer.print( | ||
| """ | ||
| let environment = try JavaVirtualMachine.shared().environment() | ||
| """ | ||
| ) | ||
| printer.printBraceBlock("defer") { printer in | ||
| printer.print("environment.interface.DeleteGlobalRef(environment, globalFuture)") | ||
| for outParameter in outParameters { | ||
| printer.print("environment.interface.DeleteGlobalRef(environment, \(outParameter.name))") | ||
| } | ||
| } | ||
| printer.print("environment = try JavaVirtualMachine.shared().environment()") | ||
| let inner = inner.render(&printer, "swiftResult$") | ||
| if swiftFunctionResultType.isVoid { | ||
| printer.print(inner) | ||
| printer.print("environment.interface.CallBooleanMethodA(environment, globalFuture, _JNIMethodIDCache.CompletableFuture.complete, [jvalue(l: nil)])") | ||
| } else { | ||
| printer.printBraceBlock("withVaList([SwiftJavaRuntimeSupport._JNIBoxedConversions.box(\(inner), in: environment)])") { printer in | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On Android, I'm getting this compilation error: This appears to originate from this code, though it compiles fine on Darwin. I'm not certain if this is an issue with my local Android sdk or not so just wanted to flag it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @0xZaph thanks for reporting this! seems like the issue is that the Android JNI imports jobjects as I'll move away from |
||
| printer.print("environment.interface.CallBooleanMethodV(environment, globalFuture, completeMethodID, $0)") | ||
| printer.print("environment.interface.CallBooleanMethodV(environment, globalFuture, _JNIMethodIDCache.CompletableFuture.complete, $0)") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return "" | ||
| func printTask(printer: inout CodePrinter) { | ||
| printer.printBraceBlock("defer") { printer in | ||
| // Defer might on any thread, so we need to attach environment. | ||
| printer.print("let deferEnvironment = try! JavaVirtualMachine.shared().environment()") | ||
| printer.print("environment.interface.DeleteGlobalRef(deferEnvironment, globalFuture)") | ||
| for outParameter in outParameters { | ||
| printer.print("environment.interface.DeleteGlobalRef(deferEnvironment, \(outParameter.name))") | ||
| } | ||
madsodgaard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| if isThrowing { | ||
| printer.printBraceBlock("do") { printer in | ||
| printDo(printer: &printer) | ||
| } | ||
| printer.printBraceBlock("catch") { printer in | ||
| // We might not be on the same thread after the suspension, so we need to attach the thread again. | ||
| printer.print( | ||
| """ | ||
| let catchEnvironment = try! JavaVirtualMachine.shared().environment() | ||
| let exception = catchEnvironment.interface.NewObjectA(catchEnvironment, _JNIMethodIDCache.Exception.class, _JNIMethodIDCache.Exception.constructWithMessage, [String(describing: error).getJValue(in: catchEnvironment)]) | ||
| catchEnvironment.interface.CallBooleanMethodA(catchEnvironment, globalFuture, _JNIMethodIDCache.CompletableFuture.completeExceptionally, [jvalue(l: exception)]) | ||
| """ | ||
| ) | ||
| } | ||
| } else { | ||
| printDo(printer: &printer) | ||
| } | ||
| } | ||
|
|
||
| // printer.print("let _semaphore$ = _Semaphore(value: 0)") | ||
| // let resultType = isThrowing ? "Result<\(swiftFunctionResultType), any Error>" : swiftFunctionResultType.description | ||
| // printer.print("var swiftResult$: \(resultType)!") | ||
| // | ||
| // func printInner(printer: inout CodePrinter) { | ||
| // if isThrowing { | ||
| // printer.printBraceBlock("do") { printer in | ||
| // printer.print("swiftResult$ = await Result.success(\(placeholder))") | ||
| // } | ||
| // printer.printBraceBlock("catch") { printer in | ||
| // printer.print("swiftResult$ = Result.failure(error)") | ||
| // } | ||
| // } else { | ||
| // printer.print("swiftResult$ = await \(placeholder)") | ||
| // } | ||
| // printer.print("_semaphore$.signal()") | ||
| // } | ||
| // | ||
| // printer.printBraceBlock("if #available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, *)") { printer in | ||
| // printer.printBraceBlock("Task.immediate") { printer in | ||
| // printInner(printer: &printer) | ||
| // } | ||
| // } | ||
| // printer.printBraceBlock("else") { printer in | ||
| // printer.printBraceBlock("Task") { printer in | ||
| // printInner(printer: &printer) | ||
| // } | ||
| // } | ||
| // printer.print( | ||
| // """ | ||
| // _semaphore$.wait() | ||
| // """ | ||
| // ) | ||
| // let inner = inner.render(&printer, isThrowing ? "try swiftResult$.get()" : "swiftResult$") | ||
| // return inner | ||
| printer.printBraceBlock("if #available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, *)") { printer in | ||
| printer.printBraceBlock("Task.immediate") { printer in | ||
| // Immediate runs on the caller thread, so we don't need to attach the environment again. | ||
| printer.print("var environment = environment!") // this is to ensure we always use the same environment name, even though we are rebinding it. | ||
| printTask(printer: &printer) | ||
| } | ||
| } | ||
| printer.printBraceBlock("else") { printer in | ||
| printer.printBraceBlock("Task") { printer in | ||
| // We can be on any thread, so we need to attach the thread. | ||
| printer.print("var environment = try! JavaVirtualMachine.shared().environment()") | ||
| printTask(printer: &printer) | ||
| } | ||
| } | ||
|
|
||
| return "" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import SwiftJava | ||
|
|
||
| extension _JNIMethodIDCache { | ||
| public enum CompletableFuture { | ||
| private static let completeMethod = Method( | ||
| name: "complete", | ||
| signature: "(Ljava/lang/Object;)Z" | ||
| ) | ||
|
|
||
| private static let completeExceptionallyMethod = Method( | ||
| name: "completeExceptionally", | ||
| signature: "(Ljava/lang/Throwable;)Z" | ||
| ) | ||
|
|
||
| private static let cache = _JNIMethodIDCache( | ||
| environment: try! JavaVirtualMachine.shared().environment(), | ||
| className: "java/util/concurrent/CompletableFuture", | ||
| methods: [completeMethod, completeExceptionallyMethod] | ||
| ) | ||
|
|
||
| public static var `class`: jclass { | ||
| cache.javaClass | ||
| } | ||
|
|
||
| /// CompletableFuture<T>.complete(T) | ||
| public static var complete: jmethodID { | ||
| cache.methods[completeMethod]! | ||
| } | ||
|
|
||
| /// CompletableFuture<T>.completeExceptionally(Throwable) | ||
| public static var completeExceptionally: jmethodID { | ||
| cache.methods[completeExceptionallyMethod]! | ||
| } | ||
| } | ||
|
|
||
| public enum Exception { | ||
| private static let messageConstructor = Method(name: "<init>", signature: "(Ljava/lang/String;)V") | ||
|
|
||
| private static let cache = _JNIMethodIDCache( | ||
| environment: try! JavaVirtualMachine.shared().environment(), | ||
| className: "java/lang/Exception", | ||
| methods: [messageConstructor] | ||
| ) | ||
|
|
||
| public static var `class`: jclass { | ||
| cache.javaClass | ||
| } | ||
|
|
||
| public static var constructWithMessage: jmethodID { | ||
| cache.methods[messageConstructor]! | ||
| } | ||
| } | ||
| } |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.