diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index 384ca35a2..81888845b 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -2179,6 +2179,34 @@ fileprivate func _bjs_ArrayRoundtrip_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_ArrayRoundtrip_wrap_extern(pointer) } +extension SimpleStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SimpleStruct.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Person: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Person.bridgeJSMakeTypeHandle() +} + +extension ComplexStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexStruct.bridgeJSMakeTypeHandle() +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkHelperNoop") fileprivate func bjs_benchmarkHelperNoop_extern() -> Void @@ -2238,4 +2266,40 @@ func _$benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_Benchmarks_register_type_handles") +fileprivate func _bjs_Benchmarks_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_Benchmarks_register_type_handles") +public func _bjs_Benchmarks_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + SimpleStruct.bridgeJSTypeID, + Address.bridgeJSTypeID, + Person.bridgeJSTypeID, + ComplexStruct.bridgeJSTypeID, + Point.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_Benchmarks_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Examples/Embedded/Package.swift b/Examples/Embedded/Package.swift index 42702394a..1f88a8947 100644 --- a/Examples/Embedded/Package.swift +++ b/Examples/Embedded/Package.swift @@ -16,6 +16,9 @@ let package = Package( swiftSettings: [ .enableExperimentalFeature("Extern") ], + plugins: [ + .plugin(name: "BridgeJS", package: "JavaScriptKit") + ] ) ], swiftLanguageModes: [.v5] diff --git a/Examples/Embedded/Sources/EmbeddedApp/main.swift b/Examples/Embedded/Sources/EmbeddedApp/main.swift index 5e7f01a3c..c3e0dd3cd 100644 --- a/Examples/Embedded/Sources/EmbeddedApp/main.swift +++ b/Examples/Embedded/Sources/EmbeddedApp/main.swift @@ -1,5 +1,12 @@ import JavaScriptKit +@JS struct CounterLabel { + var count: Int + var text: String +} + +@JSFunction func echoValue(_ value: T) throws(JSException) -> T + let alert = JSObject.global.alert.object! let document = JSObject.global.document @@ -46,6 +53,17 @@ _ = encoderContainer.appendChild(textInputElement) _ = encoderContainer.appendChild(encodeResultElement) _ = document.body.appendChild(encoderContainer) +let genericResultElement = document.createElement("pre") +do { + let number = try echoValue(42) + let text = try echoValue("hello") + let label = try echoValue(CounterLabel(count: number, text: text)) + genericResultElement.innerText = .string("Generic import round-trip: \(label.text) \(label.count)") +} catch { + genericResultElement.innerText = "Generic import round-trip failed" +} +_ = document.body.appendChild(genericResultElement) + func print(_ message: String) { _ = JSObject.global.console.log(message) } diff --git a/Examples/Embedded/index.html b/Examples/Embedded/index.html index 93868214d..d280d7067 100644 --- a/Examples/Embedded/index.html +++ b/Examples/Embedded/index.html @@ -8,7 +8,13 @@ diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 10976f793..dff715c64 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -231,6 +231,18 @@ fileprivate func _bjs_PlayBridgeJS_wrap_extern(_ pointer: UnsafeMutableRawPointe return _bjs_PlayBridgeJS_wrap_extern(pointer) } +extension PlayBridgeJSOutput: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSOutput.bridgeJSMakeTypeHandle() +} + +extension PlayBridgeJSDiagnostic: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSDiagnostic.bridgeJSMakeTypeHandle() +} + +extension PlayBridgeJSResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSResult.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "PlayBridgeJS", name: "bjs_createTS2Swift") fileprivate func bjs_createTS2Swift_extern() -> Int32 @@ -274,4 +286,36 @@ func _$TS2Swift_convert(_ self: JSObject, _ ts: String) throws(JSException) -> S throw error } return String.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_PlayBridgeJS_register_type_handles") +fileprivate func _bjs_PlayBridgeJS_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_PlayBridgeJS_register_type_handles") +public func _bjs_PlayBridgeJS_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PlayBridgeJSOutput.bridgeJSTypeID, + PlayBridgeJSDiagnostic.bridgeJSTypeID, + PlayBridgeJSResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_PlayBridgeJS_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/README.md b/Plugins/BridgeJS/README.md index 9e1e0aa08..0905695c5 100644 --- a/Plugins/BridgeJS/README.md +++ b/Plugins/BridgeJS/README.md @@ -98,7 +98,7 @@ graph LR | `Dictionary` | `Record` | - | [#495](https://github.com/swiftwasm/JavaScriptKit/issues/495) | | `Set` | `Set` | - | [#397](https://github.com/swiftwasm/JavaScriptKit/issues/397) | | `Foundation.URL` | `string` | - | [#496](https://github.com/swiftwasm/JavaScriptKit/issues/496) | -| Generics | - | - | [#398](https://github.com/swiftwasm/JavaScriptKit/issues/398) | +| Generic function or method (`T`, `[T]`, `T?`, `[String: T]`) | `(value: T): T` | Depends on `T` | ✅ imports only ([#398](https://github.com/swiftwasm/JavaScriptKit/issues/398) for exports) | ### Import-specific (TypeScript -> Swift) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 2cc551857..e4d0f5b02 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -91,6 +91,15 @@ public class ExportSwift { } } + withSpan("Render Generic Bridgeable Conformances") { [self] in + // Emitted unconditionally: a module cannot know whether a dependent + // module passes its types to a generic imported function. + let genericConformanceCodegen = GenericConformanceCodegen() + for entry in skeleton.genericBridgeableTypeEntries { + decls.append(contentsOf: genericConformanceCodegen.renderConformance(typeName: entry.swiftName)) + } + } + try withSpan("Render Async Promise Helpers") { [self] in let asyncResolveTypes = skeleton.asyncPromiseResolveReturnTypes if !asyncResolveTypes.isEmpty { @@ -875,6 +884,63 @@ public class ExportSwift { } } +// MARK: - GenericConformanceCodegen + +/// Renders `BridgedSwiftGenericBridgeable` conformances for `@JS` types so they +/// can be used as the generic argument of a generic imported `@JSFunction`. +struct GenericConformanceCodegen { + func renderConformance(typeName: String) -> [DeclSyntax] { + let printer = CodeFragmentPrinter() + printer.write("extension \(typeName): BridgedSwiftGenericBridgeable {") + printer.indent { + printer.write( + "@_spi(BridgeJS) public static let bridgeJSTypeHandle = \(typeName).bridgeJSMakeTypeHandle()" + ) + } + printer.write("}") + return ["\(raw: printer.lines.joined(separator: "\n"))"] + } +} + +// MARK: - GenericTypeRegistrationCodegen + +/// Renders the `bjs__register_type_handles` wasm export: it lowers each +/// registered type's `bridgeJSTypeID` into a buffer, in the canonical order of +/// `BridgeJSSkeleton.typeRegistrationEntries`, and passes it to the JS import +/// hook of the same name, which pairs the IDs with its codec array by index. +public struct GenericTypeRegistrationCodegen { + public init() {} + + public func render(for skeleton: BridgeJSSkeleton) -> String? { + guard let entries = skeleton.typeRegistrationEntries else { return nil } + let abiName = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + let printer = CodeFragmentPrinter() + printer.write("#if arch(wasm32)") + printer.write("@_extern(wasm, module: \"bjs\", name: \"\(abiName)\")") + printer.write("fileprivate func _\(abiName)_extern(_ base: UnsafePointer?, _ count: Int32)") + printer.nextLine() + printer.write("@_expose(wasm, \"\(abiName)\")") + printer.write("public func _\(abiName)() {") + printer.indent { + printer.write("let typeIds: [Int32] = [") + printer.indent { + for entry in entries { + printer.write("\(entry.swiftName).bridgeJSTypeID,") + } + } + printer.write("]") + printer.write("typeIds.withUnsafeBufferPointer { buffer in") + printer.indent { + printer.write("_\(abiName)_extern(buffer.baseAddress, Int32(buffer.count))") + } + printer.write("}") + } + printer.write("}") + printer.write("#endif") + return printer.lines.joined(separator: "\n") + } +} + // MARK: - StackCodegen /// Helper for stack-based lifting and lowering operations. @@ -896,6 +962,10 @@ struct StackCodegen { return "JSObject.bridgeJSStackPop()" case .void, .namespaceEnum: return "()" + case .generic: + fatalError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -908,7 +978,7 @@ struct StackCodegen { return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()" case .jsObject(let className?): return "\(raw: typeName).bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }" - case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol: + case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol, .generic: fatalError("Invalid nullable wrapped type: \(wrappedType)") } } @@ -941,6 +1011,10 @@ struct StackCodegen { return lowerArrayStatements(elementType: elementType, accessor: accessor, varPrefix: varPrefix) case .dictionary(let valueType): return lowerDictionaryStatements(valueType: valueType, accessor: accessor, varPrefix: varPrefix) + case .generic: + fatalError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -1596,12 +1670,34 @@ extension BridgeType { case .associatedValueEnum: return ["_BridgedSwiftAssociatedValueEnum"] case .rawValueEnum, .void, .unsafePointer, .namespaceEnum, - .swiftProtocol, .closure, .nullable, .array, .dictionary, .alias: + .swiftProtocol, .closure, .nullable, .array, .dictionary, .alias, .generic: // Not supported yet. return nil } } + /// Stack expressions for bare `T` and `T?`, the only generic shapes that + /// cannot reuse the concrete emission: `bridgeJSLowerParameter()` names + /// per-type members that the generic constraint erases to the stack, so + /// `bridgeJSStackPush()`/`bridgeJSStackPop()` is the shared spelling. + /// `[T]` and `[String: T]` go through the ordinary paths via the `Array` + /// and `Dictionary` stack conformances. + var genericStackPopExpression: String? { + switch self { + case .generic(let name): return "\(name).bridgeJSStackPop()" + case .nullable(.generic(let name), _): return "Optional<\(name)>.bridgeJSStackPop()" + default: return nil + } + } + + func genericStackPushStatement(value: String) -> String? { + switch self { + case .generic, .nullable(.generic, _): + return "\(value).bridgeJSStackPush()" + default: return nil + } + } + var swiftType: String { switch self { case .bool: return "Bool" @@ -1631,6 +1727,7 @@ extension BridgeType { let closureType = "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)" return useJSTypedClosure ? "JSTypedClosure<\(closureType)>" : closureType case .alias(let name, _): return name + case .generic(let name): return name } } @@ -1717,6 +1814,10 @@ extension BridgeType { return LiftingIntrinsicInfo(parameters: []) case .alias(_, let underlying): return try underlying.liftParameterInfo() + case .generic: + throw BridgeJSCoreError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -1770,6 +1871,10 @@ extension BridgeType { return .array case .alias(_, let underlying): return try underlying.loweringReturnInfo() + case .generic: + throw BridgeJSCoreError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 286352915..cb5a88e93 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -143,6 +143,11 @@ public struct ImportTS { } func lowerParameter(param: Parameter) throws { + if let genericPush = param.type.genericStackPushStatement(value: param.name) { + stackLoweringStmts.insert(genericPush, at: 0) + return + } + let loweringInfo = try param.type.loweringParameterInfo(context: context) switch param.type { @@ -237,6 +242,18 @@ public struct ImportTS { abiParameterForwardings.insert(contentsOf: ["resolveRef", "rejectRef"], at: 0) } + private func appendTypeIDParameter(index: Int, genericParameterName: String) { + let abiParamName = ABINameGenerator.genericTypeIdParameterName(index: index) + abiParameterSignatures.append((abiParamName, .i32)) + abiParameterForwardings.append("\(genericParameterName).bridgeJSTypeID") + } + + func appendTypeIDParameters(_ genericParameterNames: [String]) { + for (index, name) in genericParameterNames.enumerated() { + appendTypeIDParameter(index: index, genericParameterName: name) + } + } + func call() throws { for stmt in stackLoweringStmts { body.write(stmt.description) @@ -293,14 +310,18 @@ public struct ImportTS { body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()") } else { let liftExpr: String - switch returnType { - case .closure(let signature, _): - liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)" - default: - if liftingInfo.valueToLift != nil { - liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)" - } else { - liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()" + if let genericPop = returnType.genericStackPopExpression { + liftExpr = genericPop + } else { + switch returnType { + case .closure(let signature, _): + liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)" + default: + if liftingInfo.valueToLift != nil { + liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)" + } else { + liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()" + } } } body.write("return \(liftExpr)") @@ -359,7 +380,8 @@ public struct ImportTS { name: String, parameters: [Parameter], returnType: BridgeType, - effects: Effects + effects: Effects, + genericParameters: [String] = [] ) -> DeclSyntax { let printer = CodeFragmentPrinter() let signature = SwiftSignatureBuilder.buildFunctionSignature( @@ -368,7 +390,12 @@ public struct ImportTS { effects: effects, useWildcardLabels: true ) - printer.write("func \(name.backtickIfNeeded())\(signature) {") + let genericClause = + genericParameters.isEmpty + ? "" + : "<" + genericParameters.map { "\($0): BridgedSwiftGenericBridgeable" }.joined(separator: ", ") + + ">" + printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {") printer.indent { printer.write(lines: body.lines) } @@ -428,6 +455,7 @@ public struct ImportTS { for param in function.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(function.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -436,7 +464,8 @@ public struct ImportTS { name: Self.thunkName(function: function), parameters: function.parameters, returnType: function.returnType, - effects: function.effects + effects: function.effects, + genericParameters: function.genericParameterNames ) .with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation)) ] @@ -457,6 +486,7 @@ public struct ImportTS { for param in method.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(method.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -465,7 +495,8 @@ public struct ImportTS { name: Self.thunkName(type: type, method: method), parameters: [selfParameter] + method.parameters, returnType: method.returnType, - effects: method.effects + effects: method.effects, + genericParameters: method.genericParameterNames ) ] } @@ -481,6 +512,7 @@ public struct ImportTS { for param in method.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(method.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -489,7 +521,8 @@ public struct ImportTS { name: Self.thunkName(type: type, method: method), parameters: method.parameters, returnType: method.returnType, - effects: method.effects + effects: method.effects, + genericParameters: method.genericParameterNames ) ] } @@ -505,6 +538,7 @@ public struct ImportTS { for param in constructor.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(constructor.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -513,7 +547,8 @@ public struct ImportTS { name: Self.thunkName(type: type), parameters: constructor.parameters, returnType: .jsObject(nil), - effects: effects + effects: effects, + genericParameters: constructor.genericParameterNames ) ] } @@ -932,9 +967,6 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) case .associatedValueEnum: return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) - case .swiftStruct: - // `@JS struct` parameters always use the stack ABI (same as arrays/dictionaries). - return LoweringParameterInfo(loweredParameters: []) case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as parameters") case .nullable(let wrappedType, _): @@ -942,7 +974,10 @@ extension BridgeType { var params = [("isSome", WasmCoreType.i32)] params.append(contentsOf: wrappedInfo.loweredParameters) return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing) - case .array, .dictionary: + case .swiftStruct: + // `@JS struct` parameters always use the stack ABI (same as arrays/dictionaries). + return LoweringParameterInfo(loweredParameters: []) + case .array, .dictionary, .generic: return LoweringParameterInfo(loweredParameters: []) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching loweringParameterInfo") @@ -995,9 +1030,6 @@ extension BridgeType { return LiftingReturnInfo(valueToLift: wasmType) case .associatedValueEnum: return LiftingReturnInfo(valueToLift: .i32) - case .swiftStruct: - // `@JS struct` returns always use the stack ABI (same as arrays/dictionaries). - return LiftingReturnInfo(valueToLift: nil) case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") case .nullable(let wrappedType, _): @@ -1008,7 +1040,10 @@ extension BridgeType { } let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) - case .array, .dictionary: + case .swiftStruct: + // `@JS struct` returns always use the stack ABI (same as arrays/dictionaries). + return LiftingReturnInfo(valueToLift: nil) + case .array, .dictionary, .generic: return LiftingReturnInfo(valueToLift: nil) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching liftingReturnInfo") diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index d327de307..27ed8c160 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -7,6 +7,79 @@ import BridgeJSUtilities import BridgeJSSkeleton #endif +/// Outcome of attempting to resolve a type as a reference to a generic parameter. +enum GenericParameterResolution { + case resolved(BridgeType) + /// A non-nil message is a hard diagnostic; `nil` means the type isn't generic + /// and the caller should fall back to normal type resolution. + case rejected(String?) +} + +func resolveGenericTypeReference( + for type: TypeSyntax, + genericParameterNames: [String] +) -> GenericParameterResolution { + if let identifier = type.as(IdentifierTypeSyntax.self), + identifier.genericArgumentClause == nil, + genericParameterNames.contains(identifier.name.text) + { + return .resolved(.generic(identifier.name.text)) + } + if let wrapped = wrappedGenericBridgeType(for: type, genericParameterNames: genericParameterNames) { + return .resolved(wrapped) + } + if !genericParameterNames.isEmpty, + let wrapped = wrappedGenericParameter(in: type, genericParameterNames: genericParameterNames) + { + return .rejected( + "Generic parameter '\(wrapped)' may only be used as a bare type; wrapping it beyond 'T?', '[T]' and '[String: T]' is not supported." + ) + } + return .rejected(nil) +} + +private func wrappedGenericParameter( + in type: TypeSyntax, + genericParameterNames: [String] +) -> String? { + for token in type.tokens(viewMode: .sourceAccurate) { + if case .identifier(let text) = token.tokenKind, genericParameterNames.contains(text) { + return text + } + } + return nil +} + +private func wrappedGenericBridgeType( + for type: TypeSyntax, + genericParameterNames: [String] +) -> BridgeType? { + func bareGenericName(_ inner: TypeSyntax) -> String? { + guard let identifier = inner.as(IdentifierTypeSyntax.self), + identifier.genericArgumentClause == nil, + genericParameterNames.contains(identifier.name.text) + else { + return nil + } + return identifier.name.text + } + if let arrayType = type.as(ArrayTypeSyntax.self), let name = bareGenericName(arrayType.element) { + return .array(.generic(name)) + } + if let optionalType = type.as(OptionalTypeSyntax.self), let name = bareGenericName(optionalType.wrappedType) { + return .nullable(.generic(name), .null) + } + if let dictType = type.as(DictionaryTypeSyntax.self), + let keyIdentifier = dictType.key.as(IdentifierTypeSyntax.self), + keyIdentifier.genericArgumentClause == nil, + keyIdentifier.name.text == "String", + let name = bareGenericName(dictType.value) + { + return .dictionary(.generic(name)) + } + return nil +} + /// Builds BridgeJS skeletons from Swift source files using SwiftSyntax walk for API collection. /// /// This is a shared entry point for producing: @@ -731,6 +804,11 @@ public final class SwiftToSkeleton { return String(name.dropFirst().dropLast()) } + fileprivate static func isBridgeableGenericConstraint(_ constraint: String?) -> Bool { + constraint == "BridgedSwiftGenericBridgeable" + || constraint == "JavaScriptKit.BridgedSwiftGenericBridgeable" + } + } private enum ExportSwiftConstants { @@ -1202,10 +1280,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue } - if case .nullable(let wrappedType, _) = type, wrappedType.isOptional { - diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) - continue - } let name = param.secondName?.text ?? param.firstName.text let label = param.firstName.text @@ -1290,6 +1364,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return nil } + if let genericClause = node.genericParameterClause, let firstGenericParam = genericClause.parameters.first { + diagnose( + node: firstGenericParam, + message: + "Generic parameters on exported @JS functions are not supported yet. Generic functions are currently only supported on imported @JSFunction declarations." + ) + return nil + } + let name = node.name.text let attributeNamespace = extractNamespace(from: jsAttribute) @@ -1712,6 +1795,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { message: "Class visibility must be at least internal" ) let classIdentityMode = extractIdentityMode(from: jsAttribute) + let isFinal = node.modifiers.contains { $0.name.tokenKind == .keyword(.final) } ? true : nil let exportedClass = ExportedClass( name: name, swiftCallName: swiftCallName, @@ -1721,7 +1805,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { properties: [], namespace: effectiveNamespace, identityMode: classIdentityMode, - documentation: extractDocumentation(from: node) + documentation: extractDocumentation(from: node), + isFinal: isFinal ) let uniqueKey = makeKey(name: name, namespace: effectiveNamespace) @@ -3118,24 +3203,101 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { // MARK: - Parsing Methods + /// Validates and collects the generic parameter names of an imported + /// `@JSFunction` declaration (function, method or initializer). + /// + /// Returns `nil` when a diagnostic was emitted; an empty array when the + /// declaration is not generic. + private func parseGenericParameterNames( + genericParameterClause: GenericParameterClauseSyntax?, + genericWhereClause: GenericWhereClauseSyntax?, + node: Syntax + ) -> [String]? { + var genericParameterNames: [String] = [] + if let genericParameterClause { + for genericParam in genericParameterClause.parameters { + let paramName = genericParam.name.text + let constraintText = genericParam.inheritedType?.trimmedDescription + guard SwiftToSkeleton.isBridgeableGenericConstraint(constraintText) else { + errors.append( + DiagnosticError( + node: Syntax(genericParam), + message: + "Generic parameter '\(paramName)' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + ) + return nil + } + genericParameterNames.append(paramName) + } + } + if genericWhereClause != nil { + errors.append( + DiagnosticError( + node: node, + message: "'where' clauses are not supported on @JSFunction declarations." + ) + ) + return nil + } + return genericParameterNames + } + private func parseConstructor( _ initializer: InitializerDeclSyntax, typeName: String ) -> ImportedConstructorSkeleton? { guard - validateEffects(initializer.signature.effectSpecifiers, node: initializer, attributeName: "JSFunction") - != nil + let effects = validateEffects( + initializer.signature.effectSpecifiers, + node: initializer, + attributeName: "JSFunction" + ) + else { + return nil + } + guard + let genericParameterNames = parseGenericParameterNames( + genericParameterClause: initializer.genericParameterClause, + genericWhereClause: initializer.genericWhereClause, + node: Syntax(initializer) + ) else { return nil } + if !genericParameterNames.isEmpty && effects.isAsync { + errors.append( + DiagnosticError( + node: Syntax(initializer), + message: "Generic @JSFunction declarations cannot be 'async' yet." + ) + ) + return nil + } + let parameters = parseParameters( + from: initializer.signature.parameterClause, + genericParameterNames: genericParameterNames + ) + for genericName in genericParameterNames + where !parameters.contains(where: { $0.type.referencedGenericName == genericName }) { + errors.append( + DiagnosticError( + node: Syntax(initializer), + message: + "The generic parameter '\(genericName)' must be used in a parameter of a generic @JSFunction initializer." + ) + ) + return nil + } // Initializers without an explicit modifier inherit access from the // enclosing `@JSClass` (the user's example pattern: `public init(...)` // inside `public struct JSDocument`). let parentLevel = currentType?.accessLevel ?? .internal let accessLevel = Self.bridgeAccessLevel(from: initializer.modifiers, default: parentLevel) return ImportedConstructorSkeleton( - parameters: parseParameters(from: initializer.signature.parameterClause), - accessLevel: accessLevel + parameters: parameters, + accessLevel: accessLevel, + genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames ) } @@ -3153,6 +3315,16 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } + guard + let genericParameterNames = parseGenericParameterNames( + genericParameterClause: node.genericParameterClause, + genericWhereClause: node.genericWhereClause, + node: Syntax(node) + ) + else { + return nil + } + let baseName = SwiftToSkeleton.normalizeIdentifier(node.name.text) let extractedJSName = extractJSName(from: jsFunction) let from = extractJSImportFrom(from: jsFunction) @@ -3160,16 +3332,51 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let jsName = extractedJSName?.memberName let name = baseName - let parameters = parseParameters(from: node.signature.parameterClause) + let parameters = parseParameters( + from: node.signature.parameterClause, + genericParameterNames: genericParameterNames + ) let returnType: BridgeType if let returnTypeSyntax = node.signature.returnClause?.type { - guard let resolved = withLookupErrors({ parent.lookupType(for: returnTypeSyntax, errors: &$0) }) else { + guard + let resolved = lookupTypeWithGenerics( + for: returnTypeSyntax, + genericParameterNames: genericParameterNames + ) + else { return nil } returnType = resolved } else { returnType = .void } + + if !genericParameterNames.isEmpty { + if effects.isAsync { + errors.append( + DiagnosticError( + node: node, + message: "Generic @JSFunction declarations cannot be 'async' yet." + ) + ) + return nil + } + for genericName in genericParameterNames { + let usedInParameter = parameters.contains { $0.type.referencedGenericName == genericName } + let usedInReturn = returnType.referencedGenericName == genericName + if !usedInParameter && !usedInReturn { + errors.append( + DiagnosticError( + node: node, + message: + "The generic parameter '\(genericName)' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + ) + return nil + } + } + } + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) return ImportedFunctionSkeleton( name: name, @@ -3179,7 +3386,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { returnType: returnType, effects: effects, documentation: nil, - accessLevel: accessLevel + accessLevel: accessLevel, + genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames ) } @@ -3256,7 +3464,26 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { // MARK: - Type and Parameter Parsing - private func parseParameters(from clause: FunctionParameterClauseSyntax) -> [Parameter] { + private func lookupTypeWithGenerics( + for type: TypeSyntax, + genericParameterNames: [String] + ) -> BridgeType? { + switch resolveGenericTypeReference(for: type, genericParameterNames: genericParameterNames) { + case .resolved(let bridgeType): + return bridgeType + case .rejected(let message): + if let message { + errors.append(DiagnosticError(node: Syntax(type), message: message)) + return nil + } + return withLookupErrors { parent.lookupType(for: type, errors: &$0) } + } + } + + private func parseParameters( + from clause: FunctionParameterClauseSyntax, + genericParameterNames: [String] = [] + ) -> [Parameter] { clause.parameters.compactMap { param in let type = param.type if type.is(MissingTypeSyntax.self) { @@ -3268,7 +3495,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { ) return nil } - guard let bridgeType = withLookupErrors({ parent.lookupType(for: type, errors: &$0) }) else { + guard let bridgeType = lookupTypeWithGenerics(for: type, genericParameterNames: genericParameterNames) + else { return nil } let nameToken = param.secondName ?? param.firstName diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 1b6300595..680e5cb39 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -31,6 +31,10 @@ public struct BridgeJSLink { skeletons.compactMap(\.exported).compactMap(\.identityMode).first ?? "none" } + var hasGenerics: Bool { + skeletons.contains { $0.imported?.hasGenericDeclarations ?? false } + } + /// Whether a class should use identity caching based on its annotation and the config default. private func shouldUseIdentityCache(for klass: ExportedClass) -> Bool { // Per-class annotation takes priority @@ -311,7 +315,7 @@ public struct BridgeJSLink { } private func generateVariableDeclarations() -> [String] { - return [ + var declarations: [String] = [ "let \(JSGlueVariableScope.reservedInstance);", "let \(JSGlueVariableScope.reservedMemory);", "let \(JSGlueVariableScope.reservedSetException);", @@ -335,10 +339,36 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedTaStack) = [];", "const \(JSGlueVariableScope.reservedEnumHelpers) = {};", "const \(JSGlueVariableScope.reservedStructHelpers) = {};", + ] + if hasGenerics { + declarations.append("const \(JSGlueVariableScope.reservedCodecByTypeId) = new Map();") + declarations.append("let __bjs_typeHandlesRegistered = false;") + // Registration is hybrid eager+lazy. The registration exports + // execute Swift code, which must not happen before WASI + // initialization (setInstance runs earlier than that), so the + // instantiator exposes an `afterInitialize` hook that hosts call + // once the instance is initialized (the `instantiate.js` template + // does). The guard below keeps the lazy path — first generic call + // — as a fallback for instantiation paths that skip the hook. + declarations.append("function __bjs_registerTypeHandles() {") + declarations.append(" if (__bjs_typeHandlesRegistered) {") + declarations.append(" return;") + declarations.append(" }") + declarations.append(" __bjs_typeHandlesRegistered = true;") + for skeleton in skeletons { + guard skeleton.typeRegistrationEntries != nil else { continue } + let name = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + declarations.append(" \(JSGlueVariableScope.reservedInstance).exports[\"\(name)\"]();") + } + declarations.append("}") + declarations.append(contentsOf: GenericJSCodegen.runtimeHelperDeclarations()) + } + declarations.append(contentsOf: [ "", "let _exports = null;", "let bjs = null;", - ] + ]) + return declarations } /// JS const (in the import glue scope) holding the `Symbol` under which a promise's @@ -375,6 +405,86 @@ public struct BridgeJSLink { printer.write(lines: lines) } + /// A print context detached from any thunk, used for codec literal emission. + private func makeCodecPrintContext(printer: CodeFragmentPrinter) -> IntrinsicJSFragment.PrintCodeContext { + IntrinsicJSFragment.PrintCodeContext( + scope: JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry), + printer: printer, + hasDirectAccessToSwiftClass: false, + classNamespaces: intrinsicRegistry.classNamespaces + ) + } + + /// Emits a `{ lower, lift }` codec literal for one bridgeable type. + /// `prefix` is prepended to the opening brace (e.g. an assignment) and + /// `suffix` is appended to the closing brace (e.g. `","` in an array). + private func appendGenericCodecLiteral( + type: BridgeType, + into printer: CodeFragmentPrinter, + prefix: String = "", + suffix: String = "," + ) throws { + try ContainerCodecJS.writeCodecLiteral( + type: type, + into: printer, + context: makeCodecPrintContext(printer: printer), + prefix: prefix, + suffix: suffix + ) + } + + /// Installs the per-module `bjs__register_type_handles` import + /// hooks. A module with a registration function always carries the wasm + /// import, so a hook is always installed; without generics anywhere in the + /// build it is a no-op and the registration export is never called. + private func generateTypeRegistrationHooks(into printer: CodeFragmentPrinter) throws { + for skeleton in skeletons { + guard skeleton.typeRegistrationEntries != nil else { continue } + let hookName = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + guard hasGenerics else { + printer.write("bjs[\"\(hookName)\"] = function() {};") + continue + } + // The hooks resolve type IDs against the shared primitive codec table. + try ContainerCodecJS.registerPrimitiveCodecs(context: makeCodecPrintContext(printer: printer)) + let moduleEntries = skeleton.exported?.genericBridgeableTypeEntries ?? [] + printer.write("bjs[\"\(hookName)\"] = function(base, count) {") + try printer.indent { + // Same canonical order as the Swift registration function: + // primitives first, then the module's own types. + printer.write("const codecs = [") + printer.indent { + for primitive in BridgeType.genericBridgeablePrimitives { + printer.write("\(JSGlueVariableScope.reservedPrimitiveCodecs).\(primitive.token),") + } + } + printer.write("].concat([") + try printer.indent { + for entry in moduleEntries { + try appendGenericCodecLiteral(type: entry.bridgeType, into: printer) + } + } + printer.write("]);") + printer.write("if (count !== codecs.length) {") + printer.indent { + printer.write( + "throw new Error(\"BridgeJS: type handle registration mismatch for module '\(skeleton.moduleName)'\");" + ) + } + printer.write("}") + printer.write( + "const typeIds = new Int32Array(\(JSGlueVariableScope.reservedMemory).buffer, base >>> 0, count >>> 0);" + ) + printer.write("for (let i = 0; i < count; i++) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedCodecByTypeId).set(typeIds[i], codecs[i]);") + } + printer.write("}") + } + printer.write("}") + } + } + private func generateAddImports(needsImportsObject: Bool) throws -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 } @@ -544,6 +654,7 @@ public struct BridgeJSLink { printer.write("}") } } + try generateTypeRegistrationHooks(into: printer) // Always provided: the runtime's `_bjs_makePromise` imports it unconditionally. // The settlers are stored under a Symbol to avoid clashing with promise fields. @@ -1023,7 +1134,7 @@ public struct BridgeJSLink { self.renderExportedStructExportEntry(structDef) }, renderFunctionEntry: { function in - self.renderJSDoc(documentation: function.documentation, parameters: function.parameters) + return self.renderJSDoc(documentation: function.documentation, parameters: function.parameters) + [ "\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] @@ -1060,6 +1171,7 @@ public struct BridgeJSLink { printer.write(lines: [ "addImports: (importObject: WebAssembly.Imports) => void;", "setInstance: (instance: WebAssembly.Instance) => void;", + "afterInitialize?: () => void;", "createExports: (instance: WebAssembly.Instance) => Exports;", ]) } @@ -1198,6 +1310,19 @@ public struct BridgeJSLink { printer.write("},") } + // afterInitialize method: eager type-handle registration. Only emitted + // when the generic runtime exists; otherwise the hook is absent and + // callers use optional chaining. + if hasGenerics { + printer.indent { + printer.write("afterInitialize: () => {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedRegisterTypeHandles)();") + } + printer.write("},") + } + } + // createExports method printer.indent { printer.write(lines: [ @@ -1371,8 +1496,9 @@ public struct BridgeJSLink { // Add methods for method in type.methods { let methodName = method.jsName ?? method.name + let genericClause = renderGenericClause(method.genericParameterNames) let methodSignature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" printer.write(methodSignature) } @@ -1587,6 +1713,10 @@ public struct BridgeJSLink { return "(\(parameterSignatures.joined(separator: ", "))): \(returnTypeWithEffect)" } + private func renderGenericClause(_ genericParameterNames: [String]) -> String { + genericParameterNames.isEmpty ? "" : "<\(genericParameterNames.joined(separator: ", "))>" + } + private func renderTSPropertyName(_ name: String) -> String { // TypeScript allows quoted property names for keys that aren't valid identifiers. if name.range(of: #"^[$A-Z_][0-9A-Z_$]*$"#, options: [.regularExpression, .caseInsensitive]) != nil { @@ -2379,6 +2509,8 @@ extension BridgeJSLink { var parameterNames: [String] = [] var parameterForwardings: [String] = [] var returnExpr: String? + var genericCodecVariables: [String: String] = [:] + var genericTypeIdParameters: [String: String] = [:] let printContext: IntrinsicJSFragment.PrintCodeContext init( @@ -2404,7 +2536,36 @@ extension BridgeJSLink { parameterNames.append("self") } + func declareGenericCodecs(genericParameters: [String]) { + if !genericParameters.isEmpty { + // Generic call sites instantiate the shared container codec + // combinators with the codecs resolved from type IDs. + ContainerCodecJS.registerCombinators(scope: scope) + } + for genericParam in genericParameters { + let typeIdParam = scope.variable("\(genericParam.lowercased())TypeId") + let codecVar = scope.variable("codec\(genericParam)") + body.write("const \(codecVar) = __bjs_codecForTypeId(\(typeIdParam));") + genericCodecVariables[genericParam] = codecVar + genericTypeIdParameters[genericParam] = typeIdParam + } + } + func liftParameter(param: Parameter) throws { + if let name = param.type.referencedGenericName { + guard let codecVar = genericCodecVariables[name] else { + throw BridgeJSLinkError( + message: "Generic codec for '\(name)' was not declared before lifting parameter '\(param.name)'" + ) + } + let valueVar = scope.variable(param.name) + let liftExpr = + GenericJSCodegen.genericCodecLiftExpression(type: param.type, codec: codecVar) + ?? "\(codecVar).lift()" + body.write("const \(valueVar) = \(liftExpr);") + parameterForwardings.append(valueVar) + return + } let liftingFragment = try IntrinsicJSFragment.liftParameter(type: param.type, context: context) let valuesToLift: [String] if liftingFragment.parameters.count == 0 { @@ -2421,6 +2582,16 @@ extension BridgeJSLink { parameterForwardings.append(contentsOf: liftedValues) } + func liftParametersAndGenericTypeIds(_ parameters: [Parameter], genericParameters: [String]) throws { + declareGenericCodecs(genericParameters: genericParameters) + for param in parameters { + try liftParameter(param: param) + } + for genericParam in genericParameters { + parameterNames.append(genericTypeIdParameters[genericParam] ?? genericParam) + } + } + func renderFunction(name: String?) -> [String] { if effects.isAsync { return renderAsyncFunction(name: name) @@ -2497,6 +2668,25 @@ extension BridgeJSLink { body.write("\(callExpr).then(resolve, reject);") return } + if let name = returnType.referencedGenericName { + guard let codecVar = genericCodecVariables[name] else { + throw BridgeJSLinkError( + message: "Generic codec for return type '\(name)' was not declared before the call" + ) + } + let resultVariable = scope.variable("ret") + body.write("let \(resultVariable) = \(callExpr);") + let lowerStmt = + GenericJSCodegen.genericCodecLowerStatement( + type: returnType, + codec: codecVar, + value: resultVariable + ) + ?? "\(codecVar).lower(\(resultVariable));" + body.write(lowerStmt) + self.returnExpr = nil + return + } let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: returnType, context: context) let returnExpr: String? if loweringFragment.parameters.count == 0 { @@ -3476,9 +3666,11 @@ extension BridgeJSLink { returnType: function.returnType, intrinsicRegistry: intrinsicRegistry ) - for param in function.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = function.genericParameterNames + try thunkBuilder.liftParametersAndGenericTypeIds( + function.parameters, + genericParameters: genericParameters + ) let jsName = function.jsName ?? function.name let calleeExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, @@ -3489,9 +3681,10 @@ extension BridgeJSLink { try thunkBuilder.call(calleeExpr: calleeExpr) let funcLines = thunkBuilder.renderFunction(name: function.abiName(context: nil)) if function.from == nil { + let genericClause = renderGenericClause(genericParameters) importObjectBuilder.appendDts( [ - "\(renderTSPropertyName(jsName))\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(renderTSPropertyName(jsName))\(genericClause)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] ) } @@ -3580,14 +3773,16 @@ extension BridgeJSLink { dtsPrinter.indent { if let constructor = type.constructor { let returnType = BridgeType.jsObject(type.name) + let genericClause = renderGenericClause(constructor.genericParameterNames) dtsPrinter.write( - "new\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));" + "new\(genericClause)\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));" ) } for method in type.staticMethods { let methodName = method.jsName ?? method.name + let genericClause = renderGenericClause(method.genericParameterNames) let signature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" dtsPrinter.write(signature) } } @@ -3611,9 +3806,10 @@ extension BridgeJSLink { returnType: BridgeType.jsObject(type.name), intrinsicRegistry: intrinsicRegistry ) - for param in constructor.parameters { - try thunkBuilder.liftParameter(param: param) - } + try thunkBuilder.liftParametersAndGenericTypeIds( + constructor.parameters, + genericParameters: constructor.genericParameterNames + ) let ctorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, from: type.from, @@ -3670,9 +3866,10 @@ extension BridgeJSLink { returnType: method.returnType, intrinsicRegistry: intrinsicRegistry ) - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: method.genericParameterNames + ) let constructorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: swiftModuleName, from: context.from, @@ -3694,9 +3891,11 @@ extension BridgeJSLink { intrinsicRegistry: intrinsicRegistry ) thunkBuilder.liftSelf() - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = method.genericParameterNames + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: genericParameters + ) try thunkBuilder.callMethod(name: method.jsName ?? method.name) let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context)) @@ -4040,6 +4239,8 @@ extension BridgeType { return "Record" case .alias(_, let underlying): return underlying.tsType + case .generic(let name): + return name } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 1cf0fa298..49dd5b75e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -35,6 +35,11 @@ final class JSGlueVariableScope { static let reservedSwiftClosureRegistry = "swiftClosureRegistry" static let reservedMakeSwiftClosure = "makeClosure" static let reservedTaStack = "taStack" + static let reservedCodecByTypeId = "__bjs_codecByTypeId" + static let reservedPrimitiveCodecs = "__bjs_primitiveCodecs" + static let reservedStringCodec = "__bjs_stringCodec" + static let reservedTypeHandlesRegistered = "__bjs_typeHandlesRegistered" + static let reservedRegisterTypeHandles = "__bjs_registerTypeHandles" private let intrinsicRegistry: JSIntrinsicRegistry @@ -65,6 +70,11 @@ final class JSGlueVariableScope { reservedSwiftClosureRegistry, reservedMakeSwiftClosure, reservedTaStack, + reservedCodecByTypeId, + reservedPrimitiveCodecs, + reservedStringCodec, + reservedTypeHandlesRegistered, + reservedRegisterTypeHandles, ] init(intrinsicRegistry: JSIntrinsicRegistry) { @@ -138,6 +148,271 @@ extension JSGlueVariableScope { } } +enum GenericJSCodegen { + /// Wraps a bare element codec into the codec for the wrapped form (`[T]`, + /// `T?`, `[String: T]`) used at a generic call site, or `nil` when the type + /// is not a generic reference. + static func genericCodecExpression(type: BridgeType, codec: String) -> String? { + switch type { + case .generic: return codec + case .array(.generic): return "\(ContainerCodecJS.arrayCodec)(\(codec))" + case .nullable(.generic, let kind): + return ContainerCodecJS.optionalCodecExpression(elementCodec: codec, kind: kind) + case .dictionary(.generic): return "\(ContainerCodecJS.dictCodec)(\(codec))" + default: return nil + } + } + + static func genericCodecLowerStatement(type: BridgeType, codec: String, value: String) -> String? { + genericCodecExpression(type: type, codec: codec).map { "\($0).lower(\(value));" } + } + + static func genericCodecLiftExpression(type: BridgeType, codec: String) -> String? { + genericCodecExpression(type: type, codec: codec).map { "\($0).lift()" } + } + + /// Generic-only runtime: resolves a wasm-side type ID to the codec + /// registered for it. The container codec combinators themselves live in + /// `ContainerCodecJS` and are shared with the non-generic bridging paths. + static func runtimeHelperDeclarations() -> [String] { + let codecByTypeId = JSGlueVariableScope.reservedCodecByTypeId + return [ + "function __bjs_codecForTypeId(typeId) {", + " __bjs_registerTypeHandles();", + " const codec = \(codecByTypeId).get(typeId);", + " if (!codec) {", + " throw new Error(\"BridgeJS: no codec registered for type ID \" + typeId);", + " }", + " return codec;", + "}", + ] + } +} + +/// Shared `{ lower, lift }` codec codegen: each container's stack ABI is +/// described once by a combinator and instantiated with an element codec by +/// both the generic and non-generic paths. Emitted lazily via the intrinsic +/// registry, so builds that bridge no containers pay nothing. +enum ContainerCodecJS { + static let arrayCodec = "__bjs_arrayCodec" + static let optionalCodec = "__bjs_optionalCodec" + static let dictCodec = "__bjs_dictCodec" + static let enumCodec = "__bjs_enumCodec" + + private static let combinatorIntrinsicName = "containerCodecCombinators" + private static let primitiveCodecIntrinsicName = "containerPrimitiveCodecs" + + /// The single description of each container shape's stack ABI. + static func combinatorDeclarations() -> [String] { + let i32 = JSGlueVariableScope.reservedI32Stack + let stringCodec = JSGlueVariableScope.reservedStringCodec + return [ + "function \(arrayCodec)(elementCodec) {", + " return {", + " lower(value) {", + " for (let i = 0; i < value.length; i++) {", + " elementCodec.lower(value[i]);", + " }", + " \(i32).push(value.length);", + " },", + " lift() {", + " const count = \(i32).pop();", + " if (count === -1) {", + " return \(JSGlueVariableScope.reservedTaStack).pop();", + " }", + " const result = new Array(count);", + " for (let i = count - 1; i >= 0; i--) {", + " result[i] = elementCodec.lift();", + " }", + " return result;", + " },", + " };", + "}", + // `isUndefinedOr` selects the `JSUndefinedOr` flavor: `null` is then a + // present value and absence surfaces as `undefined` instead of `null`. + "function \(optionalCodec)(elementCodec, isUndefinedOr = false) {", + " return {", + " lower(value) {", + " const isSome = isUndefinedOr ? value !== undefined : value != null;", + " if (isSome) {", + " elementCodec.lower(value);", + " \(i32).push(1);", + " } else {", + " \(i32).push(0);", + " }", + " },", + " lift() {", + " if (\(i32).pop() === 0) {", + " return isUndefinedOr ? undefined : null;", + " }", + " return elementCodec.lift();", + " },", + " };", + "}", + "function \(dictCodec)(valueCodec) {", + " return {", + " lower(value) {", + " const keys = Object.keys(value);", + " for (let i = 0; i < keys.length; i++) {", + " \(stringCodec).lower(keys[i]);", + " valueCodec.lower(value[keys[i]]);", + " }", + " \(i32).push(keys.length);", + " },", + " lift() {", + " const count = \(i32).pop();", + " const result = {};", + " for (let i = 0; i < count; i++) {", + " const value = valueCodec.lift();", + " const key = \(stringCodec).lift();", + " result[key] = value;", + " }", + " return result;", + " },", + " };", + "}", + // Adapts an associated-value enum helper (whose lower returns the case + // tag and whose lift takes it) to the plain stack codec protocol. + "function \(enumCodec)(helper) {", + " return {", + " lower(value) {", + " \(i32).push(helper.lower(value));", + " },", + " lift() {", + " return helper.lift(\(i32).pop());", + " },", + " };", + "}", + ] + } + + static func optionalCodecExpression(elementCodec: String, kind: JSOptionalKind) -> String { + switch kind { + case .null: return "\(optionalCodec)(\(elementCodec))" + case .undefined: return "\(optionalCodec)(\(elementCodec), true)" + } + } + + static func registerCombinators(scope: JSGlueVariableScope) { + scope.registerIntrinsic(combinatorIntrinsicName) { printer in + printer.write(lines: combinatorDeclarations()) + } + } + + /// Emits `__bjs_stringCodec` and the `__bjs_primitiveCodecs` table shared + /// by combinator instantiations and the generic type-handle registration. + static func registerPrimitiveCodecs(context: IntrinsicJSFragment.PrintCodeContext) throws { + try context.scope.registerIntrinsic(primitiveCodecIntrinsicName) { printer in + let stringCodec = JSGlueVariableScope.reservedStringCodec + // The String codec is named so the dictionary codec combinator can + // lower/lift keys through it. + try writeCodecLiteral( + type: .string, + into: printer, + context: context, + prefix: "const \(stringCodec) = ", + suffix: ";" + ) + printer.write("const \(JSGlueVariableScope.reservedPrimitiveCodecs) = {") + try printer.indent { + for primitive in BridgeType.genericBridgeablePrimitives { + if case .string = primitive.type { + printer.write("\(primitive.token): \(stringCodec),") + } else { + try writeCodecLiteral( + type: primitive.type, + into: printer, + context: context, + prefix: "\(primitive.token): ", + suffix: "," + ) + } + } + } + printer.write("};") + } + } + + /// Emits a `{ lower, lift }` codec literal for one bridgeable type. + /// `prefix` is prepended to the opening brace (e.g. an assignment) and + /// `suffix` is appended to the closing brace (e.g. `","` in an object). + static func writeCodecLiteral( + type: BridgeType, + into printer: CodeFragmentPrinter, + context: IntrinsicJSFragment.PrintCodeContext, + prefix: String = "", + suffix: String = "," + ) throws { + func literalContext() -> IntrinsicJSFragment.PrintCodeContext { + context.with(\.printer, printer).with(\.scope, context.scope.makeChildScope()) + } + let lowerFragment = try IntrinsicJSFragment.stackLowerFragment(elementType: type) + let liftFragment = try IntrinsicJSFragment.stackLiftFragment(elementType: type) + printer.write("\(prefix){") + try printer.indent { + printer.write("lower: (v) => {") + try printer.indent { + _ = try lowerFragment.printCode(["v"], literalContext()) + } + printer.write("},") + printer.write("lift: () => {") + try printer.indent { + let results = try liftFragment.printCode([], literalContext()) + printer.write("return \(results[0]);") + } + printer.write("},") + } + printer.write("}\(suffix)") + } + + /// Returns a JS expression evaluating to the `{ lower, lift }` codec for + /// one element type, registering the shared codec runtime as needed. May + /// write supporting statements (a local codec literal) to the context's + /// printer for element shapes without a named shared codec. + static func codecExpression( + for elementType: BridgeType, + context: IntrinsicJSFragment.PrintCodeContext + ) throws -> String { + registerCombinators(scope: context.scope) + try registerPrimitiveCodecs(context: context) + let type = elementType.unaliased + switch type { + case .array(let element): + return "\(arrayCodec)(\(try codecExpression(for: element, context: context)))" + case .dictionary(let value): + return "\(dictCodec)(\(try codecExpression(for: value, context: context)))" + case .nullable(let wrapped, let kind): + let element = try codecExpression(for: wrapped, context: context) + return optionalCodecExpression(elementCodec: element, kind: kind) + case .string, .rawValueEnum(_, .string): + return JSGlueVariableScope.reservedStringCodec + case .swiftStruct(let fullName): + // `@JS` struct helpers already expose the codec protocol. + let base = fullName.replacingOccurrences(of: ".", with: "_") + return "\(JSGlueVariableScope.reservedStructHelpers).\(base)" + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + return "\(enumCodec)(\(JSGlueVariableScope.reservedEnumHelpers).\(base))" + default: + if let token = BridgeType.genericBridgeablePrimitives.first(where: { $0.type == type })?.token { + return "\(JSGlueVariableScope.reservedPrimitiveCodecs).\(token)" + } + // Element shapes without a named shared codec (case enums, non-string + // raw-value enums, JSObject, Swift heap objects, ...) get a local + // codec literal built from the same element stack fragments. + let codecVar = context.scope.variable("elemCodec") + try writeCodecLiteral( + type: type, + into: context.printer, + context: context, + prefix: "const \(codecVar) = ", + suffix: ";" + ) + return codecVar + } + } +} + /// A fragment of JS code used to convert a value between Swift and JS. /// /// See `BridgeJSIntrinsics.swift` in the main JavaScriptKit module for Swift side lowering/lifting implementation. @@ -681,6 +956,12 @@ struct IntrinsicJSFragment: Sendable { ) } + /// Lift an optional parameter whose presence flag arrives as a wasm + /// parameter (not on the i32 stack), with the payload either in further + /// wasm parameters or on the stacks. The shared optional codec combinator + /// pops its flag from the i32 stack, so this ABI cannot go through it; + /// stack-convention payloads still lift through the shared container + /// codecs via `stackLiftFragment`. private static func compositeOptionalLiftParameter( wrappedType: BridgeType, kind: JSOptionalKind, @@ -761,26 +1042,26 @@ struct IntrinsicJSFragment: Sendable { ) } - let innerFragment = - if wrappedType.optionalParameterUsesStackABI { - try stackLowerFragment(elementType: wrappedType) - } else { - try lowerParameter(type: wrappedType) - } + if wrappedType.optionalParameterUsesStackABI { + // Stack convention: the conditional flag-plus-payload protocol is + // the shared optional codec's stack ABI. + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) + } return try compositeOptionalLowerParameter( wrappedType: wrappedType, kind: kind, - innerFragment: innerFragment + innerFragment: try lowerParameter(type: wrappedType) ) } + /// Lower an optional parameter using the direct `(isSome, ...payload)` wasm + /// parameter ABI with zero placeholders for nil. This is not the container + /// stack ABI, so it cannot go through the shared optional codec combinator. private static func compositeOptionalLowerParameter( wrappedType: BridgeType, kind: JSOptionalKind, innerFragment: IntrinsicJSFragment ) throws -> IntrinsicJSFragment { - let isStackConvention = wrappedType.optionalParameterUsesStackABI - return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -797,7 +1078,7 @@ struct IntrinsicJSFragment: Sendable { let resultVars = innerResults.map { _ in scope.variable("result") } assert( - isStackConvention || resultVars.count == wrappedType.wasmParams.count, + resultVars.count == wrappedType.wasmParams.count, "Inner fragment result count (\(resultVars.count)) must match wasmParams count (\(wrappedType.wasmParams.count)) for \(wrappedType)" ) if !resultVars.isEmpty { @@ -814,8 +1095,7 @@ struct IntrinsicJSFragment: Sendable { } } - let hasPlaceholders = !isStackConvention && !wrappedType.wasmParams.isEmpty - if hasPlaceholders { + if !wrappedType.wasmParams.isEmpty { printer.write("} else {") printer.indent { for (resultVar, param) in zip(resultVars, wrappedType.wasmParams) { @@ -825,12 +1105,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("}") - if isStackConvention { - scope.emitPushI32Parameter("+\(isSomeVar)", printer: printer) - return [] - } else { - return ["+\(isSomeVar)"] + resultVars - } + return ["+\(isSomeVar)"] + resultVars } ) } @@ -848,6 +1123,9 @@ struct IntrinsicJSFragment: Sendable { ) } + /// Lift an optional return whose presence flag travels on the i32 stack but + /// whose payload uses the wrapped type's regular (non-stack) return ABI, so + /// it cannot go through the shared optional codec combinator. private static func optionalLiftReturnWithPresenceFlag( wrappedType: BridgeType, kind: JSOptionalKind @@ -860,12 +1138,7 @@ struct IntrinsicJSFragment: Sendable { let isSomeVar = scope.variable("isSome") printer.write("const \(isSomeVar) = \(scope.popI32());") - let innerFragment = - if wrappedType.optionalConvention == .stackABI { - try stackLiftFragment(elementType: wrappedType) - } else { - try liftReturn(type: wrappedType) - } + let innerFragment = try liftReturn(type: wrappedType) let innerPrinter = CodeFragmentPrinter() let innerResults = try innerFragment.printCode([], context.with(\.printer, innerPrinter)) @@ -942,31 +1215,13 @@ struct IntrinsicJSFragment: Sendable { ) } - private static func optionalLiftReturnStruct( - fullName: String, - kind: JSOptionalKind - ) -> IntrinsicJSFragment { - let base = fullName.replacingOccurrences(of: ".", with: "_") - let absenceLiteral = kind.absenceLiteral - return IntrinsicJSFragment( - parameters: [], - printCode: { _, context in - let (scope, printer) = (context.scope, context.printer) - let isSomeVar = scope.variable("isSome") - let resultVar = scope.variable("optResult") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write( - "const \(resultVar) = \(isSomeVar) ? \(JSGlueVariableScope.reservedStructHelpers).\(base).lift() : \(absenceLiteral);" - ) - return [resultVar] - } - ) - } - static func optionalLiftReturn( wrappedType: BridgeType, kind: JSOptionalKind - ) -> IntrinsicJSFragment { + ) throws -> IntrinsicJSFragment { + // Side-channel optionals deliver their payload through dedicated + // storage/imports instead of the bridge stacks, so they cannot go + // through the shared optional codec combinator. if let scalarKind = wrappedType.optionalScalarKind { return optionalLiftReturnFromStorage(storage: scalarKind.storageName) } @@ -974,18 +1229,21 @@ struct IntrinsicJSFragment: Sendable { return optionalLiftReturnFromStorage(storage: JSGlueVariableScope.reservedStorageToReturnString) } + // Heap object optionals use the tmpRetOptionalHeapObject side channel. if case .swiftHeapObject(let className) = wrappedType { return optionalLiftReturnHeapObject(className: className, kind: kind) } - if case .swiftStruct(let fullName) = wrappedType { - return optionalLiftReturnStruct(fullName: fullName, kind: kind) - } - + // Sentinel optionals encode nil in-band (tag -1), with no presence flag. if wrappedType.nilSentinel.hasSentinel, case .associatedValueEnum(let fullName) = wrappedType { return optionalLiftReturnAssociatedEnum(fullName: fullName, kind: kind) } + if wrappedType.optionalConvention == .stackABI { + // Stack convention: route through the shared optional codec combinator. + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) + } + return optionalLiftReturnWithPresenceFlag(wrappedType: wrappedType, kind: kind) } @@ -1111,12 +1369,8 @@ struct IntrinsicJSFragment: Sendable { } if wrappedType.optionalConvention == .stackABI { - let innerFragment = try stackLowerFragment(elementType: wrappedType) - return stackOptionalLower( - wrappedType: wrappedType, - kind: kind, - innerFragment: innerFragment - ) + // Stack convention: route through the shared optional codec combinator. + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) } if wrappedType.nilSentinel.hasSentinel { @@ -1248,39 +1502,6 @@ struct IntrinsicJSFragment: Sendable { } } - /// Lower an optional value to the stack using the **conditional** protocol: - /// push isSome flag, then conditionally push the payload (no placeholders for nil). - private static func stackOptionalLower( - wrappedType: BridgeType, - kind: JSOptionalKind, - innerFragment: IntrinsicJSFragment - ) -> IntrinsicJSFragment { - IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - - let ifBodyPrinter = CodeFragmentPrinter() - try ifBodyPrinter.indent { - let _ = try innerFragment.printCode( - [value], - context.with(\.printer, ifBodyPrinter) - ) - } - printer.write("if (\(isSomeVar)) {") - for line in ifBodyPrinter.lines { - printer.write(line) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } - ) - } - // MARK: - ExportSwift /// Returns a fragment that lowers a JS value to Wasm core values for parameters @@ -1357,7 +1578,7 @@ struct IntrinsicJSFragment: Sendable { case .swiftProtocol: return .jsObjectLiftReturn case .void: return .void case .nullable(let wrappedType, let kind): - return .optionalLiftReturn(wrappedType: wrappedType, kind: kind) + return try .optionalLiftReturn(wrappedType: wrappedType, kind: kind) case .rawValueEnum(_, .string): return .stringLiftReturn case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName @@ -1807,133 +2028,61 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Array Helpers - /// Lowers an array from JS to Swift by iterating elements and pushing to stacks + /// Lowers an array from JS to Swift through the shared array codec combinator static func arrayLower(elementType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["arr"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let arr = arguments[0] - - let elemVar = scope.variable("elem") - printer.write("for (const \(elemVar) of \(arr)) {") - try printer.indent { - let elementFragment = try stackLowerFragment(elementType: elementType) - let _ = try elementFragment.printCode( - [elemVar], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(arr).length", printer: printer) + let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) + context.printer.write("\(ContainerCodecJS.arrayCodec)(\(element)).lower(\(arguments[0]));") return [] } ) } - /// Lowers a dictionary from JS to Swift by iterating entries and pushing to stacks + /// Lowers a dictionary from JS to Swift through the shared dictionary codec combinator static func dictionaryLower(valueType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["dict"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let dict = arguments[0] - - let entriesVar = scope.variable("entries") - let entryVar = scope.variable("entry") - printer.write("const \(entriesVar) = Object.entries(\(dict));") - printer.write("for (const \(entryVar) of \(entriesVar)) {") - try printer.indent { - let keyVar = scope.variable("key") - let valueVar = scope.variable("value") - printer.write("const [\(keyVar), \(valueVar)] = \(entryVar);") - - let keyFragment = try stackLowerFragment(elementType: .string) - let _ = try keyFragment.printCode( - [keyVar], - context - ) - - let valueFragment = try stackLowerFragment(elementType: valueType) - let _ = try valueFragment.printCode( - [valueVar], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(entriesVar).length", printer: printer) + let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) + context.printer.write("\(ContainerCodecJS.dictCodec)(\(value)).lower(\(arguments[0]));") return [] } ) } - /// Lifts an array from Swift to JS by popping elements from stacks + /// Lifts an array from Swift to JS through the shared array codec combinator static func arrayLift(elementType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let resultVar = scope.variable("arrayResult") - let lenVar = scope.variable("arrayLen") - - printer.write("const \(lenVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(lenVar) === -1) {") - printer.indent { - // Bulk path: Swift pushed a typed array onto the typed-array stack - printer.write("\(resultVar) = \(JSGlueVariableScope.reservedTaStack).pop();") - } - printer.write("} else {") - try printer.indent { - // Element-by-element path (original behavior) - let iVar = scope.variable("i") - printer.write("\(resultVar) = [];") - printer.write("for (let \(iVar) = 0; \(iVar) < \(lenVar); \(iVar)++) {") - try printer.indent { - let elementFragment = try stackLiftFragment(elementType: elementType) - let elementResults = try elementFragment.printCode([], context) - if let elementExpr = elementResults.first { - printer.write("\(resultVar).push(\(elementExpr));") - } - } - printer.write("}") - printer.write("\(resultVar).reverse();") - } - printer.write("}") + printCode: { _, context in + let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) + let resultVar = context.scope.variable("arrayResult") + context.printer.write( + "const \(resultVar) = \(ContainerCodecJS.arrayCodec)(\(element)).lift();" + ) return [resultVar] } ) } - /// Lifts a dictionary from Swift to JS by popping key/value pairs from stacks + /// Lifts a dictionary from Swift to JS through the shared dictionary codec combinator static func dictionaryLift(valueType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let resultVar = scope.variable("dictResult") - let lenVar = scope.variable("dictLen") - let iVar = scope.variable("i") - - printer.write("const \(lenVar) = \(scope.popI32());") - printer.write("const \(resultVar) = {};") - printer.write("for (let \(iVar) = 0; \(iVar) < \(lenVar); \(iVar)++) {") - try printer.indent { - let valueFragment = try stackLiftFragment(elementType: valueType) - let valueResults = try valueFragment.printCode([], context) - let keyFragment = try stackLiftFragment(elementType: .string) - let keyResults = try keyFragment.printCode([], context) - if let keyExpr = keyResults.first, let valueExpr = valueResults.first { - printer.write("\(resultVar)[\(keyExpr)] = \(valueExpr);") - } - } - printer.write("}") + printCode: { _, context in + let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) + let resultVar = context.scope.variable("dictResult") + context.printer.write( + "const \(resultVar) = \(ContainerCodecJS.dictCodec)(\(value)).lift();" + ) return [resultVar] } ) } - private static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { if case .nullable(let wrappedType, let kind) = elementType { return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) } @@ -2060,7 +2209,7 @@ struct IntrinsicJSFragment: Sendable { } } - private static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { if case .nullable(let wrappedType, let kind) = elementType { return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) } @@ -2181,43 +2330,27 @@ struct IntrinsicJSFragment: Sendable { } } + /// Lift an optional from the stack (isSome flag, then conditional payload) + /// through the shared optional codec combinator. private static func optionalElementRaiseFragment( wrappedType: BridgeType, kind: JSOptionalKind ) throws -> IntrinsicJSFragment { - let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let isSomeVar = scope.variable("isSome") - let resultVar = scope.variable("optValue") - - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(isSomeVar) === 0) {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } - printer.write("} else {") - try printer.indent { - let innerFragment = try stackLiftFragment(elementType: wrappedType) - let innerResults = try innerFragment.printCode([], context) - if let innerResult = innerResults.first { - printer.write("\(resultVar) = \(innerResult);") - } else { - printer.write("\(resultVar) = undefined;") - } - } - printer.write("}") - + printCode: { _, context in + let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) + let resultVar = context.scope.variable("optValue") + let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) + context.printer.write("const \(resultVar) = \(codec).lift();") return [resultVar] } ) } - /// Lower an optional element to the stack using the **conditional** protocol: - /// push isSome flag, then conditionally push the payload (no placeholders for nil). + /// Lower an optional value to the stack using the **conditional** protocol + /// (push isSome flag, then conditionally push the payload) through the + /// shared optional codec combinator. private static func optionalElementLowerFragment( wrappedType: BridgeType, kind: JSOptionalKind @@ -2225,23 +2358,9 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - - let presenceExpr = kind.presenceCheck(value: value) - printer.write("const \(isSomeVar) = \(presenceExpr) ? 1 : 0;") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let innerFragment = try stackLowerFragment(elementType: wrappedType) - let _ = try innerFragment.printCode( - [value], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter(isSomeVar, printer: printer) - + let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) + let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) + context.printer.write("\(codec).lower(\(arguments[0]));") return [] } ) @@ -2608,7 +2727,7 @@ private extension BridgeType { return .inlineFlag case .closure: return .inlineFlag - case .swiftStruct, .array, .dictionary, .void, .namespaceEnum: + case .swiftStruct, .array, .dictionary, .void, .namespaceEnum, .generic: return .stackABI case .nullable(let wrapped, _): return wrapped.optionalConvention @@ -2706,7 +2825,7 @@ private extension BridgeType { return [("caseId", .i32)] case .closure: return [("funcRef", .i32)] - case .void, .namespaceEnum, .swiftStruct, .array, .dictionary: + case .void, .namespaceEnum, .swiftStruct, .array, .dictionary, .generic: return [] case .nullable(let wrapped, _): return wrapped.wasmParams diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 5507f39c2..854be2193 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -22,6 +22,16 @@ extension NamespacedExportedType { public struct ABINameGenerator { static let prefixComponent = "bjs" + /// ABI parameter name carrying the runtime type ID for the generic parameter at `index`. + public static func genericTypeIdParameterName(index: Int) -> String { "_generic\(index)TypeId" } + + /// Name of the per-module type-handle registration function. The wasm module + /// exports it under this name, and it calls back into a JS import hook of the + /// same name (in the `bjs` import namespace) with a buffer of type IDs. + public static func typeRegistrationFunctionName(moduleName: String) -> String { + "bjs_\(moduleName)_register_type_handles" + } + /// Generates ABI name using standardized namespace + context pattern public static func generateABIName( baseName: String, @@ -273,10 +283,120 @@ public enum BridgeType: Codable, Equatable, Hashable, Sendable { case namespaceEnum(String) case swiftProtocol(String) case swiftStruct(String) + case generic(String) indirect case closure(ClosureSignature, useJSTypedClosure: Bool) indirect case alias(name: String, underlying: BridgeType) } +extension BridgeType { + public var referencedGenericName: String? { + switch self { + case .generic(let name): return name + case .array(.generic(let name)): return name + case .nullable(.generic(let name), _): return name + case .dictionary(.generic(let name)): return name + default: return nil + } + } + + public static let genericBridgeablePrimitives: [(token: String, type: BridgeType)] = [ + ("Bool", .bool), + ("Int", .integer(.int)), + ("Int8", .integer(.int8)), + ("UInt8", .integer(.uint8)), + ("Int16", .integer(.int16)), + ("UInt16", .integer(.uint16)), + ("Int32", .integer(.int32)), + ("UInt32", .integer(.uint32)), + ("UInt", .integer(.uint)), + ("Int64", .integer(.int64)), + ("UInt64", .integer(.uint64)), + ("Float", .float), + ("Double", .double), + ("String", .string), + ("JSValue", .jsValue), + ] + +} + +// MARK: - Generic type registration + +/// One `BridgedSwiftGenericBridgeable` type participating in generic bridging. +/// +/// `swiftName` is the Swift expression naming the type (used by Swift codegen to +/// read `.bridgeJSTypeID`); `bridgeType` describes the stack ABI (used +/// by the JS link layer to emit the matching codec). +public struct GenericBridgeableTypeEntry: Sendable { + public let swiftName: String + public let bridgeType: BridgeType + + public init(swiftName: String, bridgeType: BridgeType) { + self.swiftName = swiftName + self.bridgeType = bridgeType + } +} + +extension ExportedEnum { + /// The `BridgeType` an enum bridges as when used as a generic argument, or + /// `nil` when it can't be one (namespace enums). + public var genericBridgeType: BridgeType? { + switch enumType { + case .simple: + return .caseEnum(name) + case .rawValue: + guard let rawType = rawType else { return nil } + return .rawValueEnum(name, rawType) + case .associatedValue: + return .associatedValueEnum(name) + case .namespace: + return nil + } + } +} + +extension ExportedSkeleton { + /// The module's `@JS` types that conform to `BridgedSwiftGenericBridgeable`. + /// The order is the contract between the Swift registration function and the + /// JS codec array; both derive it from this skeleton, so they line up. + public var genericBridgeableTypeEntries: [GenericBridgeableTypeEntry] { + var entries: [GenericBridgeableTypeEntry] = [] + for structDef in structs { + entries.append( + GenericBridgeableTypeEntry( + swiftName: structDef.swiftCallName, + bridgeType: .swiftStruct(structDef.abiName) + ) + ) + } + for klass in classes where klass.isFinal == true { + entries.append( + GenericBridgeableTypeEntry(swiftName: klass.swiftCallName, bridgeType: .swiftHeapObject(klass.name)) + ) + } + for enumDef in enums { + guard let bridgeType = enumDef.genericBridgeType else { continue } + entries.append(GenericBridgeableTypeEntry(swiftName: enumDef.swiftCallName, bridgeType: bridgeType)) + } + return entries + } +} + +extension BridgeJSSkeleton { + /// The ordered list of types this module registers type handles for, or + /// `nil` when it emits no registration function. Primitive handles are + /// library singletons, so every module re-registering them writes the same + /// ID-to-codec pair, and a pure-import build still gets a populated table. + public var typeRegistrationEntries: [GenericBridgeableTypeEntry]? { + let exportedEntries = exported?.genericBridgeableTypeEntries ?? [] + let hasGenericImports = imported?.hasGenericDeclarations ?? false + guard !exportedEntries.isEmpty || hasGenericImports else { return nil } + let primitives = BridgeType.genericBridgeablePrimitives.map { + GenericBridgeableTypeEntry(swiftName: $0.token, bridgeType: $0.type) + } + return primitives + exportedEntries + } +} + public enum WasmCoreType: String, Codable, Sendable { case i32, i64, f32, f64, pointer } @@ -900,6 +1020,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { public var namespace: [String]? public var identityMode: Bool? // nil = use config default, true/false = override public var documentation: String? + public var isFinal: Bool? public init( name: String, @@ -910,7 +1031,8 @@ public struct ExportedClass: Codable, NamespacedExportedType { properties: [ExportedProperty] = [], namespace: [String]? = nil, identityMode: Bool? = nil, - documentation: String? = nil + documentation: String? = nil, + isFinal: Bool? = nil ) { self.name = name self.swiftCallName = swiftCallName @@ -921,6 +1043,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { self.namespace = namespace self.identityMode = identityMode self.documentation = documentation + self.isFinal = isFinal } } @@ -1244,6 +1367,9 @@ public struct ImportedFunctionSkeleton: Codable { /// determine the access level of bridge-generated helpers (e.g. typed /// closure inits) that surface through this function's signature. public let accessLevel: BridgeJSAccessLevel + public let genericParameters: [String]? + public var genericParameterNames: [String] { genericParameters ?? [] } + public var isGeneric: Bool { !genericParameterNames.isEmpty } public init( name: String, @@ -1253,7 +1379,8 @@ public struct ImportedFunctionSkeleton: Codable { returnType: BridgeType, effects: Effects = Effects(isAsync: false, isThrows: true), documentation: String? = nil, - accessLevel: BridgeJSAccessLevel = .internal + accessLevel: BridgeJSAccessLevel = .internal, + genericParameters: [String]? = nil ) { self.name = name self.jsName = jsName @@ -1263,10 +1390,11 @@ public struct ImportedFunctionSkeleton: Codable { self.effects = effects self.documentation = documentation self.accessLevel = accessLevel + self.genericParameters = genericParameters } private enum CodingKeys: String, CodingKey { - case name, jsName, from, parameters, returnType, effects, documentation, accessLevel + case name, jsName, from, parameters, returnType, effects, documentation, accessLevel, genericParameters } public init(from decoder: any Decoder) throws { @@ -1279,6 +1407,7 @@ public struct ImportedFunctionSkeleton: Codable { self.effects = try container.decode(Effects.self, forKey: .effects) self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal + self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -1299,20 +1428,29 @@ public struct ImportedConstructorSkeleton: Codable { /// Source access level of the originating Swift `init`. Inherits from the /// enclosing `@JSClass` type when not annotated explicitly. public let accessLevel: BridgeJSAccessLevel + public let genericParameters: [String]? + public var genericParameterNames: [String] { genericParameters ?? [] } + public var isGeneric: Bool { !genericParameterNames.isEmpty } - public init(parameters: [Parameter], accessLevel: BridgeJSAccessLevel = .internal) { + public init( + parameters: [Parameter], + accessLevel: BridgeJSAccessLevel = .internal, + genericParameters: [String]? = nil + ) { self.parameters = parameters self.accessLevel = accessLevel + self.genericParameters = genericParameters } private enum CodingKeys: String, CodingKey { - case parameters, accessLevel + case parameters, accessLevel, genericParameters } public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.parameters = try container.decode([Parameter].self, forKey: .parameters) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal + self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton) -> String { @@ -1553,6 +1691,17 @@ public struct ImportedFileSkeleton: Codable { } } +extension ImportedFileSkeleton { + public var hasGenericDeclarations: Bool { + functions.contains(where: \.isGeneric) + || types.contains { + $0.methods.contains(where: \.isGeneric) + || $0.staticMethods.contains(where: \.isGeneric) + || ($0.constructor?.isGeneric ?? false) + } + } +} + public struct ImportedModuleSkeleton: Codable { public var children: [ImportedFileSkeleton] @@ -1561,6 +1710,12 @@ public struct ImportedModuleSkeleton: Codable { } } +extension ImportedModuleSkeleton { + public var hasGenericDeclarations: Bool { + children.contains { $0.hasGenericDeclarations } + } +} + // MARK: - Closure signature collection visitor public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { @@ -1735,7 +1890,7 @@ extension BridgeType { case .bool, .integer, .float, .double, .string, .jsValue, .jsObject, .swiftHeapObject, .unsafePointer, .swiftProtocol, .void, .caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, - .namespaceEnum, .closure: + .namespaceEnum, .closure, .generic: return self } } @@ -1782,6 +1937,8 @@ extension BridgeType { return nil case .alias(_, let underlying): return underlying.abiReturnType + case .generic: + return nil } } @@ -1873,6 +2030,8 @@ extension BridgeType { // `name` is the namespace-qualified swiftCallName (unique), so the underlying // representation isn't mangled in - aliases bridge via their JS type's ABI. return "Al\(name.count)\(name)" + case .generic(let name): + return "\(name.count)\(name)T" } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift index 140ebda63..96d9c4705 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -240,9 +240,12 @@ import BridgeJSUtilities return try exporter?.finalize() } + // Type-handle registration is shared by exported types and generic imports. + let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) + // Combine and write unified Swift output let outputSwiftURL = outputDirectory.appending(path: "BridgeJS.swift") - let combinedSwift = [closureSupport, exportResult, importResult].compactMap { $0 } + let combinedSwift = [closureSupport, exportResult, importResult, typeRegistration].compactMap { $0 } let outputSwift = combineGeneratedSwift( combinedSwift, importingExternalModules: skeleton.usedExternalModules diff --git a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift index cb6a5481c..971c9608e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift @@ -98,7 +98,8 @@ import ArgumentParser skeleton: $0 ).finalize() } - let combinedSwift = [exported, imported].compactMap { $0 } + let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) + let combinedSwift = [exported, imported, typeRegistration].compactMap { $0 } print(combinedSwift.joined(separator: "\n\n")) } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 60b2fd485..6d2f3d453 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -141,6 +141,9 @@ import Testing swiftParts.append(s) } } + if let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) { + swiftParts.append(typeRegistration) + } let combinedSwift = swiftParts .map { $0.trimmingCharacters(in: .newlines) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 642debedc..23ffb3c6d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -139,6 +139,126 @@ import Testing try snapshot(bridgeJSLink: bridgeJSLink, name: "MixedModules") } + private func linkedJS(forFixture input: String) throws -> String { + let url = Self.inputsDirectory.appendingPathComponent(input) + let name = url.deletingPathExtension().lastPathComponent + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let importSwift = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + importSwift.addSourceFile(sourceFile, inputFilePath: "\(name).swift") + let importResult = try importSwift.finalize() + var bridgeJSLink = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let unifiedData = try encoder.encode(importResult) + try bridgeJSLink.addSkeletonFile(data: unifiedData) + return try bridgeJSLink.link().0 + } + + @Test + func genericRuntimeIsGatedToGenericBuilds() throws { + let genericJS = try linkedJS(forFixture: "GenericImports.swift") + #expect(genericJS.contains("__bjs_codecByTypeId")) + #expect(genericJS.contains("__bjs_primitiveCodecs")) + #expect(genericJS.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(genericJS.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + // Eager registration hook: called by the instantiate.js template right + // after WASI initialization (the lazy guard remains as a fallback). + #expect(genericJS.contains("afterInitialize: () => {")) + + // Modules with @JS types but no generic declarations still emit a Swift + // registration export (their types may be used by a dependent module's + // generic function), so the link layer must install a no-op hook for the + // wasm import — but the generic runtime itself must be omitted. The + // shared codec runtime (combinators + primitive codecs) gates + // independently: it is emitted because the fixture bridges an optional + // struct through the container stack ABI. + let nonGenericJS = try linkedJS(forFixture: "SwiftStructImports.swift") + #expect(!nonGenericJS.contains("__bjs_codecByTypeId")) + #expect(nonGenericJS.contains("__bjs_optionalCodec(structHelpers.Point)")) + #expect(nonGenericJS.contains("__bjs_primitiveCodecs")) + #expect(nonGenericJS.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function() {};")) + #expect(!nonGenericJS.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + // Without the generic runtime the hook is not emitted at all; the + // instantiate template calls it with optional chaining. + #expect(!nonGenericJS.contains("afterInitialize: () => {")) + + // Builds that bridge no containers at all pay nothing for the shared + // codec runtime either. + let containerFreeJS = try linkedJS(forFixture: "PrimitiveParameters.swift") + #expect(!containerFreeJS.contains("__bjs_arrayCodec")) + #expect(!containerFreeJS.contains("__bjs_optionalCodec")) + #expect(!containerFreeJS.contains("__bjs_dictCodec")) + #expect(!containerFreeJS.contains("__bjs_primitiveCodecs")) + #expect(!containerFreeJS.contains("__bjs_stringCodec")) + } + + @Test + func sameTypeNameAcrossModulesLinksWithHandleIdentity() throws { + // Type identity is pointer-based (each type owns a BridgeJSTypeHandle), + // so two modules defining a same-named @JS type must link fine: each + // module registers its own handle IDs against its own codec array. + let structSource = """ + @JS public struct Point { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """ + let first = try makeSkeleton( + structSource + """ + + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + moduleName: "FirstModule" + ) + let second = try makeSkeleton(structSource, moduleName: "SecondModule") + let bridgeJSLink = BridgeJSLink(skeletons: [first, second], sharedMemory: false) + let js = try bridgeJSLink.link().outputJs + #expect(js.contains("bjs[\"bjs_FirstModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("bjs[\"bjs_SecondModule_register_type_handles\"] = function(base, count) {")) + } + + @Test + func moduleWithoutGenericsStillRegistersItsTypeCodecs() throws { + // A module cannot know whether a dependent module will pass its types to + // a generic function, so a module with @JS types but no generic + // declaration of its own still registers a codec for each of them, and + // the linked glue drives every module's registration export. This is + // what lets a type defined in Core be the generic argument of a generic + // import declared in App. + let core = try makeSkeleton( + """ + @JS public struct Vector3D { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """, + moduleName: "Core" + ) + let app = try makeSkeleton( + """ + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + moduleName: "App" + ) + + // Core declares nothing imported at all, yet still registers its types. + #expect(core.imported == nil) + let coreEntries = try #require(core.typeRegistrationEntries) + #expect(coreEntries.contains { $0.swiftName == "Vector3D" }) + + let js = try BridgeJSLink(skeletons: [core, app], sharedMemory: false).link().outputJs + #expect(js.contains("instance.exports[\"bjs_Core_register_type_handles\"]();")) + #expect(js.contains("instance.exports[\"bjs_App_register_type_handles\"]();")) + // `lower(v)` is unique to a codec literal in a registration array; + // `structHelpers.Vector3D` on its own is emitted for every @JS struct. + #expect(js.contains("structHelpers.Vector3D.lower(v);")) + } + @Test func perClassIdentityModeFromAnnotation() throws { let url = Self.inputsDirectory.appendingPathComponent("IdentityModeClass.swift") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift new file mode 100644 index 000000000..b855982b1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift @@ -0,0 +1,51 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSLink +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +func makeSkeleton( + _ source: String, + moduleName: String = "TestModule", + dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)] = [] +) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: moduleName, + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: dependencies) + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "\(moduleName).swift") + return try swiftAPI.finalize() +} + +func expectDiagnostic( + source: String, + moduleName: String = "App", + contains message: String, + sourceLocation: Testing.SourceLocation = #_sourceLocation +) { + do { + _ = try makeSkeleton(source, moduleName: moduleName) + Issue.record("Expected diagnostic but resolution succeeded", sourceLocation: sourceLocation) + } catch let error as BridgeJSCoreDiagnosticError { + let combined = error.diagnostics.map(\.diagnostic.message).joined(separator: "\n") + #expect(combined.contains(message), sourceLocation: sourceLocation) + } catch { + Issue.record("Unexpected error: \(error)", sourceLocation: sourceLocation) + } +} + +func linkSource(_ source: String, moduleName: String = "TestModule") throws -> (js: String, dts: String) { + let skeleton = try makeSkeleton(source, moduleName: moduleName) + var bridgeJSLink = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let unifiedData = try encoder.encode(skeleton) + try bridgeJSLink.addSkeletonFile(data: unifiedData) + let result = try bridgeJSLink.link() + return (result.outputJs, result.outputDts) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift new file mode 100644 index 000000000..d0666f89f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift @@ -0,0 +1,41 @@ +import Testing + +@testable import BridgeJSLink +@testable import BridgeJSSkeleton + +/// The codec a generic call site instantiates for each supported wrapped form +/// of a generic parameter (`T`, `[T]`, `T?`, `[String: T]`). +@Suite struct GenericCodecExpressionTests { + @Test func bareGenericUsesTheElementCodecDirectly() { + #expect(GenericJSCodegen.genericCodecExpression(type: .generic("T"), codec: "c") == "c") + } + + @Test func wrappedGenericsInstantiateTheSharedCombinators() { + #expect( + GenericJSCodegen.genericCodecExpression(type: .array(.generic("T")), codec: "c") + == "__bjs_arrayCodec(c)" + ) + #expect( + GenericJSCodegen.genericCodecExpression(type: .dictionary(.generic("T")), codec: "c") + == "__bjs_dictCodec(c)" + ) + } + + /// The optional combinator carries the null-vs-undefined flavour in its + /// second argument, so the generic path must not drop `JSOptionalKind`. + @Test func optionalGenericPreservesTheOptionalKind() { + #expect( + GenericJSCodegen.genericCodecExpression(type: .nullable(.generic("T"), .null), codec: "c") + == "__bjs_optionalCodec(c)" + ) + #expect( + GenericJSCodegen.genericCodecExpression(type: .nullable(.generic("T"), .undefined), codec: "c") + == "__bjs_optionalCodec(c, true)" + ) + } + + @Test func nonGenericTypesHaveNoGenericCodec() { + #expect(GenericJSCodegen.genericCodecExpression(type: .string, codec: "c") == nil) + #expect(GenericJSCodegen.genericCodecExpression(type: .array(.integer(.int)), codec: "c") == nil) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift new file mode 100644 index 000000000..61e1e8a84 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift @@ -0,0 +1,65 @@ +import Testing + +@testable import BridgeJSCore + +@Suite struct GenericExportDiagnosticsTests { + + @Test + func genericExportedFunctionRejected() { + expectDiagnostic( + source: """ + @JS public func identity(_ value: T) -> T { value } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericMethodOnExportedClassRejected() { + expectDiagnostic( + source: """ + @JS final class Box { + @JS init() {} + @JS func wrap(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericMethodOnExportedStructRejected() { + expectDiagnostic( + source: """ + @JS struct Pair { + @JS init() {} + @JS func first(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericStaticMethodOnExportedEnumRejected() { + expectDiagnostic( + source: """ + @JS enum Factory { + case primary + @JS static func one(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func unconstrainedGenericExportedFunctionRejected() { + expectDiagnostic( + source: """ + @JS public func identity(_ value: T) -> T { value } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift new file mode 100644 index 000000000..fc91eea7d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift @@ -0,0 +1,214 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct GenericImportDiagnosticsTests { + + @Test + func genericParameterRequiresBridgeableConstraint() { + expectDiagnostic( + source: """ + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + contains: "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable'" + ) + } + + @Test + func genericWhereClauseUnsupported() { + expectDiagnostic( + source: """ + @JSFunction func identity(_ value: T) throws(JSException) -> T where T: Sendable + """, + contains: "'where' clauses are not supported on @JSFunction" + ) + } + + @Test + func asyncGenericImportUnsupported() { + expectDiagnostic( + source: """ + @JSFunction func identityAsync(_ value: T) async throws(JSException) -> T + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedMethodIsParsed() throws { + let skeleton = try makeSkeleton( + """ + @JSClass struct Box { + @JSFunction func member(_ value: T) throws(JSException) -> T + } + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let types = imported.children.flatMap { $0.types } + let box = try #require(types.first { $0.name == "Box" }) + let method = try #require(box.methods.first { $0.name == "member" }) + #expect(method.genericParameters == ["T"]) + } + + @Test + func genericImportedConstructorIsParsed() throws { + let skeleton = try makeSkeleton( + """ + @JSClass struct Box { + @JSFunction init(_ value: T) throws(JSException) + } + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let types = imported.children.flatMap { $0.types } + let box = try #require(types.first { $0.name == "Box" }) + let constructor = try #require(box.constructor) + #expect(constructor.genericParameters == ["T"]) + #expect(constructor.parameters.map(\.type) == [.generic("T")]) + } + + @Test + func genericImportedConstructorUnconstrainedParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: T) throws(JSException) + } + """, + contains: + "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + } + + @Test + func genericImportedConstructorUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: Int) throws(JSException) + } + """, + contains: + "The generic parameter 'T' must be used in a parameter of a generic @JSFunction initializer." + ) + } + + @Test + func genericImportedConstructorAsyncIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: T) async throws(JSException) + } + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedConstructorUnsupportedWrapperFormIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: [[T]]) throws(JSException) + } + """, + contains: "may only be used as a bare type" + ) + } + + @Test(arguments: [ + ("[[T]]", "@JSFunction func f(_ v: [[T]]) throws(JSException)"), + ("[T?]", "@JSFunction func f(_ v: [T?]) throws(JSException)"), + ("T??", "@JSFunction func f(_ v: T??) throws(JSException)"), + ("[Int: T]", "@JSFunction func f(_ v: [Int: T]) throws(JSException)"), + ]) + func unsupportedGenericWrapperFormsInParameter(label: String, source: String) { + expectDiagnostic( + source: source, + contains: "may only be used as a bare type" + ) + } + + @Test(arguments: [ + ("[[T]]", "@JSFunction func f(_ v: T) throws(JSException) -> [[T]]"), + ("[T?]", "@JSFunction func f(_ v: T) throws(JSException) -> [T?]"), + ("T??", "@JSFunction func f(_ v: T) throws(JSException) -> T??"), + ("[Int: T]", "@JSFunction func f(_ v: T) throws(JSException) -> [Int: T]"), + ]) + func unsupportedGenericWrapperFormsInReturn(label: String, source: String) { + expectDiagnostic( + source: source, + contains: "may only be used as a bare type" + ) + } + + @Test + func genericImportedMethodAsyncIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member(_ value: T) async throws(JSException) -> T + } + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedMethodUnconstrainedParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member(_ value: T) throws(JSException) -> T + } + """, + contains: + "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + } + + @Test + func genericImportedFunctionUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSFunction func unused() throws(JSException) -> Int + """, + contains: + "The generic parameter 'T' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + } + + @Test + func genericImportedMethodUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member() throws(JSException) -> Int + } + """, + contains: + "The generic parameter 'T' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + } + + @Test + func genericImportedReturnOnlyTypeParamIsAllowed() throws { + let skeleton = try makeSkeleton( + """ + @JSFunction func make() throws(JSException) -> T + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let functions = imported.children.flatMap { $0.functions } + let function = try #require(functions.first { $0.name == "make" }) + #expect(function.genericParameters == ["T"]) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift new file mode 100644 index 000000000..7cb690678 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift @@ -0,0 +1,39 @@ +import Testing + +@Suite struct GenericMethodOnlyModuleCodegenTests { + @Test + func importMethodOnlyEmitsJSRuntimeInfrastructure() throws { + // A module with generic imports but no exported @JS types still needs a + // populated codec table for the primitives, so it registers them itself. + let js = try linkSource( + """ + @JSClass struct OnlyConsumer { + @JSFunction func identity(_ value: T) throws(JSException) -> T + } + """ + ).js + #expect(js.contains("const __bjs_codecByTypeId = new Map();")) + #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) + #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + } + + @Test + func importConstructorOnlyEmitsJSRuntimeInfrastructure() throws { + // A generic initializer alone must switch the generic runtime on: its + // thunk calls __bjs_codecForTypeId, so a module whose only generic + // declaration is an initializer would otherwise emit a call to a + // function that was never defined. + let js = try linkSource( + """ + @JSClass struct OnlyBoxed { + @JSFunction init(_ value: T) throws(JSException) + } + """ + ).js + #expect(js.contains("const __bjs_codecByTypeId = new Map();")) + #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) + #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift new file mode 100644 index 000000000..5fd3d0226 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift @@ -0,0 +1,74 @@ +@JS +struct GenericPoint { + var x: Int + var y: Int +} + +@JS enum GenericColor { + case red + case green +} + +@JS enum GenericMode: String { + case light + case dark +} + +@JS enum GenericTagged { + case number(value: Int) + case text(value: String) +} + +@JS final class GenericImportBox { + @JS var value: Int + @JS init(value: Int) { + self.value = value + } + @JS func get() -> Int { + value + } +} + +@JSFunction func genericRoundTrip(_ value: T) throws(JSException) -> T + +@JSFunction func genericParse(_ json: String) throws(JSException) -> T + +@JSFunction func importGenericCombine( + _ a: T, + _ b: U +) throws(JSException) -> U + +@JSFunction func importGenericCaseDistinct( + _ a: T, + _ b: t +) throws(JSException) -> T + +@JSFunction func importGenericArray(_ values: [T]) throws(JSException) -> [T] + +@JSFunction func importGenericOptional(_ value: T?) throws(JSException) -> T? + +@JSFunction func importGenericDictionary( + _ values: [String: T] +) throws(JSException) -> [String: T] + +// A generic parameter alongside another parameter that pushes onto the shared +// stacks: both are lowered in reverse declaration order. +@JSFunction func importGenericAfterOptionalArray( + _ values: [Int]?, + _ value: T +) throws(JSException) -> T + +@JSClass struct GenericPairFactory { + @JSFunction init( + _ tag: String, + _ first: T, + _ second: U + ) throws(JSException) +} + +@JSClass struct GenericConsumer { + @JSFunction init(_ value: T) throws(JSException) + @JSFunction func accept(_ value: T) throws(JSException) + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) throws(JSException) -> T +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json index bcdc43375..b47afb905 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json @@ -79,6 +79,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PolygonReference_snapshot", @@ -196,6 +197,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift index a9252e57f..7fc853579 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift @@ -257,6 +257,18 @@ fileprivate func _bjs_TagReference_wrap_extern(_ pointer: UnsafeMutableRawPointe return _bjs_TagReference_wrap_extern(pointer) } +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + +extension TagReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagReference.bridgeJSMakeTypeHandle() +} + +extension InnerTag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = InnerTag.bridgeJSMakeTypeHandle() +} + extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} extension Tag: _BridgedSwiftAlias, _BridgedSwiftStackType {} @@ -394,4 +406,36 @@ func _$Surface_label_get(_ self: JSObject) throws(JSException) -> String { throw error } return String.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + TagReference.bridgeJSTypeID, + InnerTag.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json index d76761e0b..c9107133d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json @@ -34,6 +34,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift index 3c87bcdcc..9d9c40502 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift @@ -187,4 +187,38 @@ fileprivate func _bjs_PolygonReference_wrap_extern(_ pointer: UnsafeMutableRawPo return _bjs_PolygonReference_wrap_extern(pointer) } -extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + +extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index 51c6911bd..af2ddb544 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -501,6 +501,18 @@ fileprivate func _bjs_MultiArrayContainer_wrap_extern(_ pointer: UnsafeMutableRa return _bjs_MultiArrayContainer_wrap_extern(pointer) } +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_checkArray") fileprivate func bjs_checkArray_extern(_ a: Int32) -> Void @@ -643,4 +655,36 @@ func _$importProcessBooleans(_ values: [Bool]) throws(JSException) -> [Bool] { throw error } return [Bool].bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index f2223ee7c..bb51829d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -335,6 +335,18 @@ public func _bjs_asyncRoundTripEnumDictionary() -> Int32 { #endif } +extension AsyncPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPoint.bridgeJSMakeTypeHandle() +} + +extension AsyncDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncDirection.bridgeJSMakeTypeHandle() +} + +extension AsyncTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncTheme.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -713,4 +725,36 @@ func _$Promise_resolve_SD14AsyncDirectionO(_ promise: JSObject, _ value: [String let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_SD14AsyncDirectionO(promiseValue) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + AsyncPoint.bridgeJSTypeID, + AsyncDirection.bridgeJSTypeID, + AsyncTheme.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift index 3208eda33..8ea2e5449 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift @@ -52,6 +52,10 @@ public func _bjs_asyncRoundTripOptionalAssociatedValueEnum(_ valueIsSome: Int32, #endif } +extension AsyncPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPayloadResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -113,4 +117,34 @@ func _$Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Opt let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_Sq18AsyncPayloadResultO(promiseValue, valueIsSome, valueCaseId) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + AsyncPayloadResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift index 52c633045..b8736635d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift @@ -174,4 +174,43 @@ fileprivate func _bjs_Account_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Account_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Account_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Account.Credentials: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Account.Credentials.bridgeJSMakeTypeHandle() +} + +extension Account.Role: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Account.Role.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Account.Credentials.bridgeJSTypeID, + Account.Role.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index 507827646..4f343476a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -636,4 +636,48 @@ fileprivate func _bjs_ConstructorDefaults_wrap_extern(_ pointer: UnsafeMutableRa #endif @inline(never) fileprivate func _bjs_ConstructorDefaults_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_ConstructorDefaults_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Config: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Config.bridgeJSMakeTypeHandle() +} + +extension MathOperations: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MathOperations.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Config.bridgeJSTypeID, + MathOperations.bridgeJSTypeID, + Status.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index 26a4c087e..090e93eb0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -149,6 +149,10 @@ fileprivate func _bjs_Box_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int return _bjs_Box_wrap_extern(pointer) } +extension Counters: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Counters.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_importMirrorDictionary") fileprivate func bjs_importMirrorDictionary_extern() -> Void @@ -168,4 +172,34 @@ func _$importMirrorDictionary(_ values: [String: Double]) throws(JSException) -> throw error } return [String: Double].bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Counters.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift index f91df6c26..03dfba96a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift @@ -314,4 +314,43 @@ fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Greeter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension Color: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Color.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + Color.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json index 0d63db899..c876db410 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json @@ -31,6 +31,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift index 1e74a127b..812ece23e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift @@ -51,4 +51,38 @@ fileprivate func _bjs_ColorBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) - return _bjs_ColorBox_wrap_extern(pointer) } -extension Color: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file +extension ColorBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ColorBox.bridgeJSMakeTypeHandle() +} + +extension Color: _BridgedSwiftAlias, _BridgedSwiftStackType {} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + ColorBox.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 6d5549699..875d6f601 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -631,4 +631,88 @@ fileprivate func _bjs_User_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> In #endif @inline(never) fileprivate func _bjs_User_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_User_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + +extension Utilities.Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Utilities.Result.bridgeJSMakeTypeHandle() +} + +extension NetworkingResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NetworkingResult.bridgeJSMakeTypeHandle() +} + +extension APIOptionalResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIOptionalResult.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension CardinalDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CardinalDirection.bridgeJSMakeTypeHandle() +} + +extension TypedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TypedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension AllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AllTypesResult.bridgeJSMakeTypeHandle() +} + +extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + Utilities.Result.bridgeJSTypeID, + NetworkingResult.bridgeJSTypeID, + APIOptionalResult.bridgeJSTypeID, + Precision.bridgeJSTypeID, + CardinalDirection.bridgeJSTypeID, + TypedPayloadResult.bridgeJSTypeID, + AllTypesResult.bridgeJSTypeID, + OptionalAllTypesResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift index 55d1992a3..5e597d6ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift @@ -26,6 +26,10 @@ extension PayloadSignal: _BridgedSwiftAssociatedValueEnum { } } +extension PayloadSignal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PayloadSignal.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_roundTrip_static") fileprivate func bjs_PayloadSignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 @@ -109,4 +113,34 @@ func _$PayloadSignalControls_roundTripOptional(_ self: JSObject, _ signal: Optio throw error } return Optional.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PayloadSignal.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift index 66692ee14..c8ea2699f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift @@ -227,4 +227,53 @@ public func _bjs_roundTripOptionalTSDirection(_ inputIsSome: Int32, _ inputValue #else fatalError("Only available on WebAssembly") #endif -} \ No newline at end of file +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + +extension TSDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSDirection.bridgeJSMakeTypeHandle() +} + +extension PublicStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PublicStatus.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + TSDirection.bridgeJSTypeID, + PublicStatus.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift index f297e1620..9bab304a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -33,6 +33,10 @@ extension Signal: _BridgedSwiftCaseEnum { } } +extension Signal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Signal.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_SignalControls_roundTrip_static") fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 @@ -94,4 +98,34 @@ func _$SignalControls_current(_ self: JSObject) throws(JSException) -> Signal { throw error } return Signal.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Signal.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 4f588f6c7..2801e1788 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -358,4 +358,53 @@ fileprivate func _bjs_Formatting_Converter_wrap_extern(_ pointer: UnsafeMutableR #endif @inline(never) fileprivate func _bjs_Formatting_Converter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Formatting_Converter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 4f588f6c7..2801e1788 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -358,4 +358,53 @@ fileprivate func _bjs_Formatting_Converter_wrap_extern(_ pointer: UnsafeMutableR #endif @inline(never) fileprivate func _bjs_Formatting_Converter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Formatting_Converter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index e70a6b0aa..e91f1b231 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -451,6 +451,54 @@ public func _bjs_validateSession(_ session: Int64) -> Void { #endif } +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension TSTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSTheme.bridgeJSMakeTypeHandle() +} + +extension FeatureFlag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FeatureFlag.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension TSHttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSHttpStatus.bridgeJSMakeTypeHandle() +} + +extension Priority: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Priority.bridgeJSMakeTypeHandle() +} + +extension FileSize: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FileSize.bridgeJSMakeTypeHandle() +} + +extension UserId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UserId.bridgeJSMakeTypeHandle() +} + +extension TokenId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TokenId.bridgeJSMakeTypeHandle() +} + +extension SessionId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionId.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension Ratio: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Ratio.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_takesFeatureFlag") fileprivate func bjs_takesFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Void @@ -490,4 +538,45 @@ func _$returnsFeatureFlag() throws(JSException) -> FeatureFlag { throw error } return FeatureFlag.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Theme.bridgeJSTypeID, + TSTheme.bridgeJSTypeID, + FeatureFlag.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + TSHttpStatus.bridgeJSTypeID, + Priority.bridgeJSTypeID, + FileSize.bridgeJSTypeID, + UserId.bridgeJSTypeID, + TokenId.bridgeJSTypeID, + SessionId.bridgeJSTypeID, + Precision.bridgeJSTypeID, + Ratio.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json new file mode 100644 index 000000000..c7f3e98ae --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json @@ -0,0 +1,669 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_GenericImportBox_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "isFinal" : true, + "methods" : [ + { + "abiName" : "bjs_GenericImportBox_get", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "get", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "GenericImportBox", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericImportBox" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + } + ], + "emitStyle" : "const", + "name" : "GenericColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericColor", + "tsFullPath" : "GenericColor" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light" + }, + { + "associatedValues" : [ + + ], + "name" : "dark" + } + ], + "emitStyle" : "const", + "name" : "GenericMode", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericMode", + "tsFullPath" : "GenericMode" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "label" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "number" + }, + { + "associatedValues" : [ + { + "label" : "value", + "type" : { + "string" : { + + } + } + } + ], + "name" : "text" + } + ], + "emitStyle" : "const", + "name" : "GenericTagged", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericTagged", + "tsFullPath" : "GenericTagged" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + + ], + "name" : "GenericPoint", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericPoint" + } + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "genericRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "genericParse", + "parameters" : [ + { + "name" : "json", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "U" + ], + "name" : "importGenericCombine", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "U" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "t" + ], + "name" : "importGenericCaseDistinct", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "t" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericOptional", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericDictionary", + "parameters" : [ + { + "name" : "values", + "type" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericAfterOptionalArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + }, + "_1" : "null" + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "types" : [ + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T", + "U" + ], + "parameters" : [ + { + "name" : "tag", + "type" : { + "string" : { + + } + } + }, + { + "name" : "first", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "second", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "GenericPairFactory", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T" + ], + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "accept", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "identity", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "GenericConsumer", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "box", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift new file mode 100644 index 000000000..044fd0e57 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift @@ -0,0 +1,520 @@ +extension GenericColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> GenericColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> GenericColor { + return GenericColor(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .red + case 1: + self = .green + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .green: + return 1 + } + } +} + +extension GenericMode: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericTagged: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> GenericTagged { + switch caseId { + case 0: + return .number(value: Int.bridgeJSStackPop()) + case 1: + return .text(value: String.bridgeJSStackPop()) + default: + fatalError("Unknown GenericTagged case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .number(let value): + value.bridgeJSStackPush() + return Int32(0) + case .text(let value): + value.bridgeJSStackPush() + return Int32(1) + } + } +} + +extension GenericPoint: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericPoint { + let y = Int.bridgeJSStackPop() + let x = Int.bridgeJSStackPop() + return GenericPoint(x: x, y: y) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.x.bridgeJSStackPush() + self.y.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericPoint(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericPoint())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericPoint") +fileprivate func _bjs_struct_lower_GenericPoint_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericPoint_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericPoint(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericPoint_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericPoint") +fileprivate func _bjs_struct_lift_GenericPoint_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericPoint_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericPoint() -> Int32 { + return _bjs_struct_lift_GenericPoint_extern() +} + +@_expose(wasm, "bjs_GenericImportBox_init") +@_cdecl("bjs_GenericImportBox_init") +public func _bjs_GenericImportBox_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = GenericImportBox(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_get") +@_cdecl("bjs_GenericImportBox_get") +public func _bjs_GenericImportBox_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = GenericImportBox.bridgeJSLiftParameter(_self).get() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_value_get") +@_cdecl("bjs_GenericImportBox_value_get") +public func _bjs_GenericImportBox_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = GenericImportBox.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_value_set") +@_cdecl("bjs_GenericImportBox_value_set") +public func _bjs_GenericImportBox_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + GenericImportBox.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_deinit") +@_cdecl("bjs_GenericImportBox_deinit") +public func _bjs_GenericImportBox_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension GenericImportBox: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_GenericImportBox_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GenericImportBox_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericImportBox_wrap") +fileprivate func _bjs_GenericImportBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_GenericImportBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_GenericImportBox_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_GenericImportBox_wrap_extern(pointer) +} + +extension GenericPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericPoint.bridgeJSMakeTypeHandle() +} + +extension GenericImportBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericImportBox.bridgeJSMakeTypeHandle() +} + +extension GenericColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericColor.bridgeJSMakeTypeHandle() +} + +extension GenericMode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericMode.bridgeJSMakeTypeHandle() +} + +extension GenericTagged: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericTagged.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_genericRoundTrip") +fileprivate func bjs_genericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_genericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_genericRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_genericRoundTrip_extern(_generic0TypeId) +} + +func _$genericRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_genericRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_genericParse") +fileprivate func bjs_genericParse_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_genericParse_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_genericParse(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_genericParse_extern(jsonBytes, jsonLength, _generic0TypeId) +} + +func _$genericParse(_ json: String) throws(JSException) -> T { + json.bridgeJSWithLoweredParameter { (jsonBytes, jsonLength) in + bjs_genericParse(jsonBytes, jsonLength, T.bridgeJSTypeID) + } + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericCombine") +fileprivate func bjs_importGenericCombine_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericCombine_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericCombine(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_importGenericCombine_extern(_generic0TypeId, _generic1TypeId) +} + +func _$importGenericCombine(_ a: T, _ b: U) throws(JSException) -> U { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_importGenericCombine(T.bridgeJSTypeID, U.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return U.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericCaseDistinct") +fileprivate func bjs_importGenericCaseDistinct_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericCaseDistinct_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericCaseDistinct(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_importGenericCaseDistinct_extern(_generic0TypeId, _generic1TypeId) +} + +func _$importGenericCaseDistinct(_ a: T, _ b: t) throws(JSException) -> T { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_importGenericCaseDistinct(T.bridgeJSTypeID, t.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericArray") +fileprivate func bjs_importGenericArray_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericArray_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericArray(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericArray_extern(_generic0TypeId) +} + +func _$importGenericArray(_ values: [T]) throws(JSException) -> [T] { + let _ = values.bridgeJSLowerParameter() + bjs_importGenericArray(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericOptional") +fileprivate func bjs_importGenericOptional_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericOptional_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericOptional(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericOptional_extern(_generic0TypeId) +} + +func _$importGenericOptional(_ value: Optional) throws(JSException) -> Optional { + value.bridgeJSStackPush() + bjs_importGenericOptional(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericDictionary") +fileprivate func bjs_importGenericDictionary_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericDictionary_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericDictionary(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericDictionary_extern(_generic0TypeId) +} + +func _$importGenericDictionary(_ values: [String: T]) throws(JSException) -> [String: T] { + let _ = values.bridgeJSLowerParameter() + bjs_importGenericDictionary(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [String: T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericAfterOptionalArray") +fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericAfterOptionalArray(_ values: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_importGenericAfterOptionalArray_extern(values, _generic0TypeId) +} + +func _$importGenericAfterOptionalArray(_ values: Optional<[Int]>, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let valuesIsSome = values.bridgeJSLowerParameter() + bjs_importGenericAfterOptionalArray(valuesIsSome, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericPairFactory_init") +fileprivate func bjs_GenericPairFactory_init_extern(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 +#else +fileprivate func bjs_GenericPairFactory_init_extern(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericPairFactory_init(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 { + return bjs_GenericPairFactory_init_extern(tagBytes, tagLength, _generic0TypeId, _generic1TypeId) +} + +func _$GenericPairFactory_init(_ tag: String, _ first: T, _ second: U) throws(JSException) -> JSObject { + let ret0 = tag.bridgeJSWithLoweredParameter { (tagBytes, tagLength) in + second.bridgeJSStackPush() + first.bridgeJSStackPush() + let ret = bjs_GenericPairFactory_init(tagBytes, tagLength, T.bridgeJSTypeID, U.bridgeJSTypeID) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_init") +fileprivate func bjs_GenericConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_GenericConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_init(_ _generic0TypeId: Int32) -> Int32 { + return bjs_GenericConsumer_init_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_box_static") +fileprivate func bjs_GenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_box_static(_ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_box_static_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_accept") +fileprivate func bjs_GenericConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_accept(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_accept_extern(self, _generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_identity") +fileprivate func bjs_GenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_identity(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_identity_extern(self, _generic0TypeId) +} + +func _$GenericConsumer_init(_ value: T) throws(JSException) -> JSObject { + value.bridgeJSStackPush() + let ret = bjs_GenericConsumer_init(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$GenericConsumer_box(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_GenericConsumer_box_static(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +func _$GenericConsumer_accept(_ self: JSObject, _ value: T) throws(JSException) -> Void { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_GenericConsumer_accept(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$GenericConsumer_identity(_ self: JSObject, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_GenericConsumer_identity(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + GenericPoint.bridgeJSTypeID, + GenericImportBox.bridgeJSTypeID, + GenericColor.bridgeJSTypeID, + GenericMode.bridgeJSTypeID, + GenericTagged.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index 62f9a3b68..dfec6b6a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -104,6 +104,10 @@ public func _bjs_roundtripFooContainer() -> Void { #endif } +extension FooContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FooContainer.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Foo_init") fileprivate func bjs_Foo_init_extern() -> Int32 @@ -122,4 +126,34 @@ func _$Foo_init() throws(JSException) -> JSObject { throw error } return JSObject.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + FooContainer.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift index ed1a080e9..ca1c98a75 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -176,4 +176,43 @@ fileprivate func _bjs_Player_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Player_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Player_wrap_extern(pointer) -} \ No newline at end of file +} + +extension User.Stats: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = User.Stats.bridgeJSMakeTypeHandle() +} + +extension Player.Stats: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Player.Stats.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + User.Stats.bridgeJSTypeID, + Player.Stats.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index cfda92ac0..2ef680b8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1043,4 +1043,53 @@ fileprivate func _bjs_DelegateManager_wrap_extern(_ pointer: UnsafeMutableRawPoi #endif @inline(never) fileprivate func _bjs_DelegateManager_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_DelegateManager_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension ExampleEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ExampleEnum.bridgeJSMakeTypeHandle() +} + +extension Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Result.bridgeJSMakeTypeHandle() +} + +extension Priority: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Priority.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Direction.bridgeJSTypeID, + ExampleEnum.bridgeJSTypeID, + Result.bridgeJSTypeID, + Priority.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 896258915..18e91616c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -207,4 +207,43 @@ fileprivate func _bjs_MathUtils_wrap_extern(_ pointer: UnsafeMutableRawPointer) #endif @inline(never) fileprivate func _bjs_MathUtils_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_MathUtils_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Calculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Calculator.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Calculator.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 896258915..18e91616c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -207,4 +207,43 @@ fileprivate func _bjs_MathUtils_wrap_extern(_ pointer: UnsafeMutableRawPointer) #endif @inline(never) fileprivate func _bjs_MathUtils_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_MathUtils_wrap_extern(pointer) -} \ No newline at end of file +} + +extension Calculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Calculator.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Calculator.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index ded55dbd4..75c4382dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -338,4 +338,38 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint #endif @inline(never) fileprivate func _bjs_PropertyClass_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_PropertyClass_wrap_extern(pointer) -} \ No newline at end of file +} + +extension PropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PropertyEnum.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index ded55dbd4..75c4382dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -338,4 +338,38 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint #endif @inline(never) fileprivate func _bjs_PropertyClass_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_PropertyClass_wrap_extern(pointer) -} \ No newline at end of file +} + +extension PropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PropertyEnum.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift index ad99f0a03..1b8a69739 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift @@ -246,4 +246,68 @@ public func _bjs_Widget_Bounds_static_zero() -> Void { #else fatalError("Only available on WebAssembly") #endif -} \ No newline at end of file +} + +extension Shape: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.bridgeJSMakeTypeHandle() +} + +extension Widget: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.bridgeJSMakeTypeHandle() +} + +extension Widget.Layout: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Layout.bridgeJSMakeTypeHandle() +} + +extension Widget.Bounds: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Bounds.bridgeJSMakeTypeHandle() +} + +extension Shape.Kind: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.Kind.bridgeJSMakeTypeHandle() +} + +extension Widget.Variant: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Variant.bridgeJSMakeTypeHandle() +} + +extension Widget.Layout.Alignment: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Layout.Alignment.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Shape.bridgeJSTypeID, + Widget.bridgeJSTypeID, + Widget.Layout.bridgeJSTypeID, + Widget.Bounds.bridgeJSTypeID, + Shape.Kind.bridgeJSTypeID, + Widget.Variant.bridgeJSTypeID, + Widget.Layout.Alignment.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index c7ac02fb1..bad3ba0e1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -2637,6 +2637,26 @@ fileprivate func _bjs_TestProcessor_wrap_extern(_ pointer: UnsafeMutableRawPoint return _bjs_TestProcessor_wrap_extern(pointer) } +extension Animal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Animal.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -2720,4 +2740,38 @@ func _$Promise_resolve_9APIResultO(_ promise: JSObject, _ value: APIResult) thro let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_9APIResultO(promiseValue, valueCaseId) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Animal.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Theme.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index f98038b45..7aca6afd5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -630,4 +630,78 @@ fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Greeter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension DataPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = DataPoint.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Person: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Person.bridgeJSMakeTypeHandle() +} + +extension Session: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Session.bridgeJSMakeTypeHandle() +} + +extension Measurement: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Measurement.bridgeJSMakeTypeHandle() +} + +extension ConfigStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ConfigStruct.bridgeJSMakeTypeHandle() +} + +extension Container: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Container.bridgeJSMakeTypeHandle() +} + +extension Vector2D: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Vector2D.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + DataPoint.bridgeJSTypeID, + Address.bridgeJSTypeID, + Person.bridgeJSTypeID, + Session.bridgeJSTypeID, + Measurement.bridgeJSTypeID, + ConfigStruct.bridgeJSTypeID, + Container.bridgeJSTypeID, + Vector2D.bridgeJSTypeID, + Precision.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index 38ec94c0d..a5c5d9fd8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -46,6 +46,10 @@ fileprivate func _bjs_struct_lift_Point_extern() -> Int32 { return _bjs_struct_lift_Point_extern() } +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_translate") fileprivate func bjs_translate_extern(_ dx: Int32, _ dy: Int32) -> Void @@ -88,4 +92,34 @@ func _$roundTripOptional(_ point: Optional) throws(JSException) -> Option throw error } return Optional.bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift index b97729084..615608687 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift @@ -177,4 +177,38 @@ public func _bjs_roundTripPointerFields() -> Void { #else fatalError("Only available on WebAssembly") #endif -} \ No newline at end of file +} + +extension PointerFields: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PointerFields.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PointerFields.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts index e3092afb3..9815b6514 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts @@ -67,5 +67,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index 92fb5a109..d8a23090a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -37,6 +37,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createInnerTagValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -139,6 +449,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -284,12 +595,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_produceOptionalCanvas"] = function bjs_produceOptionalCanvas() { try { let ret = imports.produceOptionalCanvas(); - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -440,24 +758,29 @@ export async function createInstantiator(options, swift) { return optResult; }, polygonArray: function bjs_polygonArray(polygons) { - for (const elem of polygons) { - ptrStack.push(elem.pointer); - } - i32Stack.push(polygons.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = PolygonReference.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(polygons); instance.exports.bjs_polygonArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = PolygonReference.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, validatePolygon: function bjs_validatePolygon(polygon) { @@ -477,35 +800,9 @@ export async function createInstantiator(options, swift) { return TagReference.__construct(ret); }, roundtripTags: function bjs_roundtripTags(xs) { - for (const elem of xs) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const caseId = enumHelpers.InnerTag.lower(elem); - i32Stack.push(caseId); - } - i32Stack.push(isSome); - } - i32Stack.push(xs.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lower(xs); instance.exports.bjs_roundtripTags(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const enumValue = enumHelpers.InnerTag.lift(i32Stack.pop()); - optValue = enumValue; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lift(); return arrayResult; }, describeUser: function bjs_describeUser(owner) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts index 73ea3b570..4d2bab311 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts @@ -27,5 +27,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js index a38fa118e..cb130421b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts index f48189956..529b16095 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts @@ -91,5 +91,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 419cf15d5..39c0507c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -44,6 +44,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -138,6 +448,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -264,18 +575,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_importProcessNumbers"] = function bjs_importProcessNumbers() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); imports.importProcessNumbers(arrayResult); } catch (error) { setException(error); @@ -284,82 +584,34 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importGetNumbers"] = function bjs_importGetNumbers() { try { let ret = imports.importGetNumbers(); - for (const elem of ret) { - f64Stack.push(elem); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importTransformNumbers"] = function bjs_importTransformNumbers() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); let ret = imports.importTransformNumbers(arrayResult); - for (const elem of ret) { - f64Stack.push(elem); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessStrings"] = function bjs_importProcessStrings() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); let ret = imports.importProcessStrings(arrayResult); - for (const elem of ret) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessBooleans"] = function bjs_importProcessBooleans() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); let ret = imports.importProcessBooleans(arrayResult); - for (const elem of ret) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(ret); } catch (error) { setException(error); } @@ -442,50 +694,19 @@ export async function createInstantiator(options, swift) { } constructor(nums, strs) { - for (const elem of nums) { - i32Stack.push((elem | 0)); - } - i32Stack.push(nums.length); - for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(strs.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); + __bjs_arrayCodec(__bjs_stringCodec).lower(strs); const ret = instance.exports.bjs_MultiArrayContainer_init(); return MultiArrayContainer.__construct(ret); } get numbers() { instance.exports.bjs_MultiArrayContainer_numbers_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; } get strings() { instance.exports.bjs_MultiArrayContainer_strings_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; } } @@ -494,161 +715,90 @@ export async function createInstantiator(options, swift) { const exports = { processIntArray: function bjs_processIntArray(values) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_processIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, processStringArray: function bjs_processStringArray(values) { - for (const elem of values) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(values); instance.exports.bjs_processStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; }, processDoubleArray: function bjs_processDoubleArray(values) { - for (const elem of values) { - f64Stack.push(elem); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); instance.exports.bjs_processDoubleArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); return arrayResult; }, processBoolArray: function bjs_processBoolArray(values) { - for (const elem of values) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(values); instance.exports.bjs_processBoolArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); return arrayResult; }, processPointArray: function bjs_processPointArray(points) { - for (const elem of points) { - structHelpers.Point.lower(elem); - } - i32Stack.push(points.length); + __bjs_arrayCodec(structHelpers.Point).lower(points); instance.exports.bjs_processPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const struct = structHelpers.Point.lift(); - arrayResult.push(struct); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(structHelpers.Point).lift(); return arrayResult; }, processDirectionArray: function bjs_processDirectionArray(directions) { - for (const elem of directions) { - i32Stack.push((elem | 0)); - } - i32Stack.push(directions.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(elemCodec).lower(directions); instance.exports.bjs_processDirectionArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const caseId = i32Stack.pop(); - arrayResult.push(caseId); - } - arrayResult.reverse(); - } + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processStatusArray: function bjs_processStatusArray(statuses) { - for (const elem of statuses) { - i32Stack.push((elem | 0)); - } - i32Stack.push(statuses.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + __bjs_arrayCodec(elemCodec).lower(statuses); instance.exports.bjs_processStatusArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const rawValue = i32Stack.pop(); - arrayResult.push(rawValue); - } - arrayResult.reverse(); - } + return rawValue; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, sumIntArray: function bjs_sumIntArray(values) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); const ret = instance.exports.bjs_sumIntArray(); return ret; }, findFirstPoint: function bjs_findFirstPoint(points, matching) { - for (const elem of points) { - structHelpers.Point.lower(elem); - } - i32Stack.push(points.length); + __bjs_arrayCodec(structHelpers.Point).lower(points); const matchingBytes = textEncoder.encode(matching); const matchingId = swift.memory.retain(matchingBytes); instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length); @@ -656,544 +806,318 @@ export async function createInstantiator(options, swift) { return structValue; }, processUnsafeRawPointerArray: function bjs_processUnsafeRawPointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processUnsafeRawPointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processUnsafeMutableRawPointerArray: function bjs_processUnsafeMutableRawPointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processUnsafeMutableRawPointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOpaquePointerArray: function bjs_processOpaquePointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processOpaquePointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalIntArray: function bjs_processOptionalIntArray(values) { - for (const elem of values) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processOptionalIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); return arrayResult; }, processOptionalStringArray: function bjs_processOptionalStringArray(values) { - for (const elem of values) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_processOptionalStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lift(); return arrayResult; }, processOptionalArray: function bjs_processOptionalArray(values) { - const isSome = values != null; - if (isSome) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processOptionalArray(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - optResult = arrayResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + return optValue; }, processOptionalPointArray: function bjs_processOptionalPointArray(points) { - for (const elem of points) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - structHelpers.Point.lower(elem); - } - i32Stack.push(isSome); - } - i32Stack.push(points.length); + __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lower(points); instance.exports.bjs_processOptionalPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const struct = structHelpers.Point.lift(); - optValue = struct; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lift(); return arrayResult; }, processOptionalDirectionArray: function bjs_processOptionalDirectionArray(directions) { - for (const elem of directions) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(directions.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(directions); instance.exports.bjs_processOptionalDirectionArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const caseId = i32Stack.pop(); - optValue = caseId; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processOptionalStatusArray: function bjs_processOptionalStatusArray(statuses) { - for (const elem of statuses) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(statuses.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(statuses); instance.exports.bjs_processOptionalStatusArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const rawValue = i32Stack.pop(); - optValue = rawValue; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processNestedIntArray: function bjs_processNestedIntArray(values) { - for (const elem of values) { - for (const elem1 of elem) { - i32Stack.push((elem1 | 0)); - } - i32Stack.push(elem.length); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processNestedIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int = i32Stack.pop(); - arrayResult1.push(int); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return arrayResult; }, processNestedStringArray: function bjs_processNestedStringArray(values) { - for (const elem of values) { - for (const elem1 of elem) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(elem.length); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_processNestedStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const string = strStack.pop(); - arrayResult1.push(string); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lift(); return arrayResult; }, processNestedPointArray: function bjs_processNestedPointArray(points) { - for (const elem of points) { - for (const elem1 of elem) { - structHelpers.Point.lower(elem1); - } - i32Stack.push(elem.length); - } - i32Stack.push(points.length); + __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lower(points); instance.exports.bjs_processNestedPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const struct = structHelpers.Point.lift(); - arrayResult1.push(struct); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lift(); return arrayResult; }, processItemArray: function bjs_processItemArray(items) { - for (const elem of items) { - ptrStack.push(elem.pointer); - } - i32Stack.push(items.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(items); instance.exports.bjs_processItemArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Item.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processNestedItemArray: function bjs_processNestedItemArray(items) { - for (const elem of items) { - for (const elem1 of elem) { - ptrStack.push(elem1.pointer); - } - i32Stack.push(elem.length); - } - i32Stack.push(items.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(items); instance.exports.bjs_processNestedItemArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - arrayResult1.push(obj); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); return arrayResult; }, processJSObjectArray: function bjs_processJSObjectArray(objects) { - for (const elem of objects) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(objects.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(objects); instance.exports.bjs_processJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalJSObjectArray: function bjs_processOptionalJSObjectArray(objects) { - for (const elem of objects) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(elem); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(isSome); - } - i32Stack.push(objects.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(objects); instance.exports.bjs_processOptionalJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - optValue = obj; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processNestedJSObjectArray: function bjs_processNestedJSObjectArray(objects) { - for (const elem of objects) { - for (const elem1 of elem) { - const objId = swift.memory.retain(elem1); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(elem.length); - } - i32Stack.push(objects.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(objects); instance.exports.bjs_processNestedJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult1.push(obj); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); return arrayResult; }, multiArrayParams: function bjs_multiArrayParams(nums, strs) { - for (const elem of nums) { - i32Stack.push((elem | 0)); - } - i32Stack.push(nums.length); - for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(strs.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); + __bjs_arrayCodec(__bjs_stringCodec).lower(strs); const ret = instance.exports.bjs_multiArrayParams(); return ret; }, multiOptionalArrayParams: function bjs_multiOptionalArrayParams(a, b) { - const isSome = a != null; - if (isSome) { - for (const elem of a) { - i32Stack.push((elem | 0)); - } - i32Stack.push(a.length); - } - i32Stack.push(+isSome); - const isSome1 = b != null; - if (isSome1) { - for (const elem1 of b) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(b.length); - } - i32Stack.push(+isSome1); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(a); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(b); const ret = instance.exports.bjs_multiOptionalArrayParams(); return ret; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts index 507a96d4a..fefbf0039 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts @@ -55,5 +55,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 9f2faf589..497c71bf8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -41,6 +41,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -223,6 +444,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.AsyncPoint.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -340,18 +562,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa10AsyncPointV"] = function(promise) { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const struct = structHelpers.AsyncPoint.lift(); - arrayResult.push(struct); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(structHelpers.AsyncPoint).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -359,18 +570,16 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa14AsyncDirectionO"] = function(promise) { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const caseId = i32Stack.pop(); - arrayResult.push(caseId); - } - arrayResult.reverse(); - } + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -378,13 +587,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD10AsyncPointV"] = function(promise) { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const struct = structHelpers.AsyncPoint.lift(); - const string = strStack.pop(); - dictResult[string] = struct; - } + const dictResult = __bjs_dictCodec(structHelpers.AsyncPoint).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -392,13 +595,16 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD14AsyncDirectionO"] = function(promise) { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const caseId = i32Stack.pop(); - const string = strStack.pop(); - dictResult[string] = caseId; - } + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -643,63 +849,53 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncRoundTripOptionalStruct: function bjs_asyncRoundTripOptionalStruct(v) { - const isSome = v != null; - if (isSome) { - structHelpers.AsyncPoint.lower(v); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripOptionalStruct(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructArray: function bjs_asyncRoundTripStructArray(v) { - for (const elem of v) { - structHelpers.AsyncPoint.lower(elem); - } - i32Stack.push(v.length); + __bjs_arrayCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripStructArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumArray: function bjs_asyncRoundTripEnumArray(v) { - for (const elem of v) { - i32Stack.push((elem | 0)); - } - i32Stack.push(v.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(elemCodec).lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructDictionary: function bjs_asyncRoundTripStructDictionary(v) { - const entries = Object.entries(v); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - structHelpers.AsyncPoint.lower(value); - } - i32Stack.push(entries.length); + __bjs_dictCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripStructDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumDictionary: function bjs_asyncRoundTripEnumDictionary(v) { - const entries = Object.entries(v); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value | 0)); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_dictCodec(elemCodec).lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts index d25336ef7..c0c8900d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js index 98c0aff46..8e09e38d9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js @@ -239,6 +239,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts index e612ae1e1..f1bf7e0c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts index 491a66795..97a9c23ad 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts index 5537696c4..a2bd7b41b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts @@ -47,5 +47,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js index 272bb8c49..db3288037 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Account_Credentials.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts index 961b9fa5b..7cec6e66b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts @@ -161,5 +161,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index ba2b7cc77..16505d112 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -37,6 +37,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createConfigHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); @@ -162,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.MathOperations.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -535,137 +846,51 @@ export async function createInstantiator(options, swift) { return EmptyGreeter.__construct(ret); }, testOptionalStructDefault: function bjs_testOptionalStructDefault(point = null) { - const isSome = point != null; - if (isSome) { - structHelpers.Config.lower(point); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Config).lower(point); instance.exports.bjs_testOptionalStructDefault(); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Config.lift() : null; - return optResult; + const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + return optValue; }, testOptionalStructWithValueDefault: function bjs_testOptionalStructWithValueDefault(point = { name: "default", value: 42, enabled: true }) { - const isSome = point != null; - if (isSome) { - structHelpers.Config.lower(point); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Config).lower(point); instance.exports.bjs_testOptionalStructWithValueDefault(); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Config.lift() : null; - return optResult; + const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + return optValue; }, testIntArrayDefault: function bjs_testIntArrayDefault(values = [1, 2, 3]) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_testIntArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, testStringArrayDefault: function bjs_testStringArrayDefault(names = ["a", "b", "c"]) { - for (const elem of names) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(names.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(names); instance.exports.bjs_testStringArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; }, testDoubleArrayDefault: function bjs_testDoubleArrayDefault(values = [1.5, 2.5, 3.5]) { - for (const elem of values) { - f64Stack.push(elem); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); instance.exports.bjs_testDoubleArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); return arrayResult; }, testBoolArrayDefault: function bjs_testBoolArrayDefault(flags = [true, false, true]) { - for (const elem of flags) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(flags.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(flags); instance.exports.bjs_testBoolArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); return arrayResult; }, testEmptyArrayDefault: function bjs_testEmptyArrayDefault(items = []) { - for (const elem of items) { - i32Stack.push((elem | 0)); - } - i32Stack.push(items.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(items); instance.exports.bjs_testEmptyArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, testMixedWithArrayDefault: function bjs_testMixedWithArrayDefault(name = "test", values = [10, 20, 30], enabled = true) { const nameBytes = textEncoder.encode(name); const nameId = swift.memory.retain(nameBytes); - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_testMixedWithArrayDefault(nameId, nameBytes.length, enabled); const ret = tmpRetString; tmpRetString = undefined; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts index 652177cd8..2479e3f25 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts @@ -35,5 +35,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index d0ac5307f..78e1d4c54 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -31,44 +31,328 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createCountersHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - const entries = Object.entries(value.counts); - for (const entry of entries) { - const [key, value] = entry; - const bytes1 = textEncoder.encode(key); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - const isSome = value != null ? 1 : 0; - if (isSome) { - i32Stack.push((value | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(value.counts); }, lift: () => { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } - const string = strStack.pop(); - dictResult[string] = optValue; - } - const string1 = strStack.pop(); - return { name: string1, counts: dictResult }; + const dictResult = __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); + const string = strStack.pop(); + return { name: string, counts: dictResult }; } }); @@ -154,6 +438,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Counters.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -262,24 +547,9 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_importMirrorDictionary"] = function bjs_importMirrorDictionary() { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const f64 = f64Stack.pop(); - const string = strStack.pop(); - dictResult[string] = f64; - } + const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Double).lift(); let ret = imports.importMirrorDictionary(dictResult); - const entries = Object.entries(ret); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - f64Stack.push(value); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } @@ -361,149 +631,73 @@ export async function createInstantiator(options, swift) { const exports = { mirrorDictionary: function bjs_mirrorDictionary(values) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value | 0)); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_mirrorDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const int = i32Stack.pop(); - const string = strStack.pop(); - dictResult[string] = int; - } + const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Int).lift(); return dictResult; }, optionalDictionary: function bjs_optionalDictionary(values) { - const isSome = values != null; - if (isSome) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const bytes1 = textEncoder.encode(value); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - } - i32Stack.push(entries.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_optionalDictionary(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const string = strStack.pop(); - const string1 = strStack.pop(); - dictResult[string1] = string; - } - optResult = dictResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lift(); + return optValue; }, nestedDictionary: function bjs_nestedDictionary(values) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - for (const elem of value) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.length); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_nestedDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i1 = 0; i1 < arrayLen; i1++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - const string = strStack.pop(); - dictResult[string] = arrayResult; - } + const dictResult = __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return dictResult; }, boxDictionary: function bjs_boxDictionary(boxes) { - const entries = Object.entries(boxes); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - ptrStack.push(value.pointer); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(boxes); instance.exports.bjs_boxDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec1).lift(); return dictResult; }, optionalBoxDictionary: function bjs_optionalBoxDictionary(boxes) { - const entries = Object.entries(boxes); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const isSome = value != null ? 1 : 0; - if (isSome) { - ptrStack.push(value.pointer); - } - i32Stack.push(isSome); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + __bjs_dictCodec(__bjs_optionalCodec(elemCodec)).lower(boxes); instance.exports.bjs_optionalBoxDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Box.__construct(ptr); - optValue = obj; - } - const string = strStack.pop(); - dictResult[string] = optValue; - } + return obj; + }, + }; + const dictResult = __bjs_dictCodec(__bjs_optionalCodec(elemCodec1)).lift(); return dictResult; }, roundtripCounters: function bjs_roundtripCounters(counters) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts index 196ef73fe..f37d8945d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts @@ -136,5 +136,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js index f29814675..53cd64917 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts index d2772fa8b..4921cd937 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts @@ -26,5 +26,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js index 42f3fd958..43ff590b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts index 36fc92474..9e6d967ff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts @@ -195,5 +195,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 36683fd58..814736050 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -112,6 +112,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -382,48 +692,18 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIOptionalResultValues.Tag.Success: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.param0); return APIOptionalResultValues.Tag.Success; } case APIOptionalResultValues.Tag.Failure: { - const isSome = value.param1 != null ? 1 : 0; - if (isSome) { - i32Stack.push(value.param1 ? 1 : 0); - } - i32Stack.push(isSome); - const isSome1 = value.param0 != null ? 1 : 0; - if (isSome1) { - i32Stack.push((value.param0 | 0)); - } - i32Stack.push(isSome1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param0); return APIOptionalResultValues.Tag.Failure; } case APIOptionalResultValues.Tag.Status: { - const isSome = value.param2 != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); - const isSome1 = value.param1 != null ? 1 : 0; - if (isSome1) { - i32Stack.push((value.param1 | 0)); - } - i32Stack.push(isSome1); - const isSome2 = value.param0 != null ? 1 : 0; - if (isSome2) { - i32Stack.push(value.param0 ? 1 : 0); - } - i32Stack.push(isSome2); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.param2); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param0); return APIOptionalResultValues.Tag.Status; } default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); @@ -433,60 +713,18 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case APIOptionalResultValues.Tag.Success: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); return { tag: APIOptionalResultValues.Tag.Success, param0: optValue }; } case APIOptionalResultValues.Tag.Failure: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue = bool; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); return { tag: APIOptionalResultValues.Tag.Failure, param0: optValue1, param1: optValue }; } case APIOptionalResultValues.Tag.Status: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } - const isSome2 = i32Stack.pop(); - let optValue2; - if (isSome2 === 0) { - optValue2 = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue2 = bool; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); + const optValue2 = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); return { tag: APIOptionalResultValues.Tag.Status, param0: optValue2, param1: optValue1, param2: optValue }; } default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); @@ -506,19 +744,29 @@ export async function createInstantiator(options, swift) { return TypedPayloadResultValues.Tag.Direction; } case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - f32Stack.push(Math.fround(value.param0)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return TypedPayloadResultValues.Tag.OptPrecision; } case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.param0 | 0)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return TypedPayloadResultValues.Tag.OptDirection; } case TypedPayloadResultValues.Tag.Empty: { @@ -539,25 +787,29 @@ export async function createInstantiator(options, swift) { return { tag: TypedPayloadResultValues.Tag.Direction, param0: caseId }; } case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const rawValue = f32Stack.pop(); - optValue = rawValue; - } + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optValue }; } case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const caseId = i32Stack.pop(); - optValue = caseId; - } + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optValue }; } case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; @@ -588,10 +840,7 @@ export async function createInstantiator(options, swift) { return AllTypesResultValues.Tag.NestedEnum; } case AllTypesResultValues.Tag.ArrayPayload: { - for (const elem of value.param0) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.param0.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(value.param0); return AllTypesResultValues.Tag.ArrayPayload; } case AllTypesResultValues.Tag.Empty: { @@ -623,18 +872,7 @@ export async function createInstantiator(options, swift) { return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; } case AllTypesResultValues.Tag.ArrayPayload: { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; } case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; @@ -647,48 +885,45 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - structHelpers.Point.lower(value.param0); - } - i32Stack.push(isSome); + __bjs_optionalCodec(structHelpers.Point).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptStruct; } case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - ptrStack.push(value.param0.pointer); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptClass; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.param0); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptJSObject; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const caseId = enumHelpers.APIResult.lower(value.param0); - i32Stack.push(caseId); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptNestedEnum; } case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - for (const elem of value.param0) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.param0.length); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptArray; } case OptionalAllTypesResultValues.Tag.Empty: { @@ -701,72 +936,45 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const struct = structHelpers.Point.lift(); - optValue = struct; - } + const optValue = __bjs_optionalCodec(structHelpers.Point).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const ptr = ptrStack.pop(); - const obj = _exports['User'].__construct(ptr); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); - optValue = enumValue; - } + const optValue = __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - optValue = arrayResult; - } + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optValue }; } case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; @@ -856,6 +1064,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts index d29256af4..c980b7dbf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts @@ -35,5 +35,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js index de374bd70..a31c96450 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts index 5581df31e..8ea0aa79b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts @@ -56,5 +56,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index c2ae031bb..169ade160 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts index fe48c9174..03e210f3c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js index f2d6b8750..fa128130a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts index 0ca8b16b9..403ef2149 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts @@ -154,5 +154,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 6c45f0333..859703175 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts index b5a85a082..f5d357a64 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts @@ -115,5 +115,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 2a9e7948a..81c1eacd9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts index fbd5ad637..e43673e7a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts @@ -169,5 +169,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 9e18a8d80..ac8dc0ff5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -106,6 +106,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -182,6 +492,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -448,15 +759,17 @@ export async function createInstantiator(options, swift) { roundTripOptionalFileSize: function bjs_roundTripOptionalFileSize(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0n); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const rawValue = i64Stack.pop(); - optResult = rawValue; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, setUserId: function bjs_setUserId(id) { instance.exports.bjs_setUserId(id); @@ -496,15 +809,17 @@ export async function createInstantiator(options, swift) { roundTripOptionalSessionId: function bjs_roundTripOptionalSessionId(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0n); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const rawValue = i64Stack.pop(); - optResult = rawValue; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, setPrecision: function bjs_setPrecision(precision) { instance.exports.bjs_setPrecision(precision); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts index d6ab5aa8f..3eea52594 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts new file mode 100644 index 000000000..fc8b4b868 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts @@ -0,0 +1,88 @@ +// 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 GenericColorValues: { + readonly Red: 0; + readonly Green: 1; +}; +export type GenericColorTag = typeof GenericColorValues[keyof typeof GenericColorValues]; + +export const GenericModeValues: { + readonly Light: "light"; + readonly Dark: "dark"; +}; +export type GenericModeTag = typeof GenericModeValues[keyof typeof GenericModeValues]; + +export const GenericTaggedValues: { + readonly Tag: { + readonly Number: 0; + readonly Text: 1; + }; +}; + +export type GenericTaggedTag = + { tag: typeof GenericTaggedValues.Tag.Number; value: number } | { tag: typeof GenericTaggedValues.Tag.Text; value: string } + +export interface GenericPoint { + x: number; + y: number; +} +export type GenericColorObject = typeof GenericColorValues; + +export type GenericModeObject = typeof GenericModeValues; + +export type GenericTaggedObject = typeof GenericTaggedValues; + +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface GenericImportBox extends SwiftHeapObject { + get(): number; + value: number; +} +export interface GenericPairFactory { +} +export interface GenericConsumer { + accept(value: T): void; + identity(value: T): T; +} +export type Exports = { + GenericColor: GenericColorObject + GenericMode: GenericModeObject + GenericTagged: GenericTaggedObject + GenericImportBox: { + new(value: number): GenericImportBox; + }, +} +export type Imports = { + genericRoundTrip(value: T): T; + genericParse(json: string): T; + importGenericCombine(a: T, b: U): U; + importGenericCaseDistinct(a: T, b: t): T; + importGenericArray(values: T[]): T[]; + importGenericOptional(value: T | null): T | null; + importGenericDictionary(values: Record): Record; + importGenericAfterOptionalArray(values: number[] | null, value: T): T; + GenericPairFactory: { + new(tag: string, first: T, second: U): GenericPairFactory; + } + GenericConsumer: { + new(value: T): GenericConsumer; + box(value: T): T; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js new file mode 100644 index 000000000..3ac1ea77e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -0,0 +1,936 @@ +// 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 GenericColorValues = { + Red: 0, + Green: 1, +}; + +export const GenericModeValues = { + Light: "light", + Dark: "dark", +}; + +export const GenericTaggedValues = { + Tag: { + Number: 0, + Text: 1, + }, +}; +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + const __bjs_codecByTypeId = new Map(); + let __bjs_typeHandlesRegistered = false; + function __bjs_registerTypeHandles() { + if (__bjs_typeHandlesRegistered) { + return; + } + __bjs_typeHandlesRegistered = true; + instance.exports["bjs_TestModule_register_type_handles"](); + } + function __bjs_codecForTypeId(typeId) { + __bjs_registerTypeHandles(); + const codec = __bjs_codecByTypeId.get(typeId); + if (!codec) { + throw new Error("BridgeJS: no codec registered for type ID " + typeId); + } + return codec; + } + + let _exports = null; + let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + + const __bjs_createGenericPointHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.x | 0)); + i32Stack.push((value.y | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + const int1 = i32Stack.pop(); + return { x: int1, y: int }; + } + }); + const __bjs_createGenericTaggedValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case GenericTaggedValues.Tag.Number: { + i32Stack.push((value.value | 0)); + return GenericTaggedValues.Tag.Number; + } + case GenericTaggedValues.Tag.Text: { + const bytes = textEncoder.encode(value.value); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return GenericTaggedValues.Tag.Text; + } + default: throw new Error("Unknown GenericTaggedValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case GenericTaggedValues.Tag.Number: { + const int = i32Stack.pop(); + return { tag: GenericTaggedValues.Tag.Number, value: int }; + } + case GenericTaggedValues.Tag.Text: { + const string = strStack.pop(); + return { tag: GenericTaggedValues.Tag.Text, value: string }; + } + default: throw new Error("Unknown GenericTaggedValues tag returned from Swift: " + String(tag)); + } + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + const imports = options.getImports(importsContext); + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 0); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + bjs["swift_js_push_typed_array"] = function(kind, ptr, count) { + const Ctor = taCtors[kind]; + const byteLen = count * Ctor.BYTES_PER_ELEMENT; + const copy = memory.buffer.slice(ptr, ptr + byteLen); + taStack.push(Array.from(new Ctor(copy))); + } + bjs["swift_js_struct_lower_GenericPoint"] = function(objectId) { + structHelpers.GenericPoint.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_GenericPoint"] = function() { + const value = structHelpers.GenericPoint.lift(); + return swift.memory.retain(value); + } + bjs["bjs_TestModule_register_type_handles"] = function(base, count) { + const codecs = [ + __bjs_primitiveCodecs.Bool, + __bjs_primitiveCodecs.Int, + __bjs_primitiveCodecs.Int8, + __bjs_primitiveCodecs.UInt8, + __bjs_primitiveCodecs.Int16, + __bjs_primitiveCodecs.UInt16, + __bjs_primitiveCodecs.Int32, + __bjs_primitiveCodecs.UInt32, + __bjs_primitiveCodecs.UInt, + __bjs_primitiveCodecs.Int64, + __bjs_primitiveCodecs.UInt64, + __bjs_primitiveCodecs.Float, + __bjs_primitiveCodecs.Double, + __bjs_primitiveCodecs.String, + __bjs_primitiveCodecs.JSValue, + ].concat([ + { + lower: (v) => { + structHelpers.GenericPoint.lower(v); + }, + lift: () => { + const struct = structHelpers.GenericPoint.lift(); + return struct; + }, + }, + { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['GenericImportBox'].__construct(ptr); + return obj; + }, + }, + { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }, + { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const rawValue = strStack.pop(); + return rawValue; + }, + }, + { + lower: (v) => { + const caseId = enumHelpers.GenericTagged.lower(v); + i32Stack.push(caseId); + }, + lift: () => { + const enumValue = enumHelpers.GenericTagged.lift(i32Stack.pop()); + return enumValue; + }, + }, + ]); + if (count !== codecs.length) { + throw new Error("BridgeJS: type handle registration mismatch for module 'TestModule'"); + } + const typeIds = new Int32Array(memory.buffer, base >>> 0, count >>> 0); + for (let i = 0; i < count; i++) { + __bjs_codecByTypeId.set(typeIds[i], codecs[i]); + } + } + const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); + bjs["swift_js_make_promise"] = function() { + let resolve, reject; + const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); + promise[__bjs_promiseSettlers] = { resolve, reject }; + return swift.memory.retain(promise); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_GenericImportBox_wrap"] = function(pointer) { + const obj = _exports['GenericImportBox'].__construct(pointer); + return swift.memory.retain(obj); + }; + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_genericRoundTrip"] = function bjs_genericRoundTrip(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.genericRoundTrip(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_genericParse"] = function bjs_genericParse(jsonBytes, jsonCount, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const string = decodeString(jsonBytes, jsonCount); + let ret = imports.genericParse(string); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericCombine"] = function bjs_importGenericCombine(tTypeId, uTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codecU = __bjs_codecForTypeId(uTypeId); + const a = codecT.lift(); + const b = codecU.lift(); + let ret = imports.importGenericCombine(a, b); + codecU.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericCaseDistinct"] = function bjs_importGenericCaseDistinct(tTypeId, tTypeId1) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codect = __bjs_codecForTypeId(tTypeId1); + const a = codecT.lift(); + const b = codect.lift(); + let ret = imports.importGenericCaseDistinct(a, b); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericArray"] = function bjs_importGenericArray(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const values = __bjs_arrayCodec(codecT).lift(); + let ret = imports.importGenericArray(values); + __bjs_arrayCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericOptional"] = function bjs_importGenericOptional(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = __bjs_optionalCodec(codecT).lift(); + let ret = imports.importGenericOptional(value); + __bjs_optionalCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericDictionary"] = function bjs_importGenericDictionary(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const values = __bjs_dictCodec(codecT).lift(); + let ret = imports.importGenericDictionary(values); + __bjs_dictCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericAfterOptionalArray"] = function bjs_importGenericAfterOptionalArray(values, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + let optResult; + if (values) { + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + optResult = arrayResult; + } else { + optResult = null; + } + const value = codecT.lift(); + let ret = imports.importGenericAfterOptionalArray(optResult, value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericPairFactory_init"] = function bjs_GenericPairFactory_init(tagBytes, tagCount, tTypeId, uTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codecU = __bjs_codecForTypeId(uTypeId); + const string = decodeString(tagBytes, tagCount); + const first = codecT.lift(); + const second = codecU.lift(); + return swift.memory.retain(new imports.GenericPairFactory(string, first, second)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericConsumer_init"] = function bjs_GenericConsumer_init(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + return swift.memory.retain(new imports.GenericConsumer(value)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericConsumer_box_static"] = function bjs_GenericConsumer_box_static(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.GenericConsumer.box(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericConsumer_accept"] = function bjs_GenericConsumer_accept(self, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + swift.memory.getObject(self).accept(value); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericConsumer_identity"] = function bjs_GenericConsumer_identity(self, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = swift.memory.getObject(self).identity(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + afterInitialize: () => { + __bjs_registerTypeHandles(); + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.hasReleased) { + return; + } + state.hasReleased = true; + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype, identityCache) { + pointer = pointer >>> 0; + const makeFresh = (identityMap) => { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false, identityMap }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + if (identityMap) { + identityMap.set(pointer, new WeakRef(obj)); + } + return obj; + }; + + if (!identityCache) { + return makeFresh(null); + } + + const cached = identityCache.get(pointer)?.deref(); + if (cached && !cached.__swiftHeapObjectState.hasReleased) { + deinit(pointer); + return cached; + } + if (identityCache.has(pointer)) { + identityCache.delete(pointer); + } + + return makeFresh(identityCache); + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + } + } + class GenericImportBox extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GenericImportBox_deinit, GenericImportBox.prototype, null); + } + + constructor(value) { + const ret = instance.exports.bjs_GenericImportBox_init(value); + return GenericImportBox.__construct(ret); + } + get() { + const ret = instance.exports.bjs_GenericImportBox_get(this.pointer); + return ret; + } + get value() { + const ret = instance.exports.bjs_GenericImportBox_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_GenericImportBox_value_set(this.pointer, value); + } + } + const GenericPointHelpers = __bjs_createGenericPointHelpers(); + structHelpers.GenericPoint = GenericPointHelpers; + + const GenericTaggedHelpers = __bjs_createGenericTaggedValuesHelpers(); + enumHelpers.GenericTagged = GenericTaggedHelpers; + + const exports = { + GenericColor: GenericColorValues, + GenericMode: GenericModeValues, + GenericTagged: GenericTaggedValues, + GenericImportBox, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts index 312f56786..e4754d8e0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts index ae1152016..0dbdafe7b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts index cd4f822e2..e0da68c50 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 07341894e..bf1707b56 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -207,41 +517,16 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_roundtrip"] = function bjs_roundtrip() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.roundtrip(arrayResult); - for (const elem of ret) { - i32Stack.push((elem | 0)); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_logStrings"] = function bjs_logStrings() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); imports.logStrings(arrayResult); } catch (error) { setException(error); @@ -251,34 +536,12 @@ export async function createInstantiator(options, swift) { try { let optResult; if (a) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); optResult = arrayResult; } else { optResult = null; } - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int1 = i32Stack.pop(); - arrayResult1.push(int1); - } - arrayResult1.reverse(); - } + const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.optionalArrayThenArray(optResult, arrayResult1); return ret; } catch (error) { @@ -291,34 +554,12 @@ export async function createInstantiator(options, swift) { const string = decodeString(sBytes, sCount); let optResult; if (a) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); optResult = arrayResult; } else { optResult = null; } - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int1 = i32Stack.pop(); - arrayResult1.push(int1); - } - arrayResult1.reverse(); - } + const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.borrowedStringAroundStackParams(string, optResult, arrayResult1); return ret; } catch (error) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts index 22b4e6a1c..1d5f31efd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts @@ -26,5 +26,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 4328e4d4e..8974e3722 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createFooContainerHelpers = () => ({ lower: (value) => { let id; @@ -40,24 +350,34 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalFoo != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.optionalFoo); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalFoo); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { @@ -152,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.FooContainer.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -289,60 +610,63 @@ export async function createInstantiator(options, swift) { return ret1; }, processFooArray: function bjs_processFooArray(foos) { - for (const elem of foos) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(foos.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(foos); instance.exports.bjs_processFooArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalFooArray: function bjs_processOptionalFooArray(foos) { - for (const elem of foos) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(elem); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(isSome); - } - i32Stack.push(foos.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(foos); instance.exports.bjs_processOptionalFooArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - optValue = obj; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, roundtripFooContainer: function bjs_roundtripFooContainer(container) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts index ac0e05a91..edc243baa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts @@ -33,5 +33,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts index aaf227cf7..e6dfad7fa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts @@ -27,5 +27,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts index 3b2b5de99..3cb232260 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts @@ -28,5 +28,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts index a6267bd31..b0c2eff74 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts index 818d57a9d..e9f73cfae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts @@ -13,5 +13,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts index 624691d83..9afd16f74 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts index b842e7d7d..c77ca0828 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts index 85109479e..951f1e7aa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts @@ -36,5 +36,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index ae59008ba..f39091a1f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -31,6 +31,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -316,29 +537,9 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_jsEchoJSValueArray"] = function bjs_jsEchoJSValueArray() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); let ret = imports.jsEchoJSValueArray(arrayResult); - for (const elem of ret) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(ret); } catch (error) { setException(error); } @@ -564,67 +765,16 @@ export async function createInstantiator(options, swift) { return optResult; }, roundTripJSValueArray: function bjs_roundTripJSValueArray(values) { - for (const elem of values) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(values); instance.exports.bjs_roundTripJSValueArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); return arrayResult; }, roundTripOptionalJSValueArray: function bjs_roundTripOptionalJSValueArray(values) { - const isSome = values != null; - if (isSome) { - for (const elem of values) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(values.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lower(values); instance.exports.bjs_roundTripOptionalJSValueArray(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } - optResult = arrayResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lift(); + return optValue; }, JSValueHolder, }; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts index c7ff9a39c..737e94bce 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts index 01a392e91..88d337296 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts @@ -51,5 +51,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts index 89aad5c32..634065017 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts index ac9ea13c4..76daa290c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts @@ -126,5 +126,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index aa5e3dbb4..fcb6dd88d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -356,19 +666,17 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Greeter.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts index debd3ffcf..59961720b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts @@ -73,5 +73,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 9a5c6473e..ef083c4d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -356,19 +666,17 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Greeter.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts index c418ed8a5..5dfb48fcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts @@ -42,5 +42,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index 972f9ae74..e03b09221 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -145,6 +145,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Player_Stats.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index 0f64324cd..324947e18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -82,5 +82,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 5a253cdc0..0a4fcc28c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -314,12 +624,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_childOrNull_get"] = function bjs_WithOptionalJSClass_childOrNull_get(self) { try { let ret = swift.memory.getObject(self).childOrNull; - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -490,12 +807,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, valueIsSome, valueObjectId) { try { let ret = swift.memory.getObject(self).roundTripChildOrNull(valueIsSome ? swift.memory.getObject(valueObjectId) : null); - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -722,17 +1046,20 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSObject(+isSome, result); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, roundTripExportedOptionalJSClass: function bjs_roundTripExportedOptionalJSClass(value) { const isSome = value != null; @@ -743,17 +1070,20 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSClass(+isSome, result); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, roundTripString: function bjs_roundTripString(name) { const isSome = name != null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts index 961f97635..19680ec06 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts index 77e269d16..a28a7b4bb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts @@ -20,5 +20,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts index 5872a3020..d7cd0e2e6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts @@ -44,5 +44,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts index a413fa500..f55109d2b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts @@ -119,5 +119,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index b2a894ffa..e2c711f8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -55,6 +55,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createResultValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -163,6 +473,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -724,11 +1035,19 @@ export async function createInstantiator(options, swift) { } constructor(delegates) { - for (const elem of delegates) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(delegates.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(delegates); const ret = instance.exports.bjs_DelegateManager_init(); return DelegateManager.__construct(ret); } @@ -737,55 +1056,68 @@ export async function createInstantiator(options, swift) { } get delegates() { instance.exports.bjs_DelegateManager_delegates_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { const objId = i32Stack.pop(); const obj = swift.memory.getObject(objId); swift.memory.release(objId); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } set delegates(value) { - for (const elem of value) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(value.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(value); instance.exports.bjs_DelegateManager_delegates_set(this.pointer); } get delegatesByName() { instance.exports.bjs_DelegateManager_delegatesByName_get(this.pointer); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec).lift(); return dictResult; } set delegatesByName(value) { - const entries = Object.entries(value); - for (const entry of entries) { - const [key, value1] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const objId = swift.memory.retain(value1); - i32Stack.push(objId); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(value); instance.exports.bjs_DelegateManager_delegatesByName_set(this.pointer); } } @@ -794,50 +1126,63 @@ export async function createInstantiator(options, swift) { const exports = { processDelegates: function bjs_processDelegates(delegates) { - for (const elem of delegates) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(delegates.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(delegates); instance.exports.bjs_processDelegates(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processDelegatesByName: function bjs_processDelegatesByName(delegates) { - const entries = Object.entries(delegates); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const objId = swift.memory.retain(value); - i32Stack.push(objId); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(delegates); instance.exports.bjs_processDelegatesByName(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec1).lift(); return dictResult; }, Direction: DirectionValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts index 7d5a3c9aa..ce87ccd29 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts @@ -34,5 +34,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts index e5602e42d..b97a1bd8e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -73,5 +73,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 25f989a00..8f783865e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index a168f3ad1..6176abb6f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -63,5 +63,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index ca4093992..4841e3350 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts index b54e14def..42cfe5870 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts @@ -68,5 +68,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 63dd9cba5..189db1f0e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts index aea927c79..42ff8507c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts @@ -54,5 +54,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index b5680b9b0..a5a003a1c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts index 5e45162a1..8d562d13a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts index b43ff062c..667db342e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts index fe4708fd8..cf231e076 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts @@ -69,5 +69,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js index ee5cc0a3e..3270abd58 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js @@ -193,6 +193,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Widget_Bounds.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 2f56a1cb8..d0c84e109 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -43,5 +43,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts index 70f23c11a..81fd7f109 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts @@ -114,5 +114,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 62c2de8c6..bebe9179d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -61,6 +61,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -330,6 +551,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Animal.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -863,32 +1085,23 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = callback(optResult); - const isSome = ret != null; - if (isSome) { - structHelpers.Animal.lower(ret); - } - i32Stack.push(isSome ? 1 : 0); + __bjs_optionalCodec(structHelpers.Animal).lower(ret); } catch (error) { setException(error); } } bjs["make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV = function(param0) { - const isSome = param0 != null; - if (isSome) { - structHelpers.Animal.lower(param0); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Animal).lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(boxPtr); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Animal.lift() : null; + const optValue = __bjs_optionalCodec(structHelpers.Animal).lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } - return optResult; + return optValue; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts index b66f960f8..47f1b89f9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 3b394fb06..3503e138e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -90,5 +90,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index 92a99becb..c16b674ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -36,6 +36,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createDataPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -44,34 +354,12 @@ export async function createInstantiator(options, swift) { const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - const isSome = value.optCount != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.optCount | 0)); - } - i32Stack.push(isSome); - const isSome1 = value.optFlag != null ? 1 : 0; - if (isSome1) { - i32Stack.push(value.optFlag ? 1 : 0); - } - i32Stack.push(isSome1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.optCount); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.optFlag); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue = bool; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); @@ -88,21 +376,10 @@ export async function createInstantiator(options, swift) { const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - const isSome = value.zipCode != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.zipCode | 0)); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.zipCode); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); const string = strStack.pop(); const string1 = strStack.pop(); return { street: string1, city: string, zipCode: optValue }; @@ -116,28 +393,14 @@ export async function createInstantiator(options, swift) { i32Stack.push(id); i32Stack.push((value.age | 0)); structHelpers.Address.lower(value.address); - const isSome = value.email != null ? 1 : 0; - if (isSome) { - const bytes1 = textEncoder.encode(value.email); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.email); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); const struct = structHelpers.Address.lift(); const int = i32Stack.pop(); - const string1 = strStack.pop(); - return { name: string1, age: int, address: struct, email: optValue }; + const string = strStack.pop(); + return { name: string, age: int, address: struct, email: optValue }; } }); const __bjs_createSessionHelpers = () => ({ @@ -156,24 +419,31 @@ export async function createInstantiator(options, swift) { lower: (value) => { f64Stack.push(value.value); f32Stack.push(Math.fround(value.precision)); - const isSome = value.optionalPrecision != null ? 1 : 0; - if (isSome) { - f32Stack.push(Math.fround(value.optionalPrecision)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalPrecision); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const rawValue = f32Stack.pop(); - optValue = rawValue; - } - const rawValue1 = f32Stack.pop(); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + const rawValue = f32Stack.pop(); const f64 = f64Stack.pop(); - return { value: f64, precision: rawValue1, optionalPrecision: optValue }; + return { value: f64, precision: rawValue, optionalPrecision: optValue }; } }); const __bjs_createConfigStructHelpers = () => ({ @@ -192,24 +462,34 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalObject != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.optionalObject); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalObject); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { @@ -382,6 +662,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Vector2D.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts index e97b50fda..e95b78349 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 4a2e18d6b..9d613c8a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); @@ -125,6 +435,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -242,11 +553,7 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = imports.roundTripOptional(optResult); - const isSome = ret != null; - if (isSome) { - structHelpers.Point.lower(ret); - } - i32Stack.push(isSome ? 1 : 0); + __bjs_optionalCodec(structHelpers.Point).lower(ret); } catch (error) { setException(error); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts index 99adf95b6..606de53ad 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts index 9199ad1ae..13dccd568 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts @@ -14,5 +14,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts index 5a4ee78ce..b1ecc2000 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts @@ -34,5 +34,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 457bfa973..704dbb021 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.PointerFields.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts index 7acba67a0..d15ce0a8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 36d840099..6181afe48 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -74,6 +74,8 @@ async function createInstantiator(options, swift) { }, /** @param {WebAssembly.Instance} instance */ setInstance: (instance) => {}, + /** Called once the instance is fully initialized and Swift code may run. */ + afterInitialize: () => {}, /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { return {}; @@ -84,17 +86,18 @@ async function createInstantiator(options, swift) { /** @type {import('./instantiate.d').instantiate} */ export async function instantiate(options) { - const result = await _instantiate(options); + const { instantiator, ...result } = await _instantiate(options); /* #if IS_WASI */ options.wasi.initialize(result.instance); /* #endif */ + instantiator.afterInitialize?.(); result.swift.main(); return result; } /** @type {import('./instantiate.d').instantiateForThread} */ export async function instantiateForThread(tid, startArg, options) { - const result = await _instantiate(options); + const { instantiator, ...result } = await _instantiate(options); /* #if IS_WASI */ options.wasi.setInstance(result.instance); /* #endif */ @@ -102,7 +105,7 @@ export async function instantiateForThread(tid, startArg, options) { return result; } -/** @type {import('./instantiate.d').instantiate} */ +/** @param {import('./instantiate.d').InstantiateOptions} options */ async function _instantiate(options) { const _WebAssembly = options.WebAssembly || WebAssembly; const moduleSource = options.module; @@ -184,5 +187,6 @@ async function _instantiate(options) { instance, swift, exports, + instantiator, }; } diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 4eeae4dac..b15e07b5d 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -204,6 +204,58 @@ extension _BridgedSwiftStackType { } } +/// Types usable as the generic argument of a generic imported `@JSFunction`. +/// Each conforming type owns a ``BridgeJSTypeHandle`` whose pointer is the +/// runtime type ID that selects the matching JS codec. Do not conform types by +/// hand; marking them `@JS` emits the conformance together with the JS codec. +public protocol BridgedSwiftGenericBridgeable: _BridgedSwiftStackType +where StackLiftResult == Self { + @_spi(BridgeJS) static var bridgeJSTypeHandle: BridgeJSTypeHandle { get } +} + +extension BridgedSwiftGenericBridgeable { + /// The runtime type ID passed across the bridge for this type. + @_spi(BridgeJS) public static var bridgeJSTypeID: Int32 { bridgeJSTypeHandle.typeID } + + /// Creates the type's unique handle. A generic static function so + /// conformances compile under Embedded Swift. + @_spi(BridgeJS) public static func bridgeJSMakeTypeHandle() -> BridgeJSTypeHandle { + #if hasFeature(Embedded) + return BridgeJSTypeHandle() + #else + return BridgeJSTypeHandle(Self.self) + #endif + } +} + +/// A per-type identity token for generic bridging: each conforming type stores +/// exactly one handle in a `static let`, so the handle's pointer identifies the +/// type at runtime without relying on type names, which could collide across +/// modules. +public final class BridgeJSTypeHandle: Sendable { + #if hasFeature(Embedded) + public init() {} + #else + /// The conforming type, for exported generics (planned follow-up) to map a + /// type ID back to. `nonisolated(unsafe)`: an immutable metatype is safe to + /// share, but the compiler cannot infer that. + public nonisolated(unsafe) let type: any BridgedSwiftGenericBridgeable.Type + + public init(_ type: any BridgedSwiftGenericBridgeable.Type) { + self.type = type + } + #endif + + /// The handle object's own address; pointers are 32-bit on wasm32. + @_spi(BridgeJS) public var typeID: Int32 { + #if arch(wasm32) + return Int32(bitPattern: UInt32(UInt(bitPattern: Unmanaged.passUnretained(self).toOpaque()))) + #else + _onlyAvailableOnWasm() + #endif + } +} + /// Types that bridge with the same (isSome, value) ABI as Optional. /// Used by JSUndefinedOr so all bridge methods delegate to Optional. public protocol _BridgedAsOptional { @@ -808,6 +860,49 @@ extension String: _BridgedSwiftStackType { } } +extension Bool: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Bool.bridgeJSMakeTypeHandle() +} +extension Int: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int.bridgeJSMakeTypeHandle() +} +extension Float: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Float.bridgeJSMakeTypeHandle() +} +extension Double: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Double.bridgeJSMakeTypeHandle() +} +extension String: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = String.bridgeJSMakeTypeHandle() +} +extension UInt: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt.bridgeJSMakeTypeHandle() +} +extension Int8: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int8.bridgeJSMakeTypeHandle() +} +extension UInt8: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt8.bridgeJSMakeTypeHandle() +} +extension Int16: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int16.bridgeJSMakeTypeHandle() +} +extension UInt16: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt16.bridgeJSMakeTypeHandle() +} +extension Int32: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int32.bridgeJSMakeTypeHandle() +} +extension UInt32: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt32.bridgeJSMakeTypeHandle() +} +extension Int64: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int64.bridgeJSMakeTypeHandle() +} +extension UInt64: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt64.bridgeJSMakeTypeHandle() +} + extension JSObject: _BridgedSwiftStackType { // JSObject is a non-final class, so we must explicitly specify the associated type // rather than relying on the default `Self` (which Swift requires for covariant returns). @@ -914,6 +1009,10 @@ extension JSValue: _BridgedSwiftStackType { } } +extension JSValue: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSValue.bridgeJSMakeTypeHandle() +} + /// A protocol that Swift heap objects exposed to JavaScript via `@JS class` must conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md index 9c0a80dc1..5a47746d6 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md @@ -416,4 +416,4 @@ When a TypeScript name is not a valid Swift identifier (e.g. contains dashes, sp ## Limitations - No first-class support for async/Promise-returning functions;. -- No generic type parameter can appear on a bridged function signature. \ No newline at end of file +- No generic type parameter can appear on a bridged function signature generated from TypeScript; a type parameter is lowered to `JSObject`. Generic imports are available only through `@JSFunction` declarations written in Swift — see . \ No newline at end of file diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md index 1b2be6cb0..ebc9ac857 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md @@ -77,11 +77,23 @@ If you used `from: .global` or `.module`, do not pass the function in `getImport Bound functions are `throws(JSException)`. Call them with `try` or `try?`; they throw when the JavaScript implementation throws. +## Generic functions + +A `@JSFunction` can be generic over a type parameter constrained to `BridgedSwiftGenericBridgeable`, so one declaration serves every bridged type: + +```swift +@JSFunction func parse(_ json: String) throws(JSException) -> T + +let user: User = try parse(jsonString) // T inferred from the call site +``` + +`T` can be any supported primitive, `String`, `JSValue`, or a `@JS` struct, `@JS` enum, or `final @JS class` (see ), used bare or wrapped as `[T]`, `T?`, or `[String: T]`. A function may declare multiple type parameters, and a return-only generic (`func make() -> T`) works too. Generic initializers, methods, and static methods on `@JSClass` types are supported the same way. `async` generic functions and `where` clauses are not supported. + ## Supported features | Feature | Status | |:--|:--| | Primitive parameter/result types (e.g. `Double`, `Bool`) | ✅ | | `String` parameter/result type | ✅ | +| Generic parameter/result types (constrained to `BridgedSwiftGenericBridgeable`) | ✅ | | Async function | ❌ | -| Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md index 5c609ab72..539f7ce15 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md @@ -31,6 +31,10 @@ When using `JSTypedArray` (or convenience typealiases) in `@JS` signatures, t See for usage details. +## Generic type parameters + +An imported `@JSFunction` can be generic over a type parameter constrained to `BridgedSwiftGenericBridgeable` (see ); exported `@JS` functions cannot yet. The constraint is satisfied by all supported primitives, `String`, `JSValue`, and any `@JS` struct, `@JS` enum, or `final @JS class`, including ones from another linked module. Do not write the conformance by hand; marking the type `@JS` is what provides it, together with the JavaScript side of the bridge. + ## See Also - diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index 4e35a1c9f..deedc1ccf 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -353,4 +353,53 @@ fileprivate func _bjs_GlobalUtils_PublicConverter_wrap_extern(_ pointer: UnsafeM #endif @inline(never) fileprivate func _bjs_GlobalUtils_PublicConverter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_GlobalUtils_PublicConverter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension GlobalNetworking.API.CallMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalNetworking.API.CallMethod.bridgeJSMakeTypeHandle() +} + +extension GlobalConfiguration.PublicLogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalConfiguration.PublicLogLevel.bridgeJSMakeTypeHandle() +} + +extension GlobalConfiguration.AvailablePort: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalConfiguration.AvailablePort.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedServerMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedServerMethod.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_BridgeJSGlobalTests_register_type_handles") +fileprivate func _bjs_BridgeJSGlobalTests_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_BridgeJSGlobalTests_register_type_handles") +public func _bjs_BridgeJSGlobalTests_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + GlobalNetworking.API.CallMethod.bridgeJSTypeID, + GlobalConfiguration.PublicLogLevel.bridgeJSTypeID, + GlobalConfiguration.AvailablePort.bridgeJSTypeID, + Internal.SupportedServerMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_BridgeJSGlobalTests_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index ad6f3fa24..5ebe5f4c3 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -5991,6 +5991,75 @@ extension ImportedPayloadSignal: _BridgedSwiftAssociatedValueEnum { } } +extension GenericRTColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> GenericRTColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> GenericRTColor { + return GenericRTColor(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .red + case 1: + self = .green + case 2: + self = .blue + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .green: + return 1 + case .blue: + return 2 + } + } +} + +extension GenericRTMode: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericRTLevel: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericRTOutcome: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> GenericRTOutcome { + switch caseId { + case 0: + return .ok(code: Int.bridgeJSStackPop()) + case 1: + return .fail(message: String.bridgeJSStackPop()) + default: + fatalError("Unknown GenericRTOutcome case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .ok(let code): + code.bridgeJSStackPush() + return Int32(0) + case .fail(let message): + message.bridgeJSStackPush() + return Int32(1) + } + } +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -6779,6 +6848,102 @@ public func _bjs_NestedTypeHost_Label_static_untitled() -> Void { #endif } +extension GenericRTPoint: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTPoint { + let y = Int.bridgeJSStackPop() + let x = Int.bridgeJSStackPop() + return GenericRTPoint(x: x, y: y) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.x.bridgeJSStackPush() + self.y.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericRTPoint(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericRTPoint())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericRTPoint") +fileprivate func _bjs_struct_lower_GenericRTPoint_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericRTPoint_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericRTPoint(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericRTPoint_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericRTPoint") +fileprivate func _bjs_struct_lift_GenericRTPoint_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericRTPoint_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericRTPoint() -> Int32 { + return _bjs_struct_lift_GenericRTPoint_extern() +} + +extension GenericRTNamespace.Metadata: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTNamespace.Metadata { + let count = Int.bridgeJSStackPop() + let label = String.bridgeJSStackPop() + return GenericRTNamespace.Metadata(label: label, count: count) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + self.count.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericRTNamespace_Metadata(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericRTNamespace_Metadata())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericRTNamespace_Metadata") +fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericRTNamespace_Metadata_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericRTNamespace_Metadata") +fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata() -> Int32 { + return _bjs_struct_lift_GenericRTNamespace_Metadata_extern() +} + extension Point: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Point { let y = Int.bridgeJSStackPop() @@ -13162,6 +13327,80 @@ fileprivate func _bjs_NestedTypeHost_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_NestedTypeHost_wrap_extern(pointer) } +@_expose(wasm, "bjs_ImportGenericBox_init") +@_cdecl("bjs_ImportGenericBox_init") +public func _bjs_ImportGenericBox_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ImportGenericBox(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_get") +@_cdecl("bjs_ImportGenericBox_get") +public func _bjs_ImportGenericBox_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ImportGenericBox.bridgeJSLiftParameter(_self).get() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_value_get") +@_cdecl("bjs_ImportGenericBox_value_get") +public func _bjs_ImportGenericBox_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ImportGenericBox.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_value_set") +@_cdecl("bjs_ImportGenericBox_value_set") +public func _bjs_ImportGenericBox_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + ImportGenericBox.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_deinit") +@_cdecl("bjs_ImportGenericBox_deinit") +public func _bjs_ImportGenericBox_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ImportGenericBox: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ImportGenericBox_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ImportGenericBox_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBox_wrap") +fileprivate func _bjs_ImportGenericBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ImportGenericBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ImportGenericBox_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ImportGenericBox_wrap_extern(pointer) +} + @_expose(wasm, "bjs_OptionalHolder_init") @_cdecl("bjs_OptionalHolder_init") public func _bjs_OptionalHolder_init(_ nullableGreeterIsSome: Int32, _ nullableGreeterValue: UnsafeMutableRawPointer, _ undefinedNumberIsSome: Int32, _ undefinedNumberValue: Float64) -> UnsafeMutableRawPointer { @@ -13479,6 +13718,274 @@ fileprivate func _bjs_LeakCheck_wrap_extern(_ pointer: UnsafeMutableRawPointer) return _bjs_LeakCheck_wrap_extern(pointer) } +extension JSCoordinate: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSCoordinate.bridgeJSMakeTypeHandle() +} + +extension NestedStructGroupA.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedStructGroupA.Metadata.bridgeJSMakeTypeHandle() +} + +extension NestedStructGroupB.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedStructGroupB.Metadata.bridgeJSMakeTypeHandle() +} + +extension NestedTypeHost.Label: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Label.bridgeJSMakeTypeHandle() +} + +extension GenericRTPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTPoint.bridgeJSMakeTypeHandle() +} + +extension GenericRTNamespace.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTNamespace.Metadata.bridgeJSMakeTypeHandle() +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension PointerFields: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PointerFields.bridgeJSMakeTypeHandle() +} + +extension DataPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = DataPoint.bridgeJSMakeTypeHandle() +} + +extension PublicPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PublicPoint.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Contact: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Contact.bridgeJSMakeTypeHandle() +} + +extension Config: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Config.bridgeJSMakeTypeHandle() +} + +extension SessionData: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionData.bridgeJSMakeTypeHandle() +} + +extension ValidationReport: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ValidationReport.bridgeJSMakeTypeHandle() +} + +extension AdvancedConfig: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AdvancedConfig.bridgeJSMakeTypeHandle() +} + +extension MeasurementConfig: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MeasurementConfig.bridgeJSMakeTypeHandle() +} + +extension MathOperations: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MathOperations.bridgeJSMakeTypeHandle() +} + +extension CopyableCart: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableCart.bridgeJSMakeTypeHandle() +} + +extension CopyableCartItem: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableCartItem.bridgeJSMakeTypeHandle() +} + +extension CopyableNestedCart: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableNestedCart.bridgeJSMakeTypeHandle() +} + +extension ConfigStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ConfigStruct.bridgeJSMakeTypeHandle() +} + +extension Vector2D: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Vector2D.bridgeJSMakeTypeHandle() +} + +extension JSObjectContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSObjectContainer.bridgeJSMakeTypeHandle() +} + +extension FooContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FooContainer.bridgeJSMakeTypeHandle() +} + +extension ArrayMembers: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ArrayMembers.bridgeJSMakeTypeHandle() +} + +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + +extension TagReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagReference.bridgeJSMakeTypeHandle() +} + +extension TagHolderReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagHolderReference.bridgeJSMakeTypeHandle() +} + +extension PriorityReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PriorityReference.bridgeJSMakeTypeHandle() +} + +extension ImportGenericBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ImportGenericBox.bridgeJSMakeTypeHandle() +} + +extension Severity: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Severity.bridgeJSMakeTypeHandle() +} + +extension Shape: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.bridgeJSMakeTypeHandle() +} + +extension InnerTag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = InnerTag.bridgeJSMakeTypeHandle() +} + +extension AsyncImportedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncImportedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension FileSize: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FileSize.bridgeJSMakeTypeHandle() +} + +extension SessionId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionId.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension Ratio: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Ratio.bridgeJSMakeTypeHandle() +} + +extension TSDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSDirection.bridgeJSMakeTypeHandle() +} + +extension TSTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSTheme.bridgeJSMakeTypeHandle() +} + +extension AsyncPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPayloadResult.bridgeJSMakeTypeHandle() +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + +extension Utilities.Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Utilities.Result.bridgeJSMakeTypeHandle() +} + +extension API.NetworkingResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = API.NetworkingResult.bridgeJSMakeTypeHandle() +} + +extension AllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AllTypesResult.bridgeJSMakeTypeHandle() +} + +extension TypedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TypedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension StaticCalculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = StaticCalculator.bridgeJSMakeTypeHandle() +} + +extension StaticPropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = StaticPropertyEnum.bridgeJSMakeTypeHandle() +} + +extension NestedTypeHost.Variant: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Variant.bridgeJSMakeTypeHandle() +} + +extension LightColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = LightColor.bridgeJSMakeTypeHandle() +} + +extension ImportedPayloadSignal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ImportedPayloadSignal.bridgeJSMakeTypeHandle() +} + +extension GenericRTColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTColor.bridgeJSMakeTypeHandle() +} + +extension GenericRTMode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTMode.bridgeJSMakeTypeHandle() +} + +extension GenericRTLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTLevel.bridgeJSMakeTypeHandle() +} + +extension GenericRTOutcome: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTOutcome.bridgeJSMakeTypeHandle() +} + +extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() +} + +extension APIOptionalResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIOptionalResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -16688,6 +17195,346 @@ func _$jsJoinStringThenStackParams(_ s: String, _ a: Optional<[Int]>, _ b: [Int] return String.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericRoundTrip") +fileprivate func bjs_jsGenericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_jsGenericRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericRoundTripClass") +fileprivate func bjs_jsGenericRoundTripClass_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericRoundTripClass_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericRoundTripClass(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericRoundTripClass_extern(_generic0TypeId) +} + +func _$jsGenericRoundTripClass(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_jsGenericRoundTripClass(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericParsePoint") +fileprivate func bjs_jsGenericParsePoint_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericParsePoint_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericParsePoint(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericParsePoint_extern(jsonBytes, jsonLength, _generic0TypeId) +} + +func _$jsGenericParsePoint(_ json: String) throws(JSException) -> T { + json.bridgeJSWithLoweredParameter { (jsonBytes, jsonLength) in + bjs_jsGenericParsePoint(jsonBytes, jsonLength, T.bridgeJSTypeID) + } + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportPickFirst") +fileprivate func bjs_jsImportPickFirst_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportPickFirst_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportPickFirst(_ _generic0TypeId: Int32) -> Void { + return bjs_jsImportPickFirst_extern(_generic0TypeId) +} + +func _$jsImportPickFirst(_ a: T, _ b: T) throws(JSException) -> T { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_jsImportPickFirst(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportMakeInt") +fileprivate func bjs_jsImportMakeInt_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportMakeInt_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportMakeInt(_ _generic0TypeId: Int32) -> Void { + return bjs_jsImportMakeInt_extern(_generic0TypeId) +} + +func _$jsImportMakeInt() throws(JSException) -> T { + bjs_jsImportMakeInt(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportCombineSecond") +fileprivate func bjs_jsImportCombineSecond_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportCombineSecond_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportCombineSecond(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_jsImportCombineSecond_extern(_generic0TypeId, _generic1TypeId) +} + +func _$jsImportCombineSecond(_ a: T, _ b: U) throws(JSException) -> U { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_jsImportCombineSecond(T.bridgeJSTypeID, U.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return U.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericArrayRoundTrip") +fileprivate func bjs_jsGenericArrayRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericArrayRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericArrayRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericArrayRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericArrayRoundTrip(_ values: [T]) throws(JSException) -> [T] { + let _ = values.bridgeJSLowerParameter() + bjs_jsGenericArrayRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericOptionalRoundTrip") +fileprivate func bjs_jsGenericOptionalRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericOptionalRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericOptionalRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericOptionalRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericOptionalRoundTrip(_ value: Optional) throws(JSException) -> Optional { + value.bridgeJSStackPush() + bjs_jsGenericOptionalRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericDictRoundTrip") +fileprivate func bjs_jsGenericDictRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericDictRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericDictRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericDictRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericDictRoundTrip(_ values: [String: T]) throws(JSException) -> [String: T] { + let _ = values.bridgeJSLowerParameter() + bjs_jsGenericDictRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [String: T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericAfterOptionalArray") +fileprivate func bjs_jsGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_jsGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericAfterOptionalArray(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 { + return bjs_jsGenericAfterOptionalArray_extern(values, _generic0TypeId) +} + +func _$jsGenericAfterOptionalArray(_ values: Optional<[Int]>, _ value: T) throws(JSException) -> String { + value.bridgeJSStackPush() + let valuesIsSome = values.bridgeJSLowerParameter() + let ret = bjs_jsGenericAfterOptionalArray(valuesIsSome, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return String.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericThrowOrRoundTrip") +fileprivate func bjs_jsGenericThrowOrRoundTrip_extern(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericThrowOrRoundTrip_extern(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericThrowOrRoundTrip(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericThrowOrRoundTrip_extern(shouldThrow, _generic0TypeId) +} + +func _$jsGenericThrowOrRoundTrip(_ shouldThrow: Bool, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let shouldThrowValue = shouldThrow.bridgeJSLowerParameter() + bjs_jsGenericThrowOrRoundTrip(shouldThrowValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_init") +fileprivate func bjs_ImportGenericConsumer_init_extern() -> Int32 +#else +fileprivate func bjs_ImportGenericConsumer_init_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_init() -> Int32 { + return bjs_ImportGenericConsumer_init_extern() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_box_static") +fileprivate func bjs_ImportGenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_box_static(_ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericConsumer_box_static_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_identity") +fileprivate func bjs_ImportGenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_identity(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericConsumer_identity_extern(self, _generic0TypeId) +} + +func _$ImportGenericConsumer_init() throws(JSException) -> JSObject { + let ret = bjs_ImportGenericConsumer_init() + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$ImportGenericConsumer_box(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_ImportGenericConsumer_box_static(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +func _$ImportGenericConsumer_identity(_ self: JSObject, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_ImportGenericConsumer_identity(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBoxed_init") +fileprivate func bjs_ImportGenericBoxed_init_extern(_ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_ImportGenericBoxed_init_extern(_ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericBoxed_init(_ _generic0TypeId: Int32) -> Int32 { + return bjs_ImportGenericBoxed_init_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBoxed_unwrap") +fileprivate func bjs_ImportGenericBoxed_unwrap_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericBoxed_unwrap_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericBoxed_unwrap(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericBoxed_unwrap_extern(self, _generic0TypeId) +} + +func _$ImportGenericBoxed_init(_ value: T) throws(JSException) -> JSObject { + value.bridgeJSStackPush() + let ret = bjs_ImportGenericBoxed_init(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$ImportGenericBoxed_unwrap(_ self: JSObject) throws(JSException) -> T { + let selfValue = self.bridgeJSLowerParameter() + bjs_ImportGenericBoxed_unwrap(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ dx: Int32, _ dy: Int32) -> Void @@ -18062,4 +18909,100 @@ func _$SwiftClassSupportImports_jsConsumeOptionalLeakCheck(_ value: Optional?, _ count: Int32) + +@_expose(wasm, "bjs_BridgeJSRuntimeTests_register_type_handles") +public func _bjs_BridgeJSRuntimeTests_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + JSCoordinate.bridgeJSTypeID, + NestedStructGroupA.Metadata.bridgeJSTypeID, + NestedStructGroupB.Metadata.bridgeJSTypeID, + NestedTypeHost.Label.bridgeJSTypeID, + GenericRTPoint.bridgeJSTypeID, + GenericRTNamespace.Metadata.bridgeJSTypeID, + Point.bridgeJSTypeID, + PointerFields.bridgeJSTypeID, + DataPoint.bridgeJSTypeID, + PublicPoint.bridgeJSTypeID, + Address.bridgeJSTypeID, + Contact.bridgeJSTypeID, + Config.bridgeJSTypeID, + SessionData.bridgeJSTypeID, + ValidationReport.bridgeJSTypeID, + AdvancedConfig.bridgeJSTypeID, + MeasurementConfig.bridgeJSTypeID, + MathOperations.bridgeJSTypeID, + CopyableCart.bridgeJSTypeID, + CopyableCartItem.bridgeJSTypeID, + CopyableNestedCart.bridgeJSTypeID, + ConfigStruct.bridgeJSTypeID, + Vector2D.bridgeJSTypeID, + JSObjectContainer.bridgeJSTypeID, + FooContainer.bridgeJSTypeID, + ArrayMembers.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + TagReference.bridgeJSTypeID, + TagHolderReference.bridgeJSTypeID, + PriorityReference.bridgeJSTypeID, + ImportGenericBox.bridgeJSTypeID, + Severity.bridgeJSTypeID, + Shape.bridgeJSTypeID, + InnerTag.bridgeJSTypeID, + AsyncImportedPayloadResult.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + Theme.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + FileSize.bridgeJSTypeID, + SessionId.bridgeJSTypeID, + Precision.bridgeJSTypeID, + Ratio.bridgeJSTypeID, + TSDirection.bridgeJSTypeID, + TSTheme.bridgeJSTypeID, + AsyncPayloadResult.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + Utilities.Result.bridgeJSTypeID, + API.NetworkingResult.bridgeJSTypeID, + AllTypesResult.bridgeJSTypeID, + TypedPayloadResult.bridgeJSTypeID, + StaticCalculator.bridgeJSTypeID, + StaticPropertyEnum.bridgeJSTypeID, + NestedTypeHost.Variant.bridgeJSTypeID, + LightColor.bridgeJSTypeID, + ImportedPayloadSignal.bridgeJSTypeID, + GenericRTColor.bridgeJSTypeID, + GenericRTMode.bridgeJSTypeID, + GenericRTLevel.bridgeJSTypeID, + GenericRTOutcome.bridgeJSTypeID, + OptionalAllTypesResult.bridgeJSTypeID, + APIOptionalResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_BridgeJSRuntimeTests_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index e2a8575e1..c22116435 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -127,6 +127,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PolygonReference_vertexCount", @@ -265,6 +266,7 @@ "swiftCallName" : "PolygonReference" }, { + "isFinal" : true, "methods" : [ { "abiName" : "bjs_TagReference_describe", @@ -327,6 +329,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_TagHolderReference_describe", @@ -380,6 +383,7 @@ "swiftCallName" : "TagHolderReference" }, { + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PriorityReference_describe", @@ -4840,6 +4844,70 @@ ], "swiftCallName" : "NestedTypeHost" }, + { + "constructor" : { + "abiName" : "bjs_ImportGenericBox_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "isFinal" : true, + "methods" : [ + { + "abiName" : "bjs_ImportGenericBox_get", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "get", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "ImportGenericBox", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "ImportGenericBox" + }, { "constructor" : { "abiName" : "bjs_OptionalHolder_init", @@ -10244,6 +10312,152 @@ { "cases" : [ + ], + "emitStyle" : "const", + "name" : "GenericRTNamespace", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTNamespace", + "tsFullPath" : "GenericRTNamespace" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + }, + { + "associatedValues" : [ + + ], + "name" : "blue" + } + ], + "emitStyle" : "const", + "name" : "GenericRTColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTColor", + "tsFullPath" : "GenericRTColor" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light" + }, + { + "associatedValues" : [ + + ], + "name" : "dark" + } + ], + "emitStyle" : "const", + "name" : "GenericRTMode", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTMode", + "tsFullPath" : "GenericRTMode" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "low", + "rawValue" : "1" + }, + { + "associatedValues" : [ + + ], + "name" : "high", + "rawValue" : "9" + } + ], + "emitStyle" : "const", + "name" : "GenericRTLevel", + "rawType" : "Int", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTLevel", + "tsFullPath" : "GenericRTLevel" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "label" : "code", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "ok" + }, + { + "associatedValues" : [ + { + "label" : "message", + "type" : { + "string" : { + + } + } + } + ], + "name" : "fail" + } + ], + "emitStyle" : "const", + "name" : "GenericRTOutcome", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTOutcome", + "tsFullPath" : "GenericRTOutcome" + }, + { + "cases" : [ + ], "emitStyle" : "const", "name" : "IntegerTypesSupportExports", @@ -18288,6 +18502,82 @@ { "methods" : [ + ], + "name" : "GenericRTPoint", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericRTPoint" + }, + { + "methods" : [ + + ], + "name" : "Metadata", + "namespace" : [ + "GenericRTNamespace" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "GenericRTNamespace" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "count", + "namespace" : [ + "GenericRTNamespace" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericRTNamespace.Metadata" + }, + { + "methods" : [ + ], "name" : "Point", "properties" : [ @@ -23578,6 +23868,498 @@ ] }, + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericRoundTripClass", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericParsePoint", + "parameters" : [ + { + "name" : "json", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsImportPickFirst", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsImportMakeInt", + "parameters" : [ + + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "U" + ], + "name" : "jsImportCombineSecond", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "U" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericArrayRoundTrip", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericOptionalRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericDictRoundTrip", + "parameters" : [ + { + "name" : "values", + "type" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericAfterOptionalArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + }, + "_1" : "null" + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericThrowOrRoundTrip", + "parameters" : [ + { + "name" : "shouldThrow", + "type" : { + "bool" : { + + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "types" : [ + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "parameters" : [ + + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "identity", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "ImportGenericConsumer", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "box", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T" + ], + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "unwrap", + "parameters" : [ + + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "ImportGenericBoxed", + "setters" : [ + + ], + "staticMethods" : [ + + ] + } + ] + }, { "functions" : [ { diff --git a/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift new file mode 100644 index 000000000..bfd63839f --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift @@ -0,0 +1,280 @@ +import Testing +import JavaScriptKit + +@JS struct GenericRTPoint { + var x: Int + var y: Int +} + +@JS enum GenericRTNamespace { + @JS struct Metadata { + var label: String + var count: Int + } +} + +@JS enum GenericRTColor { + case red + case green + case blue +} + +@JS enum GenericRTMode: String { + case light + case dark +} + +@JS enum GenericRTLevel: Int { + case low = 1 + case high = 9 +} + +@JS enum GenericRTOutcome { + case ok(code: Int) + case fail(message: String) +} + +@JS final class ImportGenericBox { + @JS var value: Int + @JS init(value: Int) { + self.value = value + } + @JS func get() -> Int { + value + } +} + +@JSFunction func jsGenericRoundTrip(_ value: T) throws(JSException) -> T +@JSFunction func jsGenericRoundTripClass(_ value: T) throws(JSException) -> T +@JSFunction func jsGenericParsePoint(_ json: String) throws(JSException) -> T +@JSFunction func jsImportPickFirst(_ a: T, _ b: T) throws(JSException) -> T +@JSFunction func jsImportMakeInt() throws(JSException) -> T +@JSFunction func jsImportCombineSecond( + _ a: T, + _ b: U +) throws(JSException) -> U +@JSFunction func jsGenericArrayRoundTrip(_ values: [T]) throws(JSException) -> [T] +@JSFunction func jsGenericOptionalRoundTrip(_ value: T?) throws(JSException) -> T? +@JSFunction func jsGenericDictRoundTrip( + _ values: [String: T] +) throws(JSException) -> [String: T] +@JSFunction func jsGenericAfterOptionalArray( + _ values: [Int]?, + _ value: T +) throws(JSException) -> String + +@JSClass struct ImportGenericConsumer { + @JSFunction init() throws(JSException) + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) throws(JSException) -> T +} + +@JSFunction func jsGenericThrowOrRoundTrip( + _ shouldThrow: Bool, + _ value: T +) throws(JSException) -> T + +@JSClass struct ImportGenericBoxed { + @JSFunction init(_ value: T) throws(JSException) + @JSFunction func unwrap() throws(JSException) -> T +} + +@Suite struct ImportGenericAPITests { + @Test func genericRoundTripScalars() throws { + #expect(try jsGenericRoundTrip(42) == 42) + #expect(try jsGenericRoundTrip(-7) == -7) + #expect(try jsGenericRoundTrip(3.5) == 3.5) + #expect(try jsGenericRoundTrip(Float(1.25)) == Float(1.25)) + #expect(try jsGenericRoundTrip(true) == true) + #expect(try jsGenericRoundTrip(false) == false) + #expect(try jsGenericRoundTrip("hello") == "hello") + #expect(try jsGenericRoundTrip("") == "") + } + + @Test func genericRoundTripNumerics() throws { + #expect(try jsGenericRoundTrip(Int8(-5)) == Int8(-5)) + #expect(try jsGenericRoundTrip(Int8.min) == Int8.min) + #expect(try jsGenericRoundTrip(Int8.max) == Int8.max) + #expect(try jsGenericRoundTrip(UInt8(200)) == UInt8(200)) + #expect(try jsGenericRoundTrip(UInt8.max) == UInt8.max) + #expect(try jsGenericRoundTrip(Int16(-1000)) == Int16(-1000)) + #expect(try jsGenericRoundTrip(UInt16(60000)) == UInt16(60000)) + #expect(try jsGenericRoundTrip(Int32(-123456)) == Int32(-123456)) + #expect(try jsGenericRoundTrip(UInt32(3_000_000_000)) == UInt32(3_000_000_000)) + #expect(try jsGenericRoundTrip(UInt32.max) == UInt32.max) + #expect(try jsGenericRoundTrip(UInt(42)) == UInt(42)) + #expect(try jsGenericRoundTrip(UInt(4_000_000_000)) == UInt(4_000_000_000)) + #expect(try jsGenericRoundTrip(Int64(-9_000_000_000)) == Int64(-9_000_000_000)) + #expect(try jsGenericRoundTrip(Int64.min) == Int64.min) + #expect(try jsGenericRoundTrip(Int64.max) == Int64.max) + #expect(try jsGenericRoundTrip(UInt64(18_000_000_000_000_000_000)) == UInt64(18_000_000_000_000_000_000)) + #expect(try jsGenericRoundTrip(UInt64.max) == UInt64.max) + } + + @Test func genericRoundTripJSValue() throws { + let number = try jsGenericRoundTrip(JSValue.number(3.5)) + #expect(number.number == 3.5) + let string = try jsGenericRoundTrip(JSValue.string("hi")) + #expect(string.string == "hi") + let boolean = try jsGenericRoundTrip(JSValue.boolean(true)) + #expect(boolean.boolean == true) + #expect(try jsGenericRoundTrip(JSValue.null).isNull) + #expect(try jsGenericRoundTrip(JSValue.undefined).isUndefined) + let object = JSObject.global.Object.function!.new() + object.tag = 7 + let roundTripped = try jsGenericRoundTrip(JSValue.object(object)) + #expect(roundTripped.object?.tag.number == 7) + } + + @Test func genericWrappedRoundTrip() throws { + #expect(try jsGenericArrayRoundTrip([1, 2, 3]) == [1, 2, 3]) + #expect(try jsGenericArrayRoundTrip(["a", "b"]) == ["a", "b"]) + #expect(try jsGenericArrayRoundTrip([Int]()) == []) + #expect(try jsGenericOptionalRoundTrip(Optional.some(7)) == 7) + #expect(try jsGenericOptionalRoundTrip(Optional.none) == nil) + #expect(try jsGenericOptionalRoundTrip(Optional.some("hi")) == "hi") + let outcome = try jsGenericOptionalRoundTrip(Optional.some(.ok(code: 5))) + guard case .some(.ok(let code)) = outcome else { + Issue.record("expected .ok") + return + } + #expect(code == 5) + #expect(try jsGenericOptionalRoundTrip(Optional.none) == nil) + #expect(try jsGenericDictRoundTrip(["x": 1, "y": 2]) == ["x": 1, "y": 2]) + #expect(try jsGenericDictRoundTrip([String: String]()) == [:]) + } + + @Test func genericRoundTripEnums() throws { + #expect(try jsGenericRoundTrip(GenericRTColor.red) == .red) + #expect(try jsGenericRoundTrip(GenericRTColor.blue) == .blue) + #expect(try jsGenericRoundTrip(GenericRTMode.dark) == .dark) + #expect(try jsGenericRoundTrip(GenericRTMode.light).rawValue == "light") + #expect(try jsGenericRoundTrip(GenericRTLevel.high) == .high) + let outcome = try jsGenericRoundTrip(GenericRTOutcome.ok(code: 42)) + guard case .ok(let code) = outcome else { + Issue.record("expected .ok") + return + } + #expect(code == 42) + let failure = try jsGenericRoundTrip(GenericRTOutcome.fail(message: "boom")) + guard case .fail(let message) = failure else { + Issue.record("expected .fail") + return + } + #expect(message == "boom") + } + + @Test func genericRoundTripStruct() throws { + let point = try jsGenericRoundTrip(GenericRTPoint(x: 1, y: 2)) + #expect(point.x == 1) + #expect(point.y == 2) + } + + @Test func genericRoundTripNestedStruct() throws { + let metadata = try jsGenericRoundTrip(GenericRTNamespace.Metadata(label: "alpha", count: 7)) + #expect(metadata.label == "alpha") + #expect(metadata.count == 7) + } + + @Test func genericParse() throws { + let point: GenericRTPoint = try jsGenericParsePoint("{\"x\": 10, \"y\": 20}") + #expect(point.x == 10) + #expect(point.y == 20) + let n: Int = try jsGenericParsePoint("42") + #expect(n == 42) + let string: String = try jsGenericParsePoint("\"hi\"") + #expect(string == "hi") + } + + @Test func genericPickFirstMultiUse() throws { + #expect(try jsImportPickFirst(10, 20) as Int == 10) + #expect(try jsImportPickFirst("a", "b") as String == "a") + let firstPoint = try jsImportPickFirst(GenericRTPoint(x: 1, y: 2), GenericRTPoint(x: 3, y: 4)) + #expect(firstPoint.x == 1) + #expect(firstPoint.y == 2) + } + + @Test func genericMakeReturnOnly() throws { + let made: Int = try jsImportMakeInt() + #expect(made == 123) + } + + @Test func genericCombineSecondMultiParameter() throws { + #expect(try jsImportCombineSecond(7, "hello") as String == "hello") + #expect(try jsImportCombineSecond("x", 9) as Int == 9) + let point = try jsImportCombineSecond(42, GenericRTPoint(x: 5, y: 6)) + #expect(point.x == 5) + #expect(point.y == 6) + } + + @Test func genericRoundTripHeapObjectClass() throws { + let box = ImportGenericBox(value: 314) + #expect(box.get() == 314) + let sameBox = try jsGenericRoundTripClass(box) + #expect(sameBox.get() == 314) + sameBox.value = 271 + #expect(box.get() == 271) + } + + @Test func genericMixedConsecutiveCalls() throws { + #expect(try jsGenericRoundTrip(1) == 1) + #expect(try jsGenericRoundTrip("two") == "two") + #expect(try jsGenericRoundTrip(3.0) == 3.0) + let p = try jsGenericRoundTrip(GenericRTPoint(x: 4, y: 5)) + #expect(p.x == 4) + #expect(p.y == 5) + } + + @Test func importGenericInstanceMethod() throws { + let consumer = try ImportGenericConsumer() + #expect(try consumer.identity(42) == 42) + #expect(try consumer.identity(-7) == -7) + #expect(try consumer.identity("hi") == "hi") + #expect(try consumer.identity(true) == true) + #expect(try consumer.identity(false) == false) + let point = try consumer.identity(GenericRTPoint(x: 3, y: 4)) + #expect(point.x == 3) + #expect(point.y == 4) + } + + /// A generic parameter shares the stacks with any other stack-lowered + /// parameter, so both have to arrive in declaration order. + @Test func genericAlongsideOptionalArray() throws { + #expect(try jsGenericAfterOptionalArray([1, 2], 42) == "[1,2]|42") + #expect(try jsGenericAfterOptionalArray([1, 2], GenericRTPoint(x: 3, y: 4)) == #"[1,2]|{"x":3,"y":4}"#) + #expect(try jsGenericAfterOptionalArray(nil, "x") == #"null|"x""#) + } + + @Test func genericImportPropagatesJSException() throws { + #expect(try jsGenericThrowOrRoundTrip(false, 42) == 42) + #expect(try jsGenericThrowOrRoundTrip(false, GenericRTPoint(x: 1, y: 2)).x == 1) + do { + let _: Int = try jsGenericThrowOrRoundTrip(true, 0) + Issue.record("Expected exception") + } catch { + #expect(error.description.contains("TestError")) + } + // A throwing generic call must not strand its argument on the shared + // stack: the next call has to read its own value back. + #expect(try jsGenericThrowOrRoundTrip(false, GenericRTPoint(x: 7, y: 8)).y == 8) + } + + @Test func importGenericConstructor() throws { + let boxedInt = try ImportGenericBoxed(42) + #expect(try boxedInt.unwrap() == 42) + let boxedText = try ImportGenericBoxed("boxed") + #expect(try boxedText.unwrap() == "boxed") + let boxedPoint = try ImportGenericBoxed(GenericRTPoint(x: 1, y: 2)) + let point: GenericRTPoint = try boxedPoint.unwrap() + #expect(point.x == 1) + #expect(point.y == 2) + } + + @Test func importGenericStaticMethod() throws { + #expect(try ImportGenericConsumer.box(7) == 7) + #expect(try ImportGenericConsumer.box("s") == "s") + #expect(try ImportGenericConsumer.box(true) == true) + let color = try ImportGenericConsumer.box(GenericRTColor.green) + #expect(color == .green) + } +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 42a0e3ea4..7dc6ad82f 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -161,6 +161,38 @@ export async function setupOptions(options, context) { jsJoinOptionalStructThenArray: joinStackParams, jsJoinEnumThenArray: joinStackParams, jsJoinStringThenStackParams: joinStackParams, + jsGenericRoundTrip: (v) => v, + jsGenericRoundTripClass: (v) => v, + jsGenericParsePoint: (json) => JSON.parse(json), + jsImportPickFirst: (a, b) => a, + jsImportMakeInt: () => 123, + jsImportCombineSecond: (a, b) => b, + jsGenericThrowOrRoundTrip: (shouldThrow, v) => { + if (shouldThrow) { + throw new Error("TestError"); + } + return v; + }, + jsGenericArrayRoundTrip: (v) => v, + jsGenericOptionalRoundTrip: (v) => v, + jsGenericDictRoundTrip: (v) => v, + jsGenericAfterOptionalArray: (a, b) => `${JSON.stringify(a)}|${JSON.stringify(b)}`, + ImportGenericConsumer: class { + identity(value) { + return value; + } + static box(value) { + return value; + } + }, + ImportGenericBoxed: class { + constructor(value) { + this.value = value; + } + unwrap() { + return this.value; + } + }, roundTripArrayMembers: (value) => { return value; },