diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index e5648ccf7..142050f56 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -12,9 +12,9 @@ public struct ClosureCodegen { public init() {} private func swiftClosureType(for signature: ClosureSignature) -> String { - let closureParams = signature.parameters.map { "\($0.swiftType)" }.joined(separator: ", ") + let closureParams = signature.parameters.map { "\($0.closureSwiftType)" }.joined(separator: ", ") let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") - let swiftReturnType = signature.returnType.swiftType + let swiftReturnType = signature.returnType.closureSwiftType return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" } @@ -158,7 +158,26 @@ public struct ClosureCodegen { printer.write(closureCallExpr.description) } else { printer.write("let result = \(closureCallExpr)") - printer.write("return result.bridgeJSLowerReturn()") + switch signature.returnType { + case .swiftProtocol: + printer.write( + "return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()" + ) + case .nullable(.swiftProtocol, _): + printer.write("if let result {") + printer.indent { + printer.write( + "_swift_js_return_optional_object(1, (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + } + printer.write("} else {") + printer.indent { + printer.write("_swift_js_return_optional_object(0, 0)") + } + printer.write("}") + default: + printer.write("return result.bridgeJSLowerReturn()") + } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 8ccbbee76..eab3a0831 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1454,6 +1454,16 @@ extension BridgeType { } } + var closureSwiftType: String { + switch self { + case .swiftProtocol(let name): return "any \(name)" + case .nullable(let wrappedType, let kind): + let wrappedClosureType = wrappedType.closureSwiftType + return kind == .null ? "Optional<\(wrappedClosureType)>" : "JSUndefinedOr<\(wrappedClosureType)>" + default: return swiftType + } + } + var isClosureType: Bool { if case .closure = self { return true } return false diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 1b7dce434..7d9a6f087 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -163,8 +163,28 @@ public struct ImportTS { } ) ) + } else if case .nullable(.swiftProtocol, _) = param.type, context == .exportSwift { + body.write("let \(pattern): (Int32, Int32)") + body.write("if let \(param.name) {") + body.indent { + body.write( + "\(pattern) = (1, (\(param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + } + body.write("} else {") + body.indent { + body.write("\(pattern) = (0, 0)") + } + body.write("}") } else { - let initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") + let initializerExpr: ExprSyntax + if case .swiftProtocol = param.type, context == .exportSwift { + initializerExpr = ExprSyntax( + "(\(raw: param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()" + ) + } else { + initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") + } if loweringInfo.loweredParameters.isEmpty { stackLoweringStmts.insert("let _ = \(initializerExpr)", at: 0) @@ -817,7 +837,12 @@ extension BridgeType { case .swiftHeapObject: return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)]) case .swiftProtocol: - throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + switch context { + case .importTS: + throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + case .exportSwift: + return LoweringParameterInfo(loweredParameters: [("objectId", .i32)]) + } case .caseEnum: switch context { case .importTS: @@ -891,7 +916,12 @@ extension BridgeType { case .swiftHeapObject: return LiftingReturnInfo(valueToLift: .pointer) case .swiftProtocol: - throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + switch context { + case .importTS: + throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + case .exportSwift: + return LiftingReturnInfo(valueToLift: .i32) + } case .caseEnum: switch context { case .importTS: diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift new file mode 100644 index 000000000..cb814adf2 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift @@ -0,0 +1,18 @@ +import JavaScriptKit + +@JS protocol Renderable { + func render() -> String +} + +@JS class Widget { + @JS var name: String + + @JS init(name: String) { + self.name = name + } +} + +@JS func processRenderable(_ item: Renderable, transform: (Renderable) -> String) -> String +@JS func makeRenderableFactory(defaultName: String) -> () -> Renderable +@JS func roundtripRenderable(_ callback: (Renderable) -> Renderable) -> (Renderable) -> Renderable +@JS func processOptionalRenderable(_ callback: (Renderable?) -> String) -> String diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json new file mode 100644 index 000000000..4ba7ba9a5 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json @@ -0,0 +1,281 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Widget_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Widget", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Widget" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_processRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "item", + "type" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + { + "label" : "transform", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeRenderableFactory", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeRenderableFactory", + "parameters" : [ + { + "label" : "defaultName", + "name" : "defaultName", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuley_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_roundtripRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_processOptionalRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuleSq10RenderableP_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + ], + "protocols" : [ + { + "methods" : [ + { + "abiName" : "bjs_Renderable_render", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "render", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Renderable", + "properties" : [ + + ] + } + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift new file mode 100644 index 000000000..26c3d1db0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift @@ -0,0 +1,388 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP") +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule10RenderableP_10RenderableP { + static func bridgeJSLift(_ callbackId: Int32) -> (any Renderable) -> any Renderable { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP(callbackValue, param0ObjectId) + return AnyRenderable.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any Renderable) -> any Renderable { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any Renderable) -> any Renderable) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +@_cdecl("invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +public func _invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any Renderable) -> any Renderable>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyRenderable.bridgeJSLiftParameter(param0)) + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule10RenderableP_SS") +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule10RenderableP_SS") +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule10RenderableP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (any Renderable) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_TestModule_10TestModule10RenderableP_SS(callbackValue, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any Renderable) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any Renderable) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule10RenderableP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule10RenderableP_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModule10RenderableP_SS") +public func _invoke_swift_closure_TestModule_10TestModule10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any Renderable) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyRenderable.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS") +fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(callback, param0IsSome, param0ObjectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleSq10RenderableP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0ObjectId): (Int32, Int32) + if let param0 { + (param0IsSome, param0ObjectId) = (1, (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + (param0IsSome, param0ObjectId) = (0, 0) + } + let ret = invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS(callbackValue, param0IsSome, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +public func _invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuley_10RenderableP") +fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(_ callback: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(_ callback: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP(_ callback: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuley_10RenderableP") +fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuley_10RenderableP { + static func bridgeJSLift(_ callbackId: Int32) -> () -> any Renderable { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret = invoke_js_callback_TestModule_10TestModuley_10RenderableP(callbackValue) + return AnyRenderable.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> any Renderable { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> any Renderable) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuley_10RenderableP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuley_10RenderableP") +@_cdecl("invoke_swift_closure_TestModule_10TestModuley_10RenderableP") +public func _invoke_swift_closure_TestModule_10TestModuley_10RenderableP(_ boxPtr: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> any Renderable>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure() + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +struct AnyRenderable: Renderable, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + func render() -> String { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = _extern_render(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRenderable(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Renderable_render") +fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _extern_render(_ jsObject: Int32) -> Int32 { + return _extern_render_extern(jsObject) +} + +@_expose(wasm, "bjs_processRenderable") +@_cdecl("bjs_processRenderable") +public func _bjs_processRenderable(_ item: Int32, _ transform: Int32) -> Void { + #if arch(wasm32) + let ret = processRenderable(_: AnyRenderable.bridgeJSLiftParameter(item), transform: _BJS_Closure_10TestModule10RenderableP_SS.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeRenderableFactory") +@_cdecl("bjs_makeRenderableFactory") +public func _bjs_makeRenderableFactory(_ defaultNameBytes: Int32, _ defaultNameLength: Int32) -> Int32 { + #if arch(wasm32) + let ret = makeRenderableFactory(defaultName: String.bridgeJSLiftParameter(defaultNameBytes, defaultNameLength)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripRenderable") +@_cdecl("bjs_roundtripRenderable") +public func _bjs_roundtripRenderable(_ callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundtripRenderable(_: _BJS_Closure_10TestModule10RenderableP_10RenderableP.bridgeJSLift(callback)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processOptionalRenderable") +@_cdecl("bjs_processOptionalRenderable") +public func _bjs_processOptionalRenderable(_ callback: Int32) -> Void { + #if arch(wasm32) + let ret = processOptionalRenderable(_: _BJS_Closure_10TestModuleSq10RenderableP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_init") +@_cdecl("bjs_Widget_init") +public func _bjs_Widget_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Widget(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_name_get") +@_cdecl("bjs_Widget_name_get") +public func _bjs_Widget_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Widget.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_name_set") +@_cdecl("bjs_Widget_name_set") +public func _bjs_Widget_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + Widget.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_deinit") +@_cdecl("bjs_Widget_deinit") +public func _bjs_Widget_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Widget: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Widget_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Widget_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Widget_wrap") +fileprivate func _bjs_Widget_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Widget_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Widget_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Widget_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts new file mode 100644 index 000000000..6b7a9d28d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts @@ -0,0 +1,38 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export interface Renderable { + render(): string; +} + +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface Widget extends SwiftHeapObject { + name: string; +} +export type Exports = { + Widget: { + new(name: string): Widget; + } + processRenderable(item: Renderable, transform: (arg0: Renderable) => string): string; + makeRenderableFactory(defaultName: string): () => Renderable; + roundtripRenderable(callback: (arg0: Renderable) => Renderable): (arg0: Renderable) => Renderable; + processOptionalRenderable(callback: (arg0: Renderable | null) => string): string; +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js new file mode 100644 index 000000000..ffdac6fa6 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -0,0 +1,436 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr, len); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(swift.memory.getObject(param0)); + return swift.memory.retain(ret); + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule10RenderableP_10RenderableP = function(param0) { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(boxPtr, swift.memory.retain(param0)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_10RenderableP); + } + bjs["invoke_js_callback_TestModule_10TestModule10RenderableP_SS"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(swift.memory.getObject(param0)); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModule10RenderableP_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule10RenderableP_SS = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_SS(boxPtr, swift.memory.retain(param0)); + const ret = tmpRetString; + tmpRetString = undefined; + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_SS); + } + bjs["invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS"] = function(callbackId, param0IsSome, param0ObjectId) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(param0IsSome ? swift.memory.getObject(param0ObjectId) : null); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleSq10RenderableP_SS = function(param0) { + const isSome = param0 != null; + let result; + if (isSome) { + result = swift.memory.retain(param0); + } else { + result = 0; + } + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(boxPtr, +isSome, result); + const ret = tmpRetString; + tmpRetString = undefined; + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10RenderableP_SS); + } + bjs["invoke_js_callback_TestModule_10TestModuley_10RenderableP"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(); + return swift.memory.retain(ret); + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModuley_10RenderableP"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuley_10RenderableP = function() { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuley_10RenderableP(boxPtr); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuley_10RenderableP); + } + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_Widget_wrap"] = function(pointer) { + const obj = _exports['Widget'].__construct(pointer); + return swift.memory.retain(obj); + }; + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_Renderable_render"] = function bjs_Renderable_render(self) { + try { + let ret = swift.memory.getObject(self).render(); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.hasReleased) { + return; + } + state.hasReleased = true; + state.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype) { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + return obj; + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.deinit(state.pointer); + } + } + class Widget extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Widget_deinit, Widget.prototype); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_Widget_init(nameId, nameBytes.length); + return Widget.__construct(ret); + } + get name() { + instance.exports.bjs_Widget_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_Widget_name_set(this.pointer, valueId, valueBytes.length); + } + } + const exports = { + Widget, + processRenderable: function bjs_processRenderable(item, transform) { + const callbackId = swift.memory.retain(transform); + instance.exports.bjs_processRenderable(swift.memory.retain(item), callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + makeRenderableFactory: function bjs_makeRenderableFactory(defaultName) { + const defaultNameBytes = textEncoder.encode(defaultName); + const defaultNameId = swift.memory.retain(defaultNameBytes); + const ret = instance.exports.bjs_makeRenderableFactory(defaultNameId, defaultNameBytes.length); + return swift.memory.getObject(ret); + }, + roundtripRenderable: function bjs_roundtripRenderable(callback) { + const callbackId = swift.memory.retain(callback); + const ret = instance.exports.bjs_roundtripRenderable(callbackId); + return swift.memory.getObject(ret); + }, + processOptionalRenderable: function bjs_processOptionalRenderable(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_processOptionalRenderable(callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 9ef28f844..c2d1c4cd8 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -578,6 +578,10 @@ extension _BridgedSwiftProtocolWrapper { bridgeJSStackPop() } + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Self { + bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Int32 { jsObject.bridgeJSLowerReturn() } diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 6407a175b..d2fe49db2 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1206,6 +1206,34 @@ enum GraphOperations { } } } + + @JS func processDataProcessor(_ callback: (DataProcessor) -> String) -> String { + let processor = SwiftDataProcessor() + processor.increment(by: 42) + return callback(processor) + } + + @JS func makeDataProcessorFactory() -> () -> DataProcessor { + var count = 0 + return { + count += 1 + let p = SwiftDataProcessor() + p.increment(by: count * 10) + return p + } + } + + @JS func roundtripDataProcessor( + _ callback: @escaping (DataProcessor) -> DataProcessor + ) -> (DataProcessor) -> DataProcessor { + return callback + } + + @JS func processOptionalDataProcessor(_ callback: (DataProcessor?) -> String) -> String { + let processor = SwiftDataProcessor() + processor.increment(by: 7) + return callback(processor) + " | " + callback(nil) + } } class ExportAPITests: XCTestCase { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index db3132c37..e9c0e7653 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -70,6 +70,132 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests10H #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP { + static func bridgeJSLift(_ callbackId: Int32) -> (any DataProcessor) -> any DataProcessor { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(callbackValue, param0ObjectId) + return AnyDataProcessor.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any DataProcessor) -> any DataProcessor { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any DataProcessor) -> any DataProcessor) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any DataProcessor) -> any DataProcessor>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyDataProcessor.bridgeJSLiftParameter(param0)) + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (any DataProcessor) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(callbackValue, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any DataProcessor) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any DataProcessor) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any DataProcessor) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyDataProcessor.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 @@ -1033,6 +1159,74 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSi_ #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(callback, param0IsSome, param0ObjectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSq13DataProcessorP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0ObjectId): (Int32, Int32) + if let param0 { + (param0IsSome, param0ObjectId) = (1, (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + (param0IsSome, param0ObjectId) = (0, 0) + } + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(callbackValue, param0IsSome, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 @@ -1480,6 +1674,68 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqS #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ callback: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ callback: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ callback: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsy_13DataProcessorP { + static func bridgeJSLift(_ callbackId: Int32) -> () -> any DataProcessor { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(callbackValue) + return AnyDataProcessor.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> any DataProcessor { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> any DataProcessor) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> any DataProcessor>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure() + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_Sb") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_Sb_extern(_ callback: Int32) -> Int32 @@ -9069,6 +9325,50 @@ public func _bjs_TextProcessor_makeOptionalDirectionFormatter(_ _self: UnsafeMut #endif } +@_expose(wasm, "bjs_TextProcessor_processDataProcessor") +@_cdecl("bjs_TextProcessor_processDataProcessor") +public func _bjs_TextProcessor_processDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeDataProcessorFactory") +@_cdecl("bjs_TextProcessor_makeDataProcessorFactory") +public func _bjs_TextProcessor_makeDataProcessorFactory(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeDataProcessorFactory() + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_roundtripDataProcessor") +@_cdecl("bjs_TextProcessor_roundtripDataProcessor") +public func _bjs_TextProcessor_roundtripDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).roundtripDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP.bridgeJSLift(callback)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalDataProcessor") +@_cdecl("bjs_TextProcessor_processOptionalDataProcessor") +public func _bjs_TextProcessor_processOptionalDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTestsSq13DataProcessorP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_TextProcessor_deinit") @_cdecl("bjs_TextProcessor_deinit") public func _bjs_TextProcessor_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index da05bc5ae..8a3656b65 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -3595,6 +3595,189 @@ "useJSTypedClosure" : false } } + }, + { + "abiName" : "bjs_TextProcessor_processDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeDataProcessorFactory", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeDataProcessorFactory", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsy_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_TextProcessor_roundtripDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSq13DataProcessorP_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } } ], "name" : "TextProcessor", diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs index 0d5560fae..ebe00548b 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs @@ -77,15 +77,23 @@ export function getImports(importsContext) { } }, jsOptionalInvoke: (fn) => { - if (fn == null) { return false; } + if (fn == null) { + return false; + } return fn(); }, - jsStoreClosure: (fn) => { globalThis.__storedClosure = fn; }, - jsCallStoredClosure: () => { return globalThis.__storedClosure?.(); }, + jsStoreClosure: (fn) => { + globalThis.__storedClosure = fn; + }, + jsCallStoredClosure: () => { + return globalThis.__storedClosure?.(); + }, runJsClosureSupportTests: () => { const exports = importsContext.getExports(); - if (!exports) { throw new Error("No exports!?"); } + if (!exports) { + throw new Error("No exports!?"); + } runJsClosureSupportTests(exports); }, }; @@ -103,19 +111,32 @@ export function runJsClosureSupportTests(exports) { const multiParamTransform = (count, text, ratio) => { return `${text.toUpperCase()}-${count}-${ratio.toFixed(2)}`; }; - assert.equal(processor.processWithCustom("world", multiParamTransform), "WORLD-42-3.14"); + assert.equal( + processor.processWithCustom("world", multiParamTransform), + "WORLD-42-3.14", + ); assert.equal(processor.process("test"), "TEST"); const greeterForClosure = new exports.Greeter("World"); const greeterCaller = new exports.Greeter("Caller"); - const customGreeting = (greeter) => `Custom greeting for ${greeter.name}: ${greeter.greet()}`; - const greetResult = greeterCaller.greetWith(greeterForClosure, customGreeting); + const customGreeting = (greeter) => + `Custom greeting for ${greeter.name}: ${greeter.greet()}`; + const greetResult = greeterCaller.greetWith( + greeterForClosure, + customGreeting, + ); assert.equal(greetResult, "Custom greeting for World: Hello, World!"); greeterForClosure.release(); greeterCaller.release(); - assert.equal(exports.formatName("ada", (name) => name.toUpperCase()), "ADA"); - assert.equal(exports.formatName("grace", (name) => `Dr. ${name}`), "Dr. grace"); + assert.equal( + exports.formatName("ada", (name) => name.toUpperCase()), + "ADA", + ); + assert.equal( + exports.formatName("grace", (name) => `Dr. ${name}`), + "Dr. grace", + ); const addDr = exports.makeFormatter("Dr."); assert.equal(addDr("Ada"), "Dr. Ada"); @@ -137,8 +158,14 @@ export function runJsClosureSupportTests(exports) { const greeterForFormatter = new exports.Greeter("Formatter"); const greeterFormatter = greeterForFormatter.makeFormatter(" [suffix]"); - assert.equal(greeterFormatter("test"), "Hello, Formatter! - test - [suffix]"); - assert.equal(greeterFormatter("data"), "Hello, Formatter! - data - [suffix]"); + assert.equal( + greeterFormatter("test"), + "Hello, Formatter! - test - [suffix]", + ); + assert.equal( + greeterFormatter("data"), + "Hello, Formatter! - data - [suffix]", + ); greeterForFormatter.release(); const greeterCreator = exports.Greeter.makeCreator("Default"); @@ -206,11 +233,16 @@ export function runJsClosureSupportTests(exports) { const dirResult = processor.processDirection((dir) => { switch (dir) { - case exports.Direction.North: return "Going North"; - case exports.Direction.South: return "Going South"; - case exports.Direction.East: return "Going East"; - case exports.Direction.West: return "Going West"; - default: return "Unknown"; + case exports.Direction.North: + return "Going North"; + case exports.Direction.South: + return "Going South"; + case exports.Direction.East: + return "Going East"; + case exports.Direction.West: + return "Going West"; + default: + return "Unknown"; } }); assert.equal(dirResult, "Going North"); @@ -251,12 +283,27 @@ export function runJsClosureSupportTests(exports) { assert.equal(statusExtractor(exports.HttpStatus.Unknown), -1); const apiHandler = processor.makeAPIResultHandler(); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Success, param0: "done" }), "Success: done"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Failure, param0: 500 }), "Failure: 500"); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Success, param0: "done" }), + "Success: done", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Failure, param0: 500 }), + "Failure: 500", + ); assert.equal(apiHandler({ tag: exports.APIResult.Tag.Info }), "Info"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Flag, param0: true }), "Flag: true"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Rate, param0: 1.5 }), "Rate: 1.5"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Precise, param0: 3.14159 }), "Precise: 3.14159"); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Flag, param0: true }), + "Flag: true", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Rate, param0: 1.5 }), + "Rate: 1.5", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Precise, param0: 3.14159 }), + "Precise: 3.14159", + ); const optDirResult = processor.processOptionalDirection((dir) => { return dir !== null ? `Dir: ${dir}` : "Dir: null"; @@ -284,28 +331,55 @@ export function runJsClosureSupportTests(exports) { assert.equal(optDirFormatter(exports.Direction.West), "W"); assert.equal(optDirFormatter(null), "nil"); - processor.release(); + const dpResult = processor.processDataProcessor((dp) => { + return `Value: ${dp.getValue()}`; + }); + assert.equal(dpResult, "Value: 42"); + const dpFactory = processor.makeDataProcessorFactory(); + const dp1 = dpFactory(); + assert.equal(dp1.getValue(), 10); + const dp2 = dpFactory(); + assert.equal(dp2.getValue(), 20); + + const dpRoundtrip = processor.roundtripDataProcessor((dp) => { + dp.increment(100); + return dp; + }); + const testDp = new exports.SwiftDataProcessor(); + const roundtrippedDp = dpRoundtrip(testDp); + assert.equal(roundtrippedDp.getValue(), 100); + + const optDpResult = processor.processOptionalDataProcessor((dp) => { + return dp !== null ? `DP: ${dp.getValue()}` : "DP: null"; + }); + assert.equal(optDpResult, "DP: 7 | DP: null"); + + processor.release(); const intToInt = exports.ClosureSupportExports.makeIntToInt(10); assert.equal(intToInt(0), 10); assert.equal(intToInt(32), 42); - const doubleToDouble = exports.ClosureSupportExports.makeDoubleToDouble(10.0); + const doubleToDouble = + exports.ClosureSupportExports.makeDoubleToDouble(10.0); assert.equal(doubleToDouble(0.0), 10.0); assert.equal(doubleToDouble(32.0), 42.0); - const stringToString = exports.ClosureSupportExports.makeStringToString("Hello, "); + const stringToString = + exports.ClosureSupportExports.makeStringToString("Hello, "); assert.equal(stringToString("world!"), "Hello, world!"); const jsIntToInt = exports.ClosureSupportExports.makeJSIntToInt(10); assert.equal(jsIntToInt(0), 10); assert.equal(jsIntToInt(32), 42); - const jsDoubleToDouble = exports.ClosureSupportExports.makeJSDoubleToDouble(10.0); + const jsDoubleToDouble = + exports.ClosureSupportExports.makeJSDoubleToDouble(10.0); assert.equal(jsDoubleToDouble(0.0), 10.0); assert.equal(jsDoubleToDouble(32.0), 42.0); - const jsStringToString = exports.ClosureSupportExports.makeJSStringToString("Hello, "); + const jsStringToString = + exports.ClosureSupportExports.makeJSStringToString("Hello, "); assert.equal(jsStringToString("world!"), "Hello, world!"); }