From eec3706796bbce9487116cef9c82ce752470f260 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Fri, 22 Aug 2025 15:46:53 +0200 Subject: [PATCH 1/4] BridgeJS: Enum associated value with primitives --- .../Sources/BridgeJSCore/ExportSwift.swift | 187 ++++++++++++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 258 ++++++++++++++++-- .../Inputs/EnumAssociatedValue.swift | 12 + .../ArrayParameter.Import.js | 17 ++ .../BridgeJSLinkTests/Async.Export.js | 17 ++ .../BridgeJSLinkTests/Async.Import.js | 17 ++ .../EnumAssociatedValue.Export.d.ts | 33 +++ .../EnumAssociatedValue.Export.js | 160 +++++++++++ .../BridgeJSLinkTests/EnumCase.Export.js | 17 ++ .../BridgeJSLinkTests/EnumNamespace.Export.js | 17 ++ .../BridgeJSLinkTests/EnumRawType.Export.js | 17 ++ .../BridgeJSLinkTests/Interface.Import.js | 17 ++ .../MultipleImportedTypes.Import.js | 17 ++ .../BridgeJSLinkTests/Namespaces.Export.js | 17 ++ .../PrimitiveParameters.Export.js | 17 ++ .../PrimitiveParameters.Import.js | 17 ++ .../PrimitiveReturn.Export.js | 17 ++ .../PrimitiveReturn.Import.js | 17 ++ .../StringParameter.Export.js | 17 ++ .../StringParameter.Import.js | 17 ++ .../BridgeJSLinkTests/StringReturn.Export.js | 17 ++ .../BridgeJSLinkTests/StringReturn.Import.js | 17 ++ .../BridgeJSLinkTests/SwiftClass.Export.js | 17 ++ .../TS2SkeletonLike.Import.js | 17 ++ .../BridgeJSLinkTests/Throws.Export.js | 17 ++ .../BridgeJSLinkTests/TypeAlias.Import.js | 17 ++ .../TypeScriptClass.Import.js | 17 ++ .../VoidParameterVoidReturn.Export.js | 17 ++ .../VoidParameterVoidReturn.Import.js | 17 ++ .../ExportSwiftTests/EnumAssociatedValue.json | 123 +++++++++ .../EnumAssociatedValue.swift | 89 ++++++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 37 +++ .../Generated/BridgeJS.ExportSwift.swift | 142 ++++++++++ .../JavaScript/BridgeJS.ExportSwift.json | 233 ++++++++++++++++ Tests/prelude.mjs | 33 ++- 35 files changed, 1680 insertions(+), 35 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index a5f2e108..b3962ee7 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -446,6 +446,31 @@ public class ExportSwift { ) } + if currentEnum.cases.contains(where: { !$0.associatedValues.isEmpty }) { + for c in currentEnum.cases { + let count = c.associatedValues.count + if count > 1 { + diagnose( + node: node, + message: "Multiple associated values are not supported yet", + hint: "Use a single primitive payload (String, Int, Float, Double, Bool)" + ) + } else if count == 1, let only = c.associatedValues.first { + switch only.type { + case .string, .int, .float, .double, .bool: + break + default: + diagnose( + node: node, + message: "Unsupported associated value type: \(only.type.swiftType)", + hint: + "Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums for now" + ) + } + } + } + } + let swiftCallName = ExportSwift.computeSwiftCallName(for: node, itemName: enumName) let exportedEnum = ExportedEnum( name: enumName, @@ -620,7 +645,21 @@ public class ExportSwift { { return .rawValueEnum(swiftCallName, rawType) } else { - return .caseEnum(swiftCallName) + let hasAssociatedValues = + enumDecl.memberBlock.members.contains { member in + guard let caseDecl = member.decl.as(EnumCaseDeclSyntax.self) else { return false } + return caseDecl.elements.contains { element in + if let params = element.parameterClause?.parameters { + return !params.isEmpty + } + return false + } + } + if hasAssociatedValues { + return .associatedValueEnum(swiftCallName) + } else { + return .caseEnum(swiftCallName) + } } } @@ -651,6 +690,10 @@ public class ExportSwift { decls.append(renderCaseEnumHelpers(enumDef)) } + for enumDef in exportedEnums where enumDef.enumType == .associatedValue { + decls.append(renderAssociatedValueEnumHelpers(enumDef)) + } + for function in exportedFunctions { decls.append(renderSingleExportedFunction(function: function)) } @@ -812,8 +855,21 @@ public class ExportSwift { abiParameterSignatures.append((param.name, wasmType)) } } - case .associatedValueEnum(_): - break + case .associatedValueEnum(let enumName): + let tag = "\(param.name)Tag" + let a = "\(param.name)A" + let b = "\(param.name)B" + abiParameterForwardings.append( + LabeledExprSyntax( + label: param.label, + expression: ExprSyntax( + "\(raw: enumName)(bridgeJSTag: \(raw: tag), a: \(raw: a), b: \(raw: b))!" + ) + ) + ) + abiParameterSignatures.append((tag, .i32)) + abiParameterSignatures.append((a, .i32)) + abiParameterSignatures.append((b, .i32)) case .namespaceEnum: break case .jsObject(nil): @@ -979,8 +1035,9 @@ public class ExportSwift { append("return Int32(ret.rawValue)") } } - case .associatedValueEnum: break; - case .namespaceEnum: break; + case .associatedValueEnum: + append("ret.bridgeJSReturn()") + case .namespaceEnum: break case .jsObject(nil): append( """ @@ -1276,3 +1333,123 @@ extension BridgeType { } } } + +func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { + let typeName = enumDef.swiftCallName + + func payloadInitCase(index: Int, name: String, av: AssociatedValue) -> String { + let labelPrefix = av.label.map { "\($0): " } ?? "" + switch av.type { + case .string: + return """ + case \(index): + let s = String(unsafeUninitializedCapacity: Int(b)) { buf in + _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) + return Int(b) + } + self = .\(name)(\(labelPrefix)s) + """ + case .int: + return "case \(index): self = .\(name)(\(labelPrefix)Int(a))" + case .bool: + return "case \(index): self = .\(name)(\(labelPrefix)(a != 0))" + case .float: + return "case \(index): self = .\(name)(\(labelPrefix)Float(bitPattern: UInt32(bitPattern: a)))" + case .double: + return """ + case \(index): + let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) + self = .\(name)(\(labelPrefix)Double(bitPattern: bits)) + """ + default: + return "case \(index): return nil" + } + } + + var initCases: [String] = [] + for (i, c) in enumDef.cases.enumerated() { + if let av = c.associatedValues.first { + initCases.append(payloadInitCase(index: i, name: c.name, av: av)) + } else { + initCases.append("case \(i): self = .\(c.name)") + } + } + let initSwitch = (["switch bridgeJSTag {"] + initCases + ["default: return nil", "}"]).joined(separator: "\n") + + func payloadReturnCase(index: Int, name: String, av: AssociatedValue) -> String { + switch av.type { + case .string: + return """ + case .\(name)(let value): + _swift_js_return_tag(Int32(\(index))) + var ret = value + ret.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + """ + case .int: + return """ + case .\(name)(let value): + _swift_js_return_tag(Int32(\(index))) + _swift_js_return_int(Int32(value)) + """ + case .bool: + return """ + case .\(name)(let value): + _swift_js_return_tag(Int32(\(index))) + _swift_js_return_int(value ? 1 : 0) + """ + case .float: + return """ + case .\(name)(let value): + _swift_js_return_tag(Int32(\(index))) + _swift_js_return_f32(value) + """ + case .double: + return """ + case .\(name)(let value): + _swift_js_return_tag(Int32(\(index))) + _swift_js_return_f64(value) + """ + default: + return "" + } + } + + var returnCases: [String] = [] + for (i, c) in enumDef.cases.enumerated() { + if let av = c.associatedValues.first { + returnCases.append(payloadReturnCase(index: i, name: c.name, av: av)) + } else { + returnCases.append( + """ + case .\(c.name): + _swift_js_return_tag(Int32(\(i))) + """ + ) + } + } + let returnSwitch = (["switch self {"] + returnCases + ["}"]).joined(separator: "\n") + + return """ + extension \(raw: typeName) { + init?(bridgeJSTag: Int32, a: Int32, b: Int32) { + \(raw: initSwitch) + } + + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + \(raw: returnSwitch) + } + } + """ +} diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 046cb92d..a74a207a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -70,8 +70,6 @@ struct BridgeJSLink { var namespacedFunctions: [ExportedFunction] = [] var namespacedClasses: [ExportedClass] = [] var namespacedEnums: [ExportedEnum] = [] - var enumConstantLines: [String] = [] - var dtsEnumLines: [String] = [] var topLevelEnumLines: [String] = [] var topLevelDtsEnumLines: [String] = [] @@ -120,12 +118,15 @@ struct BridgeJSLink { namespacedEnums.append(enumDefinition) } case .associatedValue: - enumConstantLines.append(contentsOf: jsEnum) - exportsLines.append("\(enumDefinition.name),") + var exportedJsEnum = jsEnum + if !exportedJsEnum.isEmpty && exportedJsEnum[0].hasPrefix("const ") { + exportedJsEnum[0] = "export " + exportedJsEnum[0] + } + topLevelEnumLines.append(contentsOf: exportedJsEnum) + topLevelDtsEnumLines.append(contentsOf: dtsEnum) if enumDefinition.namespace != nil { namespacedEnums.append(enumDefinition) } - dtsEnumLines.append(contentsOf: dtsEnum) } } } @@ -178,13 +179,9 @@ struct BridgeJSLink { ) .map { $0.indent(count: 12) }.joined(separator: "\n") - let enumSection = - enumConstantLines.isEmpty - ? "" : enumConstantLines.map { $0.indent(count: 12) }.joined(separator: "\n") + "\n" - exportsSection = """ \(classLines.map { $0.indent(count: 12) }.joined(separator: "\n")) - \(enumSection)\("const exports = {".indent(count: 12)) + \("const exports = {".indent(count: 12)) \(exportsLines.map { $0.indent(count: 16) }.joined(separator: "\n")) \("};".indent(count: 12)) @@ -194,13 +191,9 @@ struct BridgeJSLink { }, """ } else { - let enumSection = - enumConstantLines.isEmpty - ? "" : enumConstantLines.map { $0.indent(count: 12) }.joined(separator: "\n") + "\n" - exportsSection = """ \(classLines.map { $0.indent(count: 12) }.joined(separator: "\n")) - \(enumSection)\("return {".indent(count: 12)) + \("return {".indent(count: 12)) \(exportsLines.map { $0.indent(count: 16) }.joined(separator: "\n")) \("};".indent(count: 12)) }, @@ -214,7 +207,9 @@ struct BridgeJSLink { ) let namespaceAssignmentsSection = topLevelNamespaceCode.isEmpty ? "" : topLevelNamespaceCode.joined(separator: "\n") + "\n\n" - + let enumHelpers = renderEnumHelperAssignments() + let enumHelpersSection = enumHelpers.isEmpty ? "" : "\n\n" + enumHelpers.map { $0.indent(count: 12) }.joined(separator: "\n") + let outputJs = """ // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. @@ -232,6 +227,11 @@ struct BridgeJSLink { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -267,12 +267,24 @@ struct BridgeJSLink { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } \(renderSwiftClassWrappers().map { $0.indent(count: 12) }.joined(separator: "\n")) \(importObjectBuilders.flatMap { $0.importedLines }.map { $0.indent(count: 12) }.joined(separator: "\n")) }, setInstance: (i) => { instance = i; - memory = instance.exports.memory; + memory = instance.exports.memory;\(enumHelpersSection) setException = (error) => { instance.exports._swift_js_exception.value = swift.memory.retain(error) } @@ -288,7 +300,6 @@ struct BridgeJSLink { var dtsLines: [String] = [] dtsLines.append(contentsOf: namespaceDeclarationsLines) dtsLines.append(contentsOf: dtsClassLines) - dtsLines.append(contentsOf: dtsEnumLines) dtsLines.append(contentsOf: generateImportedTypeDefinitions()) dtsLines.append("export type Exports = {") dtsLines.append(contentsOf: dtsExportLines.map { $0.indent(count: 4) }) @@ -318,6 +329,25 @@ struct BridgeJSLink { return (outputJs, outputDts) } + private func renderEnumHelperAssignments() -> [String] { + var lines: [String] = [] + + for skeleton in exportedSkeletons { + for enumDef in skeleton.enums where enumDef.enumType == .associatedValue { + let base = enumDef.name + lines.append("// Set up \(base) enum helpers") + lines.append("const \(base)Helpers = __bjs_create\(base)Helpers()(textEncoder, swift);") + lines.append("globalThis.__bjs_lower_\(base) = (value) => \(base)Helpers.lower(value);") + lines.append( + "globalThis.__bjs_raise_\(base) = () => \(base)Helpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64);" + ) + lines.append("") + } + } + + return lines + } + private func renderSwiftClassWrappers() -> [String] { var wrapperLines: [String] = [] var modulesByName: [String: [ExportedClass]] = [:] @@ -342,8 +372,8 @@ struct BridgeJSLink { for klass in classes { let wrapperFunctionName = "bjs_\(klass.name)_wrap" wrapperLines.append("importObject[\"\(moduleName)\"][\"\(wrapperFunctionName)\"] = function(pointer) {") - wrapperLines.append(" const obj = \(klass.name).__construct(pointer);") - wrapperLines.append(" return swift.memory.retain(obj);") + wrapperLines.append("const obj = \(klass.name).__construct(pointer);".indent(count: 4)) + wrapperLines.append("return swift.memory.retain(obj);".indent(count: 4)) wrapperLines.append("};") } } @@ -423,9 +453,17 @@ struct BridgeJSLink { default: parameterForwardings.append("\(param.name)") } - case .associatedValueEnum: - parameterForwardings.append("0") - parameterForwardings.append("0") + case .associatedValueEnum(let enumName): + let helperBase = enumName.components(separatedBy: ".").last ?? enumName + let tagName = "\(param.name)Tag" + let aName = "\(param.name)A" + let bName = "\(param.name)B" + let cleanupName = "\(param.name)Cleanup" + bodyLines.append( + "const { tag: \(tagName), a: \(aName), b: \(bName), cleanup: \(cleanupName) } = globalThis.__bjs_lower_\(helperBase)(\(param.name));" + ) + cleanupLines.append("if (\(cleanupName)) { \(cleanupName)(); }") + parameterForwardings.append(contentsOf: [tagName, aName, bName]) case .namespaceEnum: break case .jsObject: @@ -476,9 +514,11 @@ struct BridgeJSLink { bodyLines.append("const ret = \(call);") returnExpr = "ret" } - case .associatedValueEnum: + case .associatedValueEnum(let enumName): bodyLines.append("\(call);") - returnExpr = "\"\"" + let helperBase = enumName.components(separatedBy: ".").last ?? enumName + bodyLines.append("const ret = globalThis.__bjs_raise_\(helperBase)();") + returnExpr = "ret" case .namespaceEnum: break case .int, .float, .double: @@ -668,10 +708,172 @@ struct BridgeJSLink { dtsLines.append("") } } - case .associatedValue: - jsLines.append("// TODO: Implement \(enumDefinition.enumType) enum: \(enumDefinition.name)") - dtsLines.append("// TODO: Implement \(enumDefinition.enumType) enum: \(enumDefinition.name)") + do { + let base = enumDefinition.name + jsLines.append("const \(base) = {") + jsLines.append("Tag: {".indent(count: 4)) + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + jsLines.append("\(caseName): \(index),".indent(count: 8)) + } + jsLines.append("}".indent(count: 4)) + jsLines.append("};") + jsLines.append("") + + jsLines.append("") + jsLines.append("// Helper factory for \(base) enum") + jsLines.append("const __bjs_create\(base)Helpers = () => {") + jsLines.append("const f32buf = new ArrayBuffer(4);".indent(count: 4)) + jsLines.append("const f32dv = new DataView(f32buf);".indent(count: 4)) + jsLines.append("const f64buf = new ArrayBuffer(8);".indent(count: 4)) + jsLines.append("const f64dv = new DataView(f64buf);".indent(count: 4)) + jsLines.append("") + jsLines.append( + "const f32ToI32 = (v) => { f32dv.setFloat32(0, Math.fround(v), true); return f32dv.getInt32(0, true); };" + .indent(count: 4) + ) + jsLines.append( + "const f64ToI32x2 = (v) => { f64dv.setFloat64(0, v, true); return [f64dv.getInt32(0, true), f64dv.getInt32(4, true)]; };" + .indent(count: 4) + ) + jsLines.append("") + jsLines.append("return (textEncoder, swift) => ({".indent(count: 4)) + jsLines.append("lower: (value) => {".indent(count: 8)) + jsLines.append("const t = value.tag;".indent(count: 12)) + jsLines.append("switch (t) {".indent(count: 12)) + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + if enumCase.associatedValues.isEmpty { + jsLines.append( + "case \(base).Tag.\(caseName): return { tag: \(index), a: 0, b: 0 };".indent(count: 16) + ) + } else if let av = enumCase.associatedValues.first { + switch av.type { + case .string: + jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) + jsLines.append("const bytes = textEncoder.encode(value.value);".indent(count: 20)) + jsLines.append("const id = swift.memory.retain(bytes);".indent(count: 20)) + jsLines.append( + "return { tag: \(index), a: id, b: bytes.length, cleanup: () => swift.memory.release(id) };" + .indent(count: 20) + ) + jsLines.append("}".indent(count: 16)) + case .bool: + jsLines.append( + "case \(base).Tag.\(caseName): return { tag: \(index), a: (value.value ? 1 : 0), b: 0 };" + .indent(count: 16) + ) + case .int: + jsLines.append( + "case \(base).Tag.\(caseName): return { tag: \(index), a: (value.value | 0), b: 0 };" + .indent(count: 16) + ) + case .float: + jsLines.append( + "case \(base).Tag.\(caseName): return { tag: \(index), a: f32ToI32(value.value), b: 0 };" + .indent(count: 16) + ) + case .double: + jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) + jsLines.append("const [lo, hi] = f64ToI32x2(value.value);".indent(count: 20)) + jsLines.append("return { tag: \(index), a: lo, b: hi };".indent(count: 20)) + jsLines.append("}".indent(count: 16)) + default: + jsLines.append( + "case \(base).Tag.\(caseName): return { tag: \(index), a: 0, b: 0 };".indent(count: 16) + ) + } + } + } + jsLines.append("default: throw new Error(\"Unknown \(base) tag: \" + String(t));".indent(count: 16)) + jsLines.append("}".indent(count: 12)) + jsLines.append("},".indent(count: 8)) + jsLines.append( + "raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => {".indent(count: 8) + ) + jsLines.append("const tag = tmpRetTag | 0;".indent(count: 12)) + jsLines.append("switch (tag) {".indent(count: 12)) + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + if enumCase.associatedValues.isEmpty { + jsLines.append("case \(index): return { tag: \(base).Tag.\(caseName) };".indent(count: 16)) + } else if let av = enumCase.associatedValues.first { + switch av.type { + case .string: + jsLines.append( + "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetString };".indent( + count: 16 + ) + ) + case .bool: + jsLines.append( + "case \(index): return { tag: \(base).Tag.\(caseName), value: (tmpRetInt !== 0) };" + .indent(count: 16) + ) + case .int: + jsLines.append( + "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetInt | 0 };".indent( + count: 16 + ) + ) + case .float: + jsLines.append( + "case \(index): return { tag: \(base).Tag.\(caseName), value: Math.fround(tmpRetF32) };" + .indent(count: 20) + ) + case .double: + jsLines.append( + "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetF64 };".indent( + count: 16 + ) + ) + default: + jsLines.append("case \(index): return { tag: \(base).Tag.\(caseName) };".indent(count: 16)) + } + } + } + jsLines.append( + "default: throw new Error(\"Unknown \(base) tag returned from Swift: \" + String(tag));".indent( + count: 16 + ) + ) + jsLines.append("}".indent(count: 12)) + jsLines.append("}".indent(count: 8)) + jsLines.append("});".indent(count: 4)) + jsLines.append("};") + + var dtsBuf: [String] = [] + dtsBuf.append("export const \(enumDefinition.name): {") + dtsBuf.append("readonly Tag: {".indent(count: 4)) + for (index, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + dtsBuf.append("readonly \(caseName): \(index);".indent(count: 8)) + } + dtsBuf.append("};".indent(count: 4)) + dtsBuf.append("};") + dtsBuf.append("") + var unionParts: [String] = [] + for enumCase in enumDefinition.cases { + let caseName = enumCase.name.capitalizedFirstLetter + if enumCase.associatedValues.isEmpty { + unionParts.append("{ tag: typeof \(enumDefinition.name).Tag.\(caseName) }") + } else if let av = enumCase.associatedValues.first { + let ts: String + switch av.type { + case .string: ts = "string" + case .bool: ts = "boolean" + case .int, .float, .double: ts = "number" + default: ts = "never" + } + unionParts.append("{ tag: typeof \(enumDefinition.name).Tag.\(caseName); value: \(ts) }") + } + } + dtsBuf.append("export type \(enumDefinition.name) =") + dtsBuf.append(" " + unionParts.joined(separator: " | ")) + dtsBuf.append("") + dtsLines.append(contentsOf: dtsBuf) + } case .namespace: break } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift new file mode 100644 index 00000000..c40d8c70 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift @@ -0,0 +1,12 @@ +@JS +enum APIResult { + case success(String) + case failure(Int) + case flag(Bool) + case rate(Float) + case precise(Double) + case info +} + +@JS func handle(result: APIResult) +@JS func getResult() -> APIResult diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js index c122f179..dbad58bc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkArray"] = function bjs_checkArray(a) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js index 1da2f58e..da94f9c8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js index 21d11fa4..fc6980e9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_asyncReturnVoid"] = function bjs_asyncReturnVoid() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts new file mode 100644 index 00000000..d9fe92a3 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts @@ -0,0 +1,33 @@ +// 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 const APIResult: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + readonly Flag: 2; + readonly Rate: 3; + readonly Precise: 4; + readonly Info: 5; + }; +}; + +export type APIResult = + { tag: typeof APIResult.Tag.Success; value: string } | { tag: typeof APIResult.Tag.Failure; value: number } | { tag: typeof APIResult.Tag.Flag; value: boolean } | { tag: typeof APIResult.Tag.Rate; value: number } | { tag: typeof APIResult.Tag.Precise; value: number } | { tag: typeof APIResult.Tag.Info } + +export type Exports = { + handle(result: APIResult): void; + getResult(): APIResult; +} +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/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js new file mode 100644 index 00000000..885193f4 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -0,0 +1,160 @@ +// 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 const APIResult = { + Tag: { + Success: 0, + Failure: 1, + Flag: 2, + Rate: 3, + Precise: 4, + Info: 5, + } +}; + + +// Helper factory for APIResult enum +const __bjs_createAPIResultHelpers = () => { + const f32buf = new ArrayBuffer(4); + const f32dv = new DataView(f32buf); + const f64buf = new ArrayBuffer(8); + const f64dv = new DataView(f64buf); + + const f32ToI32 = (v) => { f32dv.setFloat32(0, Math.fround(v), true); return f32dv.getInt32(0, true); }; + const f64ToI32x2 = (v) => { f64dv.setFloat64(0, v, true); return [f64dv.getInt32(0, true), f64dv.getInt32(4, true)]; }; + + return (textEncoder, swift) => ({ + lower: (value) => { + const t = value.tag; + switch (t) { + case APIResult.Tag.Success: { + const bytes = textEncoder.encode(value.value); + const id = swift.memory.retain(bytes); + return { tag: 0, a: id, b: bytes.length, cleanup: () => swift.memory.release(id) }; + } + case APIResult.Tag.Failure: return { tag: 1, a: (value.value | 0), b: 0 }; + case APIResult.Tag.Flag: return { tag: 2, a: (value.value ? 1 : 0), b: 0 }; + case APIResult.Tag.Rate: return { tag: 3, a: f32ToI32(value.value), b: 0 }; + case APIResult.Tag.Precise: { + const [lo, hi] = f64ToI32x2(value.value); + return { tag: 4, a: lo, b: hi }; + } + case APIResult.Tag.Info: return { tag: 5, a: 0, b: 0 }; + default: throw new Error("Unknown APIResult tag: " + String(t)); + } + }, + raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => { + const tag = tmpRetTag | 0; + switch (tag) { + case 0: return { tag: APIResult.Tag.Success, value: tmpRetString }; + case 1: return { tag: APIResult.Tag.Failure, value: tmpRetInt | 0 }; + case 2: return { tag: APIResult.Tag.Flag, value: (tmpRetInt !== 0) }; + case 3: return { tag: APIResult.Tag.Rate, value: Math.fround(tmpRetF32) }; + case 4: return { tag: APIResult.Tag.Precise, value: tmpRetF64 }; + case 5: return { tag: APIResult.Tag.Info }; + default: throw new Error("Unknown APIResult tag returned from Swift: " + String(tag)); + } + } + }); +}; + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + const bjs = {}; + importObject["bjs"] = bjs; + const imports = options.getImports(importsContext); + bjs["swift_js_return_string"] = function(ptr, len) { + const bytes = new Uint8Array(memory.buffer, ptr, len); + tmpRetString = textDecoder.decode(bytes); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + const bytes = new Uint8Array(memory.buffer, ptr, len); + return swift.memory.retain(textDecoder.decode(bytes)); + } + 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_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } + + + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + // Set up APIResult enum helpers + const APIResultHelpers = __bjs_createAPIResultHelpers()(textEncoder, swift); + globalThis.__bjs_lower_APIResult = (value) => APIResultHelpers.lower(value); + globalThis.__bjs_raise_APIResult = () => APIResultHelpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64); + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + + return { + handle: function bjs_handle(result) { + const { tag: resultTag, a: resultA, b: resultB, cleanup: resultCleanup } = globalThis.__bjs_lower_APIResult(result); + instance.exports.bjs_handle(resultTag, resultA, resultB); + if (resultCleanup) { resultCleanup(); } + }, + getResult: function bjs_getResult() { + instance.exports.bjs_getResult(); + const ret = globalThis.__bjs_raise_APIResult(); + return ret; + }, + }; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js index 3e080948..02ba21d8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js @@ -35,6 +35,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -70,6 +75,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js index 12613dd8..0bfc3147 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js @@ -61,6 +61,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -96,6 +101,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js index 68a2b19f..a207953e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js @@ -90,6 +90,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -125,6 +130,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js index f81c7e47..50889b14 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js index 394d996b..00490085 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createDatabaseConnection"] = function bjs_createDatabaseConnection(config) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js index 6915a61a..b5cf3bf7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js index 4873fc33..888cc3f3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js index 3b93b2dd..de2d4c24 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check(a, b) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js index 53332b97..8ed08191 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js index 1892eb46..11ca14f7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkNumber"] = function bjs_checkNumber() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js index ea47fb55..30149c58 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js index 16ed1081..8d3bc959 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString(a) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js index f98cea55..a961621b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js index 3220ae7b..e6aff66e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js index ab4caba3..c43e948c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js index 705c6a37..e8f762b2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createTS2Skeleton"] = function bjs_createTS2Skeleton() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js index b2089962..0b1d2994 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js index 2eb9dee5..b2811bd1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkSimple"] = function bjs_checkSimple(a) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js index c7d622ea..ccb3b061 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_Greeter_init"] = function bjs_Greeter_init(name) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js index c200c077..60fdbac6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js index ca497688..4cbf6739 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js @@ -14,6 +14,11 @@ export async function createInstantiator(options, swift) { let tmpRetString; let tmpRetBytes; let tmpRetException; + let tmpRetTag; + let tmpRetInt; + let tmpRetF32; + let tmpRetF64; + return { /** * @param {WebAssembly.Imports} importObject @@ -49,6 +54,18 @@ export async function createInstantiator(options, swift) { bjs["swift_js_release"] = function(id) { swift.memory.release(id); } + bjs["swift_js_return_tag"] = function(tag) { + tmpRetTag = tag | 0; + } + bjs["swift_js_return_int"] = function(v) { + tmpRetInt = v | 0; + } + bjs["swift_js_return_f32"] = function(v) { + tmpRetF32 = Math.fround(v); + } + bjs["swift_js_return_f64"] = function(v) { + tmpRetF64 = v; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json new file mode 100644 index 00000000..289c975c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json @@ -0,0 +1,123 @@ +{ + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + } + ], + "name" : "flag" + }, + { + "associatedValues" : [ + { + "type" : { + "float" : { + + } + } + } + ], + "name" : "rate" + }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + } + ], + "name" : "precise" + }, + { + "associatedValues" : [ + + ], + "name" : "info" + } + ], + "emitStyle" : "const", + "name" : "APIResult", + "swiftCallName" : "APIResult" + } + ], + "functions" : [ + { + "abiName" : "bjs_handle", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "handle", + "parameters" : [ + { + "label" : "result", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_getResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "getResult", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + ], + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift new file mode 100644 index 00000000..7220c868 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -0,0 +1,89 @@ +// 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`. + +@_spi(BridgeJS) import JavaScriptKit + +extension APIResult { + init?(bridgeJSTag: Int32, a: Int32, b: Int32) { + switch bridgeJSTag { + case 0: + let s = String(unsafeUninitializedCapacity: Int(b)) { buf in + _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) + return Int(b) + } + self = .success(s) + case 1: + self = .failure(Int(a)) + case 2: + self = .flag((a != 0)) + case 3: + self = .rate(Float(bitPattern: UInt32(bitPattern: a))) + case 4: + let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) + self = .precise(Double(bitPattern: bits)) + case 5: + self = .info + default: + return nil + } + } + + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + switch self { + case .success(let value): + _swift_js_return_tag(Int32(0)) + var ret = value + ret.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let value): + _swift_js_return_tag(Int32(1)) + _swift_js_return_int(Int32(value)) + case .flag(let value): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(value ? 1 : 0) + case .rate(let value): + _swift_js_return_tag(Int32(3)) + _swift_js_return_f32(value) + case .precise(let value): + _swift_js_return_tag(Int32(4)) + _swift_js_return_f64(value) + case .info: + _swift_js_return_tag(Int32(5)) + } + } +} + +@_expose(wasm, "bjs_handle") +@_cdecl("bjs_handle") +public func _bjs_handle(resultTag: Int32, resultA: Int32, resultB: Int32) -> Void { + #if arch(wasm32) + handle(result: APIResult(bridgeJSTag: resultTag, a: resultA, b: resultB)!) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getResult") +@_cdecl("bjs_getResult") +public func _bjs_getResult() -> Void { + #if arch(wasm32) + let ret = getResult() + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index bd080623..873294b4 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -270,6 +270,43 @@ enum Internal { } } +@JS enum APIResult { + case success(String) + case failure(Int) + case flag(Bool) + case rate(Float) + case precise(Double) + case info +} + +@JS func echoAPIResult(result: APIResult) -> APIResult { + return result +} + +@JS func makeAPIResultSuccess(_ value: String) -> APIResult { + return .success(value) +} + +@JS func makeAPIResultFailure(_ value: Int) -> APIResult { + return .failure(value) +} + +@JS func makeAPIResultInfo() -> APIResult { + return .info +} + +@JS func makeAPIResultFlag(_ value: Bool) -> APIResult { + return .flag(value) +} + +@JS func makeAPIResultRate(_ value: Float) -> APIResult { + return .rate(value) +} + +@JS func makeAPIResultPrecise(_ value: Double) -> APIResult { + return .precise(value) +} + class ExportAPITests: XCTestCase { func testAll() { var hasDeinitGreeter = false diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 15e1cfc5..07613b8c 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -144,6 +144,67 @@ extension Internal.SupportedMethod { } } +extension APIResult { + init?(bridgeJSTag: Int32, a: Int32, b: Int32) { + switch bridgeJSTag { + case 0: + let s = String(unsafeUninitializedCapacity: Int(b)) { buf in + _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) + return Int(b) + } + self = .success(s) + case 1: + self = .failure(Int(a)) + case 2: + self = .flag((a != 0)) + case 3: + self = .rate(Float(bitPattern: UInt32(bitPattern: a))) + case 4: + let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) + self = .precise(Double(bitPattern: bits)) + case 5: + self = .info + default: + return nil + } + } + + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + switch self { + case .success(let value): + _swift_js_return_tag(Int32(0)) + var ret = value + ret.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let value): + _swift_js_return_tag(Int32(1)) + _swift_js_return_int(Int32(value)) + case .flag(let value): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(value ? 1 : 0) + case .rate(let value): + _swift_js_return_tag(Int32(3)) + _swift_js_return_f32(value) + case .precise(let value): + _swift_js_return_tag(Int32(4)) + _swift_js_return_f64(value) + case .info: + _swift_js_return_tag(Int32(5)) + } + } +} + @_expose(wasm, "bjs_roundTripVoid") @_cdecl("bjs_roundTripVoid") public func _bjs_roundTripVoid() -> Void { @@ -771,6 +832,87 @@ public func _bjs_getTSTheme() -> Void { #endif } +@_expose(wasm, "bjs_echoAPIResult") +@_cdecl("bjs_echoAPIResult") +public func _bjs_echoAPIResult(resultTag: Int32, resultA: Int32, resultB: Int32) -> Void { + #if arch(wasm32) + let ret = echoAPIResult(result: APIResult(bridgeJSTag: resultTag, a: resultA, b: resultB)!) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultSuccess") +@_cdecl("bjs_makeAPIResultSuccess") +public func _bjs_makeAPIResultSuccess(valueBytes: Int32, valueLen: Int32) -> Void { + #if arch(wasm32) + let value = String(unsafeUninitializedCapacity: Int(valueLen)) { b in + _swift_js_init_memory(valueBytes, b.baseAddress.unsafelyUnwrapped) + return Int(valueLen) + } + let ret = makeAPIResultSuccess(_: value) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultFailure") +@_cdecl("bjs_makeAPIResultFailure") +public func _bjs_makeAPIResultFailure(value: Int32) -> Void { + #if arch(wasm32) + let ret = makeAPIResultFailure(_: Int(value)) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultInfo") +@_cdecl("bjs_makeAPIResultInfo") +public func _bjs_makeAPIResultInfo() -> Void { + #if arch(wasm32) + let ret = makeAPIResultInfo() + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultFlag") +@_cdecl("bjs_makeAPIResultFlag") +public func _bjs_makeAPIResultFlag(value: Int32) -> Void { + #if arch(wasm32) + let ret = makeAPIResultFlag(_: value == 1) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultRate") +@_cdecl("bjs_makeAPIResultRate") +public func _bjs_makeAPIResultRate(value: Float32) -> Void { + #if arch(wasm32) + let ret = makeAPIResultRate(_: value) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPIResultPrecise") +@_cdecl("bjs_makeAPIResultPrecise") +public func _bjs_makeAPIResultPrecise(value: Float64) -> Void { + #if arch(wasm32) + let ret = makeAPIResultPrecise(_: value) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_init") @_cdecl("bjs_Greeter_init") public func _bjs_Greeter_init(nameBytes: Int32, nameLen: Int32) -> UnsafeMutableRawPointer { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index b4642d8a..fa1d2120 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -572,6 +572,79 @@ "Internal" ], "swiftCallName" : "Internal.SupportedMethod" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + } + ], + "name" : "flag" + }, + { + "associatedValues" : [ + { + "type" : { + "float" : { + + } + } + } + ], + "name" : "rate" + }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + } + ], + "name" : "precise" + }, + { + "associatedValues" : [ + + ], + "name" : "info" + } + ], + "emitStyle" : "const", + "name" : "APIResult", + "swiftCallName" : "APIResult" } ], "functions" : [ @@ -1484,6 +1557,166 @@ "_1" : "String" } } + }, + { + "abiName" : "bjs_echoAPIResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "echoAPIResult", + "parameters" : [ + { + "label" : "result", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultSuccess", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultSuccess", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultFailure", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultFailure", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultInfo", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultInfo", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultFlag", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultFlag", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "bool" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultRate", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultRate", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "float" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + }, + { + "abiName" : "bjs_makeAPIResultPrecise", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPIResultPrecise", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } ], "moduleName" : "BridgeJSRuntimeTests" diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 6954d87c..f12b1931 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1,7 +1,7 @@ // @ts-check import { - Direction, Status, Theme, HttpStatus, TSDirection, TSTheme + Direction, Status, Theme, HttpStatus, TSDirection, TSTheme, APIResult } from '../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ @@ -252,6 +252,35 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { const globalTestServer = new globalThis.Networking.APIV2.Internal.TestServer(); globalTestServer.call(globalThis.Networking.APIV2.Internal.SupportedMethod.Post); globalTestServer.release(); + + const s1 = { tag: APIResult.Tag.Success, value: "Cześć 🙋‍♂️" }; + const f1 = { tag: APIResult.Tag.Failure, value: 42 }; + const i1 = { tag: APIResult.Tag.Info }; + + assert.deepEqual(exports.echoAPIResult(s1), s1); + assert.deepEqual(exports.echoAPIResult(f1), f1); + assert.deepEqual(exports.echoAPIResult(i1), i1); + + assert.deepEqual(exports.makeAPIResultSuccess("ok"), { tag: APIResult.Tag.Success, value: "ok" }); + assert.deepEqual(exports.makeAPIResultFailure(123), { tag: APIResult.Tag.Failure, value: 123 }); + assert.deepEqual(exports.makeAPIResultInfo(), { tag: APIResult.Tag.Info }); + + const bTrue = { tag: APIResult.Tag.Flag, value: true }; + const bFalse = { tag: APIResult.Tag.Flag, value: false }; + assert.deepEqual(exports.echoAPIResult(bTrue), bTrue); + assert.deepEqual(exports.echoAPIResult(bFalse), bFalse); + assert.deepEqual(exports.makeAPIResultFlag(true), bTrue); + assert.deepEqual(exports.makeAPIResultFlag(false), bFalse); + + const rVal = 3.25; + const r1 = { tag: APIResult.Tag.Rate, value: rVal }; + assert.deepEqual(exports.echoAPIResult(r1), r1); + assert.deepEqual(exports.makeAPIResultRate(rVal), r1); + + const pVal = 3.141592653589793; + const p1 = { tag: APIResult.Tag.Precise, value: pVal }; + assert.deepEqual(exports.echoAPIResult(p1), p1); + assert.deepEqual(exports.makeAPIResultPrecise(pVal), p1); } /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ @@ -350,4 +379,4 @@ function setupTestGlobals(global) { sym: Symbol("s"), bi: BigInt(3) }; -} +} \ No newline at end of file From 0adef4ec4b0cd3e93027b414de70e16d1757fedb Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 25 Aug 2025 16:19:34 +0200 Subject: [PATCH 2/4] BridgeJS: Naive JSON approach for multiple associated values of different types --- .../Sources/BridgeJSCore/ExportSwift.swift | 545 +++++++++++++----- .../Sources/BridgeJSLink/BridgeJSLink.swift | 181 +++--- .../Inputs/EnumAssociatedValue.swift | 11 + .../EnumAssociatedValue.Export.d.ts | 16 +- .../EnumAssociatedValue.Export.js | 139 ++++- .../ExportSwiftTests/EnumAssociatedValue.json | 103 ++++ .../EnumAssociatedValue.swift | 254 ++++++-- .../BridgeJSRuntimeTests/ExportAPITests.swift | 32 + .../Generated/BridgeJS.ExportSwift.swift | 311 ++++++++-- .../JavaScript/BridgeJS.ExportSwift.json | 217 +++++++ Tests/prelude.mjs | 54 +- 11 files changed, 1505 insertions(+), 358 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index b3962ee7..be49c791 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -448,23 +448,16 @@ public class ExportSwift { if currentEnum.cases.contains(where: { !$0.associatedValues.isEmpty }) { for c in currentEnum.cases { - let count = c.associatedValues.count - if count > 1 { - diagnose( - node: node, - message: "Multiple associated values are not supported yet", - hint: "Use a single primitive payload (String, Int, Float, Double, Bool)" - ) - } else if count == 1, let only = c.associatedValues.first { - switch only.type { + for associatedValue in c.associatedValues { + switch associatedValue.type { case .string, .int, .float, .double, .bool: break default: diagnose( node: node, - message: "Unsupported associated value type: \(only.type.swiftType)", + message: "Unsupported associated value type: \(associatedValue.type.swiftType)", hint: - "Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums for now" + "Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums" ) } } @@ -856,20 +849,18 @@ public class ExportSwift { } } case .associatedValueEnum(let enumName): - let tag = "\(param.name)Tag" - let a = "\(param.name)A" - let b = "\(param.name)B" + let enumBaseName = enumName.components(separatedBy: ".").last ?? enumName abiParameterForwardings.append( LabeledExprSyntax( label: param.label, expression: ExprSyntax( - "\(raw: enumName)(bridgeJSTag: \(raw: tag), a: \(raw: a), b: \(raw: b))!" + "\(raw: enumBaseName).dispatchConstruct(\(raw: param.name)CaseId, \(raw: param.name)ParamsId, \(raw: param.name)ParamsLen)" ) ) ) - abiParameterSignatures.append((tag, .i32)) - abiParameterSignatures.append((a, .i32)) - abiParameterSignatures.append((b, .i32)) + abiParameterSignatures.append(("\(param.name)CaseId", .i32)) + abiParameterSignatures.append(("\(param.name)ParamsId", .i32)) + abiParameterSignatures.append(("\(param.name)ParamsLen", .i32)) case .namespaceEnum: break case .jsObject(nil): @@ -1261,6 +1252,405 @@ public class ExportSwift { } """ } + + // MARK: - Variable ABI Associated Value Enum Generation + + static func renderVariableABIAssociatedValueEnum(_ enumDef: ExportedEnum) -> DeclSyntax { + let typeName = enumDef.swiftCallName + var returnCases: [String] = [] + + for (i, c) in enumDef.cases.enumerated() { + let caseName = c.name + let caseIndex = i + + if c.associatedValues.isEmpty { + returnCases.append( + """ + case .\(caseName): + _swift_js_return_tag(Int32(\(caseIndex))) + """ + ) + } else { + let returnCase = generateReturnCase( + caseName: caseName, + caseIndex: caseIndex, + associatedValues: c.associatedValues + ) + returnCases.append(returnCase) + } + } + + let returnSwitch = (["switch self {"] + returnCases + ["}"]).joined(separator: "\n ") + + let enumBaseName = typeName.components(separatedBy: ".").last ?? typeName + return """ + import Foundation + + extension \(raw: typeName) { + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + \(raw: returnSwitch) + } + } + + extension \(raw: enumBaseName) { + \(raw: generateCaseSpecificConstructors(enumDef: enumDef).joined(separator: "\n\n ")) + + static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> \(raw: typeName) { + let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + return Int(paramsLen) + } + return dispatchConstructFromJson(caseId, paramsString) + } + + static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> \(raw: typeName) { + switch caseId { + \(raw: generateStructuredDispatchCases(enumDef: enumDef).joined(separator: "\n ")) + default: fatalError("Unknown \(raw: enumBaseName) case ID: \\(caseId)") + } + } + } + """ + } + + static func generateCaseSpecificConstructors(enumDef: ExportedEnum) -> [String] { + var constructors: [String] = [] + let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName + + for (i, c) in enumDef.cases.enumerated() { + let caseName = c.name + + if c.associatedValues.isEmpty { + constructors.append( + """ + static func constructFrom\(enumBaseName)_\(i)() -> \(enumDef.swiftCallName) { + return .\(caseName) + } + """ + ) + } else { + var params: [String] = [] + var args: [String] = [] + + for (j, av) in c.associatedValues.enumerated() { + let paramName = av.label ?? "param\(j)" + + switch av.type { + case .string: + params.append("\(paramName): String") + args.append("\(paramName)") + case .int: + params.append("\(paramName): Int32") + args.append("Int(\(paramName))") + case .bool: + params.append("\(paramName): Int32") + args.append("(\(paramName) != 0)") + case .float: + params.append("\(paramName): Float32") + args.append("\(paramName)") + case .double: + params.append("\(paramName): Float64") + args.append("\(paramName)") + default: + params.append("\(paramName): Int32") + args.append("\(paramName)") + } + } + + let paramList = params.joined(separator: ", ") + let argList = args.joined(separator: ", ") + + constructors.append( + """ + static func constructFrom\(enumBaseName)_\(i)(\(paramList)) -> \(enumDef.swiftCallName) { + return .\(caseName)(\(argList)) + } + """ + ) + } + } + + return constructors + } + + static func generateDispatchCases(enumDef: ExportedEnum) -> [String] { + var cases: [String] = [] + let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName + + for (i, c) in enumDef.cases.enumerated() { + if c.associatedValues.isEmpty { + cases.append("case \(i): return constructFrom\(enumBaseName)_\(i)()") + } else { + // For cases with parameters, we'll extract them from the pointer + var paramExtractions: [String] = [] + var paramPasses: [String] = [] + var offset = 0 + + for (j, av) in c.associatedValues.enumerated() { + let paramName = av.label ?? "param\(j)" + + switch av.type { + case .string: + paramExtractions.append( + "let \(paramName)_ptr = params.load(fromByteOffset: \(offset), as: UnsafePointer.self)" + ) + paramExtractions.append( + "let \(paramName)_len = params.load(fromByteOffset: \(offset + 8), as: Int32.self)" + ) + paramPasses.append("\(paramName)_ptr: \(paramName)_ptr") + paramPasses.append("\(paramName)_len: \(paramName)_len") + offset += 16 // 8 bytes for pointer + 4 bytes for length + padding + case .int: + paramExtractions.append( + "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" + ) + paramPasses.append("\(paramName): \(paramName)") + offset += 4 + case .bool: + paramExtractions.append( + "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" + ) + paramPasses.append("\(paramName): \(paramName)") + offset += 4 + case .float: + paramExtractions.append( + "let \(paramName) = params.load(fromByteOffset: \(offset), as: Float32.self)" + ) + paramPasses.append("\(paramName): \(paramName)") + offset += 4 + case .double: + paramExtractions.append( + "let \(paramName) = params.load(fromByteOffset: \(offset), as: Float64.self)" + ) + paramPasses.append("\(paramName): \(paramName)") + offset += 8 + default: + paramExtractions.append( + "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" + ) + paramPasses.append("\(paramName): \(paramName)") + offset += 4 + } + } + + let extractionCode = paramExtractions.joined(separator: "; ") + let paramList = paramPasses.joined(separator: ", ") + + cases.append("case \(i): \(extractionCode); return constructFrom\(enumBaseName)_\(i)(\(paramList))") + } + } + + return cases + } + + static func generateReturnCase(caseName: String, caseIndex: Int, associatedValues: [AssociatedValue]) -> String { + var returnStatements: [String] = [] + returnStatements.append("_swift_js_return_tag(Int32(\(caseIndex)))") + + for (i, av) in associatedValues.enumerated() { + let paramName = av.label ?? "param\(i)" + + switch av.type { + case .string: + returnStatements.append( + """ + var mutable\(paramName.capitalized) = \(paramName) + mutable\(paramName.capitalized).withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + """ + ) + case .int: + returnStatements.append("_swift_js_return_int(Int32(\(paramName)))") + case .bool: + returnStatements.append("_swift_js_return_int(\(paramName) ? 1 : 0)") + case .float: + returnStatements.append("_swift_js_return_f32(\(paramName))") + case .double: + returnStatements.append("_swift_js_return_f64(\(paramName))") + default: + returnStatements.append("_swift_js_return_int(0)") + } + } + + let returnCode = returnStatements.joined(separator: "\n ") + return """ + case .\(caseName)(let \(associatedValues.enumerated().map { av in av.1.label ?? "param\(av.0)" }.joined(separator: ", let "))): + \(returnCode) + """ + } + + static func generateStructuredDispatchCases(enumDef: ExportedEnum) -> [String] { + var cases: [String] = [] + let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName + + for (i, c) in enumDef.cases.enumerated() { + if c.associatedValues.isEmpty { + cases.append("case \(i): return constructFrom\(enumBaseName)_\(i)()") + } else { + // Parse JSON parameters and call constructor + var paramExtractions: [String] = [] + var paramPasses: [String] = [] + + for (j, av) in c.associatedValues.enumerated() { + let paramName = av.label ?? "param\(j)" + + switch av.type { + case .string: + paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! String") + paramPasses.append("\(paramName): \(paramName)") + case .int: + paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Int32") + paramPasses.append("\(paramName): \(paramName)") + case .bool: + paramExtractions.append("let \(paramName) = Int32(params[\"\(paramName)\"] as! Bool ? 1 : 0)") + paramPasses.append("\(paramName): \(paramName)") + case .float: + paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Float32") + paramPasses.append("\(paramName): \(paramName)") + case .double: + paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Float64") + paramPasses.append("\(paramName): \(paramName)") + default: + paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Int32") + paramPasses.append("\(paramName): \(paramName)") + } + } + + let extractionCode = paramExtractions.joined(separator: "; ") + let paramList = paramPasses.joined(separator: ", ") + + cases.append( + """ + case \(i): + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + \(extractionCode) + return constructFrom\(enumBaseName)_\(i)(\(paramList)) + """ + ) + } + } + + return cases + } + + static func generateConstructorCall( + enumType: String, + caseName: String, + associatedValues: [AssociatedValue] + ) -> String { + var params: [String] = [] + + // For simplicity, we'll handle the most common case: single parameter using (a, b) as needed + if associatedValues.count == 1 { + let av = associatedValues[0] + let paramName = av.label ?? "param0" + + switch av.type { + case .string: + params.append("\(paramName)_ptr: UnsafePointer(bitPattern: UInt(a)).unsafelyUnwrapped") + params.append("\(paramName)_len: b") + case .int: + params.append("\(paramName): a") + case .bool: + params.append("\(paramName): (a != 0)") + case .float: + params.append("\(paramName): Float32(bitPattern: UInt32(a))") + case .double: + params.append("\(paramName): Double(bitPattern: UInt64(a) | (UInt64(b) << 32))") + default: + params.append("\(paramName): a") + } + } else { + // For multiple parameters, this is more complex - for now, use fatalError + return "fatalError(\"Multiple parameter cases not yet implemented for \\\(caseName)\")" + } + + return "\(enumType).create\(caseName)(\(params.joined(separator: ", ")))" + } + + static func renderCaseSpecificConstructor( + enumType: String, + caseIndex: Int, + caseName: String, + associatedValues: [AssociatedValue] + ) -> (constructorFunc: String, returnCase: String) { + + // Generate case-specific constructor function with native WASM parameters + var constructorParams: [String] = [] + var constructorArgs: [String] = [] + var returnStatements: [String] = [] + + for (i, av) in associatedValues.enumerated() { + let paramName = av.label ?? "param\(i)" + let labelPrefix = av.label.map { "\($0): " } ?? "" + + switch av.type { + case .string: + constructorParams.append("\(paramName)_ptr: UnsafePointer") + constructorParams.append("\(paramName)_len: Int32") + constructorArgs.append( + "\(labelPrefix)String(unsafeUninitializedCapacity: Int(\(paramName)_len)) { buf in _swift_js_init_memory(Int32(bitPattern: \(paramName)_ptr), buf.baseAddress.unsafelyUnwrapped); return Int(\(paramName)_len) }" + ) + returnStatements.append( + """ + var mutable\(paramName.capitalized) = \(paramName) + mutable\(paramName.capitalized).withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + """ + ) + case .int: + constructorParams.append("\(paramName): Int32") + constructorArgs.append("\(labelPrefix)Int(\(paramName))") + returnStatements.append("_swift_js_return_int(Int32(\(paramName)))") + case .bool: + constructorParams.append("\(paramName): Int32") + constructorArgs.append("\(labelPrefix)(\(paramName) != 0)") + returnStatements.append("_swift_js_return_int(\(paramName) ? 1 : 0)") + case .float: + constructorParams.append("\(paramName): Float32") + constructorArgs.append("\(labelPrefix)\(paramName)") + returnStatements.append("_swift_js_return_f32(\(paramName))") + case .double: + constructorParams.append("\(paramName): Float64") + constructorArgs.append("\(labelPrefix)\(paramName)") + returnStatements.append("_swift_js_return_f64(\(paramName))") + default: + constructorParams.append("\(paramName): Int32") + constructorArgs.append("\(labelPrefix)/* unsupported type */") + returnStatements.append("// Unsupported type for \(paramName)") + } + } + + // Generate the case-specific constructor function + let constructorFunc = """ + static func create\(caseName.capitalized)(\(constructorParams.joined(separator: ", "))) -> \(enumType) { + return .\(caseName)(\(constructorArgs.joined(separator: ", "))) + } + """ + + let returnCase = """ + case .\(caseName)(\(associatedValues.enumerated().map { i, av in "let \(av.label ?? "param\(i)")" }.joined(separator: ", "))): + _swift_js_return_tag(Int32(\(caseIndex))) + \(returnStatements.joined(separator: "\n ")) + """ + + return (constructorFunc, returnCase) + } } fileprivate enum Constants { @@ -1335,121 +1725,6 @@ extension BridgeType { } func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { - let typeName = enumDef.swiftCallName - - func payloadInitCase(index: Int, name: String, av: AssociatedValue) -> String { - let labelPrefix = av.label.map { "\($0): " } ?? "" - switch av.type { - case .string: - return """ - case \(index): - let s = String(unsafeUninitializedCapacity: Int(b)) { buf in - _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) - return Int(b) - } - self = .\(name)(\(labelPrefix)s) - """ - case .int: - return "case \(index): self = .\(name)(\(labelPrefix)Int(a))" - case .bool: - return "case \(index): self = .\(name)(\(labelPrefix)(a != 0))" - case .float: - return "case \(index): self = .\(name)(\(labelPrefix)Float(bitPattern: UInt32(bitPattern: a)))" - case .double: - return """ - case \(index): - let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) - self = .\(name)(\(labelPrefix)Double(bitPattern: bits)) - """ - default: - return "case \(index): return nil" - } - } - - var initCases: [String] = [] - for (i, c) in enumDef.cases.enumerated() { - if let av = c.associatedValues.first { - initCases.append(payloadInitCase(index: i, name: c.name, av: av)) - } else { - initCases.append("case \(i): self = .\(c.name)") - } - } - let initSwitch = (["switch bridgeJSTag {"] + initCases + ["default: return nil", "}"]).joined(separator: "\n") - - func payloadReturnCase(index: Int, name: String, av: AssociatedValue) -> String { - switch av.type { - case .string: - return """ - case .\(name)(let value): - _swift_js_return_tag(Int32(\(index))) - var ret = value - ret.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) - } - """ - case .int: - return """ - case .\(name)(let value): - _swift_js_return_tag(Int32(\(index))) - _swift_js_return_int(Int32(value)) - """ - case .bool: - return """ - case .\(name)(let value): - _swift_js_return_tag(Int32(\(index))) - _swift_js_return_int(value ? 1 : 0) - """ - case .float: - return """ - case .\(name)(let value): - _swift_js_return_tag(Int32(\(index))) - _swift_js_return_f32(value) - """ - case .double: - return """ - case .\(name)(let value): - _swift_js_return_tag(Int32(\(index))) - _swift_js_return_f64(value) - """ - default: - return "" - } - } - - var returnCases: [String] = [] - for (i, c) in enumDef.cases.enumerated() { - if let av = c.associatedValues.first { - returnCases.append(payloadReturnCase(index: i, name: c.name, av: av)) - } else { - returnCases.append( - """ - case .\(c.name): - _swift_js_return_tag(Int32(\(i))) - """ - ) - } - } - let returnSwitch = (["switch self {"] + returnCases + ["}"]).joined(separator: "\n") - - return """ - extension \(raw: typeName) { - init?(bridgeJSTag: Int32, a: Int32, b: Int32) { - \(raw: initSwitch) - } - - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - \(raw: returnSwitch) - } - } - """ + // Use Variable ABI approach for all associated value enums + return ExportSwift.renderVariableABIAssociatedValueEnum(enumDef) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index a74a207a..34ba0d7f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -208,8 +208,9 @@ struct BridgeJSLink { let namespaceAssignmentsSection = topLevelNamespaceCode.isEmpty ? "" : topLevelNamespaceCode.joined(separator: "\n") + "\n\n" let enumHelpers = renderEnumHelperAssignments() - let enumHelpersSection = enumHelpers.isEmpty ? "" : "\n\n" + enumHelpers.map { $0.indent(count: 12) }.joined(separator: "\n") - + let enumHelpersSection = + enumHelpers.isEmpty ? "" : "\n\n" + enumHelpers.map { $0.indent(count: 12) }.joined(separator: "\n") + let outputJs = """ // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. @@ -455,15 +456,17 @@ struct BridgeJSLink { } case .associatedValueEnum(let enumName): let helperBase = enumName.components(separatedBy: ".").last ?? enumName - let tagName = "\(param.name)Tag" - let aName = "\(param.name)A" - let bName = "\(param.name)B" + let caseIdName = "\(param.name)CaseId" + let paramsIdName = "\(param.name)ParamsId" + let paramsLenName = "\(param.name)ParamsLen" let cleanupName = "\(param.name)Cleanup" bodyLines.append( - "const { tag: \(tagName), a: \(aName), b: \(bName), cleanup: \(cleanupName) } = globalThis.__bjs_lower_\(helperBase)(\(param.name));" + "const { caseId: \(caseIdName), paramsId: \(paramsIdName), paramsLen: \(paramsLenName), cleanup: \(cleanupName) } = globalThis.__bjs_lower_\(helperBase)(\(param.name));" ) cleanupLines.append("if (\(cleanupName)) { \(cleanupName)(); }") - parameterForwardings.append(contentsOf: [tagName, aName, bName]) + parameterForwardings.append(caseIdName) + parameterForwardings.append(paramsIdName) + parameterForwardings.append(paramsLenName) case .namespaceEnum: break case .jsObject: @@ -724,20 +727,6 @@ struct BridgeJSLink { jsLines.append("") jsLines.append("// Helper factory for \(base) enum") jsLines.append("const __bjs_create\(base)Helpers = () => {") - jsLines.append("const f32buf = new ArrayBuffer(4);".indent(count: 4)) - jsLines.append("const f32dv = new DataView(f32buf);".indent(count: 4)) - jsLines.append("const f64buf = new ArrayBuffer(8);".indent(count: 4)) - jsLines.append("const f64dv = new DataView(f64buf);".indent(count: 4)) - jsLines.append("") - jsLines.append( - "const f32ToI32 = (v) => { f32dv.setFloat32(0, Math.fround(v), true); return f32dv.getInt32(0, true); };" - .indent(count: 4) - ) - jsLines.append( - "const f64ToI32x2 = (v) => { f64dv.setFloat64(0, v, true); return [f64dv.getInt32(0, true), f64dv.getInt32(4, true)]; };" - .indent(count: 4) - ) - jsLines.append("") jsLines.append("return (textEncoder, swift) => ({".indent(count: 4)) jsLines.append("lower: (value) => {".indent(count: 8)) jsLines.append("const t = value.tag;".indent(count: 12)) @@ -745,45 +734,49 @@ struct BridgeJSLink { for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter if enumCase.associatedValues.isEmpty { + jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) + jsLines.append("const paramsBytes = textEncoder.encode(\"{}\");".indent(count: 20)) + jsLines.append("const paramsId = swift.memory.retain(paramsBytes);".indent(count: 20)) jsLines.append( - "case \(base).Tag.\(caseName): return { tag: \(index), a: 0, b: 0 };".indent(count: 16) + "return { caseId: \(index), paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } };" + .indent(count: 20) ) - } else if let av = enumCase.associatedValues.first { - switch av.type { - case .string: - jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) - jsLines.append("const bytes = textEncoder.encode(value.value);".indent(count: 20)) - jsLines.append("const id = swift.memory.retain(bytes);".indent(count: 20)) - jsLines.append( - "return { tag: \(index), a: id, b: bytes.length, cleanup: () => swift.memory.release(id) };" - .indent(count: 20) - ) - jsLines.append("}".indent(count: 16)) - case .bool: - jsLines.append( - "case \(base).Tag.\(caseName): return { tag: \(index), a: (value.value ? 1 : 0), b: 0 };" - .indent(count: 16) - ) - case .int: - jsLines.append( - "case \(base).Tag.\(caseName): return { tag: \(index), a: (value.value | 0), b: 0 };" - .indent(count: 16) - ) - case .float: - jsLines.append( - "case \(base).Tag.\(caseName): return { tag: \(index), a: f32ToI32(value.value), b: 0 };" - .indent(count: 16) - ) - case .double: - jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) - jsLines.append("const [lo, hi] = f64ToI32x2(value.value);".indent(count: 20)) - jsLines.append("return { tag: \(index), a: lo, b: hi };".indent(count: 20)) - jsLines.append("}".indent(count: 16)) - default: - jsLines.append( - "case \(base).Tag.\(caseName): return { tag: \(index), a: 0, b: 0 };".indent(count: 16) - ) + jsLines.append("}".indent(count: 16)) + } else { + jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) + + var parameterObject: [String] = [] + + for (i, av) in enumCase.associatedValues.enumerated() { + let fieldName = av.label ?? "param\(i)" + switch av.type { + case .string: + parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + case .int: + parameterObject.append("\"\(fieldName)\": (value.\(fieldName) | 0)") + case .bool: + parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + case .float: + parameterObject.append("\"\(fieldName)\": Math.fround(value.\(fieldName))") + case .double: + parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + default: + parameterObject.append("\"\(fieldName)\": 0") + } } + + jsLines.append( + "const paramsObj = { \(parameterObject.joined(separator: ", ")) };".indent(count: 20) + ) + jsLines.append("const paramsJson = JSON.stringify(paramsObj);".indent(count: 20)) + jsLines.append("const paramsBytes = textEncoder.encode(paramsJson);".indent(count: 20)) + jsLines.append("const paramsId = swift.memory.retain(paramsBytes);".indent(count: 20)) + jsLines.append( + "return { caseId: \(index), paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } };" + .indent(count: 20) + ) + + jsLines.append("}".indent(count: 16)) } } jsLines.append("default: throw new Error(\"Unknown \(base) tag: \" + String(t));".indent(count: 16)) @@ -798,39 +791,28 @@ struct BridgeJSLink { let caseName = enumCase.name.capitalizedFirstLetter if enumCase.associatedValues.isEmpty { jsLines.append("case \(index): return { tag: \(base).Tag.\(caseName) };".indent(count: 16)) - } else if let av = enumCase.associatedValues.first { - switch av.type { - case .string: - jsLines.append( - "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetString };".indent( - count: 16 - ) - ) - case .bool: - jsLines.append( - "case \(index): return { tag: \(base).Tag.\(caseName), value: (tmpRetInt !== 0) };" - .indent(count: 16) - ) - case .int: - jsLines.append( - "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetInt | 0 };".indent( - count: 16 - ) - ) - case .float: - jsLines.append( - "case \(index): return { tag: \(base).Tag.\(caseName), value: Math.fround(tmpRetF32) };" - .indent(count: 20) - ) - case .double: - jsLines.append( - "case \(index): return { tag: \(base).Tag.\(caseName), value: tmpRetF64 };".indent( - count: 16 - ) - ) - default: - jsLines.append("case \(index): return { tag: \(base).Tag.\(caseName) };".indent(count: 16)) + } else { + var fields: [String] = ["tag: \(base).Tag.\(caseName)"] + + for (i, av) in enumCase.associatedValues.enumerated() { + let fieldName = av.label ?? "param\(i)" + switch av.type { + case .string: + fields.append("\(fieldName): tmpRetString") + case .bool: + fields.append("\(fieldName): (tmpRetInt !== 0)") + case .int: + fields.append("\(fieldName): tmpRetInt | 0") + case .float: + fields.append("\(fieldName): Math.fround(tmpRetF32)") + case .double: + fields.append("\(fieldName): tmpRetF64") + default: + fields.append("\(fieldName): undefined") + } } + + jsLines.append("case \(index): return { \(fields.joined(separator: ", ")) };".indent(count: 16)) } } jsLines.append( @@ -858,15 +840,20 @@ struct BridgeJSLink { let caseName = enumCase.name.capitalizedFirstLetter if enumCase.associatedValues.isEmpty { unionParts.append("{ tag: typeof \(enumDefinition.name).Tag.\(caseName) }") - } else if let av = enumCase.associatedValues.first { - let ts: String - switch av.type { - case .string: ts = "string" - case .bool: ts = "boolean" - case .int, .float, .double: ts = "number" - default: ts = "never" + } else { + var fields: [String] = ["tag: typeof \(enumDefinition.name).Tag.\(caseName)"] + for (i, av) in enumCase.associatedValues.enumerated() { + let fieldName = av.label ?? "param\(i)" + let ts: String + switch av.type { + case .string: ts = "string" + case .bool: ts = "boolean" + case .int, .float, .double: ts = "number" + default: ts = "never" + } + fields.append("\(fieldName): \(ts)") } - unionParts.append("{ tag: typeof \(enumDefinition.name).Tag.\(caseName); value: \(ts) }") + unionParts.append("{ \(fields.joined(separator: "; ")) }") } } dtsBuf.append("export type \(enumDefinition.name) =") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift index c40d8c70..b3c4b82a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift @@ -10,3 +10,14 @@ enum APIResult { @JS func handle(result: APIResult) @JS func getResult() -> APIResult + +@JS +enum ComplexResult { + case success(String) + case error(String, Int) + case status(Bool, String) + case info +} + +@JS func handleComplex(result: ComplexResult) +@JS func getComplexResult() -> ComplexResult diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts index d9fe92a3..51361282 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts @@ -16,11 +16,25 @@ export const APIResult: { }; export type APIResult = - { tag: typeof APIResult.Tag.Success; value: string } | { tag: typeof APIResult.Tag.Failure; value: number } | { tag: typeof APIResult.Tag.Flag; value: boolean } | { tag: typeof APIResult.Tag.Rate; value: number } | { tag: typeof APIResult.Tag.Precise; value: number } | { tag: typeof APIResult.Tag.Info } + { tag: typeof APIResult.Tag.Success; param0: string } | { tag: typeof APIResult.Tag.Failure; param0: number } | { tag: typeof APIResult.Tag.Flag; param0: boolean } | { tag: typeof APIResult.Tag.Rate; param0: number } | { tag: typeof APIResult.Tag.Precise; param0: number } | { tag: typeof APIResult.Tag.Info } + +export const ComplexResult: { + readonly Tag: { + readonly Success: 0; + readonly Error: 1; + readonly Status: 2; + readonly Info: 3; + }; +}; + +export type ComplexResult = + { tag: typeof ComplexResult.Tag.Success; param0: string } | { tag: typeof ComplexResult.Tag.Error; param0: string; param1: number } | { tag: typeof ComplexResult.Tag.Status; param0: boolean; param1: string } | { tag: typeof ComplexResult.Tag.Info } export type Exports = { handle(result: APIResult): void; getResult(): APIResult; + handleComplex(result: ComplexResult): void; + getComplexResult(): ComplexResult; } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index 885193f4..b84c2c42 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -18,48 +18,124 @@ export const APIResult = { // Helper factory for APIResult enum const __bjs_createAPIResultHelpers = () => { - const f32buf = new ArrayBuffer(4); - const f32dv = new DataView(f32buf); - const f64buf = new ArrayBuffer(8); - const f64dv = new DataView(f64buf); - - const f32ToI32 = (v) => { f32dv.setFloat32(0, Math.fround(v), true); return f32dv.getInt32(0, true); }; - const f64ToI32x2 = (v) => { f64dv.setFloat64(0, v, true); return [f64dv.getInt32(0, true), f64dv.getInt32(4, true)]; }; - return (textEncoder, swift) => ({ lower: (value) => { const t = value.tag; switch (t) { case APIResult.Tag.Success: { - const bytes = textEncoder.encode(value.value); - const id = swift.memory.retain(bytes); - return { tag: 0, a: id, b: bytes.length, cleanup: () => swift.memory.release(id) }; + const paramsObj = { "param0": value.param0 }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 0, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case APIResult.Tag.Failure: { + const paramsObj = { "param0": (value.param0 | 0) }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 1, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case APIResult.Tag.Flag: { + const paramsObj = { "param0": value.param0 }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 2, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case APIResult.Tag.Rate: { + const paramsObj = { "param0": Math.fround(value.param0) }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 3, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; } - case APIResult.Tag.Failure: return { tag: 1, a: (value.value | 0), b: 0 }; - case APIResult.Tag.Flag: return { tag: 2, a: (value.value ? 1 : 0), b: 0 }; - case APIResult.Tag.Rate: return { tag: 3, a: f32ToI32(value.value), b: 0 }; case APIResult.Tag.Precise: { - const [lo, hi] = f64ToI32x2(value.value); - return { tag: 4, a: lo, b: hi }; + const paramsObj = { "param0": value.param0 }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 4, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case APIResult.Tag.Info: { + const paramsBytes = textEncoder.encode("{}"); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 5, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; } - case APIResult.Tag.Info: return { tag: 5, a: 0, b: 0 }; default: throw new Error("Unknown APIResult tag: " + String(t)); } }, raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => { const tag = tmpRetTag | 0; switch (tag) { - case 0: return { tag: APIResult.Tag.Success, value: tmpRetString }; - case 1: return { tag: APIResult.Tag.Failure, value: tmpRetInt | 0 }; - case 2: return { tag: APIResult.Tag.Flag, value: (tmpRetInt !== 0) }; - case 3: return { tag: APIResult.Tag.Rate, value: Math.fround(tmpRetF32) }; - case 4: return { tag: APIResult.Tag.Precise, value: tmpRetF64 }; + case 0: return { tag: APIResult.Tag.Success, param0: tmpRetString }; + case 1: return { tag: APIResult.Tag.Failure, param0: tmpRetInt | 0 }; + case 2: return { tag: APIResult.Tag.Flag, param0: (tmpRetInt !== 0) }; + case 3: return { tag: APIResult.Tag.Rate, param0: Math.fround(tmpRetF32) }; + case 4: return { tag: APIResult.Tag.Precise, param0: tmpRetF64 }; case 5: return { tag: APIResult.Tag.Info }; default: throw new Error("Unknown APIResult tag returned from Swift: " + String(tag)); } } }); }; +export const ComplexResult = { + Tag: { + Success: 0, + Error: 1, + Status: 2, + Info: 3, + } +}; + + +// Helper factory for ComplexResult enum +const __bjs_createComplexResultHelpers = () => { + return (textEncoder, swift) => ({ + lower: (value) => { + const t = value.tag; + switch (t) { + case ComplexResult.Tag.Success: { + const paramsObj = { "param0": value.param0 }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 0, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case ComplexResult.Tag.Error: { + const paramsObj = { "param0": value.param0, "param1": (value.param1 | 0) }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 1, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case ComplexResult.Tag.Status: { + const paramsObj = { "param0": value.param0, "param1": value.param1 }; + const paramsJson = JSON.stringify(paramsObj); + const paramsBytes = textEncoder.encode(paramsJson); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 2, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + case ComplexResult.Tag.Info: { + const paramsBytes = textEncoder.encode("{}"); + const paramsId = swift.memory.retain(paramsBytes); + return { caseId: 3, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + } + default: throw new Error("Unknown ComplexResult tag: " + String(t)); + } + }, + raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => { + const tag = tmpRetTag | 0; + switch (tag) { + case 0: return { tag: ComplexResult.Tag.Success, param0: tmpRetString }; + case 1: return { tag: ComplexResult.Tag.Error, param0: tmpRetString, param1: tmpRetInt | 0 }; + case 2: return { tag: ComplexResult.Tag.Status, param0: (tmpRetInt !== 0), param1: tmpRetString }; + case 3: return { tag: ComplexResult.Tag.Info }; + default: throw new Error("Unknown ComplexResult tag returned from Swift: " + String(tag)); + } + } + }); +}; export async function createInstantiator(options, swift) { let instance; @@ -135,6 +211,11 @@ export async function createInstantiator(options, swift) { globalThis.__bjs_lower_APIResult = (value) => APIResultHelpers.lower(value); globalThis.__bjs_raise_APIResult = () => APIResultHelpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64); + // Set up ComplexResult enum helpers + const ComplexResultHelpers = __bjs_createComplexResultHelpers()(textEncoder, swift); + globalThis.__bjs_lower_ComplexResult = (value) => ComplexResultHelpers.lower(value); + globalThis.__bjs_raise_ComplexResult = () => ComplexResultHelpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64); + setException = (error) => { instance.exports._swift_js_exception.value = swift.memory.retain(error) } @@ -145,8 +226,8 @@ export async function createInstantiator(options, swift) { return { handle: function bjs_handle(result) { - const { tag: resultTag, a: resultA, b: resultB, cleanup: resultCleanup } = globalThis.__bjs_lower_APIResult(result); - instance.exports.bjs_handle(resultTag, resultA, resultB); + const { caseId: resultCaseId, paramsId: resultParamsId, paramsLen: resultParamsLen, cleanup: resultCleanup } = globalThis.__bjs_lower_APIResult(result); + instance.exports.bjs_handle(resultCaseId, resultParamsId, resultParamsLen); if (resultCleanup) { resultCleanup(); } }, getResult: function bjs_getResult() { @@ -154,6 +235,16 @@ export async function createInstantiator(options, swift) { const ret = globalThis.__bjs_raise_APIResult(); return ret; }, + handleComplex: function bjs_handleComplex(result) { + const { caseId: resultCaseId, paramsId: resultParamsId, paramsLen: resultParamsLen, cleanup: resultCleanup } = globalThis.__bjs_lower_ComplexResult(result); + instance.exports.bjs_handleComplex(resultCaseId, resultParamsId, resultParamsLen); + if (resultCleanup) { resultCleanup(); } + }, + getComplexResult: function bjs_getComplexResult() { + instance.exports.bjs_getComplexResult(); + const ret = globalThis.__bjs_raise_ComplexResult(); + return ret; + }, }; }, } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json index 289c975c..1652016a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json @@ -75,6 +75,69 @@ "emitStyle" : "const", "name" : "APIResult", "swiftCallName" : "APIResult" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "error" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "status" + }, + { + "associatedValues" : [ + + ], + "name" : "info" + } + ], + "emitStyle" : "const", + "name" : "ComplexResult", + "swiftCallName" : "ComplexResult" } ], "functions" : [ @@ -117,6 +180,46 @@ "_0" : "APIResult" } } + }, + { + "abiName" : "bjs_handleComplex", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "handleComplex", + "parameters" : [ + { + "label" : "result", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_getComplexResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "getComplexResult", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } } ], "moduleName" : "TestModule" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift index 7220c868..083477fa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -6,31 +6,124 @@ @_spi(BridgeJS) import JavaScriptKit +import Foundation + +extension APIResult { + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + case .failure(let param0): + _swift_js_return_tag(Int32(1)) + _swift_js_return_int(Int32(param0)) + case .flag(let param0): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(param0 ? 1 : 0) + case .rate(let param0): + _swift_js_return_tag(Int32(3)) + _swift_js_return_f32(param0) + case .precise(let param0): + _swift_js_return_tag(Int32(4)) + _swift_js_return_f64(param0) + case .info: + _swift_js_return_tag(Int32(5)) + } + } +} + extension APIResult { - init?(bridgeJSTag: Int32, a: Int32, b: Int32) { - switch bridgeJSTag { - case 0: - let s = String(unsafeUninitializedCapacity: Int(b)) { buf in - _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) - return Int(b) - } - self = .success(s) - case 1: - self = .failure(Int(a)) - case 2: - self = .flag((a != 0)) - case 3: - self = .rate(Float(bitPattern: UInt32(bitPattern: a))) - case 4: - let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) - self = .precise(Double(bitPattern: bits)) - case 5: - self = .info - default: - return nil + static func constructFromAPIResult_0(param0: String) -> APIResult { + return .success(param0) +} + + static func constructFromAPIResult_1(param0: Int32) -> APIResult { + return .failure(Int(param0)) +} + + static func constructFromAPIResult_2(param0: Int32) -> APIResult { + return .flag((param0 != 0)) +} + + static func constructFromAPIResult_3(param0: Float32) -> APIResult { + return .rate(param0) +} + + static func constructFromAPIResult_4(param0: Float64) -> APIResult { + return .precise(param0) +} + + static func constructFromAPIResult_5() -> APIResult { + return .info +} + + static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { + let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + return Int(paramsLen) + } + return dispatchConstructFromJson(caseId, paramsString) + } + + static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> APIResult { + switch caseId { + case 0: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String + return constructFromAPIResult_0(param0: param0) + case 1: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Int32 + return constructFromAPIResult_1(param0: param0) + case 2: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = Int32(params["param0"] as! Bool ? 1 : 0) + return constructFromAPIResult_2(param0: param0) + case 3: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Float32 + return constructFromAPIResult_3(param0: param0) + case 4: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Float64 + return constructFromAPIResult_4(param0: param0) + case 5: return constructFromAPIResult_5() + default: fatalError("Unknown APIResult case ID: \(caseId)") } } +} +import Foundation + +extension ComplexResult { func bridgeJSReturn() { @_extern(wasm, module: "bjs", name: "swift_js_return_tag") func _swift_js_return_tag(_: Int32) @@ -43,35 +136,91 @@ extension APIResult { @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) switch self { - case .success(let value): - _swift_js_return_tag(Int32(0)) - var ret = value - ret.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) - } - case .failure(let value): - _swift_js_return_tag(Int32(1)) - _swift_js_return_int(Int32(value)) - case .flag(let value): - _swift_js_return_tag(Int32(2)) - _swift_js_return_int(value ? 1 : 0) - case .rate(let value): - _swift_js_return_tag(Int32(3)) - _swift_js_return_f32(value) - case .precise(let value): - _swift_js_return_tag(Int32(4)) - _swift_js_return_f64(value) + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + case .error(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + _swift_js_return_int(Int32(param1)) + case .status(let param0, let param1): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(param0 ? 1 : 0) + var mutableParam1 = param1 +mutableParam1.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} case .info: - _swift_js_return_tag(Int32(5)) + _swift_js_return_tag(Int32(3)) + } + } +} + +extension ComplexResult { + static func constructFromComplexResult_0(param0: String) -> ComplexResult { + return .success(param0) +} + + static func constructFromComplexResult_1(param0: String, param1: Int32) -> ComplexResult { + return .error(param0, Int(param1)) +} + + static func constructFromComplexResult_2(param0: Int32, param1: String) -> ComplexResult { + return .status((param0 != 0), param1) +} + + static func constructFromComplexResult_3() -> ComplexResult { + return .info +} + + static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { + let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + return Int(paramsLen) + } + return dispatchConstructFromJson(caseId, paramsString) + } + + static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> ComplexResult { + switch caseId { + case 0: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String + return constructFromComplexResult_0(param0: param0) + case 1: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String; let param1 = params["param1"] as! Int32 + return constructFromComplexResult_1(param0: param0, param1: param1) + case 2: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! String + return constructFromComplexResult_2(param0: param0, param1: param1) + case 3: return constructFromComplexResult_3() + default: fatalError("Unknown ComplexResult case ID: \(caseId)") } } } @_expose(wasm, "bjs_handle") @_cdecl("bjs_handle") -public func _bjs_handle(resultTag: Int32, resultA: Int32, resultB: Int32) -> Void { +public func _bjs_handle(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - handle(result: APIResult(bridgeJSTag: resultTag, a: resultA, b: resultB)!) + handle(result: APIResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) #else fatalError("Only available on WebAssembly") #endif @@ -86,4 +235,25 @@ public func _bjs_getResult() -> Void { #else fatalError("Only available on WebAssembly") #endif +} + +@_expose(wasm, "bjs_handleComplex") +@_cdecl("bjs_handleComplex") +public func _bjs_handleComplex(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { + #if arch(wasm32) + handleComplex(result: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getComplexResult") +@_cdecl("bjs_getComplexResult") +public func _bjs_getComplexResult() -> Void { + #if arch(wasm32) + let ret = getComplexResult() + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 873294b4..f31f74bf 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -307,6 +307,38 @@ enum Internal { return .precise(value) } +@JS +enum ComplexResult { + case success(String) + case error(String, Int) + case status(Bool, String) + case info +} + +@JS func echoComplexResult(result: ComplexResult) -> ComplexResult { + return result +} + +@JS func makeComplexResultSuccess(_ value: String) -> ComplexResult { + return .success(value) +} + +@JS func makeComplexResultError(_ message: String, _ code: Int) -> ComplexResult { + return .error(message, code) +} + +@JS func makeComplexResultStatus(_ active: Bool, _ message: String) -> ComplexResult { + return .status(active, message) +} + +@JS func makeComplexResultInfo() -> ComplexResult { + return .info +} + +@JS func roundtripComplexResult(_ result: ComplexResult) -> ComplexResult { + return result +} + class ExportAPITests: XCTestCase { func testAll() { var hasDeinitGreeter = false diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 07613b8c..b9ef463e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -144,31 +144,124 @@ extension Internal.SupportedMethod { } } +import Foundation + extension APIResult { - init?(bridgeJSTag: Int32, a: Int32, b: Int32) { - switch bridgeJSTag { - case 0: - let s = String(unsafeUninitializedCapacity: Int(b)) { buf in - _swift_js_init_memory(a, buf.baseAddress.unsafelyUnwrapped) - return Int(b) - } - self = .success(s) - case 1: - self = .failure(Int(a)) - case 2: - self = .flag((a != 0)) - case 3: - self = .rate(Float(bitPattern: UInt32(bitPattern: a))) - case 4: - let bits = UInt64(UInt32(bitPattern: a)) | (UInt64(UInt32(bitPattern: b)) << 32) - self = .precise(Double(bitPattern: bits)) - case 5: - self = .info - default: - return nil + func bridgeJSReturn() { + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + case .failure(let param0): + _swift_js_return_tag(Int32(1)) + _swift_js_return_int(Int32(param0)) + case .flag(let param0): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(param0 ? 1 : 0) + case .rate(let param0): + _swift_js_return_tag(Int32(3)) + _swift_js_return_f32(param0) + case .precise(let param0): + _swift_js_return_tag(Int32(4)) + _swift_js_return_f64(param0) + case .info: + _swift_js_return_tag(Int32(5)) + } + } +} + +extension APIResult { + static func constructFromAPIResult_0(param0: String) -> APIResult { + return .success(param0) +} + + static func constructFromAPIResult_1(param0: Int32) -> APIResult { + return .failure(Int(param0)) +} + + static func constructFromAPIResult_2(param0: Int32) -> APIResult { + return .flag((param0 != 0)) +} + + static func constructFromAPIResult_3(param0: Float32) -> APIResult { + return .rate(param0) +} + + static func constructFromAPIResult_4(param0: Float64) -> APIResult { + return .precise(param0) +} + + static func constructFromAPIResult_5() -> APIResult { + return .info +} + + static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { + let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + return Int(paramsLen) + } + return dispatchConstructFromJson(caseId, paramsString) + } + + static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> APIResult { + switch caseId { + case 0: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String + return constructFromAPIResult_0(param0: param0) + case 1: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Int32 + return constructFromAPIResult_1(param0: param0) + case 2: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = Int32(params["param0"] as! Bool ? 1 : 0) + return constructFromAPIResult_2(param0: param0) + case 3: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Float32 + return constructFromAPIResult_3(param0: param0) + case 4: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! Float64 + return constructFromAPIResult_4(param0: param0) + case 5: return constructFromAPIResult_5() + default: fatalError("Unknown APIResult case ID: \(caseId)") } } +} + +import Foundation +extension ComplexResult { func bridgeJSReturn() { @_extern(wasm, module: "bjs", name: "swift_js_return_tag") func _swift_js_return_tag(_: Int32) @@ -181,26 +274,82 @@ extension APIResult { @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) switch self { - case .success(let value): - _swift_js_return_tag(Int32(0)) - var ret = value - ret.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) - } - case .failure(let value): - _swift_js_return_tag(Int32(1)) - _swift_js_return_int(Int32(value)) - case .flag(let value): - _swift_js_return_tag(Int32(2)) - _swift_js_return_int(value ? 1 : 0) - case .rate(let value): - _swift_js_return_tag(Int32(3)) - _swift_js_return_f32(value) - case .precise(let value): - _swift_js_return_tag(Int32(4)) - _swift_js_return_f64(value) + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + case .error(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var mutableParam0 = param0 +mutableParam0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + _swift_js_return_int(Int32(param1)) + case .status(let param0, let param1): + _swift_js_return_tag(Int32(2)) + _swift_js_return_int(param0 ? 1 : 0) + var mutableParam1 = param1 +mutableParam1.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} case .info: - _swift_js_return_tag(Int32(5)) + _swift_js_return_tag(Int32(3)) + } + } +} + +extension ComplexResult { + static func constructFromComplexResult_0(param0: String) -> ComplexResult { + return .success(param0) +} + + static func constructFromComplexResult_1(param0: String, param1: Int32) -> ComplexResult { + return .error(param0, Int(param1)) +} + + static func constructFromComplexResult_2(param0: Int32, param1: String) -> ComplexResult { + return .status((param0 != 0), param1) +} + + static func constructFromComplexResult_3() -> ComplexResult { + return .info +} + + static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { + let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + return Int(paramsLen) + } + return dispatchConstructFromJson(caseId, paramsString) + } + + static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> ComplexResult { + switch caseId { + case 0: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String + return constructFromComplexResult_0(param0: param0) + case 1: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = params["param0"] as! String; let param1 = params["param1"] as! Int32 + return constructFromComplexResult_1(param0: param0, param1: param1) + case 2: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! String + return constructFromComplexResult_2(param0: param0, param1: param1) + case 3: return constructFromComplexResult_3() + default: fatalError("Unknown ComplexResult case ID: \(caseId)") } } } @@ -834,9 +983,9 @@ public func _bjs_getTSTheme() -> Void { @_expose(wasm, "bjs_echoAPIResult") @_cdecl("bjs_echoAPIResult") -public func _bjs_echoAPIResult(resultTag: Int32, resultA: Int32, resultB: Int32) -> Void { +public func _bjs_echoAPIResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - let ret = echoAPIResult(result: APIResult(bridgeJSTag: resultTag, a: resultA, b: resultB)!) + let ret = echoAPIResult(result: APIResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) ret.bridgeJSReturn() #else fatalError("Only available on WebAssembly") @@ -913,6 +1062,84 @@ public func _bjs_makeAPIResultPrecise(value: Float64) -> Void { #endif } +@_expose(wasm, "bjs_echoComplexResult") +@_cdecl("bjs_echoComplexResult") +public func _bjs_echoComplexResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { + #if arch(wasm32) + let ret = echoComplexResult(result: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultSuccess") +@_cdecl("bjs_makeComplexResultSuccess") +public func _bjs_makeComplexResultSuccess(valueBytes: Int32, valueLen: Int32) -> Void { + #if arch(wasm32) + let value = String(unsafeUninitializedCapacity: Int(valueLen)) { b in + _swift_js_init_memory(valueBytes, b.baseAddress.unsafelyUnwrapped) + return Int(valueLen) + } + let ret = makeComplexResultSuccess(_: value) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultError") +@_cdecl("bjs_makeComplexResultError") +public func _bjs_makeComplexResultError(messageBytes: Int32, messageLen: Int32, code: Int32) -> Void { + #if arch(wasm32) + let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in + _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) + return Int(messageLen) + } + let ret = makeComplexResultError(_: message, _: Int(code)) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultStatus") +@_cdecl("bjs_makeComplexResultStatus") +public func _bjs_makeComplexResultStatus(active: Int32, messageBytes: Int32, messageLen: Int32) -> Void { + #if arch(wasm32) + let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in + _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) + return Int(messageLen) + } + let ret = makeComplexResultStatus(_: active == 1, _: message) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultInfo") +@_cdecl("bjs_makeComplexResultInfo") +public func _bjs_makeComplexResultInfo() -> Void { + #if arch(wasm32) + let ret = makeComplexResultInfo() + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripComplexResult") +@_cdecl("bjs_roundtripComplexResult") +public func _bjs_roundtripComplexResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { + #if arch(wasm32) + let ret = roundtripComplexResult(_: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_init") @_cdecl("bjs_Greeter_init") public func _bjs_Greeter_init(nameBytes: Int32, nameLen: Int32) -> UnsafeMutableRawPointer { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index fa1d2120..0184c7ad 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -645,6 +645,69 @@ "emitStyle" : "const", "name" : "APIResult", "swiftCallName" : "APIResult" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "error" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "status" + }, + { + "associatedValues" : [ + + ], + "name" : "info" + } + ], + "emitStyle" : "const", + "name" : "ComplexResult", + "swiftCallName" : "ComplexResult" } ], "functions" : [ @@ -1717,6 +1780,160 @@ "_0" : "APIResult" } } + }, + { + "abiName" : "bjs_echoComplexResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "echoComplexResult", + "parameters" : [ + { + "label" : "result", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_makeComplexResultSuccess", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultSuccess", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_makeComplexResultError", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultError", + "parameters" : [ + { + "label" : "_", + "name" : "message", + "type" : { + "string" : { + + } + } + }, + { + "label" : "_", + "name" : "code", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_makeComplexResultStatus", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultStatus", + "parameters" : [ + { + "label" : "_", + "name" : "active", + "type" : { + "bool" : { + + } + } + }, + { + "label" : "_", + "name" : "message", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_makeComplexResultInfo", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultInfo", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_roundtripComplexResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "roundtripComplexResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } } ], "moduleName" : "BridgeJSRuntimeTests" diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index f12b1931..35d1aa83 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1,7 +1,7 @@ // @ts-check -import { - Direction, Status, Theme, HttpStatus, TSDirection, TSTheme, APIResult +import { + Direction, Status, Theme, HttpStatus, TSDirection, TSTheme, APIResult, ComplexResult } from '../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ @@ -252,35 +252,55 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { const globalTestServer = new globalThis.Networking.APIV2.Internal.TestServer(); globalTestServer.call(globalThis.Networking.APIV2.Internal.SupportedMethod.Post); globalTestServer.release(); - - const s1 = { tag: APIResult.Tag.Success, value: "Cześć 🙋‍♂️" }; - const f1 = { tag: APIResult.Tag.Failure, value: 42 }; + + const s1 = { tag: APIResult.Tag.Success, param0: "Cześć 🙋‍♂️" }; + const f1 = { tag: APIResult.Tag.Failure, param0: 42 }; const i1 = { tag: APIResult.Tag.Info }; - + assert.deepEqual(exports.echoAPIResult(s1), s1); assert.deepEqual(exports.echoAPIResult(f1), f1); assert.deepEqual(exports.echoAPIResult(i1), i1); - assert.deepEqual(exports.makeAPIResultSuccess("ok"), { tag: APIResult.Tag.Success, value: "ok" }); - assert.deepEqual(exports.makeAPIResultFailure(123), { tag: APIResult.Tag.Failure, value: 123 }); + + assert.deepEqual(exports.makeAPIResultSuccess("Test"), { tag: APIResult.Tag.Success, param0: "Test" }); + assert.deepEqual(exports.makeAPIResultSuccess("ok"), { tag: APIResult.Tag.Success, param0: "ok" }); + assert.deepEqual(exports.makeAPIResultFailure(123), { tag: APIResult.Tag.Failure, param0: 123 }); assert.deepEqual(exports.makeAPIResultInfo(), { tag: APIResult.Tag.Info }); - - const bTrue = { tag: APIResult.Tag.Flag, value: true }; - const bFalse = { tag: APIResult.Tag.Flag, value: false }; - assert.deepEqual(exports.echoAPIResult(bTrue), bTrue); - assert.deepEqual(exports.echoAPIResult(bFalse), bFalse); + + const bTrue = { tag: APIResult.Tag.Flag, param0: true }; + const bFalse = { tag: APIResult.Tag.Flag, param0: false }; assert.deepEqual(exports.makeAPIResultFlag(true), bTrue); assert.deepEqual(exports.makeAPIResultFlag(false), bFalse); - + const rVal = 3.25; - const r1 = { tag: APIResult.Tag.Rate, value: rVal }; + const r1 = { tag: APIResult.Tag.Rate, param0: rVal }; assert.deepEqual(exports.echoAPIResult(r1), r1); assert.deepEqual(exports.makeAPIResultRate(rVal), r1); - + const pVal = 3.141592653589793; - const p1 = { tag: APIResult.Tag.Precise, value: pVal }; + const p1 = { tag: APIResult.Tag.Precise, param0: pVal }; assert.deepEqual(exports.echoAPIResult(p1), p1); assert.deepEqual(exports.makeAPIResultPrecise(pVal), p1); + + const cs1 = { tag: ComplexResult.Tag.Success, param0: "All good!" }; + const ce1 = { tag: ComplexResult.Tag.Error, param0: "Network error", param1: 503 }; + const cst1 = { tag: ComplexResult.Tag.Status, param0: true, param1: "OK" }; + const ci1 = { tag: ComplexResult.Tag.Info }; + + assert.deepEqual(exports.echoComplexResult(cs1), cs1); + assert.deepEqual(exports.echoComplexResult(ce1), ce1); + assert.deepEqual(exports.echoComplexResult(cst1), cst1); + assert.deepEqual(exports.echoComplexResult(ci1), ci1); + + assert.deepEqual(exports.roundtripComplexResult(cs1), cs1); + assert.deepEqual(exports.roundtripComplexResult(ce1), ce1); + assert.deepEqual(exports.roundtripComplexResult(cst1), cst1); + assert.deepEqual(exports.roundtripComplexResult(ci1), ci1); + + assert.deepEqual(exports.makeComplexResultSuccess("Great!"), { tag: ComplexResult.Tag.Success, param0: "Great!" }); + assert.deepEqual(exports.makeComplexResultError("Timeout", 408), { tag: ComplexResult.Tag.Error, param0: "Timeout", param1: 408 }); + assert.deepEqual(exports.makeComplexResultStatus(false, "Internal Server Error"), { tag: ComplexResult.Tag.Status, param0: false, param1: "Internal Server Error" }); + assert.deepEqual(exports.makeComplexResultInfo(), { tag: ComplexResult.Tag.Info }); } /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ From f49e5705613b2e6454d787b683cceec54967506f Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 25 Aug 2025 17:59:50 +0200 Subject: [PATCH 3/4] BridgeJS: Add support for multiple associatedValues of same type naively --- .../Sources/BridgeJSCore/ExportSwift.swift | 4 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 63 +++++++++++--- .../Inputs/EnumAssociatedValue.swift | 2 +- .../ArrayParameter.Import.js | 38 +++++++-- .../BridgeJSLinkTests/Async.Export.js | 38 +++++++-- .../BridgeJSLinkTests/Async.Import.js | 38 +++++++-- .../EnumAssociatedValue.Export.d.ts | 2 +- .../EnumAssociatedValue.Export.js | 64 +++++++++----- .../BridgeJSLinkTests/EnumCase.Export.js | 38 +++++++-- .../BridgeJSLinkTests/EnumNamespace.Export.js | 38 +++++++-- .../BridgeJSLinkTests/EnumRawType.Export.js | 38 +++++++-- .../BridgeJSLinkTests/Interface.Import.js | 38 +++++++-- .../MultipleImportedTypes.Import.js | 38 +++++++-- .../BridgeJSLinkTests/Namespaces.Export.js | 38 +++++++-- .../PrimitiveParameters.Export.js | 38 +++++++-- .../PrimitiveParameters.Import.js | 38 +++++++-- .../PrimitiveReturn.Export.js | 38 +++++++-- .../PrimitiveReturn.Import.js | 38 +++++++-- .../StringParameter.Export.js | 38 +++++++-- .../StringParameter.Import.js | 38 +++++++-- .../BridgeJSLinkTests/StringReturn.Export.js | 38 +++++++-- .../BridgeJSLinkTests/StringReturn.Import.js | 38 +++++++-- .../BridgeJSLinkTests/SwiftClass.Export.js | 38 +++++++-- .../TS2SkeletonLike.Import.js | 38 +++++++-- .../BridgeJSLinkTests/Throws.Export.js | 38 +++++++-- .../BridgeJSLinkTests/TypeAlias.Import.js | 38 +++++++-- .../TypeScriptClass.Import.js | 38 +++++++-- .../VoidParameterVoidReturn.Export.js | 38 +++++++-- .../VoidParameterVoidReturn.Import.js | 38 +++++++-- .../ExportSwiftTests/EnumAssociatedValue.json | 7 ++ .../EnumAssociatedValue.swift | 23 +++-- .../BridgeJSRuntimeTests/ExportAPITests.swift | 11 ++- .../Generated/BridgeJS.ExportSwift.swift | 67 +++++++++++---- .../JavaScript/BridgeJS.ExportSwift.json | 84 +++++++++++++++++++ Tests/prelude.mjs | 8 +- 35 files changed, 1040 insertions(+), 207 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index be49c791..cbfc5e83 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1298,6 +1298,8 @@ public class ExportSwift { func _swift_js_return_f32(_: Float32) @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) \(raw: returnSwitch) } } @@ -1473,7 +1475,7 @@ public class ExportSwift { case .int: returnStatements.append("_swift_js_return_int(Int32(\(paramName)))") case .bool: - returnStatements.append("_swift_js_return_int(\(paramName) ? 1 : 0)") + returnStatements.append("_swift_js_return_bool(\(paramName) ? 1 : 0)") case .float: returnStatements.append("_swift_js_return_f32(\(paramName))") case .double: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 34ba0d7f..8d5b0fe2 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -226,12 +226,18 @@ struct BridgeJSLink { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -243,7 +249,9 @@ struct BridgeJSLink { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len)\(sharedMemory ? ".slice()" : ""); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -270,15 +278,33 @@ struct BridgeJSLink { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } \(renderSwiftClassWrappers().map { $0.indent(count: 12) }.joined(separator: "\n")) \(importObjectBuilders.flatMap { $0.importedLines }.map { $0.indent(count: 12) }.joined(separator: "\n")) @@ -340,7 +366,7 @@ struct BridgeJSLink { lines.append("const \(base)Helpers = __bjs_create\(base)Helpers()(textEncoder, swift);") lines.append("globalThis.__bjs_lower_\(base) = (value) => \(base)Helpers.lower(value);") lines.append( - "globalThis.__bjs_raise_\(base) = () => \(base)Helpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64);" + "globalThis.__bjs_raise_\(base) = () => \(base)Helpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools);" ) lines.append("") } @@ -783,7 +809,7 @@ struct BridgeJSLink { jsLines.append("}".indent(count: 12)) jsLines.append("},".indent(count: 8)) jsLines.append( - "raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => {".indent(count: 8) + "raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => {".indent(count: 8) ) jsLines.append("const tag = tmpRetTag | 0;".indent(count: 12)) jsLines.append("switch (tag) {".indent(count: 12)) @@ -794,19 +820,30 @@ struct BridgeJSLink { } else { var fields: [String] = ["tag: \(base).Tag.\(caseName)"] + var stringIndex = 0 + var intIndex = 0 + var f32Index = 0 + var f64Index = 0 + var boolIndex = 0 + for (i, av) in enumCase.associatedValues.enumerated() { let fieldName = av.label ?? "param\(i)" switch av.type { case .string: - fields.append("\(fieldName): tmpRetString") + fields.append("\(fieldName): tmpRetStrings[\(stringIndex)]") + stringIndex += 1 case .bool: - fields.append("\(fieldName): (tmpRetInt !== 0)") + fields.append("\(fieldName): tmpRetBools[\(boolIndex)]") + boolIndex += 1 case .int: - fields.append("\(fieldName): tmpRetInt | 0") + fields.append("\(fieldName): tmpRetInts[\(intIndex)]") + intIndex += 1 case .float: - fields.append("\(fieldName): Math.fround(tmpRetF32)") + fields.append("\(fieldName): tmpRetF32s[\(f32Index)]") + f32Index += 1 case .double: - fields.append("\(fieldName): tmpRetF64") + fields.append("\(fieldName): tmpRetF64s[\(f64Index)]") + f64Index += 1 default: fields.append("\(fieldName): undefined") } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift index b3c4b82a..44530f99 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift @@ -15,7 +15,7 @@ enum APIResult { enum ComplexResult { case success(String) case error(String, Int) - case status(Bool, String) + case status(Bool, Int, String) case info } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js index dbad58bc..a152d509 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js index da94f9c8..4fc88260 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js index fc6980e9..6abd29e2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts index 51361282..c33cabdc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts @@ -28,7 +28,7 @@ export const ComplexResult: { }; export type ComplexResult = - { tag: typeof ComplexResult.Tag.Success; param0: string } | { tag: typeof ComplexResult.Tag.Error; param0: string; param1: number } | { tag: typeof ComplexResult.Tag.Status; param0: boolean; param1: string } | { tag: typeof ComplexResult.Tag.Info } + { tag: typeof ComplexResult.Tag.Success; param0: string } | { tag: typeof ComplexResult.Tag.Error; param0: string; param1: number } | { tag: typeof ComplexResult.Tag.Status; param0: boolean; param1: number; param2: string } | { tag: typeof ComplexResult.Tag.Info } export type Exports = { handle(result: APIResult): void; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index b84c2c42..baa84bbf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -65,14 +65,14 @@ const __bjs_createAPIResultHelpers = () => { default: throw new Error("Unknown APIResult tag: " + String(t)); } }, - raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => { + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { const tag = tmpRetTag | 0; switch (tag) { - case 0: return { tag: APIResult.Tag.Success, param0: tmpRetString }; - case 1: return { tag: APIResult.Tag.Failure, param0: tmpRetInt | 0 }; - case 2: return { tag: APIResult.Tag.Flag, param0: (tmpRetInt !== 0) }; - case 3: return { tag: APIResult.Tag.Rate, param0: Math.fround(tmpRetF32) }; - case 4: return { tag: APIResult.Tag.Precise, param0: tmpRetF64 }; + case 0: return { tag: APIResult.Tag.Success, param0: tmpRetStrings[0] }; + case 1: return { tag: APIResult.Tag.Failure, param0: tmpRetInts[0] }; + case 2: return { tag: APIResult.Tag.Flag, param0: tmpRetBools[0] }; + case 3: return { tag: APIResult.Tag.Rate, param0: tmpRetF32s[0] }; + case 4: return { tag: APIResult.Tag.Precise, param0: tmpRetF64s[0] }; case 5: return { tag: APIResult.Tag.Info }; default: throw new Error("Unknown APIResult tag returned from Swift: " + String(tag)); } @@ -110,7 +110,7 @@ const __bjs_createComplexResultHelpers = () => { return { caseId: 1, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; } case ComplexResult.Tag.Status: { - const paramsObj = { "param0": value.param0, "param1": value.param1 }; + const paramsObj = { "param0": value.param0, "param1": (value.param1 | 0), "param2": value.param2 }; const paramsJson = JSON.stringify(paramsObj); const paramsBytes = textEncoder.encode(paramsJson); const paramsId = swift.memory.retain(paramsBytes); @@ -124,12 +124,12 @@ const __bjs_createComplexResultHelpers = () => { default: throw new Error("Unknown ComplexResult tag: " + String(t)); } }, - raise: (tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64) => { + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { const tag = tmpRetTag | 0; switch (tag) { - case 0: return { tag: ComplexResult.Tag.Success, param0: tmpRetString }; - case 1: return { tag: ComplexResult.Tag.Error, param0: tmpRetString, param1: tmpRetInt | 0 }; - case 2: return { tag: ComplexResult.Tag.Status, param0: (tmpRetInt !== 0), param1: tmpRetString }; + case 0: return { tag: ComplexResult.Tag.Success, param0: tmpRetStrings[0] }; + case 1: return { tag: ComplexResult.Tag.Error, param0: tmpRetStrings[0], param1: tmpRetInts[0] }; + case 2: return { tag: ComplexResult.Tag.Status, param0: tmpRetBools[0], param1: tmpRetInts[0], param2: tmpRetStrings[0] }; case 3: return { tag: ComplexResult.Tag.Info }; default: throw new Error("Unknown ComplexResult tag returned from Swift: " + String(tag)); } @@ -145,12 +145,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -162,7 +168,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -189,15 +197,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } @@ -209,12 +235,12 @@ export async function createInstantiator(options, swift) { // Set up APIResult enum helpers const APIResultHelpers = __bjs_createAPIResultHelpers()(textEncoder, swift); globalThis.__bjs_lower_APIResult = (value) => APIResultHelpers.lower(value); - globalThis.__bjs_raise_APIResult = () => APIResultHelpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64); + globalThis.__bjs_raise_APIResult = () => APIResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); // Set up ComplexResult enum helpers const ComplexResultHelpers = __bjs_createComplexResultHelpers()(textEncoder, swift); globalThis.__bjs_lower_ComplexResult = (value) => ComplexResultHelpers.lower(value); - globalThis.__bjs_raise_ComplexResult = () => ComplexResultHelpers.raise(tmpRetTag, tmpRetString, tmpRetInt, tmpRetF32, tmpRetF64); + globalThis.__bjs_raise_ComplexResult = () => ComplexResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); setException = (error) => { instance.exports._swift_js_exception.value = swift.memory.retain(error) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js index 02ba21d8..03c7aec0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js @@ -33,12 +33,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -50,7 +56,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -77,15 +85,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js index 0bfc3147..355b2b46 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js @@ -59,12 +59,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -76,7 +82,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -103,15 +111,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js index a207953e..37b2312b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js @@ -88,12 +88,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -105,7 +111,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -132,15 +140,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js index 50889b14..937319ec 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js index 00490085..70254dc6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js index b5cf3bf7..0b92acfa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js index 888cc3f3..895298db 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js index de2d4c24..936367d4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js index 8ed08191..c89bc604 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js index 11ca14f7..f5bbfbc0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js index 30149c58..5bad7ab4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js index 8d3bc959..c9f577c8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js index a961621b..f113dbbb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js index e6aff66e..093080cc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js index c43e948c..842833b5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js index e8f762b2..814a7680 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js index 0b1d2994..a82ba566 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js index b2811bd1..e80cb987 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js index ccb3b061..24a28819 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js index 60fdbac6..8e77db43 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js index 4cbf6739..9a84b030 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js @@ -12,12 +12,18 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetBytes; - let tmpRetException; - let tmpRetTag; let tmpRetInt; let tmpRetF32; let tmpRetF64; + let tmpRetBytes; + let tmpRetException; + let tmpRetTag; + + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpRetBools = []; return { /** @@ -29,7 +35,9 @@ export async function createInstantiator(options, swift) { const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + const value = textDecoder.decode(bytes); + tmpRetString = value; + tmpRetStrings.push(value); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -56,15 +64,33 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; + tmpRetString = undefined; + tmpRetInt = undefined; + tmpRetF32 = undefined; + tmpRetF64 = undefined; + tmpRetStrings = []; + tmpRetInts = []; + tmpRetF32s = []; + tmpRetF64s = []; + tmpRetBools = []; } bjs["swift_js_return_int"] = function(v) { - tmpRetInt = v | 0; + const value = v | 0; + tmpRetInt = value; + tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { - tmpRetF32 = Math.fround(v); + const value = Math.fround(v); + tmpRetF32 = value; + tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { tmpRetF64 = v; + tmpRetF64s.push(v); + } + bjs["swift_js_return_bool"] = function(v) { + const value = v !== 0; + tmpRetBools.push(value); } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json index 1652016a..f36d10fd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json @@ -118,6 +118,13 @@ } } }, + { + "type" : { + "int" : { + + } + } + }, { "type" : { "string" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift index 083477fa..d844c163 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -20,6 +20,8 @@ extension APIResult { func _swift_js_return_f32(_: Float32) @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) @@ -32,7 +34,7 @@ mutableParam0.withUTF8 { ptr in _swift_js_return_int(Int32(param0)) case .flag(let param0): _swift_js_return_tag(Int32(2)) - _swift_js_return_int(param0 ? 1 : 0) + _swift_js_return_bool(param0 ? 1 : 0) case .rate(let param0): _swift_js_return_tag(Int32(3)) _swift_js_return_f32(param0) @@ -135,6 +137,8 @@ extension ComplexResult { func _swift_js_return_f32(_: Float32) @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) @@ -149,11 +153,12 @@ mutableParam0.withUTF8 { ptr in _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } _swift_js_return_int(Int32(param1)) - case .status(let param0, let param1): + case .status(let param0, let param1, let param2): _swift_js_return_tag(Int32(2)) - _swift_js_return_int(param0 ? 1 : 0) - var mutableParam1 = param1 -mutableParam1.withUTF8 { ptr in + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var mutableParam2 = param2 +mutableParam2.withUTF8 { ptr in _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } case .info: @@ -171,8 +176,8 @@ extension ComplexResult { return .error(param0, Int(param1)) } - static func constructFromComplexResult_2(param0: Int32, param1: String) -> ComplexResult { - return .status((param0 != 0), param1) + static func constructFromComplexResult_2(param0: Int32, param1: Int32, param2: String) -> ComplexResult { + return .status((param0 != 0), Int(param1), param2) } static func constructFromComplexResult_3() -> ComplexResult { @@ -208,8 +213,8 @@ extension ComplexResult { let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { fatalError("Failed to parse parameters JSON") } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! String - return constructFromComplexResult_2(param0: param0, param1: param1) + let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! Int32; let param2 = params["param2"] as! String + return constructFromComplexResult_2(param0: param0, param1: param1, param2: param2) case 3: return constructFromComplexResult_3() default: fatalError("Unknown ComplexResult case ID: \(caseId)") } diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index f31f74bf..b17b15fa 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -311,7 +311,8 @@ enum Internal { enum ComplexResult { case success(String) case error(String, Int) - case status(Bool, String) + case location(Double, Double, String) + case status(Bool, Int, String) case info } @@ -327,8 +328,12 @@ enum ComplexResult { return .error(message, code) } -@JS func makeComplexResultStatus(_ active: Bool, _ message: String) -> ComplexResult { - return .status(active, message) +@JS func makeComplexResultLocation(_ lat: Double, _ lng: Double, _ name: String) -> ComplexResult { + return .location(lat, lng, name) +} + +@JS func makeComplexResultStatus(_ active: Bool, _ code: Int, _ message: String) -> ComplexResult { + return .status(active, code, message) } @JS func makeComplexResultInfo() -> ComplexResult { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index b9ef463e..dc314f9b 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -158,6 +158,8 @@ extension APIResult { func _swift_js_return_f32(_: Float32) @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) @@ -170,7 +172,7 @@ mutableParam0.withUTF8 { ptr in _swift_js_return_int(Int32(param0)) case .flag(let param0): _swift_js_return_tag(Int32(2)) - _swift_js_return_int(param0 ? 1 : 0) + _swift_js_return_bool(param0 ? 1 : 0) case .rate(let param0): _swift_js_return_tag(Int32(3)) _swift_js_return_f32(param0) @@ -273,6 +275,8 @@ extension ComplexResult { func _swift_js_return_f32(_: Float32) @_extern(wasm, module: "bjs", name: "swift_js_return_f64") func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) @@ -287,15 +291,24 @@ mutableParam0.withUTF8 { ptr in _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } _swift_js_return_int(Int32(param1)) - case .status(let param0, let param1): + case .location(let param0, let param1, let param2): _swift_js_return_tag(Int32(2)) - _swift_js_return_int(param0 ? 1 : 0) - var mutableParam1 = param1 -mutableParam1.withUTF8 { ptr in + _swift_js_return_f64(param0) + _swift_js_return_f64(param1) + var mutableParam2 = param2 +mutableParam2.withUTF8 { ptr in _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - case .info: + case .status(let param0, let param1, let param2): _swift_js_return_tag(Int32(3)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var mutableParam2 = param2 +mutableParam2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) +} + case .info: + _swift_js_return_tag(Int32(4)) } } } @@ -309,11 +322,15 @@ extension ComplexResult { return .error(param0, Int(param1)) } - static func constructFromComplexResult_2(param0: Int32, param1: String) -> ComplexResult { - return .status((param0 != 0), param1) + static func constructFromComplexResult_2(param0: Float64, param1: Float64, param2: String) -> ComplexResult { + return .location(param0, param1, param2) } - static func constructFromComplexResult_3() -> ComplexResult { + static func constructFromComplexResult_3(param0: Int32, param1: Int32, param2: String) -> ComplexResult { + return .status((param0 != 0), Int(param1), param2) +} + + static func constructFromComplexResult_4() -> ComplexResult { return .info } @@ -346,9 +363,16 @@ extension ComplexResult { let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { fatalError("Failed to parse parameters JSON") } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! String - return constructFromComplexResult_2(param0: param0, param1: param1) - case 3: return constructFromComplexResult_3() + let param0 = params["param0"] as! Float64; let param1 = params["param1"] as! Float64; let param2 = params["param2"] as! String + return constructFromComplexResult_2(param0: param0, param1: param1, param2: param2) + case 3: + guard let data = paramsJson.data(using: .utf8), + let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + fatalError("Failed to parse parameters JSON") + } + let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! Int32; let param2 = params["param2"] as! String + return constructFromComplexResult_3(param0: param0, param1: param1, param2: param2) + case 4: return constructFromComplexResult_4() default: fatalError("Unknown ComplexResult case ID: \(caseId)") } } @@ -1103,15 +1127,30 @@ public func _bjs_makeComplexResultError(messageBytes: Int32, messageLen: Int32, #endif } +@_expose(wasm, "bjs_makeComplexResultLocation") +@_cdecl("bjs_makeComplexResultLocation") +public func _bjs_makeComplexResultLocation(lat: Float64, lng: Float64, nameBytes: Int32, nameLen: Int32) -> Void { + #if arch(wasm32) + let name = String(unsafeUninitializedCapacity: Int(nameLen)) { b in + _swift_js_init_memory(nameBytes, b.baseAddress.unsafelyUnwrapped) + return Int(nameLen) + } + let ret = makeComplexResultLocation(_: lat, _: lng, _: name) + ret.bridgeJSReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_makeComplexResultStatus") @_cdecl("bjs_makeComplexResultStatus") -public func _bjs_makeComplexResultStatus(active: Int32, messageBytes: Int32, messageLen: Int32) -> Void { +public func _bjs_makeComplexResultStatus(active: Int32, code: Int32, messageBytes: Int32, messageLen: Int32) -> Void { #if arch(wasm32) let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) return Int(messageLen) } - let ret = makeComplexResultStatus(_: active == 1, _: message) + let ret = makeComplexResultStatus(_: active == 1, _: Int(code), _: message) ret.bridgeJSReturn() #else fatalError("Only available on WebAssembly") diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index 0184c7ad..a3139ac0 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -679,6 +679,32 @@ ], "name" : "error" }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "location" + }, { "associatedValues" : [ { @@ -688,6 +714,13 @@ } } }, + { + "type" : { + "int" : { + + } + } + }, { "type" : { "string" : { @@ -1862,6 +1895,48 @@ } } }, + { + "abiName" : "bjs_makeComplexResultLocation", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultLocation", + "parameters" : [ + { + "label" : "_", + "name" : "lat", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "lng", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, { "abiName" : "bjs_makeComplexResultStatus", "effects" : { @@ -1879,6 +1954,15 @@ } } }, + { + "label" : "_", + "name" : "code", + "type" : { + "int" : { + + } + } + }, { "label" : "_", "name" : "message", diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 35d1aa83..e49bde15 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -284,22 +284,26 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { const cs1 = { tag: ComplexResult.Tag.Success, param0: "All good!" }; const ce1 = { tag: ComplexResult.Tag.Error, param0: "Network error", param1: 503 }; - const cst1 = { tag: ComplexResult.Tag.Status, param0: true, param1: "OK" }; + const cl1 = { tag: ComplexResult.Tag.Location, param0: 37.7749, param1: -122.4194, param2: "San Francisco" }; + const cst1 = { tag: ComplexResult.Tag.Status, param0: true, param1: 200, param2: "OK" }; const ci1 = { tag: ComplexResult.Tag.Info }; assert.deepEqual(exports.echoComplexResult(cs1), cs1); assert.deepEqual(exports.echoComplexResult(ce1), ce1); + assert.deepEqual(exports.echoComplexResult(cl1), cl1); assert.deepEqual(exports.echoComplexResult(cst1), cst1); assert.deepEqual(exports.echoComplexResult(ci1), ci1); assert.deepEqual(exports.roundtripComplexResult(cs1), cs1); assert.deepEqual(exports.roundtripComplexResult(ce1), ce1); + assert.deepEqual(exports.roundtripComplexResult(cl1), cl1); assert.deepEqual(exports.roundtripComplexResult(cst1), cst1); assert.deepEqual(exports.roundtripComplexResult(ci1), ci1); assert.deepEqual(exports.makeComplexResultSuccess("Great!"), { tag: ComplexResult.Tag.Success, param0: "Great!" }); assert.deepEqual(exports.makeComplexResultError("Timeout", 408), { tag: ComplexResult.Tag.Error, param0: "Timeout", param1: 408 }); - assert.deepEqual(exports.makeComplexResultStatus(false, "Internal Server Error"), { tag: ComplexResult.Tag.Status, param0: false, param1: "Internal Server Error" }); + assert.deepEqual(exports.makeComplexResultLocation(40.7128, -74.0060, "New York"), { tag: ComplexResult.Tag.Location, param0: 40.7128, param1: -74.0060, param2: "New York" }); + assert.deepEqual(exports.makeComplexResultStatus(false, 500, "Internal Server Error"), { tag: ComplexResult.Tag.Status, param0: false, param1: 500, param2: "Internal Server Error" }); assert.deepEqual(exports.makeComplexResultInfo(), { tag: ComplexResult.Tag.Info }); } From 18355f2716540d21a9278290f1285a73a519ec69 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 25 Aug 2025 22:20:53 +0200 Subject: [PATCH 4/4] BridgeJS: Binary format migration for multiple associated values in enums with helper functions --- .../Sources/BridgeJSCore/ExportSwift.swift | 617 +++++---------- .../BridgeJSCore/TypeDeclResolver.swift | 22 + .../Sources/BridgeJSLink/BridgeJSLink.swift | 339 +++++--- .../Inputs/EnumAssociatedValue.swift | 17 + .../ArrayParameter.Import.js | 9 - .../BridgeJSLinkTests/Async.Export.js | 9 - .../BridgeJSLinkTests/Async.Import.js | 9 - .../EnumAssociatedValue.Export.d.ts | 32 +- .../EnumAssociatedValue.Export.js | 327 ++++++-- .../BridgeJSLinkTests/EnumCase.Export.js | 15 +- .../BridgeJSLinkTests/EnumNamespace.Export.js | 13 +- .../BridgeJSLinkTests/EnumRawType.Export.js | 9 - .../BridgeJSLinkTests/Interface.Import.js | 9 - .../MultipleImportedTypes.Import.js | 9 - .../BridgeJSLinkTests/Namespaces.Export.js | 9 - .../PrimitiveParameters.Export.js | 9 - .../PrimitiveParameters.Import.js | 9 - .../PrimitiveReturn.Export.js | 9 - .../PrimitiveReturn.Import.js | 9 - .../StringParameter.Export.js | 9 - .../StringParameter.Import.js | 9 - .../BridgeJSLinkTests/StringReturn.Export.js | 9 - .../BridgeJSLinkTests/StringReturn.Import.js | 9 - .../BridgeJSLinkTests/SwiftClass.Export.js | 9 - .../TS2SkeletonLike.Import.js | 9 - .../BridgeJSLinkTests/Throws.Export.js | 9 - .../BridgeJSLinkTests/TypeAlias.Import.js | 9 - .../TypeScriptClass.Import.js | 9 - .../VoidParameterVoidReturn.Export.js | 9 - .../VoidParameterVoidReturn.Import.js | 9 - .../ExportSwiftTests/EnumAssociatedValue.json | 202 +++++ .../EnumAssociatedValue.swift | 535 ++++++++----- .../BridgeJSRuntimeTests/ExportAPITests.swift | 63 ++ .../Generated/BridgeJS.ExportSwift.swift | 740 +++++++++++++----- .../JavaScript/BridgeJS.ExportSwift.json | 544 +++++++++++++ Tests/prelude.mjs | 30 + 36 files changed, 2485 insertions(+), 1209 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index cbfc5e83..7634dd9d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -351,7 +351,12 @@ public class ExportSwift { return .skipChildren } - let effectiveNamespace = computedNamespace ?? attributeNamespace + let effectiveNamespace: [String]? + if computedNamespace != nil && attributeNamespace != nil { + effectiveNamespace = computedNamespace + } else { + effectiveNamespace = computedNamespace ?? attributeNamespace + } let swiftCallName = ExportSwift.computeSwiftCallName(for: node, itemName: name) let exportedClass = ExportedClass( @@ -605,39 +610,27 @@ public class ExportSwift { if let primitive = BridgeType(swiftType: type.trimmedDescription) { return primitive } - guard let identifier = type.as(IdentifierTypeSyntax.self) else { - return nil - } - guard let typeDecl = typeDeclResolver.lookupType(for: identifier) else { + guard let typeDecl = typeDeclResolver.resolve(type) else { return nil } + if let enumDecl = typeDecl.as(EnumDeclSyntax.self) { - let enumName = enumDecl.name.text - if let existingEnum = exportedEnums.first(where: { $0.name == enumName }) { - switch existingEnum.enumType { - case .simple: - return .caseEnum(existingEnum.swiftCallName) - case .rawValue: - let rawType = SwiftEnumRawType.from(existingEnum.rawType!)! - return .rawValueEnum(existingEnum.swiftCallName, rawType) - case .associatedValue: - return .associatedValueEnum(existingEnum.swiftCallName) - case .namespace: - return .namespaceEnum(existingEnum.swiftCallName) - } - } let swiftCallName = ExportSwift.computeSwiftCallName(for: enumDecl, itemName: enumDecl.name.text) let rawTypeString = enumDecl.inheritanceClause?.inheritedTypes.first { inheritedType in let typeName = inheritedType.type.trimmedDescription return Constants.supportedRawTypes.contains(typeName) }?.type.trimmedDescription - if let rawTypeString = rawTypeString, - let rawType = SwiftEnumRawType.from(rawTypeString) - { + if let rawTypeString, let rawType = SwiftEnumRawType.from(rawTypeString) { return .rawValueEnum(swiftCallName, rawType) } else { + let hasAnyCases = enumDecl.memberBlock.members.contains { member in + member.decl.is(EnumCaseDeclSyntax.self) + } + if !hasAnyCases { + return .namespaceEnum(swiftCallName) + } let hasAssociatedValues = enumDecl.memberBlock.members.contains { member in guard let caseDecl = member.decl.as(EnumCaseDeclSyntax.self) else { return false } @@ -659,7 +652,8 @@ public class ExportSwift { guard typeDecl.is(ClassDeclSyntax.self) || typeDecl.is(ActorDeclSyntax.self) else { return nil } - return .swiftHeapObject(typeDecl.name.text) + let swiftCallName = ExportSwift.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) + return .swiftHeapObject(swiftCallName) } static let prelude: DeclSyntax = """ @@ -679,6 +673,10 @@ public class ExportSwift { } decls.append(Self.prelude) + if exportedEnums.contains(where: { $0.enumType == .associatedValue }) { + decls.append(renderAssociatedValueBinaryHelpers()) + } + for enumDef in exportedEnums where enumDef.enumType == .simple { decls.append(renderCaseEnumHelpers(enumDef)) } @@ -697,29 +695,108 @@ public class ExportSwift { return decls.map { $0.formatted(using: format).description }.joined(separator: "\n\n") } - func renderCaseEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { - let typeName = enumDef.swiftCallName - var initCases: [String] = [] - var valueCases: [String] = [] - for (index, c) in enumDef.cases.enumerated() { - initCases.append("case \(index): self = .\(c.name)") - valueCases.append("case .\(c.name): return \(index)") - } - let initSwitch = (["switch bridgeJSRawValue {"] + initCases + ["default: return nil", "}"]).joined( - separator: "\n" - ) - let valueSwitch = (["switch self {"] + valueCases + ["}"]).joined(separator: "\n") - + func renderAssociatedValueBinaryHelpers() -> DeclSyntax { return """ - extension \(raw: typeName) { - init?(bridgeJSRawValue: Int32) { - \(raw: initSwitch) + fileprivate enum _BJSParamType: UInt8 { + case string = 1 + case int32 = 2 + case bool = 3 + case float32 = 4 + case float64 = 5 + } + + fileprivate struct _BJSBinaryReader { + let raw: UnsafeRawBufferPointer + var offset: Int = 0 + + @inline(__always) + mutating func readUInt8() -> UInt8 { + let b = raw[offset] + offset += 1 + return b } - var bridgeJSRawValue: Int32 { - \(raw: valueSwitch) + @inline(__always) + mutating func readUInt32() -> UInt32 { + var v = UInt32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return UInt32(littleEndian: v) + } + + @inline(__always) + mutating func readInt32() -> Int32 { + var v = Int32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Int32(littleEndian: v) + } + + @inline(__always) + mutating func readFloat32() -> Float32 { + var bits = UInt32(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Float32(bitPattern: UInt32(littleEndian: bits)) + } + + @inline(__always) + mutating func readFloat64() -> Float64 { + var bits = UInt64(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 8)])) + } + offset += 8 + return Float64(bitPattern: UInt64(littleEndian: bits)) + } + + @inline(__always) + mutating func readString() -> String { + let len = Int(readUInt32()) + let s = String(decoding: UnsafeBufferPointer( + start: raw.baseAddress!.advanced(by: offset).assumingMemoryBound(to: UInt8.self), + count: len + ), as: UTF8.self) + offset += len + return s + } + + @inline(__always) + mutating func expectTag(_ expected: _BJSParamType) { + let rawTag = readUInt8() + guard let got = _BJSParamType(rawValue: rawTag), got == expected else { + preconditionFailure("BridgeJS: mismatched enum param tag. Expected \\(expected) got \\(String(describing: _BJSParamType(rawValue: rawTag)))") + } + } + + @inline(__always) + mutating func readParamCount(expected: Int) { + let count = Int(readUInt32()) + precondition(count == expected, "BridgeJS: mismatched enum param count. Expected \\(expected) got \\(count)") } } + + @_extern(wasm, module: "bjs", name: "swift_js_init_memory") + func _swift_js_init_memory(_: Int32, _: UnsafeMutablePointer) + + @_extern(wasm, module: "bjs", name: "swift_js_return_tag") + func _swift_js_return_tag(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_string") + func _swift_js_return_string(_: UnsafePointer?, _: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_int") + func _swift_js_return_int(_: Int32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f32") + func _swift_js_return_f32(_: Float32) + @_extern(wasm, module: "bjs", name: "swift_js_return_f64") + func _swift_js_return_f64(_: Float64) + @_extern(wasm, module: "bjs", name: "swift_js_return_bool") + func _swift_js_return_bool(_: Int32) """ } @@ -849,12 +926,11 @@ public class ExportSwift { } } case .associatedValueEnum(let enumName): - let enumBaseName = enumName.components(separatedBy: ".").last ?? enumName abiParameterForwardings.append( LabeledExprSyntax( label: param.label, expression: ExprSyntax( - "\(raw: enumBaseName).dispatchConstruct(\(raw: param.name)CaseId, \(raw: param.name)ParamsId, \(raw: param.name)ParamsLen)" + "\(raw: enumName).bridgeJSLiftParameter(\(raw: param.name)CaseId, \(raw: param.name)ParamsId, \(raw: param.name)ParamsLen)" ) ) ) @@ -880,10 +956,14 @@ public class ExportSwift { ) abiParameterSignatures.append((param.name, .i32)) case .swiftHeapObject: - let objectExpr: ExprSyntax = - "Unmanaged<\(raw: param.type.swiftType)>.fromOpaque(\(raw: param.name)).takeUnretainedValue()" + // UnsafeMutableRawPointer is returned as an i32 pointer abiParameterForwardings.append( - LabeledExprSyntax(label: param.label, expression: objectExpr) + LabeledExprSyntax( + label: param.label, + expression: ExprSyntax( + "Unmanaged<\(raw: param.type.swiftType)>.fromOpaque(\(raw: param.name)).takeUnretainedValue()" + ) + ) ) abiParameterSignatures.append((param.name, .pointer)) case .void: @@ -972,6 +1052,7 @@ public class ExportSwift { case .rawValueEnum(_, let rawType): abiReturnType = rawType == .string ? nil : rawType.wasmCoreType case .associatedValueEnum: + append("ret.bridgeJSLowerReturn()") abiReturnType = nil case .namespaceEnum: abiReturnType = nil @@ -1026,8 +1107,7 @@ public class ExportSwift { append("return Int32(ret.rawValue)") } } - case .associatedValueEnum: - append("ret.bridgeJSReturn()") + case .associatedValueEnum: break case .namespaceEnum: break case .jsObject(nil): append( @@ -1253,406 +1333,146 @@ public class ExportSwift { """ } - // MARK: - Variable ABI Associated Value Enum Generation - - static func renderVariableABIAssociatedValueEnum(_ enumDef: ExportedEnum) -> DeclSyntax { + func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { let typeName = enumDef.swiftCallName - var returnCases: [String] = [] - - for (i, c) in enumDef.cases.enumerated() { - let caseName = c.name - let caseIndex = i - - if c.associatedValues.isEmpty { - returnCases.append( - """ - case .\(caseName): - _swift_js_return_tag(Int32(\(caseIndex))) - """ - ) - } else { - let returnCase = generateReturnCase( - caseName: caseName, - caseIndex: caseIndex, - associatedValues: c.associatedValues - ) - returnCases.append(returnCase) - } - } - - let returnSwitch = (["switch self {"] + returnCases + ["}"]).joined(separator: "\n ") - - let enumBaseName = typeName.components(separatedBy: ".").last ?? typeName return """ - import Foundation - - extension \(raw: typeName) { - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - @_extern(wasm, module: "bjs", name: "swift_js_return_bool") - func _swift_js_return_bool(_: Int32) - \(raw: returnSwitch) - } - } - - extension \(raw: enumBaseName) { - \(raw: generateCaseSpecificConstructors(enumDef: enumDef).joined(separator: "\n\n ")) - - static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> \(raw: typeName) { - let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in + private extension \(raw: typeName) { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> \(raw: typeName) { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) - return Int(paramsLen) + initializedCount = Int(paramsLen) } - return dispatchConstructFromJson(caseId, paramsString) - } - - static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> \(raw: typeName) { - switch caseId { - \(raw: generateStructuredDispatchCases(enumDef: enumDef).joined(separator: "\n ")) - default: fatalError("Unknown \(raw: enumBaseName) case ID: \\(caseId)") + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + \(raw: generateBinaryLiftSwitchCases(enumDef: enumDef).joined(separator: "\n ")) + default: fatalError("Unknown \(raw: typeName) case ID: \\(caseId)") + } } } - } - """ - } - - static func generateCaseSpecificConstructors(enumDef: ExportedEnum) -> [String] { - var constructors: [String] = [] - let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName - for (i, c) in enumDef.cases.enumerated() { - let caseName = c.name - - if c.associatedValues.isEmpty { - constructors.append( - """ - static func constructFrom\(enumBaseName)_\(i)() -> \(enumDef.swiftCallName) { - return .\(caseName) - } - """ - ) - } else { - var params: [String] = [] - var args: [String] = [] - - for (j, av) in c.associatedValues.enumerated() { - let paramName = av.label ?? "param\(j)" - - switch av.type { - case .string: - params.append("\(paramName): String") - args.append("\(paramName)") - case .int: - params.append("\(paramName): Int32") - args.append("Int(\(paramName))") - case .bool: - params.append("\(paramName): Int32") - args.append("(\(paramName) != 0)") - case .float: - params.append("\(paramName): Float32") - args.append("\(paramName)") - case .double: - params.append("\(paramName): Float64") - args.append("\(paramName)") - default: - params.append("\(paramName): Int32") - args.append("\(paramName)") + func bridgeJSLowerReturn() { + switch self { + \(raw: generateReturnSwitchCases(enumDef: enumDef).joined(separator: "\n ")) } } - - let paramList = params.joined(separator: ", ") - let argList = args.joined(separator: ", ") - - constructors.append( - """ - static func constructFrom\(enumBaseName)_\(i)(\(paramList)) -> \(enumDef.swiftCallName) { - return .\(caseName)(\(argList)) - } - """ - ) } - } - - return constructors + """ } - static func generateDispatchCases(enumDef: ExportedEnum) -> [String] { + func generateBinaryLiftSwitchCases(enumDef: ExportedEnum) -> [String] { var cases: [String] = [] - let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName - - for (i, c) in enumDef.cases.enumerated() { - if c.associatedValues.isEmpty { - cases.append("case \(i): return constructFrom\(enumBaseName)_\(i)()") + for (caseIndex, enumCase) in enumDef.cases.enumerated() { + if enumCase.associatedValues.isEmpty { + cases.append("case \(caseIndex): return .\(enumCase.name)") } else { - // For cases with parameters, we'll extract them from the pointer - var paramExtractions: [String] = [] - var paramPasses: [String] = [] - var offset = 0 + var lines: [String] = [] + lines.append("case \(caseIndex):") + lines.append("reader.readParamCount(expected: \(enumCase.associatedValues.count))") + var argList: [String] = [] - for (j, av) in c.associatedValues.enumerated() { - let paramName = av.label ?? "param\(j)" + for (paramIndex, associatedValue) in enumCase.associatedValues.enumerated() { + let paramName = associatedValue.label ?? "param\(paramIndex)" + argList.append(paramName) - switch av.type { + switch associatedValue.type { case .string: - paramExtractions.append( - "let \(paramName)_ptr = params.load(fromByteOffset: \(offset), as: UnsafePointer.self)" - ) - paramExtractions.append( - "let \(paramName)_len = params.load(fromByteOffset: \(offset + 8), as: Int32.self)" - ) - paramPasses.append("\(paramName)_ptr: \(paramName)_ptr") - paramPasses.append("\(paramName)_len: \(paramName)_len") - offset += 16 // 8 bytes for pointer + 4 bytes for length + padding + lines.append("reader.expectTag(.string)") + lines.append("let \(paramName) = reader.readString()") case .int: - paramExtractions.append( - "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" - ) - paramPasses.append("\(paramName): \(paramName)") - offset += 4 + lines.append("reader.expectTag(.int32)") + lines.append("let \(paramName) = Int(reader.readInt32())") case .bool: - paramExtractions.append( - "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" - ) - paramPasses.append("\(paramName): \(paramName)") - offset += 4 + lines.append("reader.expectTag(.bool)") + lines.append("let \(paramName) = Int32(reader.readUInt8()) != 0") case .float: - paramExtractions.append( - "let \(paramName) = params.load(fromByteOffset: \(offset), as: Float32.self)" - ) - paramPasses.append("\(paramName): \(paramName)") - offset += 4 + lines.append("reader.expectTag(.float32)") + lines.append("let \(paramName) = reader.readFloat32()") case .double: - paramExtractions.append( - "let \(paramName) = params.load(fromByteOffset: \(offset), as: Float64.self)" - ) - paramPasses.append("\(paramName): \(paramName)") - offset += 8 + lines.append("reader.expectTag(.float64)") + lines.append("let \(paramName) = reader.readFloat64()") default: - paramExtractions.append( - "let \(paramName) = params.load(fromByteOffset: \(offset), as: Int32.self)" - ) - paramPasses.append("\(paramName): \(paramName)") - offset += 4 + lines.append("reader.expectTag(.int32)") + lines.append("let \(paramName) = reader.readInt32()") } } - let extractionCode = paramExtractions.joined(separator: "; ") - let paramList = paramPasses.joined(separator: ", ") - - cases.append("case \(i): \(extractionCode); return constructFrom\(enumBaseName)_\(i)(\(paramList))") + lines.append("return .\(enumCase.name)(\(argList.joined(separator: ", ")))") + cases.append(lines.joined(separator: "\n ")) } } - return cases } - static func generateReturnCase(caseName: String, caseIndex: Int, associatedValues: [AssociatedValue]) -> String { - var returnStatements: [String] = [] - returnStatements.append("_swift_js_return_tag(Int32(\(caseIndex)))") - - for (i, av) in associatedValues.enumerated() { - let paramName = av.label ?? "param\(i)" - - switch av.type { - case .string: - returnStatements.append( - """ - var mutable\(paramName.capitalized) = \(paramName) - mutable\(paramName.capitalized).withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) - } - """ - ) - case .int: - returnStatements.append("_swift_js_return_int(Int32(\(paramName)))") - case .bool: - returnStatements.append("_swift_js_return_bool(\(paramName) ? 1 : 0)") - case .float: - returnStatements.append("_swift_js_return_f32(\(paramName))") - case .double: - returnStatements.append("_swift_js_return_f64(\(paramName))") - default: - returnStatements.append("_swift_js_return_int(0)") - } - } - - let returnCode = returnStatements.joined(separator: "\n ") - return """ - case .\(caseName)(let \(associatedValues.enumerated().map { av in av.1.label ?? "param\(av.0)" }.joined(separator: ", let "))): - \(returnCode) - """ - } - - static func generateStructuredDispatchCases(enumDef: ExportedEnum) -> [String] { + func generateReturnSwitchCases(enumDef: ExportedEnum) -> [String] { var cases: [String] = [] - let enumBaseName = enumDef.swiftCallName.components(separatedBy: ".").last ?? enumDef.swiftCallName - - for (i, c) in enumDef.cases.enumerated() { - if c.associatedValues.isEmpty { - cases.append("case \(i): return constructFrom\(enumBaseName)_\(i)()") + for (caseIndex, enumCase) in enumDef.cases.enumerated() { + if enumCase.associatedValues.isEmpty { + cases.append(""" + case .\(enumCase.name): + _swift_js_return_tag(Int32(\(caseIndex))) + """) } else { - // Parse JSON parameters and call constructor - var paramExtractions: [String] = [] - var paramPasses: [String] = [] - - for (j, av) in c.associatedValues.enumerated() { - let paramName = av.label ?? "param\(j)" - + var bodyLines: [String] = [] + bodyLines.append("_swift_js_return_tag(Int32(\(caseIndex)))") + for (i, av) in enumCase.associatedValues.enumerated() { + let paramName = av.label ?? "param\(i)" switch av.type { case .string: - paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! String") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append(""" + var __bjs_\(paramName) = \(paramName) + __bjs_\(paramName).withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + """) case .int: - paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Int32") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append("_swift_js_return_int(Int32(\(paramName)))") case .bool: - paramExtractions.append("let \(paramName) = Int32(params[\"\(paramName)\"] as! Bool ? 1 : 0)") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append("_swift_js_return_bool(\(paramName) ? 1 : 0)") case .float: - paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Float32") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append("_swift_js_return_f32(\(paramName))") case .double: - paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Float64") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append("_swift_js_return_f64(\(paramName))") default: - paramExtractions.append("let \(paramName) = params[\"\(paramName)\"] as! Int32") - paramPasses.append("\(paramName): \(paramName)") + bodyLines.append("preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")") } } - - let extractionCode = paramExtractions.joined(separator: "; ") - let paramList = paramPasses.joined(separator: ", ") - - cases.append( - """ - case \(i): - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - \(extractionCode) - return constructFrom\(enumBaseName)_\(i)(\(paramList)) - """ - ) + let pattern = enumCase.associatedValues.enumerated().map { i, av in "let \(av.label ?? "param\(i)")" }.joined(separator: ", ") + cases.append(""" + case .\(enumCase.name)(\(pattern)): + \(bodyLines.joined(separator: "\n ")) + """) } } - return cases } - static func generateConstructorCall( - enumType: String, - caseName: String, - associatedValues: [AssociatedValue] - ) -> String { - var params: [String] = [] - - // For simplicity, we'll handle the most common case: single parameter using (a, b) as needed - if associatedValues.count == 1 { - let av = associatedValues[0] - let paramName = av.label ?? "param0" - - switch av.type { - case .string: - params.append("\(paramName)_ptr: UnsafePointer(bitPattern: UInt(a)).unsafelyUnwrapped") - params.append("\(paramName)_len: b") - case .int: - params.append("\(paramName): a") - case .bool: - params.append("\(paramName): (a != 0)") - case .float: - params.append("\(paramName): Float32(bitPattern: UInt32(a))") - case .double: - params.append("\(paramName): Double(bitPattern: UInt64(a) | (UInt64(b) << 32))") - default: - params.append("\(paramName): a") - } - } else { - // For multiple parameters, this is more complex - for now, use fatalError - return "fatalError(\"Multiple parameter cases not yet implemented for \\\(caseName)\")" + func renderCaseEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { + let typeName = enumDef.swiftCallName + var initCases: [String] = [] + var valueCases: [String] = [] + for (index, c) in enumDef.cases.enumerated() { + initCases.append("case \(index): self = .\(c.name)") + valueCases.append("case .\(c.name): return \(index)") } + let initSwitch = (["switch bridgeJSRawValue {"] + initCases + ["default: return nil", "}"]).joined( + separator: "\n" + ) + let valueSwitch = (["switch self {"] + valueCases + ["}"]).joined(separator: "\n") - return "\(enumType).create\(caseName)(\(params.joined(separator: ", ")))" - } - - static func renderCaseSpecificConstructor( - enumType: String, - caseIndex: Int, - caseName: String, - associatedValues: [AssociatedValue] - ) -> (constructorFunc: String, returnCase: String) { - - // Generate case-specific constructor function with native WASM parameters - var constructorParams: [String] = [] - var constructorArgs: [String] = [] - var returnStatements: [String] = [] - - for (i, av) in associatedValues.enumerated() { - let paramName = av.label ?? "param\(i)" - let labelPrefix = av.label.map { "\($0): " } ?? "" - - switch av.type { - case .string: - constructorParams.append("\(paramName)_ptr: UnsafePointer") - constructorParams.append("\(paramName)_len: Int32") - constructorArgs.append( - "\(labelPrefix)String(unsafeUninitializedCapacity: Int(\(paramName)_len)) { buf in _swift_js_init_memory(Int32(bitPattern: \(paramName)_ptr), buf.baseAddress.unsafelyUnwrapped); return Int(\(paramName)_len) }" - ) - returnStatements.append( - """ - var mutable\(paramName.capitalized) = \(paramName) - mutable\(paramName.capitalized).withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) - } - """ - ) - case .int: - constructorParams.append("\(paramName): Int32") - constructorArgs.append("\(labelPrefix)Int(\(paramName))") - returnStatements.append("_swift_js_return_int(Int32(\(paramName)))") - case .bool: - constructorParams.append("\(paramName): Int32") - constructorArgs.append("\(labelPrefix)(\(paramName) != 0)") - returnStatements.append("_swift_js_return_int(\(paramName) ? 1 : 0)") - case .float: - constructorParams.append("\(paramName): Float32") - constructorArgs.append("\(labelPrefix)\(paramName)") - returnStatements.append("_swift_js_return_f32(\(paramName))") - case .double: - constructorParams.append("\(paramName): Float64") - constructorArgs.append("\(labelPrefix)\(paramName)") - returnStatements.append("_swift_js_return_f64(\(paramName))") - default: - constructorParams.append("\(paramName): Int32") - constructorArgs.append("\(labelPrefix)/* unsupported type */") - returnStatements.append("// Unsupported type for \(paramName)") - } - } + return """ + extension \(raw: typeName) { + init?(bridgeJSRawValue: Int32) { + \(raw: initSwitch) + } - // Generate the case-specific constructor function - let constructorFunc = """ - static func create\(caseName.capitalized)(\(constructorParams.joined(separator: ", "))) -> \(enumType) { - return .\(caseName)(\(constructorArgs.joined(separator: ", "))) + var bridgeJSRawValue: Int32 { + \(raw: valueSwitch) + } } """ - - let returnCase = """ - case .\(caseName)(\(associatedValues.enumerated().map { i, av in "let \(av.label ?? "param\(i)")" }.joined(separator: ", "))): - _swift_js_return_tag(Int32(\(caseIndex))) - \(returnStatements.joined(separator: "\n ")) - """ - - return (constructorFunc, returnCase) } + } fileprivate enum Constants { @@ -1725,8 +1545,3 @@ extension BridgeType { } } } - -func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { - // Use Variable ABI approach for all associated value enums - return ExportSwift.renderVariableABIAssociatedValueEnum(enumDef) -} diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift index a7b183af..d353a536 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift @@ -109,4 +109,26 @@ class TypeDeclResolver { func lookupType(fullyQualified: QualifiedName) -> TypeDecl? { return typeDeclByQualifiedName[fullyQualified] } + + /// Resolves a type usage (identifier or member type) to its declaration node + func resolve(_ type: TypeSyntax) -> TypeDecl? { + if let id = type.as(IdentifierTypeSyntax.self) { + return lookupType(for: id) + } + if let components = qualifiedComponents(from: type) { + return lookupType(fullyQualified: components) + } + return nil + } + + private func qualifiedComponents(from type: TypeSyntax) -> QualifiedName? { + if let m = type.as(MemberTypeSyntax.self) { + guard let base = qualifiedComponents(from: TypeSyntax(m.baseType)) else { return nil } + return base + [m.name.text] + } else if let id = type.as(IdentifierTypeSyntax.self) { + return [id.name.text] + } else { + return nil + } + } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 8d5b0fe2..594c6042 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -86,6 +86,10 @@ struct BridgeJSLink { ) } + let hasAssociatedValueEnums = exportedSkeletons.contains { skeleton in + skeleton.enums.contains { $0.enumType == .associatedValue } + } + for skeleton in exportedSkeletons { for klass in skeleton.classes { let (jsType, dtsType, dtsExportEntry) = renderExportedClass(klass) @@ -159,7 +163,7 @@ struct BridgeJSLink { importObjectBuilders.append(importObjectBuilder) } - let hasNamespacedItems = !namespacedFunctions.isEmpty || !namespacedClasses.isEmpty || !namespacedEnums.isEmpty + let hasNamespacedItems = !namespacedFunctions.isEmpty || !namespacedClasses.isEmpty let namespaceBuilder = NamespaceBuilder() let namespaceDeclarationsLines = namespaceBuilder.namespaceDeclarations( @@ -171,11 +175,9 @@ struct BridgeJSLink { let exportsSection: String if hasNamespacedItems { - let namespacedEnumsForExports = namespacedEnums.filter { $0.enumType == .associatedValue } let namespaceSetupCode = namespaceBuilder.renderGlobalNamespace( namespacedFunctions: namespacedFunctions, - namespacedClasses: namespacedClasses, - namespacedEnums: namespacedEnumsForExports + namespacedClasses: namespacedClasses ) .map { $0.indent(count: 12) }.joined(separator: "\n") @@ -201,6 +203,59 @@ struct BridgeJSLink { } let topLevelEnumsSection = topLevelEnumLines.isEmpty ? "" : topLevelEnumLines.joined(separator: "\n") + "\n\n" + let sharedEnumHelpersSection: String = { + guard hasAssociatedValueEnums else { return "" } + let lines: [String] = [ + "const __bjs_ParamType = { STRING: 1, INT32: 2, BOOL: 3, FLOAT32: 4, FLOAT64: 5 };", + "function __bjs_encodeEnumParams(textEncoder, swift, parts) {", + " const SIZE_U8 = 1, SIZE_U32 = 4, SIZE_F32 = 4, SIZE_F64 = 8;", + " let totalLen = SIZE_U32;", + " for (const p of parts) {", + " switch (p.t) {", + " case __bjs_ParamType.STRING: {", + " const bytes = textEncoder.encode(p.v);", + " p._bytes = bytes;", + " totalLen += SIZE_U8 + SIZE_U32 + bytes.length;", + " break;", + " }", + " case __bjs_ParamType.INT32: totalLen += SIZE_U8 + SIZE_U32; break;", + " case __bjs_ParamType.BOOL: totalLen += SIZE_U8 + SIZE_U8; break;", + " case __bjs_ParamType.FLOAT32: totalLen += SIZE_U8 + SIZE_F32; break;", + " case __bjs_ParamType.FLOAT64: totalLen += SIZE_U8 + SIZE_F64; break;", + " default: throw new Error(\"Unsupported param type tag: \" + p.t);", + " }", + " }", + " const buf = new Uint8Array(totalLen);", + " const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);", + " let off = 0;", + " view.setUint32(off, parts.length, true); off += SIZE_U32;", + " for (const p of parts) {", + " view.setUint8(off, p.t); off += SIZE_U8;", + " switch (p.t) {", + " case __bjs_ParamType.STRING: {", + " const b = p._bytes;", + " view.setUint32(off, b.length, true); off += SIZE_U32;", + " buf.set(b, off); off += b.length;", + " break;", + " }", + " case __bjs_ParamType.INT32:", + " view.setInt32(off, (p.v | 0), true); off += SIZE_U32; break;", + " case __bjs_ParamType.BOOL:", + " view.setUint8(off, p.v ? 1 : 0); off += SIZE_U8; break;", + " case __bjs_ParamType.FLOAT32:", + " view.setFloat32(off, Math.fround(p.v), true); off += SIZE_F32; break;", + " case __bjs_ParamType.FLOAT64:", + " view.setFloat64(off, p.v, true); off += SIZE_F64; break;", + " default: throw new Error(\"Unsupported param type tag: \" + p.t);", + " }", + " }", + " const paramsId = swift.memory.retain(buf);", + " return { paramsId, paramsLen: buf.length, cleanup: () => { swift.memory.release(paramsId); } };", + "}", + "", + ] + return lines.joined(separator: "\n") + }() let topLevelNamespaceCode = namespaceBuilder.renderTopLevelEnumNamespaceAssignments( namespacedEnums: namespacedEnums @@ -218,7 +273,7 @@ struct BridgeJSLink { // To update this file, just rebuild your project or run // `swift package bridge-js`. - \(topLevelEnumsSection)\(namespaceAssignmentsSection)export async function createInstantiator(options, swift) { + \(sharedEnumHelpersSection)\(topLevelEnumsSection)\(namespaceAssignmentsSection)export async function createInstantiator(options, swift) { let instance; let memory; let setException; @@ -226,9 +281,6 @@ struct BridgeJSLink { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -279,9 +331,6 @@ struct BridgeJSLink { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -290,16 +339,13 @@ struct BridgeJSLink { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { @@ -362,7 +408,6 @@ struct BridgeJSLink { for skeleton in exportedSkeletons { for enumDef in skeleton.enums where enumDef.enumType == .associatedValue { let base = enumDef.name - lines.append("// Set up \(base) enum helpers") lines.append("const \(base)Helpers = __bjs_create\(base)Helpers()(textEncoder, swift);") lines.append("globalThis.__bjs_lower_\(base) = (value) => \(base)Helpers.lower(value);") lines.append( @@ -464,7 +509,7 @@ struct BridgeJSLink { parameterForwardings.append(bytesIdLabel) parameterForwardings.append("\(bytesLabel).length") case .caseEnum(_): - parameterForwardings.append("\(param.name) | 0") + parameterForwardings.append(param.name) case .rawValueEnum(_, let rawType): switch rawType { case .string: @@ -739,164 +784,181 @@ struct BridgeJSLink { } case .associatedValue: do { - let base = enumDefinition.name - jsLines.append("const \(base) = {") + jsLines.append("const \(enumDefinition.name) = {") jsLines.append("Tag: {".indent(count: 4)) - for (index, enumCase) in enumDefinition.cases.enumerated() { + for (caseIndex, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter - jsLines.append("\(caseName): \(index),".indent(count: 8)) + jsLines.append("\(caseName): \(caseIndex),".indent(count: 8)) } jsLines.append("}".indent(count: 4)) jsLines.append("};") jsLines.append("") - jsLines.append("") - jsLines.append("// Helper factory for \(base) enum") - jsLines.append("const __bjs_create\(base)Helpers = () => {") + jsLines.append("const __bjs_create\(enumDefinition.name)Helpers = () => {") jsLines.append("return (textEncoder, swift) => ({".indent(count: 4)) + jsLines.append("lower: (value) => {".indent(count: 8)) - jsLines.append("const t = value.tag;".indent(count: 12)) - jsLines.append("switch (t) {".indent(count: 12)) - for (index, enumCase) in enumDefinition.cases.enumerated() { + jsLines.append("const enumTag = value.tag;".indent(count: 12)) + jsLines.append("switch (enumTag) {".indent(count: 12)) + for (_, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter if enumCase.associatedValues.isEmpty { - jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) - jsLines.append("const paramsBytes = textEncoder.encode(\"{}\");".indent(count: 20)) - jsLines.append("const paramsId = swift.memory.retain(paramsBytes);".indent(count: 20)) + jsLines.append("case \(enumDefinition.name).Tag.\(caseName): {".indent(count: 16)) + jsLines.append("const parts = [];".indent(count: 20)) + jsLines.append( + "const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts);" + .indent(count: 20) + ) jsLines.append( - "return { caseId: \(index), paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } };" + "return { caseId: \(enumDefinition.name).Tag.\(caseName), paramsId, paramsLen, cleanup };" .indent(count: 20) ) jsLines.append("}".indent(count: 16)) } else { - jsLines.append("case \(base).Tag.\(caseName): {".indent(count: 16)) - - var parameterObject: [String] = [] - - for (i, av) in enumCase.associatedValues.enumerated() { - let fieldName = av.label ?? "param\(i)" - switch av.type { + jsLines.append("case \(enumDefinition.name).Tag.\(caseName): {".indent(count: 16)) + var partLines: [String] = [] + for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated() { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + switch associatedValue.type { case .string: - parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + partLines.append("{ t: __bjs_ParamType.STRING, v: value.\(prop) }") case .int: - parameterObject.append("\"\(fieldName)\": (value.\(fieldName) | 0)") + partLines.append("{ t: __bjs_ParamType.INT32, v: (value.\(prop) | 0) }") case .bool: - parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + partLines.append("{ t: __bjs_ParamType.BOOL, v: value.\(prop) }") case .float: - parameterObject.append("\"\(fieldName)\": Math.fround(value.\(fieldName))") + partLines.append("{ t: __bjs_ParamType.FLOAT32, v: value.\(prop) }") case .double: - parameterObject.append("\"\(fieldName)\": value.\(fieldName)") + partLines.append("{ t: __bjs_ParamType.FLOAT64, v: value.\(prop) }") default: - parameterObject.append("\"\(fieldName)\": 0") + partLines.append("{ t: __bjs_ParamType.INT32, v: 0 }") } } - + jsLines.append("const parts = [".indent(count: 20)) + if !partLines.isEmpty { + for (i, pl) in partLines.enumerated() { + let suffix = i == partLines.count - 1 ? "" : "," + jsLines.append("\(pl)\(suffix)".indent(count: 24)) + } + } + jsLines.append("];".indent(count: 20)) jsLines.append( - "const paramsObj = { \(parameterObject.joined(separator: ", ")) };".indent(count: 20) + "const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts);" + .indent(count: 20) ) - jsLines.append("const paramsJson = JSON.stringify(paramsObj);".indent(count: 20)) - jsLines.append("const paramsBytes = textEncoder.encode(paramsJson);".indent(count: 20)) - jsLines.append("const paramsId = swift.memory.retain(paramsBytes);".indent(count: 20)) jsLines.append( - "return { caseId: \(index), paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } };" + "return { caseId: \(enumDefinition.name).Tag.\(caseName), paramsId, paramsLen, cleanup };" .indent(count: 20) ) - jsLines.append("}".indent(count: 16)) } } - jsLines.append("default: throw new Error(\"Unknown \(base) tag: \" + String(t));".indent(count: 16)) + jsLines.append( + "default: throw new Error(\"Unknown \(enumDefinition.name) tag: \" + String(enumTag));".indent( + count: 16 + ) + ) jsLines.append("}".indent(count: 12)) jsLines.append("},".indent(count: 8)) + jsLines.append( - "raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => {".indent(count: 8) + "raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => {".indent( + count: 8 + ) ) jsLines.append("const tag = tmpRetTag | 0;".indent(count: 12)) jsLines.append("switch (tag) {".indent(count: 12)) - for (index, enumCase) in enumDefinition.cases.enumerated() { + for (_, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter if enumCase.associatedValues.isEmpty { - jsLines.append("case \(index): return { tag: \(base).Tag.\(caseName) };".indent(count: 16)) + jsLines.append( + "case \(enumDefinition.name).Tag.\(caseName): return { tag: \(enumDefinition.name).Tag.\(caseName) };" + .indent(count: 16) + ) } else { - var fields: [String] = ["tag: \(base).Tag.\(caseName)"] - + var fields: [String] = ["tag: \(enumDefinition.name).Tag.\(caseName)"] var stringIndex = 0 var intIndex = 0 var f32Index = 0 var f64Index = 0 var boolIndex = 0 - - for (i, av) in enumCase.associatedValues.enumerated() { - let fieldName = av.label ?? "param\(i)" - switch av.type { + for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated() { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + switch associatedValue.type { case .string: - fields.append("\(fieldName): tmpRetStrings[\(stringIndex)]") + fields.append("\(prop): tmpRetStrings[\(stringIndex)]") stringIndex += 1 case .bool: - fields.append("\(fieldName): tmpRetBools[\(boolIndex)]") + fields.append("\(prop): tmpRetBools[\(boolIndex)]") boolIndex += 1 case .int: - fields.append("\(fieldName): tmpRetInts[\(intIndex)]") + fields.append("\(prop): tmpRetInts[\(intIndex)]") intIndex += 1 case .float: - fields.append("\(fieldName): tmpRetF32s[\(f32Index)]") + fields.append("\(prop): tmpRetF32s[\(f32Index)]") f32Index += 1 case .double: - fields.append("\(fieldName): tmpRetF64s[\(f64Index)]") + fields.append("\(prop): tmpRetF64s[\(f64Index)]") f64Index += 1 default: - fields.append("\(fieldName): undefined") + fields.append("\(prop): undefined") } } - - jsLines.append("case \(index): return { \(fields.joined(separator: ", ")) };".indent(count: 16)) + jsLines.append( + "case \(enumDefinition.name).Tag.\(caseName): return { \(fields.joined(separator: ", ")) };" + .indent(count: 16) + ) } } jsLines.append( - "default: throw new Error(\"Unknown \(base) tag returned from Swift: \" + String(tag));".indent( - count: 16 - ) + "default: throw new Error(\"Unknown \(enumDefinition.name) tag returned from Swift: \" + String(tag));" + .indent( + count: 16 + ) ) jsLines.append("}".indent(count: 12)) jsLines.append("}".indent(count: 8)) jsLines.append("});".indent(count: 4)) jsLines.append("};") - var dtsBuf: [String] = [] - dtsBuf.append("export const \(enumDefinition.name): {") - dtsBuf.append("readonly Tag: {".indent(count: 4)) - for (index, enumCase) in enumDefinition.cases.enumerated() { - let caseName = enumCase.name.capitalizedFirstLetter - dtsBuf.append("readonly \(caseName): \(index);".indent(count: 8)) - } - dtsBuf.append("};".indent(count: 4)) - dtsBuf.append("};") - dtsBuf.append("") - var unionParts: [String] = [] - for enumCase in enumDefinition.cases { - let caseName = enumCase.name.capitalizedFirstLetter - if enumCase.associatedValues.isEmpty { - unionParts.append("{ tag: typeof \(enumDefinition.name).Tag.\(caseName) }") - } else { - var fields: [String] = ["tag: typeof \(enumDefinition.name).Tag.\(caseName)"] - for (i, av) in enumCase.associatedValues.enumerated() { - let fieldName = av.label ?? "param\(i)" - let ts: String - switch av.type { - case .string: ts = "string" - case .bool: ts = "boolean" - case .int, .float, .double: ts = "number" - default: ts = "never" + if enumDefinition.namespace == nil { + dtsLines.append("export const \(enumDefinition.name): {") + dtsLines.append("readonly Tag: {".indent(count: 4)) + for (caseIndex, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + dtsLines.append("readonly \(caseName): \(caseIndex);".indent(count: 8)) + } + dtsLines.append("};".indent(count: 4)) + dtsLines.append("};") + dtsLines.append("") + var unionParts: [String] = [] + for enumCase in enumDefinition.cases { + if enumCase.associatedValues.isEmpty { + unionParts.append( + "{ tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter) }" + ) + } else { + var fields: [String] = [ + "tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter)" + ] + for (associatedValueIndex, associatedValue) in enumCase.associatedValues.enumerated() { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + let ts: String + switch associatedValue.type { + case .string: ts = "string" + case .bool: ts = "boolean" + case .int, .float, .double: ts = "number" + default: ts = "never" + } + fields.append("\(prop): \(ts)") } - fields.append("\(fieldName): \(ts)") + unionParts.append("{ \(fields.joined(separator: "; ")) }") } - unionParts.append("{ \(fields.joined(separator: "; ")) }") } + dtsLines.append("export type \(enumDefinition.name) =") + dtsLines.append(" " + unionParts.joined(separator: " | ")) + dtsLines.append("") } - dtsBuf.append("export type \(enumDefinition.name) =") - dtsBuf.append(" " + unionParts.joined(separator: " | ")) - dtsBuf.append("") - dtsLines.append(contentsOf: dtsBuf) } case .namespace: break @@ -1236,8 +1298,7 @@ struct BridgeJSLink { /// - Returns: Array of JavaScript code lines that set up the global namespace structure func renderGlobalNamespace( namespacedFunctions: [ExportedFunction], - namespacedClasses: [ExportedClass], - namespacedEnums: [ExportedEnum] + namespacedClasses: [ExportedClass] ) -> [String] { var lines: [String] = [] var uniqueNamespaces: [String] = [] @@ -1251,15 +1312,10 @@ struct BridgeJSLink { namespacedClasses .compactMap { $0.namespace } ) - let enumNamespacePaths: Set<[String]> = Set( - namespacedEnums - .compactMap { $0.namespace } - ) let allNamespacePaths = functionNamespacePaths .union(classNamespacePaths) - .union(enumNamespacePaths) allNamespacePaths.forEach { namespacePath in namespacePath.makeIterator().enumerated().forEach { (index, _) in @@ -1281,11 +1337,6 @@ struct BridgeJSLink { lines.append("globalThis.\(namespacePath).\(klass.name) = exports.\(klass.name);") } - namespacedEnums.forEach { enumDefinition in - let namespacePath: String = enumDefinition.namespace?.joined(separator: ".") ?? "" - lines.append("globalThis.\(namespacePath).\(enumDefinition.name) = exports.\(enumDefinition.name);") - } - namespacedFunctions.forEach { function in let namespacePath: String = function.namespace?.joined(separator: ".") ?? "" lines.append("globalThis.\(namespacePath).\(function.name) = exports.\(function.name);") @@ -1295,15 +1346,13 @@ struct BridgeJSLink { } func renderTopLevelEnumNamespaceAssignments(namespacedEnums: [ExportedEnum]) -> [String] { - let topLevelNamespacedEnums = namespacedEnums.filter { $0.enumType == .simple || $0.enumType == .rawValue } - - guard !topLevelNamespacedEnums.isEmpty else { return [] } + guard !namespacedEnums.isEmpty else { return [] } var lines: [String] = [] var uniqueNamespaces: [String] = [] var seen = Set() - for enumDef in topLevelNamespacedEnums { + for enumDef in namespacedEnums { guard let namespacePath = enumDef.namespace else { continue } namespacePath.enumerated().forEach { (index, _) in let path = namespacePath[0...index].joined(separator: ".") @@ -1324,7 +1373,7 @@ struct BridgeJSLink { lines.append("") } - for enumDef in topLevelNamespacedEnums { + for enumDef in namespacedEnums { let namespacePath = enumDef.namespace?.joined(separator: ".") ?? "" lines.append("globalThis.\(namespacePath).\(enumDef.name) = \(enumDef.name);") } @@ -1463,7 +1512,9 @@ struct BridgeJSLink { for (index, enumCase) in enumDefinition.cases.enumerated() { let caseName = enumCase.name.capitalizedFirstLetter dtsLines.append( - "\(caseName) = \(index),".indent(count: identBaseSize * (contentDepth + 1)) + "readonly \(caseName): \(index);".indent( + count: identBaseSize * (contentDepth + 1) + ) ) } dtsLines.append("}".indent(count: identBaseSize * contentDepth)) @@ -1535,7 +1586,53 @@ struct BridgeJSLink { .indent(count: identBaseSize * contentDepth) ) } - case .associatedValue, .namespace: + case .associatedValue: + dtsLines.append( + "const \(enumDefinition.name): {".indent(count: identBaseSize * contentDepth) + ) + dtsLines.append("readonly Tag: {".indent(count: identBaseSize * (contentDepth + 1))) + for (caseIndex, enumCase) in enumDefinition.cases.enumerated() { + let caseName = enumCase.name.capitalizedFirstLetter + dtsLines.append( + "readonly \(caseName): \(caseIndex);".indent( + count: identBaseSize * (contentDepth + 2) + ) + ) + } + dtsLines.append("};".indent(count: identBaseSize * (contentDepth + 1))) + dtsLines.append("};".indent(count: identBaseSize * contentDepth)) + + var unionParts: [String] = [] + for enumCase in enumDefinition.cases { + if enumCase.associatedValues.isEmpty { + unionParts.append( + "{ tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter) }" + ) + } else { + var fields: [String] = [ + "tag: typeof \(enumDefinition.name).Tag.\(enumCase.name.capitalizedFirstLetter)" + ] + for (associatedValueIndex, associatedValue) in enumCase.associatedValues + .enumerated() + { + let prop = associatedValue.label ?? "param\(associatedValueIndex)" + let ts: String + switch associatedValue.type { + case .string: ts = "string" + case .bool: ts = "boolean" + case .int, .float, .double: ts = "number" + default: ts = "never" + } + fields.append("\(prop): \(ts)") + } + unionParts.append("{ \(fields.joined(separator: "; ")) }") + } + } + dtsLines.append("type \(enumDefinition.name) =".indent(count: identBaseSize * contentDepth)) + dtsLines.append( + " " + unionParts.joined(separator: " | ").indent(count: identBaseSize * contentDepth) + ) + case .namespace: continue } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift index 44530f99..08d03a2b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift @@ -16,8 +16,25 @@ enum ComplexResult { case success(String) case error(String, Int) case status(Bool, Int, String) + case coordinates(Double, Double, Double) + case comprehensive(Bool, Bool, Int, Int, Double, Double, String, String, String) case info } @JS func handleComplex(result: ComplexResult) @JS func getComplexResult() -> ComplexResult + +@JS +enum Utilities { + @JS enum Result { + case success(String) + case failure(String, Int) + case status(Bool, Int, String) + } +} + +@JS(namespace: "API") +@JS enum NetworkingResult { + case success(String) + case failure(String, Int) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js index a152d509..53bd2084 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js index 4fc88260..1f2b957d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js index 6abd29e2..4d1a2e2e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts index c33cabdc..4d7394b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.d.ts @@ -23,12 +23,40 @@ export const ComplexResult: { readonly Success: 0; readonly Error: 1; readonly Status: 2; - readonly Info: 3; + readonly Coordinates: 3; + readonly Comprehensive: 4; + readonly Info: 5; }; }; export type ComplexResult = - { tag: typeof ComplexResult.Tag.Success; param0: string } | { tag: typeof ComplexResult.Tag.Error; param0: string; param1: number } | { tag: typeof ComplexResult.Tag.Status; param0: boolean; param1: number; param2: string } | { tag: typeof ComplexResult.Tag.Info } + { tag: typeof ComplexResult.Tag.Success; param0: string } | { tag: typeof ComplexResult.Tag.Error; param0: string; param1: number } | { tag: typeof ComplexResult.Tag.Status; param0: boolean; param1: number; param2: string } | { tag: typeof ComplexResult.Tag.Coordinates; param0: number; param1: number; param2: number } | { tag: typeof ComplexResult.Tag.Comprehensive; param0: boolean; param1: boolean; param2: number; param3: number; param4: number; param5: number; param6: string; param7: string; param8: string } | { tag: typeof ComplexResult.Tag.Info } + +export {}; + +declare global { + namespace API { + const NetworkingResult: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + }; + }; + type NetworkingResult = + { tag: typeof NetworkingResult.Tag.Success; param0: string } | { tag: typeof NetworkingResult.Tag.Failure; param0: string; param1: number } + } + namespace Utilities { + const Result: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + readonly Status: 2; + }; + }; + type Result = + { tag: typeof Result.Tag.Success; param0: string } | { tag: typeof Result.Tag.Failure; param0: string; param1: number } | { tag: typeof Result.Tag.Status; param0: boolean; param1: number; param2: string } + } +} export type Exports = { handle(result: APIResult): void; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index baa84bbf..ae114f63 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -4,6 +4,52 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +const __bjs_ParamType = { STRING: 1, INT32: 2, BOOL: 3, FLOAT32: 4, FLOAT64: 5 }; +function __bjs_encodeEnumParams(textEncoder, swift, parts) { + const SIZE_U8 = 1, SIZE_U32 = 4, SIZE_F32 = 4, SIZE_F64 = 8; + let totalLen = SIZE_U32; + for (const p of parts) { + switch (p.t) { + case __bjs_ParamType.STRING: { + const bytes = textEncoder.encode(p.v); + p._bytes = bytes; + totalLen += SIZE_U8 + SIZE_U32 + bytes.length; + break; + } + case __bjs_ParamType.INT32: totalLen += SIZE_U8 + SIZE_U32; break; + case __bjs_ParamType.BOOL: totalLen += SIZE_U8 + SIZE_U8; break; + case __bjs_ParamType.FLOAT32: totalLen += SIZE_U8 + SIZE_F32; break; + case __bjs_ParamType.FLOAT64: totalLen += SIZE_U8 + SIZE_F64; break; + default: throw new Error("Unsupported param type tag: " + p.t); + } + } + const buf = new Uint8Array(totalLen); + const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); + let off = 0; + view.setUint32(off, parts.length, true); off += SIZE_U32; + for (const p of parts) { + view.setUint8(off, p.t); off += SIZE_U8; + switch (p.t) { + case __bjs_ParamType.STRING: { + const b = p._bytes; + view.setUint32(off, b.length, true); off += SIZE_U32; + buf.set(b, off); off += b.length; + break; + } + case __bjs_ParamType.INT32: + view.setInt32(off, (p.v | 0), true); off += SIZE_U32; break; + case __bjs_ParamType.BOOL: + view.setUint8(off, p.v ? 1 : 0); off += SIZE_U8; break; + case __bjs_ParamType.FLOAT32: + view.setFloat32(off, Math.fround(p.v), true); off += SIZE_F32; break; + case __bjs_ParamType.FLOAT64: + view.setFloat64(off, p.v, true); off += SIZE_F64; break; + default: throw new Error("Unsupported param type tag: " + p.t); + } + } + const paramsId = swift.memory.retain(buf); + return { paramsId, paramsLen: buf.length, cleanup: () => { swift.memory.release(paramsId); } }; +} export const APIResult = { Tag: { Success: 0, @@ -16,64 +62,63 @@ export const APIResult = { }; -// Helper factory for APIResult enum const __bjs_createAPIResultHelpers = () => { return (textEncoder, swift) => ({ lower: (value) => { - const t = value.tag; - switch (t) { + const enumTag = value.tag; + switch (enumTag) { case APIResult.Tag.Success: { - const paramsObj = { "param0": value.param0 }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 0, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Success, paramsId, paramsLen, cleanup }; } case APIResult.Tag.Failure: { - const paramsObj = { "param0": (value.param0 | 0) }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 1, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.INT32, v: (value.param0 | 0) } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Failure, paramsId, paramsLen, cleanup }; } case APIResult.Tag.Flag: { - const paramsObj = { "param0": value.param0 }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 2, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.BOOL, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Flag, paramsId, paramsLen, cleanup }; } case APIResult.Tag.Rate: { - const paramsObj = { "param0": Math.fround(value.param0) }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 3, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.FLOAT32, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Rate, paramsId, paramsLen, cleanup }; } case APIResult.Tag.Precise: { - const paramsObj = { "param0": value.param0 }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 4, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.FLOAT64, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Precise, paramsId, paramsLen, cleanup }; } case APIResult.Tag.Info: { - const paramsBytes = textEncoder.encode("{}"); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 5, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = []; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: APIResult.Tag.Info, paramsId, paramsLen, cleanup }; } - default: throw new Error("Unknown APIResult tag: " + String(t)); + default: throw new Error("Unknown APIResult tag: " + String(enumTag)); } }, raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { const tag = tmpRetTag | 0; switch (tag) { - case 0: return { tag: APIResult.Tag.Success, param0: tmpRetStrings[0] }; - case 1: return { tag: APIResult.Tag.Failure, param0: tmpRetInts[0] }; - case 2: return { tag: APIResult.Tag.Flag, param0: tmpRetBools[0] }; - case 3: return { tag: APIResult.Tag.Rate, param0: tmpRetF32s[0] }; - case 4: return { tag: APIResult.Tag.Precise, param0: tmpRetF64s[0] }; - case 5: return { tag: APIResult.Tag.Info }; + case APIResult.Tag.Success: return { tag: APIResult.Tag.Success, param0: tmpRetStrings[0] }; + case APIResult.Tag.Failure: return { tag: APIResult.Tag.Failure, param0: tmpRetInts[0] }; + case APIResult.Tag.Flag: return { tag: APIResult.Tag.Flag, param0: tmpRetBools[0] }; + case APIResult.Tag.Rate: return { tag: APIResult.Tag.Rate, param0: tmpRetF32s[0] }; + case APIResult.Tag.Precise: return { tag: APIResult.Tag.Precise, param0: tmpRetF64s[0] }; + case APIResult.Tag.Info: return { tag: APIResult.Tag.Info }; default: throw new Error("Unknown APIResult tag returned from Swift: " + String(tag)); } } @@ -84,58 +129,191 @@ export const ComplexResult = { Success: 0, Error: 1, Status: 2, - Info: 3, + Coordinates: 3, + Comprehensive: 4, + Info: 5, } }; -// Helper factory for ComplexResult enum const __bjs_createComplexResultHelpers = () => { return (textEncoder, swift) => ({ lower: (value) => { - const t = value.tag; - switch (t) { + const enumTag = value.tag; + switch (enumTag) { case ComplexResult.Tag.Success: { - const paramsObj = { "param0": value.param0 }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 0, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Success, paramsId, paramsLen, cleanup }; } case ComplexResult.Tag.Error: { - const paramsObj = { "param0": value.param0, "param1": (value.param1 | 0) }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 1, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 }, + { t: __bjs_ParamType.INT32, v: (value.param1 | 0) } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Error, paramsId, paramsLen, cleanup }; } case ComplexResult.Tag.Status: { - const paramsObj = { "param0": value.param0, "param1": (value.param1 | 0), "param2": value.param2 }; - const paramsJson = JSON.stringify(paramsObj); - const paramsBytes = textEncoder.encode(paramsJson); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 2, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = [ + { t: __bjs_ParamType.BOOL, v: value.param0 }, + { t: __bjs_ParamType.INT32, v: (value.param1 | 0) }, + { t: __bjs_ParamType.STRING, v: value.param2 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Status, paramsId, paramsLen, cleanup }; + } + case ComplexResult.Tag.Coordinates: { + const parts = [ + { t: __bjs_ParamType.FLOAT64, v: value.param0 }, + { t: __bjs_ParamType.FLOAT64, v: value.param1 }, + { t: __bjs_ParamType.FLOAT64, v: value.param2 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Coordinates, paramsId, paramsLen, cleanup }; + } + case ComplexResult.Tag.Comprehensive: { + const parts = [ + { t: __bjs_ParamType.BOOL, v: value.param0 }, + { t: __bjs_ParamType.BOOL, v: value.param1 }, + { t: __bjs_ParamType.INT32, v: (value.param2 | 0) }, + { t: __bjs_ParamType.INT32, v: (value.param3 | 0) }, + { t: __bjs_ParamType.FLOAT64, v: value.param4 }, + { t: __bjs_ParamType.FLOAT64, v: value.param5 }, + { t: __bjs_ParamType.STRING, v: value.param6 }, + { t: __bjs_ParamType.STRING, v: value.param7 }, + { t: __bjs_ParamType.STRING, v: value.param8 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Comprehensive, paramsId, paramsLen, cleanup }; } case ComplexResult.Tag.Info: { - const paramsBytes = textEncoder.encode("{}"); - const paramsId = swift.memory.retain(paramsBytes); - return { caseId: 3, paramsId: paramsId, paramsLen: paramsBytes.length, cleanup: () => { swift.memory.release(paramsId); } }; + const parts = []; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: ComplexResult.Tag.Info, paramsId, paramsLen, cleanup }; } - default: throw new Error("Unknown ComplexResult tag: " + String(t)); + default: throw new Error("Unknown ComplexResult tag: " + String(enumTag)); } }, raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { const tag = tmpRetTag | 0; switch (tag) { - case 0: return { tag: ComplexResult.Tag.Success, param0: tmpRetStrings[0] }; - case 1: return { tag: ComplexResult.Tag.Error, param0: tmpRetStrings[0], param1: tmpRetInts[0] }; - case 2: return { tag: ComplexResult.Tag.Status, param0: tmpRetBools[0], param1: tmpRetInts[0], param2: tmpRetStrings[0] }; - case 3: return { tag: ComplexResult.Tag.Info }; + case ComplexResult.Tag.Success: return { tag: ComplexResult.Tag.Success, param0: tmpRetStrings[0] }; + case ComplexResult.Tag.Error: return { tag: ComplexResult.Tag.Error, param0: tmpRetStrings[0], param1: tmpRetInts[0] }; + case ComplexResult.Tag.Status: return { tag: ComplexResult.Tag.Status, param0: tmpRetBools[0], param1: tmpRetInts[0], param2: tmpRetStrings[0] }; + case ComplexResult.Tag.Coordinates: return { tag: ComplexResult.Tag.Coordinates, param0: tmpRetF64s[0], param1: tmpRetF64s[1], param2: tmpRetF64s[2] }; + case ComplexResult.Tag.Comprehensive: return { tag: ComplexResult.Tag.Comprehensive, param0: tmpRetBools[0], param1: tmpRetBools[1], param2: tmpRetInts[0], param3: tmpRetInts[1], param4: tmpRetF64s[0], param5: tmpRetF64s[1], param6: tmpRetStrings[0], param7: tmpRetStrings[1], param8: tmpRetStrings[2] }; + case ComplexResult.Tag.Info: return { tag: ComplexResult.Tag.Info }; default: throw new Error("Unknown ComplexResult tag returned from Swift: " + String(tag)); } } }); }; +export const Result = { + Tag: { + Success: 0, + Failure: 1, + Status: 2, + } +}; + + +const __bjs_createResultHelpers = () => { + return (textEncoder, swift) => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case Result.Tag.Success: { + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: Result.Tag.Success, paramsId, paramsLen, cleanup }; + } + case Result.Tag.Failure: { + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 }, + { t: __bjs_ParamType.INT32, v: (value.param1 | 0) } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: Result.Tag.Failure, paramsId, paramsLen, cleanup }; + } + case Result.Tag.Status: { + const parts = [ + { t: __bjs_ParamType.BOOL, v: value.param0 }, + { t: __bjs_ParamType.INT32, v: (value.param1 | 0) }, + { t: __bjs_ParamType.STRING, v: value.param2 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: Result.Tag.Status, paramsId, paramsLen, cleanup }; + } + default: throw new Error("Unknown Result tag: " + String(enumTag)); + } + }, + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { + const tag = tmpRetTag | 0; + switch (tag) { + case Result.Tag.Success: return { tag: Result.Tag.Success, param0: tmpRetStrings[0] }; + case Result.Tag.Failure: return { tag: Result.Tag.Failure, param0: tmpRetStrings[0], param1: tmpRetInts[0] }; + case Result.Tag.Status: return { tag: Result.Tag.Status, param0: tmpRetBools[0], param1: tmpRetInts[0], param2: tmpRetStrings[0] }; + default: throw new Error("Unknown Result tag returned from Swift: " + String(tag)); + } + } + }); +}; +export const NetworkingResult = { + Tag: { + Success: 0, + Failure: 1, + } +}; + + +const __bjs_createNetworkingResultHelpers = () => { + return (textEncoder, swift) => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case NetworkingResult.Tag.Success: { + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: NetworkingResult.Tag.Success, paramsId, paramsLen, cleanup }; + } + case NetworkingResult.Tag.Failure: { + const parts = [ + { t: __bjs_ParamType.STRING, v: value.param0 }, + { t: __bjs_ParamType.INT32, v: (value.param1 | 0) } + ]; + const { paramsId, paramsLen, cleanup } = __bjs_encodeEnumParams(textEncoder, swift, parts); + return { caseId: NetworkingResult.Tag.Failure, paramsId, paramsLen, cleanup }; + } + default: throw new Error("Unknown NetworkingResult tag: " + String(enumTag)); + } + }, + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools) => { + const tag = tmpRetTag | 0; + switch (tag) { + case NetworkingResult.Tag.Success: return { tag: NetworkingResult.Tag.Success, param0: tmpRetStrings[0] }; + case NetworkingResult.Tag.Failure: return { tag: NetworkingResult.Tag.Failure, param0: tmpRetStrings[0], param1: tmpRetInts[0] }; + default: throw new Error("Unknown NetworkingResult tag returned from Swift: " + String(tag)); + } + } + }); +}; + +if (typeof globalThis.Utilities === 'undefined') { + globalThis.Utilities = {}; +} +if (typeof globalThis.API === 'undefined') { + globalThis.API = {}; +} + +globalThis.Utilities.Result = Result; +globalThis.API.NetworkingResult = NetworkingResult; export async function createInstantiator(options, swift) { let instance; @@ -145,9 +323,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -198,9 +373,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -209,16 +381,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { @@ -232,16 +401,22 @@ export async function createInstantiator(options, swift) { instance = i; memory = instance.exports.memory; - // Set up APIResult enum helpers const APIResultHelpers = __bjs_createAPIResultHelpers()(textEncoder, swift); globalThis.__bjs_lower_APIResult = (value) => APIResultHelpers.lower(value); globalThis.__bjs_raise_APIResult = () => APIResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); - // Set up ComplexResult enum helpers const ComplexResultHelpers = __bjs_createComplexResultHelpers()(textEncoder, swift); globalThis.__bjs_lower_ComplexResult = (value) => ComplexResultHelpers.lower(value); globalThis.__bjs_raise_ComplexResult = () => ComplexResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); + const ResultHelpers = __bjs_createResultHelpers()(textEncoder, swift); + globalThis.__bjs_lower_Result = (value) => ResultHelpers.lower(value); + globalThis.__bjs_raise_Result = () => ResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); + + const NetworkingResultHelpers = __bjs_createNetworkingResultHelpers()(textEncoder, swift); + globalThis.__bjs_lower_NetworkingResult = (value) => NetworkingResultHelpers.lower(value); + globalThis.__bjs_raise_NetworkingResult = () => NetworkingResultHelpers.raise(tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s, tmpRetBools); + setException = (error) => { instance.exports._swift_js_exception.value = swift.memory.retain(error) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js index 03c7aec0..cc204376 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js @@ -33,9 +33,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -86,9 +83,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -97,16 +91,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { @@ -129,18 +120,18 @@ export async function createInstantiator(options, swift) { return { setDirection: function bjs_setDirection(direction) { - instance.exports.bjs_setDirection(direction | 0); + instance.exports.bjs_setDirection(direction); }, getDirection: function bjs_getDirection() { const ret = instance.exports.bjs_getDirection(); return ret; }, processDirection: function bjs_processDirection(input) { - const ret = instance.exports.bjs_processDirection(input | 0); + const ret = instance.exports.bjs_processDirection(input); return ret; }, setTSDirection: function bjs_setTSDirection(direction) { - instance.exports.bjs_setTSDirection(direction | 0); + instance.exports.bjs_setTSDirection(direction); }, getTSDirection: function bjs_getTSDirection() { const ret = instance.exports.bjs_getTSDirection(); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js index 355b2b46..7819d612 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js @@ -59,9 +59,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -112,9 +109,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -123,16 +117,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { @@ -214,7 +205,7 @@ export async function createInstantiator(options, swift) { return HTTPServer.__construct(ret); } call(method) { - instance.exports.bjs_HTTPServer_call(this.pointer, method | 0); + instance.exports.bjs_HTTPServer_call(this.pointer, method); } } class TestServer extends SwiftHeapObject { @@ -228,7 +219,7 @@ export async function createInstantiator(options, swift) { return TestServer.__construct(ret); } call(method) { - instance.exports.bjs_TestServer_call(this.pointer, method | 0); + instance.exports.bjs_TestServer_call(this.pointer, method); } } const exports = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js index 37b2312b..f44c7c8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js @@ -88,9 +88,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -141,9 +138,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -152,16 +146,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js index 937319ec..4bca5872 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js index 70254dc6..8335235a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js index 0b92acfa..1682c4d2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js index 895298db..6dd6b163 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js index 936367d4..4c66f1dc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js index c89bc604..88c55eac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js index f5bbfbc0..e7ea8533 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js index 5bad7ab4..21a0a88b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js index c9f577c8..f656f84e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js index f113dbbb..0b3ac72f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js index 093080cc..cf9e864c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js index 842833b5..589d6544 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js index 814a7680..498c9844 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js index a82ba566..6d755a7b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js index e80cb987..04226bd9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js index 24a28819..8e0f0ac7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js index 8e77db43..514a9910 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js index 9a84b030..e92d3f09 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js @@ -12,9 +12,6 @@ export async function createInstantiator(options, swift) { const textEncoder = new TextEncoder("utf-8"); let tmpRetString; - let tmpRetInt; - let tmpRetF32; - let tmpRetF64; let tmpRetBytes; let tmpRetException; let tmpRetTag; @@ -65,9 +62,6 @@ export async function createInstantiator(options, swift) { bjs["swift_js_return_tag"] = function(tag) { tmpRetTag = tag | 0; tmpRetString = undefined; - tmpRetInt = undefined; - tmpRetF32 = undefined; - tmpRetF64 = undefined; tmpRetStrings = []; tmpRetInts = []; tmpRetF32s = []; @@ -76,16 +70,13 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_return_int"] = function(v) { const value = v | 0; - tmpRetInt = value; tmpRetInts.push(value); } bjs["swift_js_return_f32"] = function(v) { const value = Math.fround(v); - tmpRetF32 = value; tmpRetF32s.push(value); } bjs["swift_js_return_f64"] = function(v) { - tmpRetF64 = v; tmpRetF64s.push(v); } bjs["swift_js_return_bool"] = function(v) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json index f36d10fd..1eeca1b8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.json @@ -135,6 +135,100 @@ ], "name" : "status" }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + } + ], + "name" : "coordinates" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "comprehensive" + }, { "associatedValues" : [ @@ -145,6 +239,114 @@ "emitStyle" : "const", "name" : "ComplexResult", "swiftCallName" : "ComplexResult" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "status" + } + ], + "emitStyle" : "const", + "name" : "Result", + "namespace" : [ + "Utilities" + ], + "swiftCallName" : "Utilities.Result" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + } + ], + "emitStyle" : "const", + "name" : "NetworkingResult", + "namespace" : [ + "API" + ], + "swiftCallName" : "NetworkingResult" } ], "functions" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift index d844c163..27d52b01 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -6,217 +6,402 @@ @_spi(BridgeJS) import JavaScriptKit -import Foundation +fileprivate enum _BJSParamType: UInt8 { + case string = 1 + case int32 = 2 + case bool = 3 + case float32 = 4 + case float64 = 5 +} + +fileprivate struct _BJSBinaryReader { + let raw: UnsafeRawBufferPointer + var offset: Int = 0 + + @inline(__always) + mutating func readUInt8() -> UInt8 { + let b = raw[offset] + offset += 1 + return b + } + + @inline(__always) + mutating func readUInt32() -> UInt32 { + var v = UInt32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return UInt32(littleEndian: v) + } + + @inline(__always) + mutating func readInt32() -> Int32 { + var v = Int32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Int32(littleEndian: v) + } + + @inline(__always) + mutating func readFloat32() -> Float32 { + var bits = UInt32(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Float32(bitPattern: UInt32(littleEndian: bits)) + } + + @inline(__always) + mutating func readFloat64() -> Float64 { + var bits = UInt64(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 8)])) + } + offset += 8 + return Float64(bitPattern: UInt64(littleEndian: bits)) + } + + @inline(__always) + mutating func readString() -> String { + let len = Int(readUInt32()) + let s = String(decoding: UnsafeBufferPointer( + start: raw.baseAddress!.advanced(by: offset).assumingMemoryBound(to: UInt8.self), + count: len + ), as: UTF8.self) + offset += len + return s + } + + @inline(__always) + mutating func expectTag(_ expected: _BJSParamType) { + let rawTag = readUInt8() + guard let got = _BJSParamType(rawValue: rawTag), got == expected else { + preconditionFailure("BridgeJS: mismatched enum param tag. Expected \(expected) got \(String(describing: _BJSParamType(rawValue: rawTag)))") + } + } + + @inline(__always) + mutating func readParamCount(expected: Int) { + let count = Int(readUInt32()) + precondition(count == expected, "BridgeJS: mismatched enum param count. Expected \(expected) got \(count)") + } +} + +@_extern(wasm, module: "bjs", name: "swift_js_init_memory") +func _swift_js_init_memory(_: Int32, _: UnsafeMutablePointer) + +@_extern(wasm, module: "bjs", name: "swift_js_return_tag") +func _swift_js_return_tag(_: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_string") +func _swift_js_return_string(_: UnsafePointer?, _: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_int") +func _swift_js_return_int(_: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_f32") +func _swift_js_return_f32(_: Float32) +@_extern(wasm, module: "bjs", name: "swift_js_return_f64") +func _swift_js_return_f64(_: Float64) +@_extern(wasm, module: "bjs", name: "swift_js_return_bool") +func _swift_js_return_bool(_: Int32) + +private extension APIResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 1) + reader.expectTag(.int32) + let param0 = Int(reader.readInt32()) + return .failure(param0) + case 2: + reader.readParamCount(expected: 1) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + return .flag(param0) + case 3: + reader.readParamCount(expected: 1) + reader.expectTag(.float32) + let param0 = reader.readFloat32() + return .rate(param0) + case 4: + reader.readParamCount(expected: 1) + reader.expectTag(.float64) + let param0 = reader.readFloat64() + return .precise(param0) + case 5: + return .info + default: + fatalError("Unknown APIResult case ID: \(caseId)") + } + } + } -extension APIResult { - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - @_extern(wasm, module: "bjs", name: "swift_js_return_bool") - func _swift_js_return_bool(_: Int32) + func bridgeJSLowerReturn() { switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .failure(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0): _swift_js_return_tag(Int32(1)) - _swift_js_return_int(Int32(param0)) - case .flag(let param0): + _swift_js_return_int(Int32(param0)) + case .flag(let param0): _swift_js_return_tag(Int32(2)) - _swift_js_return_bool(param0 ? 1 : 0) - case .rate(let param0): + _swift_js_return_bool(param0 ? 1 : 0) + case .rate(let param0): _swift_js_return_tag(Int32(3)) - _swift_js_return_f32(param0) - case .precise(let param0): + _swift_js_return_f32(param0) + case .precise(let param0): _swift_js_return_tag(Int32(4)) - _swift_js_return_f64(param0) - case .info: + _swift_js_return_f64(param0) + case .info: _swift_js_return_tag(Int32(5)) } } } -extension APIResult { - static func constructFromAPIResult_0(param0: String) -> APIResult { - return .success(param0) -} - - static func constructFromAPIResult_1(param0: Int32) -> APIResult { - return .failure(Int(param0)) -} - - static func constructFromAPIResult_2(param0: Int32) -> APIResult { - return .flag((param0 != 0)) -} - - static func constructFromAPIResult_3(param0: Float32) -> APIResult { - return .rate(param0) -} - - static func constructFromAPIResult_4(param0: Float64) -> APIResult { - return .precise(param0) -} - - static func constructFromAPIResult_5() -> APIResult { - return .info -} - - static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { - let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in +private extension ComplexResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) - return Int(paramsLen) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .error(param0, param1) + case 2: + reader.readParamCount(expected: 3) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + reader.expectTag(.string) + let param2 = reader.readString() + return .status(param0, param1, param2) + case 3: + reader.readParamCount(expected: 3) + reader.expectTag(.float64) + let param0 = reader.readFloat64() + reader.expectTag(.float64) + let param1 = reader.readFloat64() + reader.expectTag(.float64) + let param2 = reader.readFloat64() + return .coordinates(param0, param1, param2) + case 4: + reader.readParamCount(expected: 9) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.bool) + let param1 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param2 = Int(reader.readInt32()) + reader.expectTag(.int32) + let param3 = Int(reader.readInt32()) + reader.expectTag(.float64) + let param4 = reader.readFloat64() + reader.expectTag(.float64) + let param5 = reader.readFloat64() + reader.expectTag(.string) + let param6 = reader.readString() + reader.expectTag(.string) + let param7 = reader.readString() + reader.expectTag(.string) + let param8 = reader.readString() + return .comprehensive(param0, param1, param2, param3, param4, param5, param6, param7, param8) + case 5: + return .info + default: + fatalError("Unknown ComplexResult case ID: \(caseId)") + } } - return dispatchConstructFromJson(caseId, paramsString) } - - static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> APIResult { - switch caseId { - case 0: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + + func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .error(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = params["param0"] as! String - return constructFromAPIResult_0(param0: param0) - case 1: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + _swift_js_return_int(Int32(param1)) + case .status(let param0, let param1, let param2): + _swift_js_return_tag(Int32(2)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = params["param0"] as! Int32 - return constructFromAPIResult_1(param0: param0) - case 2: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + case .coordinates(let param0, let param1, let param2): + _swift_js_return_tag(Int32(3)) + _swift_js_return_f64(param0) + _swift_js_return_f64(param1) + _swift_js_return_f64(param2) + case .comprehensive(let param0, let param1, let param2, let param3, let param4, let param5, let param6, let param7, let param8): + _swift_js_return_tag(Int32(4)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_bool(param1 ? 1 : 0) + _swift_js_return_int(Int32(param2)) + _swift_js_return_int(Int32(param3)) + _swift_js_return_f64(param4) + _swift_js_return_f64(param5) + var __bjs_param6 = param6 + __bjs_param6.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0) - return constructFromAPIResult_2(param0: param0) - case 3: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + var __bjs_param7 = param7 + __bjs_param7.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = params["param0"] as! Float32 - return constructFromAPIResult_3(param0: param0) - case 4: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + var __bjs_param8 = param8 + __bjs_param8.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = params["param0"] as! Float64 - return constructFromAPIResult_4(param0: param0) - case 5: return constructFromAPIResult_5() - default: fatalError("Unknown APIResult case ID: \(caseId)") + case .info: + _swift_js_return_tag(Int32(5)) } } } -import Foundation +private extension Utilities.Result { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> Utilities.Result { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .failure(param0, param1) + case 2: + reader.readParamCount(expected: 3) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + reader.expectTag(.string) + let param2 = reader.readString() + return .status(param0, param1, param2) + default: + fatalError("Unknown Utilities.Result case ID: \(caseId)") + } + } + } -extension ComplexResult { - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - @_extern(wasm, module: "bjs", name: "swift_js_return_bool") - func _swift_js_return_bool(_: Int32) + func bridgeJSLowerReturn() { switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .error(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0, let param1): _swift_js_return_tag(Int32(1)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - _swift_js_return_int(Int32(param1)) - case .status(let param0, let param1, let param2): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_return_int(Int32(param1)) + case .status(let param0, let param1, let param2): _swift_js_return_tag(Int32(2)) - _swift_js_return_bool(param0 ? 1 : 0) - _swift_js_return_int(Int32(param1)) - var mutableParam2 = param2 -mutableParam2.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .info: - _swift_js_return_tag(Int32(3)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } } } } -extension ComplexResult { - static func constructFromComplexResult_0(param0: String) -> ComplexResult { - return .success(param0) -} - - static func constructFromComplexResult_1(param0: String, param1: Int32) -> ComplexResult { - return .error(param0, Int(param1)) -} - - static func constructFromComplexResult_2(param0: Int32, param1: Int32, param2: String) -> ComplexResult { - return .status((param0 != 0), Int(param1), param2) -} - - static func constructFromComplexResult_3() -> ComplexResult { - return .info -} - - static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { - let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in +private extension NetworkingResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> NetworkingResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) - return Int(paramsLen) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .failure(param0, param1) + default: + fatalError("Unknown NetworkingResult case ID: \(caseId)") + } } - return dispatchConstructFromJson(caseId, paramsString) - } - - static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> ComplexResult { - switch caseId { - case 0: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") } - let param0 = params["param0"] as! String - return constructFromComplexResult_0(param0: param0) - case 1: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + + func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = params["param0"] as! String; let param1 = params["param1"] as! Int32 - return constructFromComplexResult_1(param0: param0, param1: param1) - case 2: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") + case .failure(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! Int32; let param2 = params["param2"] as! String - return constructFromComplexResult_2(param0: param0, param1: param1, param2: param2) - case 3: return constructFromComplexResult_3() - default: fatalError("Unknown ComplexResult case ID: \(caseId)") + _swift_js_return_int(Int32(param1)) } } } @@ -225,7 +410,7 @@ extension ComplexResult { @_cdecl("bjs_handle") public func _bjs_handle(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - handle(result: APIResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) + handle(result: APIResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) #else fatalError("Only available on WebAssembly") #endif @@ -236,7 +421,7 @@ public func _bjs_handle(resultCaseId: Int32, resultParamsId: Int32, resultParams public func _bjs_getResult() -> Void { #if arch(wasm32) let ret = getResult() - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -246,7 +431,7 @@ public func _bjs_getResult() -> Void { @_cdecl("bjs_handleComplex") public func _bjs_handleComplex(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - handleComplex(result: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) + handleComplex(result: ComplexResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) #else fatalError("Only available on WebAssembly") #endif @@ -257,7 +442,7 @@ public func _bjs_handleComplex(resultCaseId: Int32, resultParamsId: Int32, resul public func _bjs_getComplexResult() -> Void { #if arch(wasm32) let ret = getComplexResult() - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index b17b15fa..e01b6665 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -313,6 +313,8 @@ enum ComplexResult { case error(String, Int) case location(Double, Double, String) case status(Bool, Int, String) + case coordinates(Double, Double, Double) + case comprehensive(Bool, Bool, Int, Int, Double, Double, String, String, String) case info } @@ -336,6 +338,24 @@ enum ComplexResult { return .status(active, code, message) } +@JS func makeComplexResultCoordinates(_ x: Double, _ y: Double, _ z: Double) -> ComplexResult { + return .coordinates(x, y, z) +} + +@JS func makeComplexResultComprehensive( + _ flag1: Bool, + _ flag2: Bool, + _ count1: Int, + _ count2: Int, + _ value1: Double, + _ value2: Double, + _ text1: String, + _ text2: String, + _ text3: String +) -> ComplexResult { + return .comprehensive(flag1, flag2, count1, count2, value1, value2, text1, text2, text3) +} + @JS func makeComplexResultInfo() -> ComplexResult { return .info } @@ -344,6 +364,49 @@ enum ComplexResult { return result } +@JS enum Utilities { + @JS enum Result { + case success(String) + case failure(String, Int) + case status(Bool, Int, String) + } +} + +@JS enum API { + @JS enum NetworkingResult { + case success(String) + case failure(String, Int) + } +} + +@JS func makeUtilitiesResultSuccess(_ message: String) -> Utilities.Result { + return .success(message) +} + +@JS func makeUtilitiesResultFailure(_ error: String, _ code: Int) -> Utilities.Result { + return .failure(error, code) +} + +@JS func makeUtilitiesResultStatus(_ active: Bool, _ code: Int, _ message: String) -> Utilities.Result { + return .status(active, code, message) +} + +@JS func makeAPINetworkingResultSuccess(_ message: String) -> API.NetworkingResult { + return .success(message) +} + +@JS func makeAPINetworkingResultFailure(_ error: String, _ code: Int) -> API.NetworkingResult { + return .failure(error, code) +} + +@JS func roundtripUtilitiesResult(_ result: Utilities.Result) -> Utilities.Result { + return result +} + +@JS func roundtripAPINetworkingResult(_ result: API.NetworkingResult) -> API.NetworkingResult { + return result +} + class ExportAPITests: XCTestCase { func testAll() { var hasDeinitGreeter = false diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index dc314f9b..f016aa9d 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -6,6 +6,107 @@ @_spi(BridgeJS) import JavaScriptKit +fileprivate enum _BJSParamType: UInt8 { + case string = 1 + case int32 = 2 + case bool = 3 + case float32 = 4 + case float64 = 5 +} + +fileprivate struct _BJSBinaryReader { + let raw: UnsafeRawBufferPointer + var offset: Int = 0 + + @inline(__always) + mutating func readUInt8() -> UInt8 { + let b = raw[offset] + offset += 1 + return b + } + + @inline(__always) + mutating func readUInt32() -> UInt32 { + var v = UInt32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return UInt32(littleEndian: v) + } + + @inline(__always) + mutating func readInt32() -> Int32 { + var v = Int32(0) + withUnsafeMutableBytes(of: &v) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Int32(littleEndian: v) + } + + @inline(__always) + mutating func readFloat32() -> Float32 { + var bits = UInt32(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 4)])) + } + offset += 4 + return Float32(bitPattern: UInt32(littleEndian: bits)) + } + + @inline(__always) + mutating func readFloat64() -> Float64 { + var bits = UInt64(0) + withUnsafeMutableBytes(of: &bits) { dst in + dst.copyBytes(from: UnsafeRawBufferPointer(rebasing: raw[offset..<(offset + 8)])) + } + offset += 8 + return Float64(bitPattern: UInt64(littleEndian: bits)) + } + + @inline(__always) + mutating func readString() -> String { + let len = Int(readUInt32()) + let s = String(decoding: UnsafeBufferPointer( + start: raw.baseAddress!.advanced(by: offset).assumingMemoryBound(to: UInt8.self), + count: len + ), as: UTF8.self) + offset += len + return s + } + + @inline(__always) + mutating func expectTag(_ expected: _BJSParamType) { + let rawTag = readUInt8() + guard let got = _BJSParamType(rawValue: rawTag), got == expected else { + preconditionFailure("BridgeJS: mismatched enum param tag. Expected \(expected) got \(String(describing: _BJSParamType(rawValue: rawTag)))") + } + } + + @inline(__always) + mutating func readParamCount(expected: Int) { + let count = Int(readUInt32()) + precondition(count == expected, "BridgeJS: mismatched enum param count. Expected \(expected) got \(count)") + } +} + +@_extern(wasm, module: "bjs", name: "swift_js_init_memory") +func _swift_js_init_memory(_: Int32, _: UnsafeMutablePointer) + +@_extern(wasm, module: "bjs", name: "swift_js_return_tag") +func _swift_js_return_tag(_: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_string") +func _swift_js_return_string(_: UnsafePointer?, _: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_int") +func _swift_js_return_int(_: Int32) +@_extern(wasm, module: "bjs", name: "swift_js_return_f32") +func _swift_js_return_f32(_: Float32) +@_extern(wasm, module: "bjs", name: "swift_js_return_f64") +func _swift_js_return_f64(_: Float64) +@_extern(wasm, module: "bjs", name: "swift_js_return_bool") +func _swift_js_return_bool(_: Int32) + extension Direction { init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { @@ -144,236 +245,318 @@ extension Internal.SupportedMethod { } } -import Foundation +private extension APIResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 1) + reader.expectTag(.int32) + let param0 = Int(reader.readInt32()) + return .failure(param0) + case 2: + reader.readParamCount(expected: 1) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + return .flag(param0) + case 3: + reader.readParamCount(expected: 1) + reader.expectTag(.float32) + let param0 = reader.readFloat32() + return .rate(param0) + case 4: + reader.readParamCount(expected: 1) + reader.expectTag(.float64) + let param0 = reader.readFloat64() + return .precise(param0) + case 5: + return .info + default: + fatalError("Unknown APIResult case ID: \(caseId)") + } + } + } -extension APIResult { - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - @_extern(wasm, module: "bjs", name: "swift_js_return_bool") - func _swift_js_return_bool(_: Int32) + func bridgeJSLowerReturn() { switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .failure(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0): _swift_js_return_tag(Int32(1)) - _swift_js_return_int(Int32(param0)) - case .flag(let param0): + _swift_js_return_int(Int32(param0)) + case .flag(let param0): _swift_js_return_tag(Int32(2)) - _swift_js_return_bool(param0 ? 1 : 0) - case .rate(let param0): + _swift_js_return_bool(param0 ? 1 : 0) + case .rate(let param0): _swift_js_return_tag(Int32(3)) - _swift_js_return_f32(param0) - case .precise(let param0): + _swift_js_return_f32(param0) + case .precise(let param0): _swift_js_return_tag(Int32(4)) - _swift_js_return_f64(param0) - case .info: + _swift_js_return_f64(param0) + case .info: _swift_js_return_tag(Int32(5)) } } } -extension APIResult { - static func constructFromAPIResult_0(param0: String) -> APIResult { - return .success(param0) -} - - static func constructFromAPIResult_1(param0: Int32) -> APIResult { - return .failure(Int(param0)) -} - - static func constructFromAPIResult_2(param0: Int32) -> APIResult { - return .flag((param0 != 0)) -} - - static func constructFromAPIResult_3(param0: Float32) -> APIResult { - return .rate(param0) -} - - static func constructFromAPIResult_4(param0: Float64) -> APIResult { - return .precise(param0) -} - - static func constructFromAPIResult_5() -> APIResult { - return .info -} - - static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> APIResult { - let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in +private extension ComplexResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) - return Int(paramsLen) + initializedCount = Int(paramsLen) } - return dispatchConstructFromJson(caseId, paramsString) - } - - static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> APIResult { - switch caseId { - case 0: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! String - return constructFromAPIResult_0(param0: param0) - case 1: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! Int32 - return constructFromAPIResult_1(param0: param0) - case 2: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0) - return constructFromAPIResult_2(param0: param0) - case 3: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! Float32 - return constructFromAPIResult_3(param0: param0) - case 4: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! Float64 - return constructFromAPIResult_4(param0: param0) - case 5: return constructFromAPIResult_5() - default: fatalError("Unknown APIResult case ID: \(caseId)") + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .error(param0, param1) + case 2: + reader.readParamCount(expected: 3) + reader.expectTag(.float64) + let param0 = reader.readFloat64() + reader.expectTag(.float64) + let param1 = reader.readFloat64() + reader.expectTag(.string) + let param2 = reader.readString() + return .location(param0, param1, param2) + case 3: + reader.readParamCount(expected: 3) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + reader.expectTag(.string) + let param2 = reader.readString() + return .status(param0, param1, param2) + case 4: + reader.readParamCount(expected: 3) + reader.expectTag(.float64) + let param0 = reader.readFloat64() + reader.expectTag(.float64) + let param1 = reader.readFloat64() + reader.expectTag(.float64) + let param2 = reader.readFloat64() + return .coordinates(param0, param1, param2) + case 5: + reader.readParamCount(expected: 9) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.bool) + let param1 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param2 = Int(reader.readInt32()) + reader.expectTag(.int32) + let param3 = Int(reader.readInt32()) + reader.expectTag(.float64) + let param4 = reader.readFloat64() + reader.expectTag(.float64) + let param5 = reader.readFloat64() + reader.expectTag(.string) + let param6 = reader.readString() + reader.expectTag(.string) + let param7 = reader.readString() + reader.expectTag(.string) + let param8 = reader.readString() + return .comprehensive(param0, param1, param2, param3, param4, param5, param6, param7, param8) + case 6: + return .info + default: + fatalError("Unknown ComplexResult case ID: \(caseId)") + } } } -} - -import Foundation -extension ComplexResult { - func bridgeJSReturn() { - @_extern(wasm, module: "bjs", name: "swift_js_return_tag") - func _swift_js_return_tag(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_string") - func _swift_js_return_string(_: UnsafePointer?, _: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_int") - func _swift_js_return_int(_: Int32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f32") - func _swift_js_return_f32(_: Float32) - @_extern(wasm, module: "bjs", name: "swift_js_return_f64") - func _swift_js_return_f64(_: Float64) - @_extern(wasm, module: "bjs", name: "swift_js_return_bool") - func _swift_js_return_bool(_: Int32) + func bridgeJSLowerReturn() { switch self { case .success(let param0): _swift_js_return_tag(Int32(0)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .error(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .error(let param0, let param1): _swift_js_return_tag(Int32(1)) - var mutableParam0 = param0 -mutableParam0.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - _swift_js_return_int(Int32(param1)) - case .location(let param0, let param1, let param2): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_return_int(Int32(param1)) + case .location(let param0, let param1, let param2): _swift_js_return_tag(Int32(2)) - _swift_js_return_f64(param0) - _swift_js_return_f64(param1) - var mutableParam2 = param2 -mutableParam2.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .status(let param0, let param1, let param2): + _swift_js_return_f64(param0) + _swift_js_return_f64(param1) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .status(let param0, let param1, let param2): _swift_js_return_tag(Int32(3)) - _swift_js_return_bool(param0 ? 1 : 0) - _swift_js_return_int(Int32(param1)) - var mutableParam2 = param2 -mutableParam2.withUTF8 { ptr in - _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) -} - case .info: + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .coordinates(let param0, let param1, let param2): _swift_js_return_tag(Int32(4)) + _swift_js_return_f64(param0) + _swift_js_return_f64(param1) + _swift_js_return_f64(param2) + case .comprehensive(let param0, let param1, let param2, let param3, let param4, let param5, let param6, let param7, let param8): + _swift_js_return_tag(Int32(5)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_bool(param1 ? 1 : 0) + _swift_js_return_int(Int32(param2)) + _swift_js_return_int(Int32(param3)) + _swift_js_return_f64(param4) + _swift_js_return_f64(param5) + var __bjs_param6 = param6 + __bjs_param6.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param7 = param7 + __bjs_param7.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param8 = param8 + __bjs_param8.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .info: + _swift_js_return_tag(Int32(6)) } } } -extension ComplexResult { - static func constructFromComplexResult_0(param0: String) -> ComplexResult { - return .success(param0) -} - - static func constructFromComplexResult_1(param0: String, param1: Int32) -> ComplexResult { - return .error(param0, Int(param1)) -} - - static func constructFromComplexResult_2(param0: Float64, param1: Float64, param2: String) -> ComplexResult { - return .location(param0, param1, param2) -} +private extension Utilities.Result { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> Utilities.Result { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in + _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) + initializedCount = Int(paramsLen) + } + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .failure(param0, param1) + case 2: + reader.readParamCount(expected: 3) + reader.expectTag(.bool) + let param0 = Int32(reader.readUInt8()) != 0 + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + reader.expectTag(.string) + let param2 = reader.readString() + return .status(param0, param1, param2) + default: + fatalError("Unknown Utilities.Result case ID: \(caseId)") + } + } + } - static func constructFromComplexResult_3(param0: Int32, param1: Int32, param2: String) -> ComplexResult { - return .status((param0 != 0), Int(param1), param2) + func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_return_int(Int32(param1)) + case .status(let param0, let param1, let param2): + _swift_js_return_tag(Int32(2)) + _swift_js_return_bool(param0 ? 1 : 0) + _swift_js_return_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + } + } } - static func constructFromComplexResult_4() -> ComplexResult { - return .info -} - - static func dispatchConstruct(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> ComplexResult { - let paramsString = String(unsafeUninitializedCapacity: Int(paramsLen)) { buf in +private extension API.NetworkingResult { + static func bridgeJSLiftParameter(_ caseId: Int32, _ paramsId: Int32, _ paramsLen: Int32) -> API.NetworkingResult { + let params: [UInt8] = .init(unsafeUninitializedCapacity: Int(paramsLen)) { buf, initializedCount in _swift_js_init_memory(paramsId, buf.baseAddress.unsafelyUnwrapped) - return Int(paramsLen) + initializedCount = Int(paramsLen) } - return dispatchConstructFromJson(caseId, paramsString) - } - - static func dispatchConstructFromJson(_ caseId: Int32, _ paramsJson: String) -> ComplexResult { - switch caseId { - case 0: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! String - return constructFromComplexResult_0(param0: param0) - case 1: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! String; let param1 = params["param1"] as! Int32 - return constructFromComplexResult_1(param0: param0, param1: param1) - case 2: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = params["param0"] as! Float64; let param1 = params["param1"] as! Float64; let param2 = params["param2"] as! String - return constructFromComplexResult_2(param0: param0, param1: param1, param2: param2) - case 3: - guard let data = paramsJson.data(using: .utf8), - let params = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - fatalError("Failed to parse parameters JSON") - } - let param0 = Int32(params["param0"] as! Bool ? 1 : 0); let param1 = params["param1"] as! Int32; let param2 = params["param2"] as! String - return constructFromComplexResult_3(param0: param0, param1: param1, param2: param2) - case 4: return constructFromComplexResult_4() - default: fatalError("Unknown ComplexResult case ID: \(caseId)") + return params.withUnsafeBytes { raw in + var reader = _BJSBinaryReader(raw: raw) + switch caseId { + case 0: + reader.readParamCount(expected: 1) + reader.expectTag(.string) + let param0 = reader.readString() + return .success(param0) + case 1: + reader.readParamCount(expected: 2) + reader.expectTag(.string) + let param0 = reader.readString() + reader.expectTag(.int32) + let param1 = Int(reader.readInt32()) + return .failure(param0, param1) + default: + fatalError("Unknown API.NetworkingResult case ID: \(caseId)") + } + } + } + + func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_return_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0, let param1): + _swift_js_return_tag(Int32(1)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_return_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_return_int(Int32(param1)) } } } @@ -1009,8 +1192,8 @@ public func _bjs_getTSTheme() -> Void { @_cdecl("bjs_echoAPIResult") public func _bjs_echoAPIResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - let ret = echoAPIResult(result: APIResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) - ret.bridgeJSReturn() + let ret = echoAPIResult(result: APIResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1025,7 +1208,7 @@ public func _bjs_makeAPIResultSuccess(valueBytes: Int32, valueLen: Int32) -> Voi return Int(valueLen) } let ret = makeAPIResultSuccess(_: value) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1036,7 +1219,7 @@ public func _bjs_makeAPIResultSuccess(valueBytes: Int32, valueLen: Int32) -> Voi public func _bjs_makeAPIResultFailure(value: Int32) -> Void { #if arch(wasm32) let ret = makeAPIResultFailure(_: Int(value)) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1047,7 +1230,7 @@ public func _bjs_makeAPIResultFailure(value: Int32) -> Void { public func _bjs_makeAPIResultInfo() -> Void { #if arch(wasm32) let ret = makeAPIResultInfo() - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1058,7 +1241,7 @@ public func _bjs_makeAPIResultInfo() -> Void { public func _bjs_makeAPIResultFlag(value: Int32) -> Void { #if arch(wasm32) let ret = makeAPIResultFlag(_: value == 1) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1069,7 +1252,7 @@ public func _bjs_makeAPIResultFlag(value: Int32) -> Void { public func _bjs_makeAPIResultRate(value: Float32) -> Void { #if arch(wasm32) let ret = makeAPIResultRate(_: value) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1080,7 +1263,7 @@ public func _bjs_makeAPIResultRate(value: Float32) -> Void { public func _bjs_makeAPIResultPrecise(value: Float64) -> Void { #if arch(wasm32) let ret = makeAPIResultPrecise(_: value) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1090,8 +1273,8 @@ public func _bjs_makeAPIResultPrecise(value: Float64) -> Void { @_cdecl("bjs_echoComplexResult") public func _bjs_echoComplexResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - let ret = echoComplexResult(result: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) - ret.bridgeJSReturn() + let ret = echoComplexResult(result: ComplexResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1106,7 +1289,7 @@ public func _bjs_makeComplexResultSuccess(valueBytes: Int32, valueLen: Int32) -> return Int(valueLen) } let ret = makeComplexResultSuccess(_: value) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1121,7 +1304,7 @@ public func _bjs_makeComplexResultError(messageBytes: Int32, messageLen: Int32, return Int(messageLen) } let ret = makeComplexResultError(_: message, _: Int(code)) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1136,7 +1319,7 @@ public func _bjs_makeComplexResultLocation(lat: Float64, lng: Float64, nameBytes return Int(nameLen) } let ret = makeComplexResultLocation(_: lat, _: lng, _: name) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1151,7 +1334,41 @@ public func _bjs_makeComplexResultStatus(active: Int32, code: Int32, messageByte return Int(messageLen) } let ret = makeComplexResultStatus(_: active == 1, _: Int(code), _: message) - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultCoordinates") +@_cdecl("bjs_makeComplexResultCoordinates") +public func _bjs_makeComplexResultCoordinates(x: Float64, y: Float64, z: Float64) -> Void { + #if arch(wasm32) + let ret = makeComplexResultCoordinates(_: x, _: y, _: z) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeComplexResultComprehensive") +@_cdecl("bjs_makeComplexResultComprehensive") +public func _bjs_makeComplexResultComprehensive(flag1: Int32, flag2: Int32, count1: Int32, count2: Int32, value1: Float64, value2: Float64, text1Bytes: Int32, text1Len: Int32, text2Bytes: Int32, text2Len: Int32, text3Bytes: Int32, text3Len: Int32) -> Void { + #if arch(wasm32) + let text1 = String(unsafeUninitializedCapacity: Int(text1Len)) { b in + _swift_js_init_memory(text1Bytes, b.baseAddress.unsafelyUnwrapped) + return Int(text1Len) + } + let text2 = String(unsafeUninitializedCapacity: Int(text2Len)) { b in + _swift_js_init_memory(text2Bytes, b.baseAddress.unsafelyUnwrapped) + return Int(text2Len) + } + let text3 = String(unsafeUninitializedCapacity: Int(text3Len)) { b in + _swift_js_init_memory(text3Bytes, b.baseAddress.unsafelyUnwrapped) + return Int(text3Len) + } + let ret = makeComplexResultComprehensive(_: flag1 == 1, _: flag2 == 1, _: Int(count1), _: Int(count2), _: value1, _: value2, _: text1, _: text2, _: text3) + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1162,7 +1379,7 @@ public func _bjs_makeComplexResultStatus(active: Int32, code: Int32, messageByte public func _bjs_makeComplexResultInfo() -> Void { #if arch(wasm32) let ret = makeComplexResultInfo() - ret.bridgeJSReturn() + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif @@ -1172,8 +1389,105 @@ public func _bjs_makeComplexResultInfo() -> Void { @_cdecl("bjs_roundtripComplexResult") public func _bjs_roundtripComplexResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { #if arch(wasm32) - let ret = roundtripComplexResult(_: ComplexResult.dispatchConstruct(resultCaseId, resultParamsId, resultParamsLen)) - ret.bridgeJSReturn() + let ret = roundtripComplexResult(_: ComplexResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeUtilitiesResultSuccess") +@_cdecl("bjs_makeUtilitiesResultSuccess") +public func _bjs_makeUtilitiesResultSuccess(messageBytes: Int32, messageLen: Int32) -> Void { + #if arch(wasm32) + let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in + _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) + return Int(messageLen) + } + let ret = makeUtilitiesResultSuccess(_: message) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeUtilitiesResultFailure") +@_cdecl("bjs_makeUtilitiesResultFailure") +public func _bjs_makeUtilitiesResultFailure(errorBytes: Int32, errorLen: Int32, code: Int32) -> Void { + #if arch(wasm32) + let error = String(unsafeUninitializedCapacity: Int(errorLen)) { b in + _swift_js_init_memory(errorBytes, b.baseAddress.unsafelyUnwrapped) + return Int(errorLen) + } + let ret = makeUtilitiesResultFailure(_: error, _: Int(code)) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeUtilitiesResultStatus") +@_cdecl("bjs_makeUtilitiesResultStatus") +public func _bjs_makeUtilitiesResultStatus(active: Int32, code: Int32, messageBytes: Int32, messageLen: Int32) -> Void { + #if arch(wasm32) + let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in + _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) + return Int(messageLen) + } + let ret = makeUtilitiesResultStatus(_: active == 1, _: Int(code), _: message) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPINetworkingResultSuccess") +@_cdecl("bjs_makeAPINetworkingResultSuccess") +public func _bjs_makeAPINetworkingResultSuccess(messageBytes: Int32, messageLen: Int32) -> Void { + #if arch(wasm32) + let message = String(unsafeUninitializedCapacity: Int(messageLen)) { b in + _swift_js_init_memory(messageBytes, b.baseAddress.unsafelyUnwrapped) + return Int(messageLen) + } + let ret = makeAPINetworkingResultSuccess(_: message) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAPINetworkingResultFailure") +@_cdecl("bjs_makeAPINetworkingResultFailure") +public func _bjs_makeAPINetworkingResultFailure(errorBytes: Int32, errorLen: Int32, code: Int32) -> Void { + #if arch(wasm32) + let error = String(unsafeUninitializedCapacity: Int(errorLen)) { b in + _swift_js_init_memory(errorBytes, b.baseAddress.unsafelyUnwrapped) + return Int(errorLen) + } + let ret = makeAPINetworkingResultFailure(_: error, _: Int(code)) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripUtilitiesResult") +@_cdecl("bjs_roundtripUtilitiesResult") +public func _bjs_roundtripUtilitiesResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { + #if arch(wasm32) + let ret = roundtripUtilitiesResult(_: Utilities.Result.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripAPINetworkingResult") +@_cdecl("bjs_roundtripAPINetworkingResult") +public func _bjs_roundtripAPINetworkingResult(resultCaseId: Int32, resultParamsId: Int32, resultParamsLen: Int32) -> Void { + #if arch(wasm32) + let ret = roundtripAPINetworkingResult(_: API.NetworkingResult.bridgeJSLiftParameter(resultCaseId, resultParamsId, resultParamsLen)) + ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index a3139ac0..6d53232f 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -731,6 +731,100 @@ ], "name" : "status" }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + } + ], + "name" : "coordinates" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "double" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "comprehensive" + }, { "associatedValues" : [ @@ -741,6 +835,114 @@ "emitStyle" : "const", "name" : "ComplexResult", "swiftCallName" : "ComplexResult" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + }, + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "status" + } + ], + "emitStyle" : "const", + "name" : "Result", + "namespace" : [ + "Utilities" + ], + "swiftCallName" : "Utilities.Result" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + }, + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + } + ], + "emitStyle" : "const", + "name" : "NetworkingResult", + "namespace" : [ + "API" + ], + "swiftCallName" : "API.NetworkingResult" } ], "functions" : [ @@ -1979,6 +2181,144 @@ } } }, + { + "abiName" : "bjs_makeComplexResultCoordinates", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultCoordinates", + "parameters" : [ + { + "label" : "_", + "name" : "x", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "y", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "z", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, + { + "abiName" : "bjs_makeComplexResultComprehensive", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeComplexResultComprehensive", + "parameters" : [ + { + "label" : "_", + "name" : "flag1", + "type" : { + "bool" : { + + } + } + }, + { + "label" : "_", + "name" : "flag2", + "type" : { + "bool" : { + + } + } + }, + { + "label" : "_", + "name" : "count1", + "type" : { + "int" : { + + } + } + }, + { + "label" : "_", + "name" : "count2", + "type" : { + "int" : { + + } + } + }, + { + "label" : "_", + "name" : "value1", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "value2", + "type" : { + "double" : { + + } + } + }, + { + "label" : "_", + "name" : "text1", + "type" : { + "string" : { + + } + } + }, + { + "label" : "_", + "name" : "text2", + "type" : { + "string" : { + + } + } + }, + { + "label" : "_", + "name" : "text3", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ComplexResult" + } + } + }, { "abiName" : "bjs_makeComplexResultInfo", "effects" : { @@ -2018,6 +2358,210 @@ "_0" : "ComplexResult" } } + }, + { + "abiName" : "bjs_makeUtilitiesResultSuccess", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeUtilitiesResultSuccess", + "parameters" : [ + { + "label" : "_", + "name" : "message", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Utilities.Result" + } + } + }, + { + "abiName" : "bjs_makeUtilitiesResultFailure", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeUtilitiesResultFailure", + "parameters" : [ + { + "label" : "_", + "name" : "error", + "type" : { + "string" : { + + } + } + }, + { + "label" : "_", + "name" : "code", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Utilities.Result" + } + } + }, + { + "abiName" : "bjs_makeUtilitiesResultStatus", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeUtilitiesResultStatus", + "parameters" : [ + { + "label" : "_", + "name" : "active", + "type" : { + "bool" : { + + } + } + }, + { + "label" : "_", + "name" : "code", + "type" : { + "int" : { + + } + } + }, + { + "label" : "_", + "name" : "message", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Utilities.Result" + } + } + }, + { + "abiName" : "bjs_makeAPINetworkingResultSuccess", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPINetworkingResultSuccess", + "parameters" : [ + { + "label" : "_", + "name" : "message", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "API.NetworkingResult" + } + } + }, + { + "abiName" : "bjs_makeAPINetworkingResultFailure", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "makeAPINetworkingResultFailure", + "parameters" : [ + { + "label" : "_", + "name" : "error", + "type" : { + "string" : { + + } + } + }, + { + "label" : "_", + "name" : "code", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "API.NetworkingResult" + } + } + }, + { + "abiName" : "bjs_roundtripUtilitiesResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "roundtripUtilitiesResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "Utilities.Result" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Utilities.Result" + } + } + }, + { + "abiName" : "bjs_roundtripAPINetworkingResult", + "effects" : { + "isAsync" : false, + "isThrows" : false + }, + "name" : "roundtripAPINetworkingResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "API.NetworkingResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "API.NetworkingResult" + } + } } ], "moduleName" : "BridgeJSRuntimeTests" diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index e49bde15..21fed0eb 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -286,25 +286,55 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { const ce1 = { tag: ComplexResult.Tag.Error, param0: "Network error", param1: 503 }; const cl1 = { tag: ComplexResult.Tag.Location, param0: 37.7749, param1: -122.4194, param2: "San Francisco" }; const cst1 = { tag: ComplexResult.Tag.Status, param0: true, param1: 200, param2: "OK" }; + const cc1 = { tag: ComplexResult.Tag.Coordinates, param0: 10.5, param1: 20.3, param2: 30.7 }; + const ccomp1 = { tag: ComplexResult.Tag.Comprehensive, param0: true, param1: false, param2: 42, param3: 100, param4: 3.14, param5: 2.718, param6: "Hello", param7: "World", param8: "Test" }; const ci1 = { tag: ComplexResult.Tag.Info }; assert.deepEqual(exports.echoComplexResult(cs1), cs1); assert.deepEqual(exports.echoComplexResult(ce1), ce1); assert.deepEqual(exports.echoComplexResult(cl1), cl1); assert.deepEqual(exports.echoComplexResult(cst1), cst1); + assert.deepEqual(exports.echoComplexResult(cc1), cc1); + assert.deepEqual(exports.echoComplexResult(ccomp1), ccomp1); assert.deepEqual(exports.echoComplexResult(ci1), ci1); assert.deepEqual(exports.roundtripComplexResult(cs1), cs1); assert.deepEqual(exports.roundtripComplexResult(ce1), ce1); assert.deepEqual(exports.roundtripComplexResult(cl1), cl1); assert.deepEqual(exports.roundtripComplexResult(cst1), cst1); + assert.deepEqual(exports.roundtripComplexResult(cc1), cc1); + assert.deepEqual(exports.roundtripComplexResult(ccomp1), ccomp1); assert.deepEqual(exports.roundtripComplexResult(ci1), ci1); assert.deepEqual(exports.makeComplexResultSuccess("Great!"), { tag: ComplexResult.Tag.Success, param0: "Great!" }); assert.deepEqual(exports.makeComplexResultError("Timeout", 408), { tag: ComplexResult.Tag.Error, param0: "Timeout", param1: 408 }); assert.deepEqual(exports.makeComplexResultLocation(40.7128, -74.0060, "New York"), { tag: ComplexResult.Tag.Location, param0: 40.7128, param1: -74.0060, param2: "New York" }); assert.deepEqual(exports.makeComplexResultStatus(false, 500, "Internal Server Error"), { tag: ComplexResult.Tag.Status, param0: false, param1: 500, param2: "Internal Server Error" }); + assert.deepEqual(exports.makeComplexResultCoordinates(1.1, 2.2, 3.3), { tag: ComplexResult.Tag.Coordinates, param0: 1.1, param1: 2.2, param2: 3.3 }); + assert.deepEqual(exports.makeComplexResultComprehensive(true, false, 10, 20, 1.5, 2.5, "First", "Second", "Third"), { tag: ComplexResult.Tag.Comprehensive, param0: true, param1: false, param2: 10, param3: 20, param4: 1.5, param5: 2.5, param6: "First", param7: "Second", param8: "Third" }); assert.deepEqual(exports.makeComplexResultInfo(), { tag: ComplexResult.Tag.Info }); + + const urSuccess = { tag: globalThis.Utilities.Result.Tag.Success, param0: "Utility operation completed" }; + const urFailure = { tag: globalThis.Utilities.Result.Tag.Failure, param0: "Utility error occurred", param1: 500 }; + const urStatus = { tag: globalThis.Utilities.Result.Tag.Status, param0: true, param1: 200, param2: "Utility status OK" }; + + assert.deepEqual(exports.roundtripUtilitiesResult(urSuccess), urSuccess); + assert.deepEqual(exports.roundtripUtilitiesResult(urFailure), urFailure); + assert.deepEqual(exports.roundtripUtilitiesResult(urStatus), urStatus); + + assert.deepEqual(exports.makeUtilitiesResultSuccess("Test"), { tag: globalThis.Utilities.Result.Tag.Success, param0: "Test" }); + assert.deepEqual(exports.makeUtilitiesResultSuccess("ok"), { tag: globalThis.Utilities.Result.Tag.Success, param0: "ok" }); + assert.deepEqual(exports.makeUtilitiesResultFailure("Error", 123), { tag: globalThis.Utilities.Result.Tag.Failure, param0: "Error", param1: 123 }); + assert.deepEqual(exports.makeUtilitiesResultStatus(true, 200, "OK"), { tag: globalThis.Utilities.Result.Tag.Status, param0: true, param1: 200, param2: "OK" }); + + const nrSuccess = { tag: globalThis.API.NetworkingResult.Tag.Success, param0: "Network request successful" }; + const nrFailure = { tag: globalThis.API.NetworkingResult.Tag.Failure, param0: "Network timeout", param1: 408 }; + + assert.deepEqual(exports.roundtripAPINetworkingResult(nrSuccess), nrSuccess); + assert.deepEqual(exports.roundtripAPINetworkingResult(nrFailure), nrFailure); + + assert.deepEqual(exports.makeAPINetworkingResultSuccess("Connected"), { tag: globalThis.API.NetworkingResult.Tag.Success, param0: "Connected" }); + assert.deepEqual(exports.makeAPINetworkingResultFailure("Timeout", 408), { tag: globalThis.API.NetworkingResult.Tag.Failure, param0: "Timeout", param1: 408 }); } /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */