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..830d87cdd 100644 --- a/Examples/Embedded/Sources/EmbeddedApp/main.swift +++ b/Examples/Embedded/Sources/EmbeddedApp/main.swift @@ -1,5 +1,15 @@ import JavaScriptKit +// BridgeJS generic imports work under Embedded Swift: `echoValue` is +// implemented in JavaScript (see index.html) and a single piece of generated +// glue serves every conforming type, selected by a runtime type ID. +@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 +56,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..7b7a2376d 100644 --- a/Examples/Embedded/index.html +++ b/Examples/Embedded/index.html @@ -8,7 +8,14 @@ diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 37b024346..87735bd5f 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..de8a7054c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -91,6 +91,17 @@ public class ExportSwift { } } + withSpan("Render Generic Bridgeable Conformances") { [self] in + // Emitted unconditionally: a module cannot know whether a dependent + // module declares a generic imported function that will be called + // with one of this module's types, so every bridgeable `@JS` type + // must conform to `BridgedSwiftGenericBridgeable`. + 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 +886,73 @@ 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`. +/// +/// The conformance gives each type a unique `BridgeJSTypeHandle`; the handle +/// object's address is the type's runtime type ID (pointer identity, so it is +/// unique across all linked modules without relying on type names). +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 per-module type-handle registration function. +/// +/// The function is exported from the wasm module as +/// `bjs__register_type_handles`. When the JS glue calls it during +/// initialization, it lowers the `bridgeJSTypeID` of every registered type into +/// a buffer — in the canonical order defined by +/// `BridgeJSSkeleton.typeRegistrationEntries` — and calls the JS import hook of +/// the same name with `(base, count)`. The JS side emits its codec array in the +/// same canonical order and pairs the two up index-by-index, so a type ID maps +/// to its codec without any string-based lookup. +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 +974,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 +990,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 +1023,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 +1682,32 @@ 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 } } + /// Wrapped generic values bridge through the same `Array`/`Optional`/`Dictionary` + /// conditional conformances that concrete types use. + var genericStackPopExpression: String? { + switch self { + case .generic(let name): return "\(name).bridgeJSStackPop()" + case .array(.generic(let name)): return "Array<\(name)>.bridgeJSStackPop()" + case .nullable(.generic(let name), _): return "Optional<\(name)>.bridgeJSStackPop()" + case .dictionary(.generic(let name)): return "Dictionary.bridgeJSStackPop()" + default: return nil + } + } + + func genericStackPushStatement(value: String) -> String? { + switch self { + case .generic, .array(.generic), .nullable(.generic, _), .dictionary(.generic): + return "\(value).bridgeJSStackPush()" + default: return nil + } + } + var swiftType: String { switch self { case .bool: return "Bool" @@ -1631,6 +1737,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 +1824,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 +1881,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 7a37b17f0..881aa8445 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 { @@ -241,6 +246,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) @@ -297,14 +314,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)") @@ -363,7 +384,8 @@ public struct ImportTS { name: String, parameters: [Parameter], returnType: BridgeType, - effects: Effects + effects: Effects, + genericParameters: [String] = [] ) -> DeclSyntax { let printer = CodeFragmentPrinter() let signature = SwiftSignatureBuilder.buildFunctionSignature( @@ -372,7 +394,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) } @@ -432,6 +459,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()) @@ -440,7 +468,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)) ] @@ -461,6 +490,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()) @@ -469,7 +499,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 ) ] } @@ -485,6 +516,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()) @@ -493,7 +525,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 ) ] } @@ -959,6 +992,8 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: []) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching loweringParameterInfo") + case .generic: + return LoweringParameterInfo(loweredParameters: []) } } @@ -1033,6 +1068,8 @@ extension BridgeType { return LiftingReturnInfo(valueToLift: nil) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching liftingReturnInfo") + case .generic: + return LiftingReturnInfo(valueToLift: nil) } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 5b5155fdc..0ffacf3b1 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: @@ -672,6 +745,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 { @@ -1143,10 +1221,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 @@ -1231,6 +1305,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) @@ -1653,6 +1736,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, @@ -1662,7 +1746,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) @@ -2914,21 +2999,84 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } + var genericParameterNames: [String] = [] + if let genericClause = node.genericParameterClause { + for genericParam in genericClause.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 node.genericWhereClause != nil { + errors.append( + DiagnosticError( + node: node, + message: "'where' clauses are not supported on @JSFunction declarations." + ) + ) + return nil + } + let baseName = SwiftToSkeleton.normalizeIdentifier(node.name.text) let jsName = AttributeChecker.extractJSName(from: jsFunction) let from = AttributeChecker.extractJSImportFrom(from: jsFunction) 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, @@ -2938,7 +3086,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { returnType: returnType, effects: effects, documentation: nil, - accessLevel: accessLevel + accessLevel: accessLevel, + genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames ) } @@ -3014,7 +3163,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) { @@ -3026,7 +3194,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 4706b14a4..adab26232 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -30,6 +30,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 @@ -308,7 +312,7 @@ public struct BridgeJSLink { } private func generateVariableDeclarations() -> [String] { - return [ + var declarations: [String] = [ "let \(JSGlueVariableScope.reservedInstance);", "let \(JSGlueVariableScope.reservedMemory);", "let \(JSGlueVariableScope.reservedSetException);", @@ -332,10 +336,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 @@ -372,6 +402,89 @@ 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. + /// + /// Every module whose generated Swift emits a registration function (any + /// module with bridgeable `@JS` types or generic imports) carries a wasm + /// import for the hook, so a hook must always be installed. When no linked + /// module declares a generic function, the whole generic runtime is omitted + /// and the hooks are no-ops (the registration exports are 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 } @@ -541,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. @@ -1020,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));" ] @@ -1057,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;", ]) } @@ -1190,6 +1305,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: [ @@ -1362,8 +1490,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) } @@ -1578,6 +1707,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 { @@ -2370,6 +2503,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( @@ -2395,7 +2530,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 { @@ -2412,6 +2576,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) @@ -2488,6 +2662,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 { @@ -3456,18 +3649,21 @@ 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 importRootExpr = function.from == .global ? "globalThis" : "imports" try thunkBuilder.call(name: jsName, fromObjectExpr: importRootExpr) 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));" ] ) } @@ -3555,8 +3751,9 @@ extension BridgeJSLink { } 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) } } @@ -3635,9 +3832,11 @@ extension BridgeJSLink { returnType: method.returnType, intrinsicRegistry: intrinsicRegistry ) - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = method.genericParameters ?? [] + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: genericParameters + ) let importRootExpr = context.from == .global ? "globalThis" : "imports" let constructorExpr = ImportedThunkBuilder.propertyAccessExpr( objectExpr: importRootExpr, @@ -3659,9 +3858,11 @@ extension BridgeJSLink { intrinsicRegistry: intrinsicRegistry ) thunkBuilder.liftSelf() - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = method.genericParameters ?? [] + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: genericParameters + ) try thunkBuilder.callMethod(name: method.jsName ?? method.name) let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context)) @@ -4005,6 +4206,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 8ef7bbeb4..4d19994c5 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,274 @@ 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, _): return "\(ContainerCodecJS.optionalCodec)(\(codec))" + 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 shape's stack ABI (`[T]`, `T?`, `[String: T]`) is described +/// exactly once, by a combinator emitted into the generated module, and is +/// instantiated with an element codec by both the generic and the non-generic +/// bridging paths. The combinators and the primitive codec table are emitted +/// lazily through the intrinsic registry, so modules that bridge no containers +/// pay nothing for them. +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 +959,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 +1045,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 +1081,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 +1098,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 +1108,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("}") - if isStackConvention { - scope.emitPushI32Parameter("+\(isSomeVar)", printer: printer) - return [] - } else { - return ["+\(isSomeVar)"] + resultVars - } + return ["+\(isSomeVar)"] + resultVars } ) } @@ -848,6 +1126,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 +1141,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 +1218,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 +1232,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 +1372,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 +1505,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 +1581,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 @@ -1817,133 +2041,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) } @@ -2070,7 +2222,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) } @@ -2191,43 +2343,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 @@ -2235,23 +2371,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 [] } ) @@ -2622,7 +2744,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 @@ -2720,7 +2842,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 7f45b6c39..58c7cbc79 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,131 @@ 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`, + /// in a canonical order. + /// + /// This order is the shared contract between the Swift codegen (which emits + /// the type-handle registration function lowering `bridgeJSTypeID`s in this + /// order) and the JS link layer (which emits the module's codec array in the + /// same order). Both sides derive it from the same skeleton, so the two + /// arrays always line up index-by-index. + 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 full, ordered list of types this module registers type handles for, or + /// `nil` when the module does not emit a registration function. + /// + /// Every module that defines bridgeable `@JS` types registers them (a module + /// cannot know whether a dependent module will pass its types to a generic + /// function). Primitives are included in every module's list: their handles + /// are singletons living in the JavaScriptKit library, so repeated + /// registration writes the same ID-to-codec pair. Modules that declare + /// generic imports but export no types still register the primitives so a + /// pure-import build has a populated codec 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 +1031,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 +1042,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 +1054,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { self.namespace = namespace self.identityMode = identityMode self.documentation = documentation + self.isFinal = isFinal } } @@ -1144,6 +1278,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, @@ -1153,7 +1290,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 @@ -1163,10 +1301,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 { @@ -1179,6 +1318,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 { @@ -1453,6 +1593,16 @@ 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) + } + } +} + public struct ImportedModuleSkeleton: Codable { public var children: [ImportedFileSkeleton] @@ -1461,6 +1611,12 @@ public struct ImportedModuleSkeleton: Codable { } } +extension ImportedModuleSkeleton { + public var hasGenericDeclarations: Bool { + children.contains { $0.hasGenericDeclarations } + } +} + // MARK: - Closure signature collection visitor public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { @@ -1635,7 +1791,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 } } @@ -1682,6 +1838,8 @@ extension BridgeType { return nil case .alias(_, let underlying): return underlying.abiReturnType + case .generic: + return nil } } @@ -1773,6 +1931,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 fa8a0a273..8657f9b39 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -234,9 +234,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 4a58f1972..9475ec5a2 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 8b8e8b8a2..588142895 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -40,6 +40,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 2f3f46fdb..c613e5730 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -126,6 +126,99 @@ 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. + func makeSkeleton(moduleName: String, source: String) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: moduleName, + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "\(moduleName).swift") + return try swiftAPI.finalize() + } + let structSource = """ + @JS public struct Point { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """ + let first = try makeSkeleton( + moduleName: "FirstModule", + source: structSource + """ + + @JSFunction func identity(_ value: T) throws(JSException) -> T + """ + ) + let second = try makeSkeleton(moduleName: "SecondModule", source: structSource) + 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 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/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..94f80c7f1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift @@ -0,0 +1,146 @@ +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(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..ae2444ed9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift @@ -0,0 +1,20 @@ +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\"]();")) + } +} 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..2075de6f9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift @@ -0,0 +1,58 @@ +@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] + +@JSClass struct GenericConsumer { + @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 38cc900ae..b6e4be5a7 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 a058d13a7..2b1a19d25 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 661fbd3a5..1115e5d7d 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 _ = value.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 7ceb8cfe3..a64677e5c 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 (valueIsSome, valueCaseId) = value.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 eaed9e413..e2b83ed2f 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 5e1db5c72..0d5a03586 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 3487ad425..6e1a1be80 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..5955d1c96 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json @@ -0,0 +1,557 @@ +{ + "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" + } + } + } + } + } + ], + "types" : [ + { + "accessLevel" : "internal", + "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..71fc2798c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift @@ -0,0 +1,451 @@ +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] { + values.bridgeJSStackPush() + bjs_importGenericArray(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Array.bridgeJSStackPop() +} + +#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] { + values.bridgeJSStackPush() + bjs_importGenericDictionary(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Dictionary.bridgeJSStackPop() +} + +#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_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 { + let selfValue = self.bridgeJSLowerParameter() + value.bridgeJSStackPush() + 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 { + let selfValue = self.bridgeJSLowerParameter() + value.bridgeJSStackPush() + 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 e8df6c966..f13d27375 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 f8f2c76a0..96e68eebb 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 valueCaseId = value.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 9f671c711..503a40043 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -619,4 +619,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 cec50ffca..e62c9deeb 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(_ point: Int32, _ dx: Int32, _ dy: Int32) -> Int32 @@ -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 680da9c5e..439417168 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; @@ -341,18 +563,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); @@ -360,18 +571,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); @@ -379,13 +588,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); @@ -393,13 +596,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); @@ -644,63 +850,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 b7f67fe15..c9800f3cd 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..e81c0737d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts @@ -0,0 +1,81 @@ +// 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 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; + 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..419fb244e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -0,0 +1,896 @@ +// 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_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 5d1e2c4dc..b88c5b62e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.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/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 2ad7251f8..33b0361f4 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); 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/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 f3b9d987c..86153cc10 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; @@ -864,32 +1086,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 14ddf714e..0d489105f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -89,5 +89,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 44ae8a39d..6473a3b5f 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) { @@ -375,6 +655,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 523861b9a..7af56d4c3 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; @@ -243,11 +554,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..4e3ed3a1e 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,20 @@ 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); + // Note: `afterInitialize` is intentionally not called here; per-thread + // instantiator state is initialized lazily on first use instead. + const { instantiator, ...result } = await _instantiate(options); /* #if IS_WASI */ options.wasi.setInstance(result.instance); /* #endif */ @@ -102,7 +107,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 +189,6 @@ async function _instantiate(options) { instance, swift, exports, + instantiator, }; } diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index a07ca0152..71e231957 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -204,6 +204,79 @@ extension _BridgedSwiftStackType { } } +/// Types that can be used as the generic argument of a generic imported +/// `@JSFunction` (`func parse(...)`). +/// +/// Each conforming type owns a unique ``BridgeJSTypeHandle`` whose object +/// identity (its pointer) is the type's runtime type ID. The generated bridge +/// passes that ID across the boundary so type-agnostic JS glue can select the +/// matching 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. Conforming types store the result in + /// their `bridgeJSTypeHandle` static property. + /// + /// This factory exists so conformances compile under Embedded Swift too: + /// `BridgeJSTypeHandle`'s memberwise initializer takes a metatype + /// existential (unavailable under Embedded), and Embedded also forbids + /// generic class initializers, while a generic static function like this is + /// statically specialized and allowed. + @_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. +/// +/// Every `BridgedSwiftGenericBridgeable` type has exactly one handle instance +/// (a `static let` on the conforming type), so the handle's pointer uniquely +/// identifies the type at runtime without relying on type-name strings, which +/// would be fragile and could collide across modules. +/// +/// On the import path the handle is only an identity token: the Swift side is +/// statically specialized, so nothing ever needs to be recovered from the ID. +/// Exported generic entry points (planned follow-up) additionally need to +/// recover the concrete type from an incoming ID via +/// `Unmanaged.fromOpaque(...).takeUnretainedValue().type`. +/// That `type` storage is a metatype existential, which Embedded Swift does not +/// support, so it is compiled out under Embedded; generic imports (the only +/// generics feature available under Embedded) never touch it. +public final class BridgeJSTypeHandle: Sendable { + #if hasFeature(Embedded) + public init() {} + #else + /// The conforming type this handle identifies. Only needed by exported + /// generic entry points to map an incoming type ID back to a Swift type. + public let type: any BridgedSwiftGenericBridgeable.Type + + public init(_ type: any BridgedSwiftGenericBridgeable.Type) { + self.type = type + } + #endif + + /// The runtime type ID for this handle: the handle object's own address. + /// + /// Pointers are 32-bit on wasm32, so the address always fits in `Int32`. + @_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 +881,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 +1030,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/BridgeJS-Internals/Design-Rationale.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Internals/Design-Rationale.md index 8bfc5d302..7e945ecf8 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Internals/Design-Rationale.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Internals/Design-Rationale.md @@ -32,6 +32,14 @@ So even if you cache the property name (e.g. with `CachedJSStrings`), you are st BridgeJS avoids this by generating **separate** access paths per property or method. Each generated getter/setter or function call has a stable shape at the engine level, so the IC can stay monomorphic or polymorphic and the fast path is used. +## Generic imports + +An imported generic `@JSFunction` (`func parse(...)`) lets one piece of glue serve many concrete types. The generic value crosses using the type's own stack ABI, and a runtime type ID selects the matching JS codec, so the type-agnostic glue can lower and lift the right representation without a specialized path per call site. + +Type identity is pointer-based rather than name-based: every conforming type owns a unique `BridgeJSTypeHandle` instance, and the handle object's address is the type ID. This makes IDs unique across all linked modules for free (type-name strings would be fragile and could collide). During initialization each module's `bjs__register_type_handles` export lowers its handle IDs — in a canonical order shared with the JS glue — and the glue pairs them index-by-index with its codec array, so a generic call site resolves its codec with a single map lookup. Because this path avoids existentials entirely, it also works under Embedded Swift; the Embedded example (`Examples/Embedded`) exercises a generic import, including a `@JS struct` round-trip. + +Generic functions on exported `@JS` declarations are a planned follow-up that will reuse the same stack ABI and codec table with the dispatch reversed. + ## What to read next - ABI and binary interface details will be documented in this section as they stabilize. 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 64475acfa..7d5d03de7 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 @@ -41,11 +41,52 @@ If you used `from: .global`, do not pass the function in `getImports()`; the run 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`. The concrete type chosen at the call site then crosses the bridge: + +```swift +@JSFunction func parse(_ json: String) throws(JSException) -> T + +let user: User = try parse(jsonString) +``` + +`T` must be a bridgeable type: a supported primitive (`Bool`, any fixed-width integer such as `Int`/`UInt`/`Int8`…`UInt64`, `Float`, `Double`, `String`, or `JSValue`), or a `@JS` struct, `final @JS class`, or `@JS enum`. You do not write any conformance yourself; marking a type `@JS` makes it usable as `T` (see ). Generics are not supported for `async` functions or `where` clauses (see ). + +A generic type parameter may be used in more than one parameter, an imported function may declare more than one distinct generic parameter, and a generic result type may be used on a function that takes no generic parameters (the JavaScript implementation produces the value): + +```swift +@JSFunction func pickFirst(_ a: T, _ b: T) throws(JSException) -> T + +@JSFunction func makeValue() throws(JSException) -> T + +@JSFunction func combine(_ a: T, _ b: U) throws(JSException) -> U +``` + +The generic parameter may also be wrapped as `[T]`, `T?`, or `[String: T]` in parameters and the result: + +```swift +@JSFunction func roundTrip(_ values: [T]) throws(JSException) -> [T] + +@JSFunction func lookup(_ values: [String: T]) throws(JSException) -> T? +``` + +### Generic methods on imported classes + +An imported `@JSClass` type can also have generic methods, both instance and static. The same constraint applies. The Swift to JavaScript bridge resolves the concrete type through an internal type id, and the JavaScript implementation is called with only the method's declared arguments: + +```swift +@JSClass struct Store { + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) throws(JSException) -> T +} +``` + ## 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..d2437907d 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md @@ -31,6 +31,18 @@ When using `JSTypedArray` (or convenience typealiases) in `@JS` signatures, t See for usage details. +## Generic type parameters + +A generic type parameter constrained to `BridgedSwiftGenericBridgeable` is supported as a parameter or result type of an imported `@JSFunction` (see ). Generic parameters on exported `@JS` functions are not supported yet. The types that satisfy that constraint are: + +- `Bool`, `Float`, `Double`, `String`, and `JSValue` +- every fixed-width integer: `Int`, `UInt`, `Int8`/`Int16`/`Int32`/`Int64`, and `UInt8`/`UInt16`/`UInt32`/`UInt64` +- any `@JS` struct, `final @JS class`, or `@JS enum` (case, raw-value, or associated-value), including ones defined in another linked module + +You do not write the conformance by hand: marking a type `@JS` (or using a built-in primitive) is what makes it usable as the generic argument. + +The generic parameter may be used bare (`T`) or wrapped in `[T]`, `T?`, or `[String: T]`. Other or nested wrappings (for example `[T?]`, `[[T]]`, or `[Int: T]`) are not supported. `JSObject` cannot be used as the generic argument; use `JSValue` instead. + ## See Also - diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md index 83213aca1..b5bf09eab 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md @@ -34,3 +34,15 @@ While using `@JS` types from another Swift module is supported, it is not possib ### Exporting Swift: types from another Swift package Types defined in a separate Swift package cannot yet be referenced from `@JS` declarations in your package. + +## Generics + +Generic functions are supported for imported JavaScript APIs, through a type parameter constrained to `BridgedSwiftGenericBridgeable`: an imported `@JSFunction` (see ), including instance and static methods on imported `@JSClass` types. A function may declare one or more distinct generic parameters, such as `combine(_ a: T, _ b: U) -> T`, and a return-only generic (such as `make() -> T`) is supported, where the JavaScript implementation produces the value. The following forms are not supported and produce build-time diagnostics: + +- Generic parameters on exported `@JS` functions or methods. Exported generics are a planned follow-up. +- `async` generic `@JSFunction` declarations. +- `where` clauses on a generic declaration. + +The generic parameter may be used bare (`T`) or wrapped in `[T]`, `T?`, or `[String: T]`. Nested or other wrappings, such as `[T?]`, `[[T]]`, `T??`, or `[Int: T]`, are not supported and produce build-time diagnostics. `JSObject` cannot be used as the generic argument (it is a non-final class); use `JSValue` instead. + +Generic imports work under Embedded Swift and are exercised by the Embedded example (`Examples/Embedded`). 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 a3104e685..bf686cd4f 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -5867,6 +5867,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 { @@ -6655,6 +6724,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() @@ -13017,6 +13182,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 { @@ -13334,6 +13573,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) @@ -16451,6 +16958,260 @@ func _$jsRoundTripOptionalImportedPayloadSignal(_ value: Optional.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] { + values.bridgeJSStackPush() + bjs_jsGenericArrayRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Array.bridgeJSStackPop() +} + +#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] { + values.bridgeJSStackPush() + bjs_jsGenericDictRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Dictionary.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 { + let selfValue = self.bridgeJSLowerParameter() + value.bridgeJSStackPush() + 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_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ point: Int32, _ dx: Int32, _ dy: Int32) -> Int32 @@ -17526,4 +18287,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 451a3213d..ce0d8d9ae 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", @@ -4742,6 +4746,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", @@ -10146,6 +10214,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", @@ -18190,6 +18404,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" : [ @@ -23287,6 +23577,365 @@ ] }, + { + "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" + } + } + } + } + } + ], + "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" + } + } + } + ] + } + ] + }, { "functions" : [ { diff --git a/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift new file mode 100644 index 000000000..04962a559 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift @@ -0,0 +1,233 @@ +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] + +@JSClass struct ImportGenericConsumer { + @JSFunction init() throws(JSException) + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) 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) + } + + @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 887510e65..046077f90 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -155,6 +155,23 @@ export async function setupOptions(options, context) { return { x: (point.x | 0) + (dx | 0), y: (point.y | 0) + (dy | 0) }; }, jsRoundTripOptionalPoint: (point) => point, + jsGenericRoundTrip: (v) => v, + jsGenericRoundTripClass: (v) => v, + jsGenericParsePoint: (json) => JSON.parse(json), + jsImportPickFirst: (a, b) => a, + jsImportMakeInt: () => 123, + jsImportCombineSecond: (a, b) => b, + jsGenericArrayRoundTrip: (v) => v, + jsGenericOptionalRoundTrip: (v) => v, + jsGenericDictRoundTrip: (v) => v, + ImportGenericConsumer: class { + identity(value) { + return value; + } + static box(value) { + return value; + } + }, roundTripArrayMembers: (value) => { return value; },