Skip to content

Commit 695a715

Browse files
committed
Add support for async in @JSFunction
1 parent cdb8013 commit 695a715

File tree

8 files changed

+755
-15
lines changed

8 files changed

+755
-15
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public struct ClosureCodegen {
232232
}
233233
}
234234
for type in file.types {
235-
for method in type.methods where method.effects.isAsync {
235+
for method in (type.methods + type.staticMethods) where method.effects.isAsync {
236236
closureSignatures.insert(
237237
ClosureSignature(
238238
parameters: [.jsValue],

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,12 +477,15 @@ public struct ImportTS {
477477

478478
func renderStaticMethod(method: ImportedFunctionSkeleton) throws -> [DeclSyntax] {
479479
let abiName = method.abiName(context: type, operation: "static")
480-
let abiReturnType: BridgeType = method.effects.isAsync ? .jsObject(nil) : method.returnType
480+
let abiReturnType: BridgeType = method.effects.isAsync ? .void : method.returnType
481481
let builder = try CallJSEmission(moduleName: moduleName, abiName: abiName, returnType: abiReturnType)
482+
if method.effects.isAsync {
483+
builder.prependClosureCallbackParams()
484+
}
482485
for param in method.parameters {
483486
try builder.lowerParameter(param: param)
484487
}
485-
try builder.call()
488+
try builder.call(skipExceptionCheck: method.effects.isAsync)
486489
if method.effects.isAsync {
487490
builder.liftAsyncReturnValue(originalReturnType: method.returnType)
488491
} else {

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ public struct BridgeJSLink {
677677
}
678678
}
679679
for type in file.types {
680-
for method in type.methods where method.effects.isAsync {
680+
for method in (type.methods + type.staticMethods) where method.effects.isAsync {
681681
closureSignatures.insert(
682682
ClosureSignature(
683683
parameters: [.jsValue],
@@ -2397,6 +2397,13 @@ extension BridgeJSLink {
23972397
)
23982398
}
23992399

2400+
/// Generates an async static method call with resolve/reject closure refs.
2401+
func callAsyncStaticMethod(on objectExpr: String, name: String) {
2402+
let calleeExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name)
2403+
let callExpr = "\(calleeExpr)(\(parameterForwardings.joined(separator: ", ")))"
2404+
body.write("\(callExpr).then(resolve, reject);")
2405+
}
2406+
24002407
func callPropertyGetter(name: String, returnType: BridgeType) throws -> String? {
24012408
let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)"
24022409
let accessExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name)
@@ -3345,7 +3352,7 @@ extension BridgeJSLink {
33453352
for method in type.staticMethods {
33463353
let methodName = method.jsName ?? method.name
33473354
let signature =
3348-
"\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));"
3355+
"\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));"
33493356
dtsPrinter.write(signature)
33503357
}
33513358
}
@@ -3429,16 +3436,23 @@ extension BridgeJSLink {
34293436
objectExpr: importRootExpr,
34303437
propertyName: context.jsName ?? context.name
34313438
)
3432-
let returnExpr = try thunkBuilder.callStaticMethod(
3433-
on: constructorExpr,
3434-
name: method.jsName ?? method.name,
3435-
returnType: method.returnType
3436-
)
3437-
let funcLines = thunkBuilder.renderFunction(
3438-
name: method.abiName(context: context, operation: "static"),
3439-
returnExpr: returnExpr,
3440-
returnType: method.returnType
3441-
)
3439+
3440+
let funcLines: [String]
3441+
if method.effects.isAsync {
3442+
thunkBuilder.callAsyncStaticMethod(on: constructorExpr, name: method.jsName ?? method.name)
3443+
funcLines = thunkBuilder.renderAsyncFunction(name: method.abiName(context: context, operation: "static"))
3444+
} else {
3445+
let returnExpr = try thunkBuilder.callStaticMethod(
3446+
on: constructorExpr,
3447+
name: method.jsName ?? method.name,
3448+
returnType: method.returnType
3449+
)
3450+
funcLines = thunkBuilder.renderFunction(
3451+
name: method.abiName(context: context, operation: "static"),
3452+
returnExpr: returnExpr,
3453+
returnType: method.returnType
3454+
)
3455+
}
34423456
return (funcLines, [])
34433457
}
34443458

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@JSClass struct AsyncBox {
2+
@JSFunction static func asyncStaticRoundTrip(_ v: Double) async throws(JSException) -> Double
3+
@JSFunction static func asyncStaticVoid() async throws(JSException)
4+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"imported" : {
3+
"children" : [
4+
{
5+
"functions" : [
6+
7+
],
8+
"types" : [
9+
{
10+
"getters" : [
11+
12+
],
13+
"methods" : [
14+
15+
],
16+
"name" : "AsyncBox",
17+
"setters" : [
18+
19+
],
20+
"staticMethods" : [
21+
{
22+
"effects" : {
23+
"isAsync" : true,
24+
"isStatic" : false,
25+
"isThrows" : true
26+
},
27+
"name" : "asyncStaticRoundTrip",
28+
"parameters" : [
29+
{
30+
"name" : "v",
31+
"type" : {
32+
"double" : {
33+
34+
}
35+
}
36+
}
37+
],
38+
"returnType" : {
39+
"double" : {
40+
41+
}
42+
}
43+
},
44+
{
45+
"effects" : {
46+
"isAsync" : true,
47+
"isStatic" : false,
48+
"isThrows" : true
49+
},
50+
"name" : "asyncStaticVoid",
51+
"parameters" : [
52+
53+
],
54+
"returnType" : {
55+
"void" : {
56+
57+
}
58+
}
59+
}
60+
]
61+
}
62+
]
63+
}
64+
]
65+
},
66+
"moduleName" : "TestModule"
67+
}
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#if arch(wasm32)
2+
@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules7JSValueV_y")
3+
fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void
4+
#else
5+
fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void {
6+
fatalError("Only available on WebAssembly")
7+
}
8+
#endif
9+
@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void {
10+
return invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2)
11+
}
12+
13+
#if arch(wasm32)
14+
@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules7JSValueV_y")
15+
fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32
16+
#else
17+
fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
18+
fatalError("Only available on WebAssembly")
19+
}
20+
#endif
21+
@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
22+
return make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(boxPtr, file, line)
23+
}
24+
25+
private enum _BJS_Closure_10TestModules7JSValueV_y {
26+
static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void {
27+
let callback = JSObject.bridgeJSLiftParameter(callbackId)
28+
return { [callback] param0 in
29+
#if arch(wasm32)
30+
let callbackValue = callback.bridgeJSLowerParameter()
31+
let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter()
32+
invoke_js_callback_TestModule_10TestModules7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2)
33+
#else
34+
fatalError("Only available on WebAssembly")
35+
#endif
36+
}
37+
}
38+
}
39+
40+
extension JSTypedClosure where Signature == (sending JSValue) -> Void {
41+
init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) {
42+
self.init(
43+
makeClosure: make_swift_closure_TestModule_10TestModules7JSValueV_y,
44+
body: body,
45+
fileID: fileID,
46+
line: line
47+
)
48+
}
49+
}
50+
51+
@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules7JSValueV_y")
52+
@_cdecl("invoke_swift_closure_TestModule_10TestModules7JSValueV_y")
53+
public func _invoke_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void {
54+
#if arch(wasm32)
55+
let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure
56+
closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2))
57+
#else
58+
fatalError("Only available on WebAssembly")
59+
#endif
60+
}
61+
62+
#if arch(wasm32)
63+
@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSd_y")
64+
fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void
65+
#else
66+
fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void {
67+
fatalError("Only available on WebAssembly")
68+
}
69+
#endif
70+
@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y(_ callback: Int32, _ param0: Float64) -> Void {
71+
return invoke_js_callback_TestModule_10TestModulesSd_y_extern(callback, param0)
72+
}
73+
74+
#if arch(wasm32)
75+
@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSd_y")
76+
fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32
77+
#else
78+
fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
79+
fatalError("Only available on WebAssembly")
80+
}
81+
#endif
82+
@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
83+
return make_swift_closure_TestModule_10TestModulesSd_y_extern(boxPtr, file, line)
84+
}
85+
86+
private enum _BJS_Closure_10TestModulesSd_y {
87+
static func bridgeJSLift(_ callbackId: Int32) -> (sending Double) -> Void {
88+
let callback = JSObject.bridgeJSLiftParameter(callbackId)
89+
return { [callback] param0 in
90+
#if arch(wasm32)
91+
let callbackValue = callback.bridgeJSLowerParameter()
92+
let param0Value = param0.bridgeJSLowerParameter()
93+
invoke_js_callback_TestModule_10TestModulesSd_y(callbackValue, param0Value)
94+
#else
95+
fatalError("Only available on WebAssembly")
96+
#endif
97+
}
98+
}
99+
}
100+
101+
extension JSTypedClosure where Signature == (sending Double) -> Void {
102+
init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Double) -> Void) {
103+
self.init(
104+
makeClosure: make_swift_closure_TestModule_10TestModulesSd_y,
105+
body: body,
106+
fileID: fileID,
107+
line: line
108+
)
109+
}
110+
}
111+
112+
@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSd_y")
113+
@_cdecl("invoke_swift_closure_TestModule_10TestModulesSd_y")
114+
public func _invoke_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void {
115+
#if arch(wasm32)
116+
let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Double) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure
117+
closure(Double.bridgeJSLiftParameter(param0))
118+
#else
119+
fatalError("Only available on WebAssembly")
120+
#endif
121+
}
122+
123+
#if arch(wasm32)
124+
@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuley_y")
125+
fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void
126+
#else
127+
fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void {
128+
fatalError("Only available on WebAssembly")
129+
}
130+
#endif
131+
@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuley_y(_ callback: Int32) -> Void {
132+
return invoke_js_callback_TestModule_10TestModuley_y_extern(callback)
133+
}
134+
135+
#if arch(wasm32)
136+
@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuley_y")
137+
fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32
138+
#else
139+
fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
140+
fatalError("Only available on WebAssembly")
141+
}
142+
#endif
143+
@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer<UInt8>, _ line: UInt32) -> Int32 {
144+
return make_swift_closure_TestModule_10TestModuley_y_extern(boxPtr, file, line)
145+
}
146+
147+
private enum _BJS_Closure_10TestModuley_y {
148+
static func bridgeJSLift(_ callbackId: Int32) -> () -> Void {
149+
let callback = JSObject.bridgeJSLiftParameter(callbackId)
150+
return { [callback] in
151+
#if arch(wasm32)
152+
let callbackValue = callback.bridgeJSLowerParameter()
153+
invoke_js_callback_TestModule_10TestModuley_y(callbackValue)
154+
#else
155+
fatalError("Only available on WebAssembly")
156+
#endif
157+
}
158+
}
159+
}
160+
161+
extension JSTypedClosure where Signature == () -> Void {
162+
init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> Void) {
163+
self.init(
164+
makeClosure: make_swift_closure_TestModule_10TestModuley_y,
165+
body: body,
166+
fileID: fileID,
167+
line: line
168+
)
169+
}
170+
}
171+
172+
@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuley_y")
173+
@_cdecl("invoke_swift_closure_TestModule_10TestModuley_y")
174+
public func _invoke_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer) -> Void {
175+
#if arch(wasm32)
176+
let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure
177+
closure()
178+
#else
179+
fatalError("Only available on WebAssembly")
180+
#endif
181+
}
182+
183+
#if arch(wasm32)
184+
@_extern(wasm, module: "TestModule", name: "bjs_AsyncBox_asyncStaticRoundTrip_static")
185+
fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void
186+
#else
187+
fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void {
188+
fatalError("Only available on WebAssembly")
189+
}
190+
#endif
191+
@inline(never) fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void {
192+
return bjs_AsyncBox_asyncStaticRoundTrip_static_extern(resolveRef, rejectRef, v)
193+
}
194+
195+
#if arch(wasm32)
196+
@_extern(wasm, module: "TestModule", name: "bjs_AsyncBox_asyncStaticVoid_static")
197+
fileprivate func bjs_AsyncBox_asyncStaticVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void
198+
#else
199+
fileprivate func bjs_AsyncBox_asyncStaticVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void {
200+
fatalError("Only available on WebAssembly")
201+
}
202+
#endif
203+
@inline(never) fileprivate func bjs_AsyncBox_asyncStaticVoid_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void {
204+
return bjs_AsyncBox_asyncStaticVoid_static_extern(resolveRef, rejectRef)
205+
}
206+
207+
func _$AsyncBox_asyncStaticRoundTrip(_ v: Double) async throws(JSException) -> Double {
208+
let resolved = try await _bjs_awaitPromise(makeResolveClosure: {
209+
JSTypedClosure<(sending Double) -> Void>($0)
210+
}, makeRejectClosure: {
211+
JSTypedClosure<(sending JSValue) -> Void>($0)
212+
}) { resolveRef, rejectRef in
213+
let vValue = v.bridgeJSLowerParameter()
214+
bjs_AsyncBox_asyncStaticRoundTrip_static(resolveRef, rejectRef, vValue)
215+
}
216+
return resolved
217+
}
218+
219+
func _$AsyncBox_asyncStaticVoid() async throws(JSException) -> Void {
220+
try await _bjs_awaitPromise(makeResolveClosure: {
221+
JSTypedClosure<() -> Void>($0)
222+
}, makeRejectClosure: {
223+
JSTypedClosure<(sending JSValue) -> Void>($0)
224+
}) { resolveRef, rejectRef in
225+
bjs_AsyncBox_asyncStaticVoid_static(resolveRef, rejectRef)
226+
}
227+
}

0 commit comments

Comments
 (0)